summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ata/atascsi.c323
-rw-r--r--sys/dev/ata/atascsi.h5
2 files changed, 113 insertions, 215 deletions
diff --git a/sys/dev/ata/atascsi.c b/sys/dev/ata/atascsi.c
index a5002ba9c72..264166eaba2 100644
--- a/sys/dev/ata/atascsi.c
+++ b/sys/dev/ata/atascsi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atascsi.c,v 1.50 2007/11/28 13:47:09 dlg Exp $ */
+/* $OpenBSD: atascsi.c,v 1.51 2007/11/28 18:16:07 dlg Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -68,30 +68,23 @@ struct scsi_device atascsi_device = {
NULL, NULL, NULL, NULL
};
-struct ata_xfer *ata_setup_identify(struct ata_port *, int);
-void ata_free_identify(struct ata_xfer *);
-void ata_complete_identify(struct ata_xfer *,
- struct ata_identify *);
+void ata_fix_identify(struct ata_identify *);
int atascsi_disk_cmd(struct scsi_xfer *);
void atascsi_disk_cmd_done(struct ata_xfer *);
int atascsi_disk_inq(struct scsi_xfer *);
-void atascsi_disk_inq_done(struct ata_xfer *);
-void atascsi_disk_serial_done(struct ata_xfer *);
+int atascsi_disk_inquiry(struct scsi_xfer *);
+int atascsi_disk_serial(struct scsi_xfer *);
int atascsi_disk_capacity(struct scsi_xfer *);
-void atascsi_disk_capacity_done(struct ata_xfer *);
int atascsi_disk_sync(struct scsi_xfer *);
void atascsi_disk_sync_done(struct ata_xfer *);
int atascsi_disk_sense(struct scsi_xfer *);
-void atascsi_empty_done(struct ata_xfer *);
-
int atascsi_atapi_cmd(struct scsi_xfer *);
void atascsi_atapi_cmd_done(struct ata_xfer *);
int atascsi_stuffup(struct scsi_xfer *);
-
int ata_running = 0;
int ata_exec(struct atascsi *, struct ata_xfer *);
@@ -173,6 +166,7 @@ atascsi_probe(struct scsi_link *link)
struct ata_port *ap;
struct ata_xfer *xa;
int port, type;
+ int rv;
/* revisit this when we do port multipliers */
if (link->lun > 0)
@@ -191,7 +185,8 @@ atascsi_probe(struct scsi_link *link)
as->as_link.quirks |= SDEV_ONLYBIG;
break;
default:
- return (ENODEV);
+ rv = ENODEV;
+ goto unsupported;
}
ap = malloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO);
@@ -199,11 +194,26 @@ atascsi_probe(struct scsi_link *link)
ap->ap_port = port;
ap->ap_type = type;
- as->as_ports[port] = ap;
-
+ /* fetch the device info */
xa = ata_get_xfer(ap, 1);
if (xa == NULL)
- return (EBUSY);
+ panic("no free xfers on a new port");
+ xa->data = &ap->ap_identify;
+ xa->datalen = sizeof(ap->ap_identify);
+ xa->fis->flags = ATA_H2D_FLAGS_CMD;
+ xa->fis->command = ATA_C_IDENTIFY;
+ xa->fis->device = 0;
+ xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL;
+ xa->complete = ata_put_xfer;
+ xa->timeout = 1000;
+ if (ata_exec(as, xa) != COMPLETE) {
+ rv = EIO;
+ goto error;
+ }
+
+ ata_fix_identify(&ap->ap_identify);
+
+ as->as_ports[port] = ap;
/*
* FREEZE LOCK the device so malicous users can't lock it on us.
@@ -212,14 +222,22 @@ atascsi_probe(struct scsi_link *link)
* checking if the device sends a command abort to tell us it doesn't
* support it
*/
+ xa = ata_get_xfer(ap, 1);
+ if (xa == NULL)
+ panic("no free xfers on a new port");
xa->fis->command = ATA_C_SEC_FREEZE_LOCK;
xa->fis->flags = ATA_H2D_FLAGS_CMD;
- xa->complete = atascsi_empty_done;
- xa->flags = ATA_F_POLL | ATA_F_PIO;
+ xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL;
+ xa->complete = ata_put_xfer;
xa->timeout = 1000;
- ata_exec(as, xa);
+ ata_exec(as, xa); /* we dont care if this works or not */
return (0);
+error:
+ free(ap, M_DEVBUF);
+unsupported:
+ as->as_methods->free(as->as_cookie, port);
+ return (rv);
}
void
@@ -246,49 +264,12 @@ atascsi_free(struct scsi_link *link)
as->as_methods->free(as->as_cookie, port);
}
-struct ata_xfer *
-ata_setup_identify(struct ata_port *ap, int nosleep)
-{
- struct ata_xfer *xa;
-
- xa = ata_get_xfer(ap, nosleep);
- if (xa == NULL)
- return (NULL);
-
- xa->data = malloc(512, M_TEMP, nosleep ? (M_NOWAIT | M_ZERO) :
- (M_WAITOK | M_ZERO));
- if (xa->data == NULL) {
- xa->state = ATA_S_ERROR;
- ata_put_xfer(xa);
- return (NULL);
- }
- xa->datalen = 512;
-
- xa->fis->flags = ATA_H2D_FLAGS_CMD;
- xa->fis->command = ATA_C_IDENTIFY;
- xa->fis->device = 0;
-
- xa->flags = ATA_F_READ | ATA_F_PIO;
-
- return (xa);
-}
-
-void
-ata_free_identify(struct ata_xfer *xa)
-{
- free(xa->data, M_TEMP);
- ata_put_xfer(xa);
-}
-
void
-ata_complete_identify(struct ata_xfer *xa, struct ata_identify *id)
+ata_fix_identify(struct ata_identify *id)
{
u_int16_t *swap;
int i;
- bcopy(xa->data, id, sizeof(struct ata_identify));
- ata_free_identify(xa);
-
swap = (u_int16_t *)id->serial;
for (i = 0; i < sizeof(id->serial) / sizeof(u_int16_t); i++)
swap[i] = swap16(swap[i]);
@@ -431,12 +412,6 @@ atascsi_disk_cmd(struct scsi_xfer *xs)
}
void
-atascsi_empty_done(struct ata_xfer *xa)
-{
- ata_put_xfer(xa);
-}
-
-void
atascsi_disk_cmd_done(struct ata_xfer *xa)
{
struct scsi_xfer *xs = xa->atascsi_private;
@@ -467,100 +442,64 @@ atascsi_disk_cmd_done(struct ata_xfer *xa)
int
atascsi_disk_inq(struct scsi_xfer *xs)
{
- struct scsi_link *link = xs->sc_link;
- struct atascsi *as = link->adapter_softc;
- struct ata_port *ap = as->as_ports[link->target];
- struct ata_xfer *xa;
- struct scsi_inquiry *inq;
- void (*complete)(struct ata_xfer *);
+ struct scsi_inquiry *inq = (struct scsi_inquiry *)xs->cmd;
- inq = (struct scsi_inquiry *)xs->cmd;
if (ISSET(inq->flags, SI_EVPD)) {
switch (inq->pagecode) {
case SI_PG_SERIAL:
- complete = atascsi_disk_serial_done;
- break;
+ return (atascsi_disk_serial(xs));
default:
return (atascsi_stuffup(xs));
}
- } else
- complete = atascsi_disk_inq_done;
-
- xa = ata_setup_identify(ap, xs->flags & SCSI_NOSLEEP);
- if (xa == NULL)
- return (NO_CCB);
-
- xa->complete = complete;
- xa->timeout = xs->timeout;
- xa->atascsi_private = xs;
- if (xs->flags & SCSI_POLL)
- xa->flags |= ATA_F_POLL;
+ }
- return (ata_exec(as, xa));
+ return (atascsi_disk_inquiry(xs));
}
-void
-atascsi_disk_inq_done(struct ata_xfer *xa)
+int
+atascsi_disk_inquiry(struct scsi_xfer *xs)
{
- struct scsi_xfer *xs = xa->atascsi_private;
struct scsi_link *link = xs->sc_link;
struct atascsi *as = link->adapter_softc;
struct ata_port *ap = as->as_ports[link->target];
- struct ata_identify id;
struct scsi_inquiry_data inq;
- int host_ncqdepth, complete = 0;
-
- switch (xa->state) {
- case ATA_S_COMPLETE:
- ata_complete_identify(xa, &id);
+ int s;
- bzero(&inq, sizeof(inq));
+ bzero(&inq, sizeof(inq));
- inq.device = T_DIRECT;
- inq.version = 0x05; /* SPC-3 */
- inq.response_format = 2;
- inq.additional_length = 32;
- bcopy("ATA ", inq.vendor, sizeof(inq.vendor));
- bcopy(id.model, inq.product, sizeof(inq.product));
- bcopy(id.firmware, inq.revision, sizeof(inq.revision));
+ inq.device = T_DIRECT;
+ inq.version = 0x05; /* SPC-3 */
+ inq.response_format = 2;
+ inq.additional_length = 32;
+ bcopy("ATA ", inq.vendor, sizeof(inq.vendor));
+ bcopy(ap->ap_identify.model, inq.product, sizeof(inq.product));
+ bcopy(ap->ap_identify.firmware, inq.revision, sizeof(inq.revision));
- bcopy(&inq, xs->data, MIN(sizeof(inq), xs->datalen));
- xs->error = XS_NOERROR;
- complete = 1;
- break;
-
- case ATA_S_ERROR:
- case ATA_S_TIMEOUT:
- ata_free_identify(xa);
- xs->error = (xa->state == ATA_S_TIMEOUT ? XS_TIMEOUT :
- XS_DRIVER_STUFFUP);
- break;
-
- default:
- panic("atascsi_disk_inq_done: unexpected ata_xfer state (%d)",
- xa->state);
- }
+ bcopy(&inq, xs->data, MIN(sizeof(inq), xs->datalen));
+ xs->error = XS_NOERROR;
xs->flags |= ITSDONE;
+ s = splbio();
scsi_done(xs);
+ splx(s);
- if (!complete || (ap->ap_features & ATA_PORT_F_PROBED))
- return;
+ if (ap->ap_features & ATA_PORT_F_PROBED)
+ return (COMPLETE);
ap->ap_features = ATA_PORT_F_PROBED;
- if (as->as_capability & ASAA_CAP_NCQ && (letoh16(id.satacap) &
- (1 << 8))) {
+ if (as->as_capability & ASAA_CAP_NCQ &&
+ (letoh16(ap->ap_identify.satacap) & (1 << 8))) {
+ int host_ncqdepth;
/*
* At this point, openings should be the number of commands the
- * host controller supports, less the one that is outstanding
- * as a result of this inquiry, less any reserved slot the
- * host controller needs for recovery.
+ * host controller supports, less any reserved slot the host
+ * controller needs for recovery.
*/
- host_ncqdepth = link->openings + 1 + ((as->as_capability &
- ASAA_CAP_NEEDS_RESERVED) ? 1 : 0);
+ host_ncqdepth = link->openings +
+ ((as->as_capability & ASAA_CAP_NEEDS_RESERVED) ? 1 : 0);
- ap->ap_ncqdepth = (letoh16(id.qdepth) & 0x1f) + 1;
+ ap->ap_ncqdepth = (letoh16(ap->ap_identify.qdepth) & 0x1f) + 1;
/* Limit the number of openings to what the device supports. */
if (host_ncqdepth > ap->ap_ncqdepth)
@@ -580,44 +519,35 @@ atascsi_disk_inq_done(struct ata_xfer *xa)
}
}
}
+
+ return (COMPLETE);
}
-void
-atascsi_disk_serial_done(struct ata_xfer *xa)
+int
+atascsi_disk_serial(struct scsi_xfer *xs)
{
- struct scsi_xfer *xs = xa->atascsi_private;
- struct ata_identify id;
+ struct scsi_link *link = xs->sc_link;
+ struct atascsi *as = link->adapter_softc;
+ struct ata_port *ap = as->as_ports[link->target];
struct scsi_inquiry_vpd vpd;
+ int s;
- switch (xa->state) {
- case ATA_S_COMPLETE:
- ata_complete_identify(xa, &id);
-
- bzero(&vpd, sizeof(vpd));
-
- vpd.device = T_DIRECT;
- vpd.page_code = SI_PG_SERIAL;
- vpd.page_length = sizeof(id.serial);
- bcopy(id.serial, vpd.serial, sizeof(id.serial));
-
- bcopy(&vpd, xs->data, MIN(sizeof(vpd), xs->datalen));
- xs->error = XS_NOERROR;
- break;
+ bzero(&vpd, sizeof(vpd));
- case ATA_S_ERROR:
- case ATA_S_TIMEOUT:
- ata_free_identify(xa);
- xs->error = (xa->state == ATA_S_TIMEOUT ? XS_TIMEOUT :
- XS_DRIVER_STUFFUP);
- break;
-
- default:
- panic("atascsi_disk_serial_done: unexpected xa state (%d)",
- xa->state);
- }
+ vpd.device = T_DIRECT;
+ vpd.page_code = SI_PG_SERIAL;
+ vpd.page_length = sizeof(ap->ap_identify.serial);
+ bcopy(ap->ap_identify.serial, vpd.serial,
+ sizeof(ap->ap_identify.serial));
+ bcopy(&vpd, xs->data, MIN(sizeof(vpd), xs->datalen));
+ xs->error = XS_NOERROR;
xs->flags |= ITSDONE;
+ s = splbio();
scsi_done(xs);
+ splx(s);
+
+ return (COMPLETE);
}
int
@@ -683,72 +613,39 @@ atascsi_disk_capacity(struct scsi_xfer *xs)
struct scsi_link *link = xs->sc_link;
struct atascsi *as = link->adapter_softc;
struct ata_port *ap = as->as_ports[link->target];
- struct ata_xfer *xa;
-
- xa = ata_setup_identify(ap, xs->flags & SCSI_NOSLEEP);
- if (xa == NULL)
- return (NO_CCB);
-
- xa->complete = atascsi_disk_capacity_done;
- xa->timeout = xs->timeout;
- xa->atascsi_private = xs;
- if (xs->flags & SCSI_POLL)
- xa->flags |= ATA_F_POLL;
-
- return (ata_exec(as, xa));
-}
-
-void
-atascsi_disk_capacity_done(struct ata_xfer *xa)
-{
- struct scsi_xfer *xs = xa->atascsi_private;
- struct ata_identify id;
- struct scsi_read_cap_data rcd;
- u_int64_t capacity;
+ struct ata_identify *id = &ap->ap_identify;
+ struct scsi_read_cap_data rcd;
+ u_int64_t capacity;
int i;
+ int s;
- switch (xa->state) {
- case ATA_S_COMPLETE:
- ata_complete_identify(xa, &id);
-
- bzero(&rcd, sizeof(rcd));
- if (letoh16(id.cmdset83) & 0x0400) {
- /* LBA48 feature set supported */
- for (i = 3; i >= 0; --i) {
- capacity <<= 16;
- capacity += letoh16(id.addrsecxt[i]);
- }
- } else {
- capacity = letoh16(id.addrsec[1]);
+ bzero(&rcd, sizeof(rcd));
+ if (letoh16(id->cmdset83) & 0x0400) {
+ /* LBA48 feature set supported */
+ for (i = 3; i >= 0; --i) {
capacity <<= 16;
- capacity += letoh16(id.addrsec[0]);
+ capacity += letoh16(id->addrsecxt[i]);
}
+ } else {
+ capacity = letoh16(id->addrsec[1]);
+ capacity <<= 16;
+ capacity += letoh16(id->addrsec[0]);
+ }
- /* XXX SCSI layer can't handle a device this big yet */
- if (capacity > 0xffffffff)
- capacity = 0xffffffff;
-
- _lto4b(capacity - 1, rcd.addr);
- _lto4b(512, rcd.length);
-
- bcopy(&rcd, xs->data, MIN(sizeof(rcd), xs->datalen));
- xs->error = XS_NOERROR;
- break;
-
- case ATA_S_ERROR:
- case ATA_S_TIMEOUT:
- ata_free_identify(xa);
- xs->error = (xa->state == ATA_S_TIMEOUT ? XS_TIMEOUT :
- XS_DRIVER_STUFFUP);
- break;
+ if (capacity > 0xffffffff)
+ capacity = 0xffffffff;
- default:
- panic("atascsi_disk_capacity_done: "
- "unexpected ata_xfer state (%d)", xa->state);
- }
+ _lto4b(capacity - 1, rcd.addr);
+ _lto4b(512, rcd.length);
+ bcopy(&rcd, xs->data, MIN(sizeof(rcd), xs->datalen));
+ xs->error = XS_NOERROR;
xs->flags |= ITSDONE;
+ s = splbio();
scsi_done(xs);
+ splx(s);
+
+ return (COMPLETE);
}
int
diff --git a/sys/dev/ata/atascsi.h b/sys/dev/ata/atascsi.h
index 5e2dccf405c..bcef4da9f67 100644
--- a/sys/dev/ata/atascsi.h
+++ b/sys/dev/ata/atascsi.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: atascsi.h,v 1.28 2007/11/26 20:13:53 dlg Exp $ */
+/* $OpenBSD: atascsi.h,v 1.29 2007/11/28 18:16:08 dlg Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -234,6 +234,7 @@ struct ata_log_page_10h {
*/
struct ata_port {
+ struct ata_identify ap_identify;
struct atascsi *ap_as;
int ap_port;
int ap_type;
@@ -251,7 +252,7 @@ struct ata_xfer {
u_int8_t *packetcmd;
u_int8_t tag;
- u_int8_t *data;
+ void *data;
size_t datalen;
size_t resid;