diff options
Diffstat (limited to 'sys/dev/ata/atascsi.c')
-rw-r--r-- | sys/dev/ata/atascsi.c | 240 |
1 files changed, 139 insertions, 101 deletions
diff --git a/sys/dev/ata/atascsi.c b/sys/dev/ata/atascsi.c index 099d1c90df6..13a97ed252d 100644 --- a/sys/dev/ata/atascsi.c +++ b/sys/dev/ata/atascsi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: atascsi.c,v 1.66 2009/10/22 07:59:26 dlg Exp $ */ +/* $OpenBSD: atascsi.c,v 1.67 2009/12/07 09:37:34 dlg Exp $ */ /* * Copyright (c) 2007 David Gwynne <dlg@openbsd.org> @@ -68,28 +68,31 @@ struct scsi_device atascsi_device = { void ata_fix_identify(struct ata_identify *); -int atascsi_disk_cmd(struct scsi_xfer *); +void atascsi_disk_cmd(struct scsi_xfer *); void atascsi_disk_cmd_done(struct ata_xfer *); -int atascsi_disk_inq(struct scsi_xfer *); -int atascsi_disk_inquiry(struct scsi_xfer *); -int atascsi_disk_vpd_supported(struct scsi_xfer *); -int atascsi_disk_vpd_serial(struct scsi_xfer *); -int atascsi_disk_vpd_ident(struct scsi_xfer *); -int atascsi_disk_capacity(struct scsi_xfer *); -int atascsi_disk_sync(struct scsi_xfer *); +void atascsi_disk_inq(struct scsi_xfer *); +void atascsi_disk_inquiry(struct scsi_xfer *); +void atascsi_disk_vpd_supported(struct scsi_xfer *); +void atascsi_disk_vpd_serial(struct scsi_xfer *); +void atascsi_disk_vpd_ident(struct scsi_xfer *); +void atascsi_disk_capacity(struct scsi_xfer *); +void atascsi_disk_sync(struct scsi_xfer *); void atascsi_disk_sync_done(struct ata_xfer *); -int atascsi_disk_sense(struct scsi_xfer *); +void atascsi_disk_sense(struct scsi_xfer *); -int atascsi_atapi_cmd(struct scsi_xfer *); +void atascsi_atapi_cmd(struct scsi_xfer *); void atascsi_atapi_cmd_done(struct ata_xfer *); -int atascsi_done(struct scsi_xfer *, int); +void atascsi_done(struct scsi_xfer *, int); -int ata_exec(struct atascsi *, struct ata_xfer *); +void ata_exec(struct atascsi *, struct ata_xfer *); struct ata_xfer *ata_get_xfer(struct ata_port *); void ata_put_xfer(struct ata_xfer *); +void ata_polled_complete(struct ata_xfer *); +int ata_polled(struct ata_xfer *); + struct atascsi * atascsi_attach(struct device *self, struct atascsi_attach_args *aaa) { @@ -204,12 +207,11 @@ atascsi_probe(struct scsi_link *link) 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; + xa->complete = ata_polled_complete; + rv = ata_polled(xa); + if (rv != 0) goto error; - } ata_fix_identify(&ap->ap_identify); @@ -227,9 +229,9 @@ atascsi_probe(struct scsi_link *link) xa->fis->features = ATA_SF_WRITECACHE_EN; xa->fis->flags = ATA_H2D_FLAGS_CMD; xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL; - xa->complete = ata_put_xfer; xa->timeout = 1000; - ata_exec(as, xa); /* we dont care if this works or not */ + xa->complete = ata_polled_complete; + ata_polled(xa); /* we dont care if it doesnt work */ } /* Enable read lookahead if supported */ @@ -241,9 +243,9 @@ atascsi_probe(struct scsi_link *link) xa->fis->features = ATA_SF_LOOKAHEAD_EN; xa->fis->flags = ATA_H2D_FLAGS_CMD; xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL; - xa->complete = ata_put_xfer; xa->timeout = 1000; - ata_exec(as, xa); /* we dont care if this works or not */ + xa->complete = ata_polled_complete; + ata_polled(xa); /* we dont care if it doesnt work */ } /* @@ -259,9 +261,9 @@ atascsi_probe(struct scsi_link *link) xa->fis->command = ATA_C_SEC_FREEZE_LOCK; xa->fis->flags = ATA_H2D_FLAGS_CMD; xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL; - xa->complete = ata_put_xfer; xa->timeout = 1000; - ata_exec(as, xa); /* we dont care if this works or not */ + xa->complete = ata_polled_complete; + ata_polled(xa); /* we dont care if it doesnt work */ return (0); error: @@ -321,22 +323,29 @@ atascsi_cmd(struct scsi_xfer *xs) struct atascsi *as = link->adapter_softc; struct ata_port *ap = as->as_ports[link->target]; - if (ap == NULL) - return (atascsi_done(xs, XS_DRIVER_STUFFUP)); + if (ap == NULL) { + atascsi_done(xs, XS_DRIVER_STUFFUP); + return (COMPLETE); + } switch (ap->ap_type) { case ATA_PORT_T_DISK: - return (atascsi_disk_cmd(xs)); + atascsi_disk_cmd(xs); + break; case ATA_PORT_T_ATAPI: - return (atascsi_atapi_cmd(xs)); + atascsi_atapi_cmd(xs); + break; case ATA_PORT_T_NONE: default: - return (atascsi_done(xs, XS_DRIVER_STUFFUP)); + atascsi_done(xs, XS_DRIVER_STUFFUP); + break; } + + return (COMPLETE); } -int +void atascsi_disk_cmd(struct scsi_xfer *xs) { struct scsi_link *link = xs->sc_link; @@ -362,26 +371,34 @@ atascsi_disk_cmd(struct scsi_xfer *xs) break; case SYNCHRONIZE_CACHE: - return (atascsi_disk_sync(xs)); + atascsi_disk_sync(xs); + return; case REQUEST_SENSE: - return (atascsi_disk_sense(xs)); + atascsi_disk_sense(xs); + return; case INQUIRY: - return (atascsi_disk_inq(xs)); + atascsi_disk_inq(xs); + return; case READ_CAPACITY: - return (atascsi_disk_capacity(xs)); + atascsi_disk_capacity(xs); + return; case TEST_UNIT_READY: case START_STOP: case PREVENT_ALLOW: - return (atascsi_done(xs, XS_NOERROR)); + atascsi_done(xs, XS_NOERROR); + return; default: - return (atascsi_done(xs, XS_DRIVER_STUFFUP)); + atascsi_done(xs, XS_DRIVER_STUFFUP); + return; } xa = ata_get_xfer(ap); - if (xa == NULL) - return (NO_CCB); + if (xa == NULL) { + atascsi_done(xs, XS_NO_CCB); + return; + } xa->flags = flags; if (xs->cmdlen == 6) { @@ -439,7 +456,7 @@ atascsi_disk_cmd(struct scsi_xfer *xs) if (xs->flags & SCSI_POLL) xa->flags |= ATA_F_POLL; - return (ata_exec(as, xa)); + ata_exec(as, xa); } void @@ -470,7 +487,7 @@ atascsi_disk_cmd_done(struct ata_xfer *xa) scsi_done(xs); } -int +void atascsi_disk_inq(struct scsi_xfer *xs) { struct scsi_inquiry *inq = (struct scsi_inquiry *)xs->cmd; @@ -478,27 +495,29 @@ atascsi_disk_inq(struct scsi_xfer *xs) if (ISSET(inq->flags, SI_EVPD)) { switch (inq->pagecode) { case SI_PG_SUPPORTED: - return (atascsi_disk_vpd_supported(xs)); + atascsi_disk_vpd_supported(xs); + break; case SI_PG_SERIAL: - return (atascsi_disk_vpd_serial(xs)); + atascsi_disk_vpd_serial(xs); + break; case SI_PG_DEVID: - return (atascsi_disk_vpd_ident(xs)); + atascsi_disk_vpd_ident(xs); + break; default: - return (atascsi_done(xs, XS_DRIVER_STUFFUP)); + atascsi_done(xs, XS_DRIVER_STUFFUP); + break; } - } - - return (atascsi_disk_inquiry(xs)); + } else + atascsi_disk_inquiry(xs); } -int +void atascsi_disk_inquiry(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 scsi_inquiry_data inq; - int rv; bzero(&inq, sizeof(inq)); @@ -512,10 +531,10 @@ atascsi_disk_inquiry(struct scsi_xfer *xs) bcopy(&inq, xs->data, MIN(sizeof(inq), xs->datalen)); - rv = atascsi_done(xs, XS_NOERROR); + atascsi_done(xs, XS_NOERROR); if (ap->ap_features & ATA_PORT_F_PROBED) - return (rv); + return; ap->ap_features = ATA_PORT_F_PROBED; @@ -550,11 +569,9 @@ atascsi_disk_inquiry(struct scsi_xfer *xs) } } } - - return (rv); } -int +void atascsi_disk_vpd_supported(struct scsi_xfer *xs) { struct { @@ -573,10 +590,10 @@ atascsi_disk_vpd_supported(struct scsi_xfer *xs) bcopy(&pg, xs->data, MIN(sizeof(pg), xs->datalen)); - return (atascsi_done(xs, XS_NOERROR)); + atascsi_done(xs, XS_NOERROR); } -int +void atascsi_disk_vpd_serial(struct scsi_xfer *xs) { struct scsi_link *link = xs->sc_link; @@ -594,10 +611,10 @@ atascsi_disk_vpd_serial(struct scsi_xfer *xs) bcopy(&pg, xs->data, MIN(sizeof(pg), xs->datalen)); - return (atascsi_done(xs, XS_NOERROR)); + atascsi_done(xs, XS_NOERROR); } -int +void atascsi_disk_vpd_ident(struct scsi_xfer *xs) { struct scsi_link *link = xs->sc_link; @@ -646,10 +663,10 @@ atascsi_disk_vpd_ident(struct scsi_xfer *xs) bcopy(&pg, xs->data, MIN(pg_len, xs->datalen)); - return (atascsi_done(xs, XS_NOERROR)); + atascsi_done(xs, XS_NOERROR); } -int +void atascsi_disk_sync(struct scsi_xfer *xs) { struct scsi_link *link = xs->sc_link; @@ -658,8 +675,10 @@ atascsi_disk_sync(struct scsi_xfer *xs) struct ata_xfer *xa; xa = ata_get_xfer(ap); - if (xa == NULL) - return (NO_CCB); + if (xa == NULL) { + atascsi_done(xs, XS_NO_CCB); + return; + } xa->datalen = 0; xa->flags = ATA_F_READ; @@ -674,7 +693,7 @@ atascsi_disk_sync(struct scsi_xfer *xs) xa->fis->command = ATA_C_FLUSH_CACHE; xa->fis->device = 0; - return (ata_exec(as, xa)); + ata_exec(as, xa); } void @@ -706,7 +725,7 @@ atascsi_disk_sync_done(struct ata_xfer *xa) scsi_done(xs); } -int +void atascsi_disk_capacity(struct scsi_xfer *xs) { struct scsi_link *link = xs->sc_link; @@ -738,10 +757,10 @@ atascsi_disk_capacity(struct scsi_xfer *xs) bcopy(&rcd, xs->data, MIN(sizeof(rcd), xs->datalen)); - return (atascsi_done(xs, XS_NOERROR)); + atascsi_done(xs, XS_NOERROR); } -int +void atascsi_disk_sense(struct scsi_xfer *xs) { struct scsi_sense_data *sd = (struct scsi_sense_data *)xs->data; @@ -751,10 +770,10 @@ atascsi_disk_sense(struct scsi_xfer *xs) sd->error_code = 0x70; /* XXX magic */ sd->flags = SKEY_NO_SENSE; - return (atascsi_done(xs, XS_NOERROR)); + atascsi_done(xs, XS_NOERROR); } -int +void atascsi_atapi_cmd(struct scsi_xfer *xs) { struct scsi_link *link = xs->sc_link; @@ -764,8 +783,10 @@ atascsi_atapi_cmd(struct scsi_xfer *xs) struct ata_fis_h2d *fis; xa = ata_get_xfer(ap); - if (xa == NULL) - return (NO_CCB); + if (xa == NULL) { + atascsi_done(xs, XS_NO_CCB); + return; + } switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { case SCSI_DATA_IN: @@ -799,7 +820,7 @@ atascsi_atapi_cmd(struct scsi_xfer *xs) /* Copy SCSI command into ATAPI packet. */ memcpy(xa->packetcmd, xs->cmd, xs->cmdlen); - return (ata_exec(as, xa)); + ata_exec(as, xa); } void @@ -840,18 +861,16 @@ atascsi_atapi_cmd_done(struct ata_xfer *xa) scsi_done(xs); } -int +void atascsi_done(struct scsi_xfer *xs, int error) { int s; xs->error = error; - xs->flags |= ITSDONE; s = splbio(); scsi_done(xs); splx(s); - return (COMPLETE); } int atascsi_ioctl_cmd(struct atascsi *, struct ata_port *, atareq_t *); @@ -879,6 +898,7 @@ atascsi_ioctl_cmd(struct atascsi *as, struct ata_port *ap, atareq_t *atareq) struct ata_fis_h2d *fis; void *buf; int rc = 0; + int s; xa = ata_get_xfer(ap); if (xa == NULL) @@ -909,21 +929,11 @@ atascsi_ioctl_cmd(struct atascsi *as, struct ata_port *ap, atareq_t *atareq) } xa->atascsi_private = NULL; - switch (as->as_methods->ata_cmd(xa)) { - case ATA_COMPLETE: - break; - case ATA_QUEUED: - while (xa->state == ATA_S_PENDING || xa->state == ATA_S_ONCHIP) - tsleep(xa, PRIBIO, "atascsi", 0); - break; - case ATA_ERROR: - free(buf, M_TEMP); - ata_put_xfer(xa); - atareq->retsts = ATACMD_ERROR; - return (EIO); - default: - panic("atascsi_ioctl_cmd: unexpected return from ata_cmd"); - } + 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: @@ -955,21 +965,10 @@ atascsi_ioctl_done(struct ata_xfer *xa) wakeup(xa); } -int +void ata_exec(struct atascsi *as, struct ata_xfer *xa) { - int polled = xa->flags & ATA_F_POLL; - - switch (as->as_methods->ata_cmd(xa)) { - case ATA_COMPLETE: - case ATA_ERROR: - return (COMPLETE); - case ATA_QUEUED: - if (!polled) - return (SUCCESSFULLY_QUEUED); - default: - panic("unexpected return from ata_exec"); - } + as->as_methods->ata_cmd(xa); } struct ata_xfer * @@ -990,3 +989,42 @@ ata_put_xfer(struct ata_xfer *xa) { xa->ata_put_xfer(xa); } + +void +ata_polled_complete(struct ata_xfer *xa) +{ + /* do nothing */ +} + +int +ata_polled(struct ata_xfer *xa) +{ + int rv; + + if (!ISSET(xa->flags, ATA_F_DONE)) + panic("ata_polled: xa isnt complete"); + + switch (xa->state) { + case ATA_S_COMPLETE: + rv = 0; + break; + case ATA_S_ERROR: + case ATA_S_TIMEOUT: + rv = EIO; + break; + default: + panic("ata_polled: xa state (%d)", + xa->state); + } + + ata_put_xfer(xa); + + return (rv); +} + +void +ata_complete(struct ata_xfer *xa) +{ + SET(xa->flags, ATA_F_DONE); + xa->complete(xa); +} |