summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ata/atascsi.c236
1 files changed, 142 insertions, 94 deletions
diff --git a/sys/dev/ata/atascsi.c b/sys/dev/ata/atascsi.c
index 386ed3695b8..33eb01a3005 100644
--- a/sys/dev/ata/atascsi.c
+++ b/sys/dev/ata/atascsi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atascsi.c,v 1.81 2010/04/22 00:58:32 dlg Exp $ */
+/* $OpenBSD: atascsi.c,v 1.82 2010/04/23 01:39:05 dlg Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -59,8 +59,6 @@ struct atascsi_port {
};
void atascsi_cmd(struct scsi_xfer *);
-int atascsi_ioctl(struct scsi_link *, u_long, caddr_t, int,
- struct proc *);
int atascsi_probe(struct scsi_link *);
void atascsi_free(struct scsi_link *);
@@ -70,7 +68,7 @@ struct scsi_adapter atascsi_switch = {
scsi_minphys, /* scsi_minphys */
atascsi_probe, /* dev_probe */
atascsi_free, /* dev_free */
- atascsi_ioctl /* ioctl */
+ NULL, /* ioctl */
};
struct scsi_device atascsi_device = {
@@ -97,6 +95,11 @@ void atascsi_disk_sense(struct scsi_xfer *);
void atascsi_atapi_cmd(struct scsi_xfer *);
void atascsi_atapi_cmd_done(struct ata_xfer *);
+void atascsi_passthru_12(struct scsi_xfer *);
+void atascsi_passthru_16(struct scsi_xfer *);
+int atascsi_passthru_map(struct scsi_xfer *, u_int8_t, u_int8_t);
+void atascsi_passthru_done(struct ata_xfer *);
+
void atascsi_done(struct scsi_xfer *, int);
void ata_exec(struct atascsi *, struct ata_xfer *);
@@ -427,6 +430,13 @@ atascsi_disk_cmd(struct scsi_xfer *xs)
atascsi_disk_capacity16(xs);
return;
+ case ATA_PASSTHRU_12:
+ atascsi_passthru_12(xs);
+ return;
+ case ATA_PASSTHRU_16:
+ atascsi_passthru_16(xs);
+ return;
+
case TEST_UNIT_READY:
case START_STOP:
case PREVENT_ALLOW:
@@ -877,6 +887,134 @@ atascsi_disk_capacity16(struct scsi_xfer *xs)
atascsi_done(xs, XS_NOERROR);
}
+int
+atascsi_passthru_map(struct scsi_xfer *xs, u_int8_t count_proto, u_int8_t flags)
+{
+ struct ata_xfer *xa = xs->io;
+
+ xa->data = xs->data;
+ xa->datalen = xs->datalen;
+ xa->timeout = xs->timeout;
+ xa->flags = 0;
+ if (xs->flags & SCSI_DATA_IN)
+ xa->flags |= ATA_F_READ;
+ if (xs->flags & SCSI_DATA_OUT)
+ xa->flags |= ATA_F_WRITE;
+ if (xs->flags & SCSI_POLL)
+ xa->flags |= ATA_F_POLL;
+
+ switch (count_proto & ATA_PASSTHRU_PROTO_MASK) {
+ case ATA_PASSTHRU_PROTO_NON_DATA:
+ case ATA_PASSTHRU_PROTO_PIO_DATAIN:
+ case ATA_PASSTHRU_PROTO_PIO_DATAOUT:
+ xa->flags |= ATA_F_PIO;
+ break;
+ default:
+ /* we dont support this yet */
+ return (1);
+ }
+
+ xa->atascsi_private = xs;
+ xa->complete = atascsi_passthru_done;
+
+ return (0);
+}
+
+void
+atascsi_passthru_12(struct scsi_xfer *xs)
+{
+ struct scsi_link *link = xs->sc_link;
+ struct atascsi *as = link->adapter_softc;
+ struct ata_xfer *xa = xs->io;
+ struct scsi_ata_passthru_12 *cdb;
+ struct ata_fis_h2d *fis;
+
+ cdb = (struct scsi_ata_passthru_12 *)xs->cmd;
+ /* validate cdb */
+
+ if (atascsi_passthru_map(xs, cdb->count_proto, cdb->flags) != 0) {
+ atascsi_done(xs, XS_DRIVER_STUFFUP);
+ return;
+ }
+
+ fis = xa->fis;
+ fis->flags = ATA_H2D_FLAGS_CMD;
+ fis->command = cdb->command;
+ fis->features = cdb->features;
+ fis->lba_low = cdb->lba_low;
+ fis->lba_mid = cdb->lba_mid;
+ fis->lba_high = cdb->lba_high;
+ fis->device = cdb->device;
+ fis->sector_count = cdb->sector_count;
+
+ ata_exec(as, xa);
+}
+
+void
+atascsi_passthru_16(struct scsi_xfer *xs)
+{
+ struct scsi_link *link = xs->sc_link;
+ struct atascsi *as = link->adapter_softc;
+ struct ata_xfer *xa = xs->io;
+ struct scsi_ata_passthru_16 *cdb;
+ struct ata_fis_h2d *fis;
+
+ cdb = (struct scsi_ata_passthru_16 *)xs->cmd;
+ /* validate cdb */
+
+ if (atascsi_passthru_map(xs, cdb->count_proto, cdb->flags) != 0) {
+ atascsi_done(xs, XS_DRIVER_STUFFUP);
+ return;
+ }
+
+ fis = xa->fis;
+ fis->flags = ATA_H2D_FLAGS_CMD;
+ fis->command = cdb->command;
+ fis->features = cdb->features[1];
+ fis->lba_low = cdb->lba_low[1];
+ fis->lba_mid = cdb->lba_mid[1];
+ fis->lba_high = cdb->lba_high[1];
+ fis->device = cdb->device;
+ fis->lba_low_exp = cdb->lba_low[0];
+ fis->lba_mid_exp = cdb->lba_mid[0];
+ fis->lba_high_exp = cdb->lba_high[0];
+ fis->features_exp = cdb->features[0];
+ fis->sector_count = cdb->sector_count[1];
+ fis->sector_count_exp = cdb->sector_count[0];
+
+ ata_exec(as, xa);
+}
+
+void
+atascsi_passthru_done(struct ata_xfer *xa)
+{
+ struct scsi_xfer *xs = xa->atascsi_private;
+
+ /*
+ * XXX need to generate sense if cdb wants it
+ */
+
+ switch (xa->state) {
+ case ATA_S_COMPLETE:
+ xs->error = XS_NOERROR;
+ break;
+ case ATA_S_ERROR:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ case ATA_S_TIMEOUT:
+ printf("atascsi_passthru_done, timeout\n");
+ xs->error = XS_TIMEOUT;
+ break;
+ default:
+ panic("atascsi_atapi_cmd_done: unexpected ata_xfer state (%d)",
+ xa->state);
+ }
+
+ xs->resid = xa->resid;
+
+ scsi_done(xs);
+}
+
void
atascsi_disk_sense(struct scsi_xfer *xs)
{
@@ -981,96 +1119,6 @@ atascsi_done(struct scsi_xfer *xs, int error)
splx(s);
}
-int atascsi_ioctl_cmd(struct atascsi *, struct atascsi_port *, atareq_t *);
-void atascsi_ioctl_done(struct ata_xfer *);
-
-int
-atascsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flags,
- struct proc *p)
-{
- struct atascsi *as = link->adapter_softc;
- struct atascsi_port *ap = as->as_ports[link->target];
-
- switch (cmd) {
- case ATAIOCCOMMAND:
- return (atascsi_ioctl_cmd(as, ap, (atareq_t *)addr));
- default:
- return (ENOTTY);
- }
-}
-
-int
-atascsi_ioctl_cmd(struct atascsi *as, struct atascsi_port *ap, atareq_t *atareq)
-{
- struct ata_xfer *xa;
- struct ata_fis_h2d *fis;
- void *buf;
- int rc = 0;
- int s;
-
- xa = scsi_io_get(&ap->ap_iopool, 0);
-
- fis = xa->fis;
- fis->flags = ATA_H2D_FLAGS_CMD;
- fis->command = atareq->command;
- fis->features = atareq->features;
- fis->lba_low = atareq->sec_num;
- fis->lba_mid = atareq->cylinder;
- fis->lba_high = atareq->cylinder >> 8;
- fis->device = atareq->head & 0x0f;
- fis->sector_count = atareq->sec_count;
-
- buf = malloc(atareq->datalen, M_TEMP, M_WAITOK);
-
- xa->data = buf;
- xa->datalen = atareq->datalen;
- xa->complete = atascsi_ioctl_done;
- xa->timeout = atareq->timeout;
- xa->flags = 0;
- if (atareq->flags & ATACMD_READ)
- xa->flags |= ATA_F_READ;
- if (atareq->flags & ATACMD_WRITE) {
- xa->flags |= ATA_F_WRITE;
- copyin(atareq->databuf, buf, atareq->datalen);
- }
- xa->atascsi_private = NULL;
-
- as->as_methods->ata_cmd(xa);
- s = splbio();
- while (!ISSET(xa->flags, ATA_F_DONE))
- tsleep(xa, PRIBIO, "atascsi", 0);
- splx(s);
-
- switch (xa->state) {
- case ATA_S_COMPLETE:
- atareq->retsts = ATACMD_OK;
- if (atareq->flags & ATACMD_READ)
- rc = copyout(buf, atareq->databuf, atareq->datalen);
- break;
- case ATA_S_ERROR:
- atareq->retsts = ATACMD_ERROR;
- break;
- case ATA_S_TIMEOUT:
- atareq->retsts = ATACMD_TIMEOUT;
- break;
- default:
- panic("atascsi_ioctl_cmd: unexpected ata_xfer state (%d)",
- xa->state);
- }
-
- free(buf, M_TEMP);
-
- scsi_io_put(&ap->ap_iopool, xa);
-
- return (rc);
-}
-
-void
-atascsi_ioctl_done(struct ata_xfer *xa)
-{
- wakeup(xa);
-}
-
void
ata_exec(struct atascsi *as, struct ata_xfer *xa)
{