summaryrefslogtreecommitdiff
path: root/sys/dev/ata/atascsi.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2010-04-22 00:58:33 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2010-04-22 00:58:33 +0000
commit511b3517d4c46d54afb7f591effdd03fdfec7f0d (patch)
tree6aee4d809dbd8852e6ddadbe1e07caae5b9ebe73 /sys/dev/ata/atascsi.c
parent6f0543ae443229c06c9b963bf86bd9a3f248c8be (diff)
cut atascsi over to providing and using iopools. this gets rid of NO_CCB
and makes the ioctl path more reliable on busy disks by allowing it to sleep in the runqueue for an io to use. mk@ did the original diff and figured most of the problems out. ok mk@
Diffstat (limited to 'sys/dev/ata/atascsi.c')
-rw-r--r--sys/dev/ata/atascsi.c118
1 files changed, 57 insertions, 61 deletions
diff --git a/sys/dev/ata/atascsi.c b/sys/dev/ata/atascsi.c
index 6e814b06d68..386ed3695b8 100644
--- a/sys/dev/ata/atascsi.c
+++ b/sys/dev/ata/atascsi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atascsi.c,v 1.80 2010/04/19 10:52:15 dlg Exp $ */
+/* $OpenBSD: atascsi.c,v 1.81 2010/04/22 00:58:32 dlg Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -33,11 +33,13 @@
#include <sys/ataio.h>
+struct atascsi_port;
+
struct atascsi {
struct device *as_dev;
void *as_cookie;
- struct ata_port **as_ports;
+ struct atascsi_port **as_ports;
struct atascsi_methods *as_methods;
struct scsi_adapter as_switch;
@@ -47,6 +49,15 @@ struct atascsi {
int as_capability;
};
+struct atascsi_port {
+ struct ata_identify ap_identify;
+ struct scsi_iopool ap_iopool;
+ struct atascsi *ap_as;
+ int ap_port;
+ int ap_type;
+ int ap_ncqdepth;
+};
+
void atascsi_cmd(struct scsi_xfer *);
int atascsi_ioctl(struct scsi_link *, u_long, caddr_t, int,
struct proc *);
@@ -90,9 +101,6 @@ void atascsi_done(struct scsi_xfer *, int);
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 *);
@@ -101,6 +109,9 @@ u_int ata_identify_blocksize(struct ata_identify *);
u_int ata_identify_block_l2p_exp(struct ata_identify *);
u_int ata_identify_block_logical_align(struct ata_identify *);
+void *atascsi_io_get(void *);
+void atascsi_io_put(void *, void *);
+
struct atascsi *
atascsi_attach(struct device *self, struct atascsi_attach_args *aaa)
{
@@ -130,7 +141,7 @@ atascsi_attach(struct device *self, struct atascsi_attach_args *aaa)
if (as->as_capability & ASAA_CAP_NEEDS_RESERVED)
as->as_link.openings--;
- as->as_ports = malloc(sizeof(struct ata_port *) * aaa->aaa_nports,
+ as->as_ports = malloc(sizeof(struct atascsi_port *) * aaa->aaa_nports,
M_DEVBUF, M_WAITOK | M_ZERO);
bzero(&saa, sizeof(saa));
@@ -174,7 +185,7 @@ int
atascsi_probe(struct scsi_link *link)
{
struct atascsi *as = link->adapter_softc;
- struct ata_port *ap;
+ struct atascsi_port *ap;
struct ata_xfer *xa;
int port, type;
int rv;
@@ -206,8 +217,11 @@ atascsi_probe(struct scsi_link *link)
ap->ap_port = port;
ap->ap_type = type;
+ scsi_iopool_init(&ap->ap_iopool, ap, atascsi_io_get, atascsi_io_put);
+ link->pool = &ap->ap_iopool;
+
/* fetch the device info */
- xa = ata_get_xfer(ap);
+ xa = scsi_io_get(&ap->ap_iopool, SCSI_NOSLEEP);
if (xa == NULL)
panic("no free xfers on a new port");
xa->data = &ap->ap_identify;
@@ -219,6 +233,7 @@ atascsi_probe(struct scsi_link *link)
xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL;
xa->timeout = 1000;
xa->complete = ata_polled_complete;
+ xa->atascsi_private = &ap->ap_iopool;
ata_exec(as, xa);
rv = ata_polled(xa);
if (rv != 0)
@@ -248,10 +263,10 @@ atascsi_probe(struct scsi_link *link)
* what the device supports.
*/
while (host_ncqdepth--) {
- xa = ata_get_xfer(ap);
+ xa = scsi_io_get(&ap->ap_iopool, SCSI_NOSLEEP);
if (xa->tag < ap->ap_ncqdepth) {
xa->state = ATA_S_COMPLETE;
- ata_put_xfer(xa);
+ scsi_io_put(&ap->ap_iopool, xa);
}
}
}
@@ -263,7 +278,7 @@ atascsi_probe(struct scsi_link *link)
/* Enable write cache if supported */
if (ISSET(cmdset, ATA_IDENTIFY_WRITECACHE)) {
- xa = ata_get_xfer(ap);
+ xa = scsi_io_get(&ap->ap_iopool, SCSI_NOSLEEP);
if (xa == NULL)
panic("no free xfers on a new port");
xa->fis->command = ATA_C_SET_FEATURES;
@@ -272,13 +287,14 @@ atascsi_probe(struct scsi_link *link)
xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL;
xa->timeout = 1000;
xa->complete = ata_polled_complete;
+ xa->atascsi_private = &ap->ap_iopool;
ata_exec(as, xa);
ata_polled(xa); /* we dont care if it doesnt work */
}
/* Enable read lookahead if supported */
if (ISSET(cmdset, ATA_IDENTIFY_LOOKAHEAD)) {
- xa = ata_get_xfer(ap);
+ xa = scsi_io_get(&ap->ap_iopool, SCSI_NOSLEEP);
if (xa == NULL)
panic("no free xfers on a new port");
xa->fis->command = ATA_C_SET_FEATURES;
@@ -287,6 +303,7 @@ atascsi_probe(struct scsi_link *link)
xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL;
xa->timeout = 1000;
xa->complete = ata_polled_complete;
+ xa->atascsi_private = &ap->ap_iopool;
ata_exec(as, xa);
ata_polled(xa); /* we dont care if it doesnt work */
}
@@ -298,7 +315,7 @@ 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);
+ xa = scsi_io_get(&ap->ap_iopool, SCSI_NOSLEEP);
if (xa == NULL)
panic("no free xfers on a new port");
xa->fis->command = ATA_C_SEC_FREEZE_LOCK;
@@ -306,6 +323,7 @@ atascsi_probe(struct scsi_link *link)
xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL;
xa->timeout = 1000;
xa->complete = ata_polled_complete;
+ xa->atascsi_private = &ap->ap_iopool;
ata_exec(as, xa);
ata_polled(xa); /* we dont care if it doesnt work */
@@ -321,7 +339,7 @@ void
atascsi_free(struct scsi_link *link)
{
struct atascsi *as = link->adapter_softc;
- struct ata_port *ap;
+ struct atascsi_port *ap;
int port;
if (link->lun > 0)
@@ -346,7 +364,7 @@ atascsi_cmd(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 atascsi_port *ap = as->as_ports[link->target];
if (ap == NULL) {
atascsi_done(xs, XS_DRIVER_STUFFUP);
@@ -373,11 +391,11 @@ atascsi_disk_cmd(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 atascsi_port *ap = as->as_ports[link->target];
+ struct ata_xfer *xa = xs->io;
int flags = 0;
struct scsi_rw *rw;
struct scsi_rw_big *rwb;
- struct ata_xfer *xa;
struct ata_fis_h2d *fis;
u_int64_t lba;
u_int32_t sector_count;
@@ -420,12 +438,6 @@ atascsi_disk_cmd(struct scsi_xfer *xs)
return;
}
- xa = ata_get_xfer(ap);
- if (xa == NULL) {
- atascsi_done(xs, XS_NO_CCB);
- return;
- }
-
xa->flags = flags;
if (xs->cmdlen == 6) {
rw = (struct scsi_rw *)xs->cmd;
@@ -507,7 +519,6 @@ atascsi_disk_cmd_done(struct ata_xfer *xa)
}
xs->resid = xa->resid;
- ata_put_xfer(xa);
scsi_done(xs);
}
@@ -547,7 +558,7 @@ 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 atascsi_port *ap = as->as_ports[link->target];
struct scsi_inquiry_data inq;
bzero(&inq, sizeof(inq));
@@ -596,7 +607,7 @@ atascsi_disk_vpd_serial(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 atascsi_port *ap = as->as_ports[link->target];
struct scsi_vpd_serial pg;
bzero(&pg, sizeof(pg));
@@ -617,7 +628,7 @@ atascsi_disk_vpd_ident(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 atascsi_port *ap = as->as_ports[link->target];
struct {
struct scsi_vpd_hdr hdr;
struct scsi_vpd_devid_hdr devid_hdr;
@@ -668,7 +679,7 @@ atascsi_disk_vpd_limits(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 atascsi_port *ap = as->as_ports[link->target];
struct scsi_vpd_disk_limits pg;
bzero(&pg, sizeof(pg));
@@ -689,7 +700,7 @@ atascsi_disk_vpd_info(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 atascsi_port *ap = as->as_ports[link->target];
struct scsi_vpd_disk_info pg;
bzero(&pg, sizeof(pg));
@@ -710,14 +721,7 @@ atascsi_disk_sync(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_get_xfer(ap);
- if (xa == NULL) {
- atascsi_done(xs, XS_NO_CCB);
- return;
- }
+ struct ata_xfer *xa = xs->io;
xa->datalen = 0;
xa->flags = ATA_F_READ;
@@ -758,8 +762,6 @@ atascsi_disk_sync_done(struct ata_xfer *xa)
xa->state);
}
- ata_put_xfer(xa);
-
scsi_done(xs);
}
@@ -835,7 +837,7 @@ 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 atascsi_port *ap = as->as_ports[link->target];
struct scsi_read_cap_data rcd;
u_int64_t capacity;
@@ -857,7 +859,7 @@ atascsi_disk_capacity16(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 atascsi_port *ap = as->as_ports[link->target];
struct scsi_read_cap_data_16 rcd;
u_int align;
@@ -893,16 +895,9 @@ atascsi_atapi_cmd(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 ata_xfer *xa = xs->io;
struct ata_fis_h2d *fis;
- xa = ata_get_xfer(ap);
- if (xa == NULL) {
- atascsi_done(xs, XS_NO_CCB);
- return;
- }
-
switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
case SCSI_DATA_IN:
xa->flags = ATA_F_PACKET | ATA_F_READ;
@@ -970,7 +965,6 @@ atascsi_atapi_cmd_done(struct ata_xfer *xa)
}
xs->resid = xa->resid;
- ata_put_xfer(xa);
scsi_done(xs);
}
@@ -987,7 +981,7 @@ atascsi_done(struct scsi_xfer *xs, int error)
splx(s);
}
-int atascsi_ioctl_cmd(struct atascsi *, struct ata_port *, atareq_t *);
+int atascsi_ioctl_cmd(struct atascsi *, struct atascsi_port *, atareq_t *);
void atascsi_ioctl_done(struct ata_xfer *);
int
@@ -995,7 +989,7 @@ atascsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flags,
struct proc *p)
{
struct atascsi *as = link->adapter_softc;
- struct ata_port *ap = as->as_ports[link->target];
+ struct atascsi_port *ap = as->as_ports[link->target];
switch (cmd) {
case ATAIOCCOMMAND:
@@ -1006,7 +1000,7 @@ atascsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flags,
}
int
-atascsi_ioctl_cmd(struct atascsi *as, struct ata_port *ap, atareq_t *atareq)
+atascsi_ioctl_cmd(struct atascsi *as, struct atascsi_port *ap, atareq_t *atareq)
{
struct ata_xfer *xa;
struct ata_fis_h2d *fis;
@@ -1014,9 +1008,7 @@ atascsi_ioctl_cmd(struct atascsi *as, struct ata_port *ap, atareq_t *atareq)
int rc = 0;
int s;
- xa = ata_get_xfer(ap);
- if (xa == NULL)
- return (ENOMEM);
+ xa = scsi_io_get(&ap->ap_iopool, 0);
fis = xa->fis;
fis->flags = ATA_H2D_FLAGS_CMD;
@@ -1068,7 +1060,7 @@ atascsi_ioctl_cmd(struct atascsi *as, struct ata_port *ap, atareq_t *atareq)
free(buf, M_TEMP);
- ata_put_xfer(xa);
+ scsi_io_put(&ap->ap_iopool, xa);
return (rc);
}
@@ -1085,9 +1077,10 @@ ata_exec(struct atascsi *as, struct ata_xfer *xa)
as->as_methods->ata_cmd(xa);
}
-struct ata_xfer *
-ata_get_xfer(struct ata_port *ap)
+void *
+atascsi_io_get(void *cookie)
{
+ struct atascsi_port *ap = cookie;
struct atascsi *as = ap->ap_as;
struct ata_xfer *xa;
@@ -1099,8 +1092,11 @@ ata_get_xfer(struct ata_port *ap)
}
void
-ata_put_xfer(struct ata_xfer *xa)
+atascsi_io_put(void *cookie, void *io)
{
+ struct ata_xfer *xa = io;
+
+ xa->state = ATA_S_COMPLETE; /* XXX this state machine is dumb */
xa->ata_put_xfer(xa);
}
@@ -1131,7 +1127,7 @@ ata_polled(struct ata_xfer *xa)
xa->state);
}
- ata_put_xfer(xa);
+ scsi_io_put(xa->atascsi_private, xa);
return (rv);
}