summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2009-11-12 06:20:28 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2009-11-12 06:20:28 +0000
commit2bdddc849c46b84f11335ec6678d463c1006b8e7 (patch)
treef26c0e47e02a7e1c8e467a1c742d16a4b476e966
parent31ba389aafb55266aeecd6e3351eea252dbeddae (diff)
revert midlayer back to it was before i put my big rewrite in. this is
causing a weird problems on an alpha and also appears responsible for isp(4) weirdness i havent had a chance to examine yet. sigh, this makes me sad.
-rw-r--r--sys/dev/ic/mpi.c4
-rw-r--r--sys/scsi/mpath.c97
-rw-r--r--sys/scsi/scsi_base.c498
-rw-r--r--sys/scsi/scsi_ioctl.c301
-rw-r--r--sys/scsi/scsiconf.c229
-rw-r--r--sys/scsi/scsiconf.h50
-rw-r--r--sys/scsi/sd.c459
-rw-r--r--sys/scsi/sdvar.h15
8 files changed, 901 insertions, 752 deletions
diff --git a/sys/dev/ic/mpi.c b/sys/dev/ic/mpi.c
index f5d048751fa..0137a8dee4b 100644
--- a/sys/dev/ic/mpi.c
+++ b/sys/dev/ic/mpi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mpi.c,v 1.120 2009/11/10 10:13:08 dlg Exp $ */
+/* $OpenBSD: mpi.c,v 1.121 2009/11/12 06:20:27 dlg Exp $ */
/*
* Copyright (c) 2005, 2006, 2009 David Gwynne <dlg@openbsd.org>
@@ -2176,6 +2176,7 @@ mpi_eventnotify_done(struct mpi_ccb *ccb)
void
mpi_evt_sas(struct mpi_softc *sc, struct mpi_rcb *rcb)
{
+#if 0
struct mpi_evt_sas_change *ch;
u_int8_t *data;
@@ -2213,6 +2214,7 @@ mpi_evt_sas(struct mpi_softc *sc, struct mpi_rcb *rcb)
"0x%02x\n", DEVNAME(sc), ch->reason);
break;
}
+#endif
}
void
diff --git a/sys/scsi/mpath.c b/sys/scsi/mpath.c
index 3372071ab79..4bccf1c9d43 100644
--- a/sys/scsi/mpath.c
+++ b/sys/scsi/mpath.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mpath.c,v 1.9 2009/11/10 10:13:08 dlg Exp $ */
+/* $OpenBSD: mpath.c,v 1.10 2009/11/12 06:20:27 dlg Exp $ */
/*
* Copyright (c) 2009 David Gwynne <dlg@openbsd.org>
@@ -47,7 +47,7 @@ struct mpath_path {
TAILQ_HEAD(mpath_paths, mpath_path);
struct mpath_node {
- struct devid *node_id;
+ struct devid node_id;
struct mpath_paths node_paths;
};
@@ -78,8 +78,6 @@ int mpath_cmd(struct scsi_xfer *);
void mpath_minphys(struct buf *, struct scsi_link *);
int mpath_probe(struct scsi_link *);
-void mpath_done(struct scsi_xfer *);
-
struct scsi_adapter mpath_switch = {
mpath_cmd,
scsi_minphys,
@@ -138,13 +136,9 @@ mpath_xs_stuffup(struct scsi_xfer *xs)
int
mpath_probe(struct scsi_link *link)
{
- struct mpath_node *n = mpath_nodes[link->target];
-
- if (link->lun != 0 || n == NULL)
+ if (link->lun != 0 || mpath_nodes[link->target] == NULL)
return (ENXIO);
- link->id = devid_copy(n->node_id);
-
return (0);
}
@@ -154,53 +148,36 @@ mpath_cmd(struct scsi_xfer *xs)
struct scsi_link *link = xs->sc_link;
struct mpath_node *n = mpath_nodes[link->target];
struct mpath_path *p = TAILQ_FIRST(&n->node_paths);
- struct scsi_xfer *mxs;
+ int rv;
+ int s;
if (n == NULL || p == NULL) {
mpath_xs_stuffup(xs);
return (COMPLETE);
}
- mxs = scsi_xs_get(p->path_link, xs->flags);
- if (mxs == NULL) {
- mpath_xs_stuffup(xs);
- return (COMPLETE);
- }
-
- memcpy(mxs->cmd, xs->cmd, xs->cmdlen);
- mxs->cmdlen = xs->cmdlen;
- mxs->data = xs->data;
- mxs->datalen = xs->datalen;
- mxs->retries = xs->retries;
- mxs->timeout = xs->timeout;
- mxs->req_sense_length = xs->req_sense_length;
-
- mxs->cookie = xs;
- mxs->done = mpath_done;
-
- scsi_xs_exec(mxs);
-
- return (COMPLETE); /* doesnt matter anymore */
-}
-
-void
-mpath_done(struct scsi_xfer *mxs)
-{
- struct scsi_xfer *xs = mxs->cookie;
- int s;
-
- xs->error = mxs->error;
- xs->status = mxs->status;
- xs->flags = mxs->flags;
- xs->resid = mxs->resid;
+ rv = scsi_scsi_cmd(p->path_link, xs->cmd, xs->cmdlen,
+ xs->data, xs->datalen,
+ 2, xs->timeout, NULL, SCSI_POLL |
+ (xs->flags & (SCSI_DATA_IN|SCSI_DATA_OUT)));
- memcpy(&xs->sense, &mxs->sense, sizeof(xs->sense));
- scsi_xs_put(mxs);
+ xs->flags |= ITSDONE;
+ if (rv == 0) {
+ xs->error = XS_NOERROR;
+ xs->status = SCSI_OK;
+ xs->resid = 0;
+ } else {
+ printf("%s: t%dl%d rv %d cmd %x\n", DEVNAME(mpath),
+ link->target, link->lun, rv, xs->cmd->opcode);
+ xs->error = XS_DRIVER_STUFFUP;
+ }
s = splbio();
scsi_done(xs);
splx(s);
+
+ return (COMPLETE);
}
void
@@ -228,14 +205,14 @@ mpath_path_attach(struct scsi_link *link)
return (ENODEV);
/* XXX this is dumb. should check inq shizz */
- if (ISSET(link->flags, SDEV_VIRTUAL) || link->id == NULL)
+ if (link->id.d_type == DEVID_NONE)
return (ENXIO);
for (target = 0; target < MPATH_BUSWIDTH; target++) {
if ((n = mpath_nodes[target]) == NULL)
continue;
- if (DEVID_CMP(n->node_id, link->id))
+ if (DEVID_CMP(&n->node_id, &link->id))
break;
n = NULL;
@@ -252,18 +229,13 @@ mpath_path_attach(struct scsi_link *link)
n = malloc(sizeof(*n), M_DEVBUF, M_WAITOK | M_ZERO);
TAILQ_INIT(&n->node_paths);
- n->node_id = devid_copy(link->id);
+ n->node_id.d_type = link->id.d_type;
+ n->node_id.d_len = link->id.d_len;
+ n->node_id.d_id = malloc(n->node_id.d_len, M_DEVBUF, M_DEVBUF);
+ memcpy(n->node_id.d_id, link->id.d_id, n->node_id.d_len);
mpath_nodes[target] = n;
probe = 1;
- } else {
- /*
- * instead of carrying identical values in different devid
- * instances, delete the new one and reference the old one in
- * the new scsi_link.
- */
- devid_free(link->id);
- link->id = devid_copy(n->node_id);
}
p = malloc(sizeof(*p), M_DEVBUF, M_WAITOK);
@@ -288,7 +260,7 @@ mpath_path_detach(struct scsi_link *link, int flags)
if ((n = mpath_nodes[target]) == NULL)
continue;
- if (DEVID_CMP(n->node_id, link->id))
+ if (DEVID_CMP(&n->node_id, &link->id))
break;
n = NULL;
@@ -307,16 +279,3 @@ mpath_path_detach(struct scsi_link *link, int flags)
panic("mpath: unable to locate path for detach");
}
-
-void
-mpath_path_activate(struct scsi_link *link)
-{
-
-}
-
-void
-mpath_path_deactivate(struct scsi_link *link)
-{
-
-}
-
diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c
index 62afc3910d4..b8810da2769 100644
--- a/sys/scsi/scsi_base.c
+++ b/sys/scsi/scsi_base.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsi_base.c,v 1.141 2009/11/10 10:51:03 dlg Exp $ */
+/* $OpenBSD: scsi_base.c,v 1.142 2009/11/12 06:20:27 dlg Exp $ */
/* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */
/*
@@ -50,14 +50,15 @@
#include <scsi/scsi_disk.h>
#include <scsi/scsiconf.h>
+static __inline struct scsi_xfer *scsi_make_xs(struct scsi_link *,
+ struct scsi_generic *, int cmdlen, u_char *data_addr,
+ int datalen, int retries, int timeout, struct buf *, int flags);
static __inline void asc2ascii(u_int8_t, u_int8_t ascq, char *result,
size_t len);
int sc_err1(struct scsi_xfer *);
int scsi_interpret_sense(struct scsi_xfer *);
char *scsi_decode_sense(struct scsi_sense_data *, int);
-void scsi_xs_done(struct scsi_xfer *);
-
/* Values for flag parameter to scsi_decode_sense. */
#define DECODE_SENSE_KEY 1
#define DECODE_ASC_ASCQ 2
@@ -94,7 +95,6 @@ scsi_init()
/* Initialize the scsi_xfer pool. */
pool_init(&scsi_xfer_pool, sizeof(struct scsi_xfer), 0,
0, 0, "scxspl", NULL);
- pool_setipl(&scsi_xfer_pool, IPL_BIO);
/* Initialize the scsi_plug pool */
pool_init(&scsi_plug_pool, sizeof(struct scsi_plug), 0,
0, 0, "scsiplug", NULL);
@@ -183,43 +183,42 @@ scsi_deinit()
*/
struct scsi_xfer *
-scsi_xs_get(struct scsi_link *link, int flags)
+scsi_get_xs(struct scsi_link *sc_link, int flags)
{
- struct scsi_xfer *xs;
+ struct scsi_xfer *xs;
+ int s;
+
+ SC_DEBUG(sc_link, SDEV_DB3, ("scsi_get_xs\n"));
- mtx_enter(&link->mtx);
- while (link->openings == 0) {
- if (ISSET(flags, SCSI_NOSLEEP)) {
- mtx_leave(&link->mtx);
+ s = splbio();
+ while (sc_link->openings == 0) {
+ SC_DEBUG(sc_link, SDEV_DB3, ("sleeping\n"));
+ if ((flags & SCSI_NOSLEEP) != 0) {
+ splx(s);
+ return (NULL);
+ }
+ sc_link->flags |= SDEV_WAITING;
+ if (tsleep(sc_link, PRIBIO|PCATCH, "getxs", 0)) {
+ /* Bail out on getting a signal. */
+ sc_link->flags &= ~SDEV_WAITING;
+ splx(s);
return (NULL);
}
-
- SET(link->flags, SDEV_WAITING);
- msleep(link, &link->mtx, PRIBIO, "getxs", 0);
}
- link->openings--;
- mtx_leave(&link->mtx);
-
- /* pool is shared, link mtx is not */
+ SC_DEBUG(sc_link, SDEV_DB3, ("calling pool_get\n"));
xs = pool_get(&scsi_xfer_pool,
- ISSET(flags, SCSI_NOSLEEP) ? PR_NOWAIT : PR_WAITOK);
- if (xs == NULL) {
- mtx_enter(&link->mtx);
- link->openings++;
- mtx_leave(&link->mtx);
- } else {
+ ((flags & SCSI_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK));
+ if (xs != NULL) {
+ bzero(xs, sizeof(*xs));
+ sc_link->openings--;
xs->flags = flags;
- xs->sc_link = link;
- xs->retries = SCSI_RETRIES;
- xs->timeout = 0;
- bzero(&xs->cmdstore, sizeof(xs->cmdstore));
- xs->cmd = &xs->cmdstore;
- xs->cmdlen = 0;
- xs->data = NULL;
- xs->datalen = 0;
- xs->resid = 0;
- xs->bp = NULL;
+ } else {
+ sc_print_addr(sc_link);
+ printf("cannot allocate scsi xs\n");
}
+ splx(s);
+
+ SC_DEBUG(sc_link, SDEV_DB3, ("returning\n"));
return (xs);
}
@@ -230,21 +229,75 @@ scsi_xs_get(struct scsi_link *link, int flags)
* If another process is waiting for an xs, do a wakeup, let it proceed
*/
void
-scsi_xs_put(struct scsi_xfer *xs)
+scsi_free_xs(struct scsi_xfer *xs, int start)
{
- struct scsi_link *link = xs->sc_link;
+ struct scsi_link *sc_link = xs->sc_link;
- pool_put(&scsi_xfer_pool, xs);
+ splassert(IPL_BIO);
- mtx_enter(&link->mtx);
- link->openings++;
+ SC_DEBUG(sc_link, SDEV_DB3, ("scsi_free_xs\n"));
+
+ pool_put(&scsi_xfer_pool, xs);
+ sc_link->openings++;
/* If someone is waiting for scsi_xfer, wake them up. */
- if (ISSET(link->flags, SDEV_WAITING)) {
- CLR(link->flags, SDEV_WAITING);
- wakeup(link);
+ if ((sc_link->flags & SDEV_WAITING) != 0) {
+ sc_link->flags &= ~SDEV_WAITING;
+ wakeup(sc_link);
+ } else if (start && sc_link->device->start) {
+ SC_DEBUG(sc_link, SDEV_DB2,
+ ("calling private start()\n"));
+ (*(sc_link->device->start)) (sc_link->device_softc);
}
- mtx_leave(&link->mtx);
+}
+
+/*
+ * Make a scsi_xfer, and return a pointer to it.
+ */
+static __inline struct scsi_xfer *
+scsi_make_xs(struct scsi_link *sc_link, struct scsi_generic *scsi_cmd,
+ int cmdlen, u_char *data_addr, int datalen, int retries, int timeout,
+ struct buf *bp, int flags)
+{
+ struct scsi_xfer *xs;
+
+ if ((xs = scsi_get_xs(sc_link, flags)) == NULL)
+ return (NULL);
+
+ /*
+ * Fill out the scsi_xfer structure. We don't know whose context
+ * the cmd is in, so copy it.
+ */
+ xs->sc_link = sc_link;
+ bcopy(scsi_cmd, &xs->cmdstore, cmdlen);
+ xs->cmd = &xs->cmdstore;
+ xs->cmdlen = cmdlen;
+ xs->data = data_addr;
+ xs->datalen = datalen;
+ xs->retries = retries;
+ xs->timeout = timeout;
+ xs->bp = bp;
+
+ /*
+ * Set the LUN in the CDB if it fits in the three bits available. This
+ * may only be needed if we have an older device. However, we also set
+ * it for more modern SCSI devices "just in case". The old code
+ * assumed everything newer than SCSI-2 would not need it, but why risk
+ * it? This was the old conditional:
+ *
+ * if ((SCSISPC(sc_link->inqdata.version) <= 2))
+ */
+ xs->cmd->bytes[0] &= ~SCSI_CMD_LUN_MASK;
+ if (sc_link->lun < 8)
+ xs->cmd->bytes[0] |= ((sc_link->lun << SCSI_CMD_LUN_SHIFT) &
+ SCSI_CMD_LUN_MASK);
+
+#ifdef SCSIDEBUG
+ if ((sc_link->flags & SDEV_DB1) != 0)
+ show_scsi_xs(xs);
+#endif /* SCSIDEBUG */
+
+ return (xs);
}
/*
@@ -706,87 +759,181 @@ scsi_report_luns(struct scsi_link *sc_link, int selectreport,
return (error);
}
+/*
+ * This routine is called by the scsi interrupt when the transfer is complete.
+ */
void
-scsi_xs_exec(struct scsi_xfer *xs)
+scsi_done(struct scsi_xfer *xs)
{
- int rv;
- int s;
+ struct scsi_link *sc_link = xs->sc_link;
+ struct buf *bp;
+ int error;
- xs->flags &= ~ITSDONE;
- xs->error = XS_NOERROR;
- xs->resid = xs->datalen;
- xs->status = 0;
+ SC_DEBUG(sc_link, SDEV_DB2, ("scsi_done\n"));
+
+ splassert(IPL_BIO);
+
+ xs->flags |= ITSDONE;
/*
- * scsi_xs_exec() guarantees that scsi_done() will be called on the xs
- * it was given. The adapter is responsible for calling scsi_done()
- * except if its scsi_cmd() routine returns NO_CCB or TRY_AGAIN_LATER.
- * In those cases we must call scsi_done().
- */
+ * If it's a user level request, bypass all usual completion processing,
+ * let the user work it out.. We take reponsibility for freeing the
+ * xs when the user returns (and restarting the device's queue).
+ */
+ if ((xs->flags & SCSI_USER) != 0) {
+ SC_DEBUG(sc_link, SDEV_DB3, ("calling user done()\n"));
+ scsi_user_done(xs); /* to take a copy of the sense etc. */
+ SC_DEBUG(sc_link, SDEV_DB3, ("returned from user done()\n"));
+
+ scsi_free_xs(xs, 1); /* restarts queue too */
+ SC_DEBUG(sc_link, SDEV_DB3, ("returning to adapter\n"));
+ return;
+ }
-retry:
- rv = xs->sc_link->adapter->scsi_cmd(xs);
- switch (rv) {
- case NO_CCB:
+ if (!((xs->flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP)) {
/*
- * Give the xs back to the device driver to retry on its own.
+ * if it's a normal upper level request, then ask
+ * the upper level code to handle error checking
+ * rather than doing it here at interrupt time
*/
+ wakeup(xs);
+ return;
+ }
- xs->error = XS_NO_CCB;
- break;
+ /*
+ * Go and handle errors now.
+ * If it returns ERESTART then we should RETRY
+ */
+retry:
+ error = sc_err1(xs);
+ if (error == ERESTART) {
+ switch ((*(sc_link->adapter->scsi_cmd)) (xs)) {
+ case SUCCESSFULLY_QUEUED:
+ return;
- case TRY_AGAIN_LATER:
- /*
- * We delay or sleep a bit and then try to shove the xs onto
- * the adapter again.
- *
- * This must be done here because scsi_xs_exec() guarantees
- * that scsi_done() will be called.
- */
+ case TRY_AGAIN_LATER:
+ xs->error = XS_BUSY;
+ /* FALLTHROUGH */
+ case COMPLETE:
+ goto retry;
+ }
+ }
- if (xs->retries-- > 0) {
- switch (xs->flags & (SCSI_POLL | SCSI_NOSLEEP)) {
- case SCSI_POLL:
- delay(1000000);
- /* FALLTHROUGH */
- case SCSI_NOSLEEP:
- /* We can't sleep, try again immediately */
- goto retry;
- case (SCSI_POLL | SCSI_NOSLEEP):
- panic("POLL and NOSLEEP specific on an xs");
- }
- if (tsleep(&lbolt, PRIBIO|PCATCH, "scbusy", 0) == 0) {
- /* if we waited, retry */
- goto retry;
- }
+ bp = xs->bp;
+ if (bp != NULL) {
+ if (error) {
+ bp->b_error = error;
+ bp->b_flags |= B_ERROR;
+ bp->b_resid = bp->b_bcount;
+ } else {
+ bp->b_error = 0;
+ bp->b_resid = xs->resid;
}
- xs->error = XS_BUSY;
- break;
+ }
- default:
+ if (sc_link->device->done) {
/*
- * The adapter has already called scsi_done(), nothing to do.
+ * Tell the device the operation is actually complete.
+ * No more will happen with this xfer. This for
+ * notification of the upper-level driver only; they
+ * won't be returning any meaningful information to us.
*/
-
- return;
+ (*sc_link->device->done)(xs);
}
-
- s = splbio();
- scsi_done(xs);
- splx(s);
+ scsi_free_xs(xs, 1);
+ if (bp != NULL)
+ biodone(bp);
}
-/*
- * This routine is called by the adapter when its xs handling is done.
- */
-void
-scsi_done(struct scsi_xfer *xs)
+int
+scsi_execute_xs(struct scsi_xfer *xs)
{
- splassert(IPL_BIO);
+ int error, flags, rslt, s;
- xs->flags |= ITSDONE;
+ xs->flags &= ~ITSDONE;
+ xs->error = XS_NOERROR;
+ xs->resid = xs->datalen;
+ xs->status = 0;
+
+ /*
+ * Do the transfer. If we are polling we will return:
+ * COMPLETE, Was poll, and scsi_done has been called
+ * TRY_AGAIN_LATER, Adapter short resources, try again
+ *
+ * if under full steam (interrupts) it will return:
+ * SUCCESSFULLY_QUEUED, will do a wakeup when complete
+ * TRY_AGAIN_LATER, (as for polling)
+ * After the wakeup, we must still check if it succeeded
+ *
+ * If we have a SCSI_NOSLEEP (typically because we have a buf)
+ * we just return. All the error processing and the buffer
+ * code both expect us to return straight to them, so as soon
+ * as the command is queued, return.
+ */
+
+ /*
+ * We save the flags here because the xs structure may already
+ * be freed by scsi_done by the time adapter->scsi_cmd returns.
+ *
+ * scsi_done is responsible for freeing the xs if either
+ * (flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP
+ * -or-
+ * (flags & SCSI_USER) != 0
+ *
+ * Note: SCSI_USER must always be called with SCSI_NOSLEEP
+ * and never with SCSI_POLL, so the second expression should be
+ * is equivalent to the first.
+ */
- xs->done(xs);
+ flags = xs->flags;
+#ifdef DIAGNOSTIC
+ if ((flags & (SCSI_USER | SCSI_NOSLEEP)) == SCSI_USER)
+ panic("scsi_execute_xs: USER without NOSLEEP");
+ if ((flags & (SCSI_USER | SCSI_POLL)) == (SCSI_USER | SCSI_POLL))
+ panic("scsi_execute_xs: USER with POLL");
+#endif
+retry:
+ rslt = (*(xs->sc_link->adapter->scsi_cmd))(xs);
+ switch (rslt) {
+ case SUCCESSFULLY_QUEUED:
+ if ((flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP)
+ return (EJUSTRETURN);
+#ifdef DIAGNOSTIC
+ if (flags & SCSI_NOSLEEP)
+ panic("scsi_execute_xs: NOSLEEP and POLL");
+#endif
+ s = splbio();
+ /* Since the xs is active we can't bail out on a signal. */
+ while ((xs->flags & ITSDONE) == 0)
+ tsleep(xs, PRIBIO + 1, "scsicmd", 0);
+ splx(s);
+ /* FALLTHROUGH */
+ case COMPLETE: /* Polling command completed ok */
+ if ((flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP)
+ return (EJUSTRETURN);
+ if (xs->bp)
+ return (EJUSTRETURN);
+ doit:
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("back in cmd()\n"));
+ if ((error = sc_err1(xs)) != ERESTART)
+ return (error);
+ goto retry;
+
+ case TRY_AGAIN_LATER: /* adapter resource shortage */
+ xs->error = XS_BUSY;
+ goto doit;
+
+ case NO_CCB:
+ return (EAGAIN);
+
+ default:
+ panic("scsi_execute_xs: invalid return code (%#x)", rslt);
+ }
+
+#ifdef DIAGNOSTIC
+ panic("scsi_execute_xs: impossible");
+#endif
+ return (EINVAL);
}
/*
@@ -796,81 +943,52 @@ scsi_done(struct scsi_xfer *xs)
* to associate with the transfer, we need that too.
*/
int
-scsi_scsi_cmd(struct scsi_link *link, struct scsi_generic *scsi_cmd,
+scsi_scsi_cmd(struct scsi_link *sc_link, struct scsi_generic *scsi_cmd,
int cmdlen, u_char *data_addr, int datalen, int retries, int timeout,
struct buf *bp, int flags)
{
- struct scsi_xfer *xs;
- int error;
- int s;
+ struct scsi_xfer *xs;
+ int error;
+ int s;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n"));
#ifdef DIAGNOSTIC
if (bp != NULL && (flags & SCSI_NOSLEEP) == 0)
panic("scsi_scsi_cmd: buffer without nosleep");
#endif
- xs = scsi_xs_get(link, flags);
- if (xs == NULL)
+ if ((xs = scsi_make_xs(sc_link, scsi_cmd, cmdlen, data_addr, datalen,
+ retries, timeout, bp, flags)) == NULL)
return (ENOMEM);
- memcpy(xs->cmd, scsi_cmd, cmdlen);
- xs->cmdlen = cmdlen;
- xs->data = data_addr;
- xs->datalen = datalen;
- xs->retries = retries;
- xs->timeout = timeout;
+#ifdef SCSIDEBUG
+ if ((sc_link->flags & SDEV_DB1) != 0)
+ if (xs->datalen && (xs->flags & SCSI_DATA_OUT))
+ show_mem(xs->data, min(64, xs->datalen));
+#endif /* SCSIDEBUG */
- xs->done = scsi_xs_done;
+ error = scsi_execute_xs(xs);
- do {
- scsi_xs_exec(xs);
- if (!ISSET(xs->flags, SCSI_POLL)) {
- s = splbio();
- while (!ISSET(xs->flags, ITSDONE))
- tsleep(xs, PRIBIO, "scsicmd", 0);
- splx(s);
- }
+#ifdef SCSIDEBUG
+ if ((sc_link->flags & SDEV_DB1) != 0)
+ if (xs->datalen && (xs->flags & SCSI_DATA_IN))
+ show_mem(xs->data, min(64, xs->datalen));
+#endif /* SCSIDEBUG */
- error = sc_err1(xs);
- } while (error == ERESTART);
-
- if (error != EAGAIN) {
- if (bp != NULL) {
- if (error) {
- bp->b_error = error;
- bp->b_flags |= B_ERROR;
- bp->b_resid = bp->b_bcount;
- } else {
- bp->b_error = 0;
- bp->b_resid = xs->resid;
- }
-
- s = splbio();
- biodone(bp);
- splx(s);
- }
+ if (error == EJUSTRETURN)
+ return (0);
- if (link->device->done) {
- /*
- * Tell the device the operation is actually complete.
- * No more will happen with this xfer. This for
- * notification of the upper-level driver only; they
- * won't be returning any meaningful information to us.
- */
- link->device->done(xs);
- }
- }
+ s = splbio();
- scsi_xs_put(xs);
+ if (error == EAGAIN)
+ scsi_free_xs(xs, 0); /* Don't restart queue. */
+ else
+ scsi_free_xs(xs, 1);
- return (error);
-}
+ splx(s);
-void
-scsi_xs_done(struct scsi_xfer *xs)
-{
- if (!ISSET(xs->flags, SCSI_POLL))
- wakeup_one(xs);
+ return (error);
}
int
@@ -933,10 +1051,6 @@ sc_err1(struct scsi_xfer *xs)
error = EIO;
break;
- case XS_NO_CCB:
- error = EAGAIN;
- break;
-
default:
sc_print_addr(xs->sc_link);
printf("unknown error category (0x%x) from scsi driver\n",
@@ -996,6 +1110,10 @@ scsi_interpret_sense(struct scsi_xfer *xs)
sense->flags & SSD_EOM ? 1 : 0,
sense->flags & SSD_FILEMARK ? 1 : 0,
sense->extra_len));
+#ifdef SCSIDEBUG
+ if ((sc_link->flags & SDEV_DB1) != 0)
+ show_mem((u_char *)&xs->sense, sizeof xs->sense);
+#endif /* SCSIDEBUG */
/*
* If the device has its own error handler, call it first.
@@ -1888,3 +2006,57 @@ scsi_decode_sense(struct scsi_sense_data *sense, int flag)
return (rqsbuf);
}
+
+#ifdef SCSIDEBUG
+/*
+ * Given a scsi_xfer, dump the request, in all its glory
+ */
+void
+show_scsi_xs(struct scsi_xfer *xs)
+{
+ u_char *b = (u_char *) xs->cmd;
+ int i = 0;
+
+ sc_print_addr(xs->sc_link);
+
+ printf("xs(%p): ", xs);
+
+ printf("flg(0x%x)", xs->flags);
+ printf("sc_link(%p)", xs->sc_link);
+ printf("retr(0x%x)", xs->retries);
+ printf("timo(0x%x)", xs->timeout);
+ printf("cmd(%p)", xs->cmd);
+ printf("len(0x%x)", xs->cmdlen);
+ printf("data(%p)", xs->data);
+ printf("len(0x%x)", xs->datalen);
+ printf("res(0x%x)", xs->resid);
+ printf("err(0x%x)", xs->error);
+ printf("bp(%p)\n", xs->bp);
+
+ printf("command: ");
+
+ if ((xs->flags & SCSI_RESET) == 0) {
+ while (i < xs->cmdlen) {
+ if (i)
+ printf(",");
+ printf("%x", b[i++]);
+ }
+ printf("-[%d bytes]\n", xs->datalen);
+ } else
+ printf("-RESET-\n");
+}
+
+void
+show_mem(u_char *address, int num)
+{
+ int x;
+
+ printf("------------------------------");
+ for (x = 0; x < num; x++) {
+ if ((x % 16) == 0)
+ printf("\n%03d: ", x);
+ printf("%02x ", *address++);
+ }
+ printf("\n------------------------------\n");
+}
+#endif /* SCSIDEBUG */
diff --git a/sys/scsi/scsi_ioctl.c b/sys/scsi/scsi_ioctl.c
index 2ccccc95b65..2b4d79d2532 100644
--- a/sys/scsi/scsi_ioctl.c
+++ b/sys/scsi/scsi_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsi_ioctl.c,v 1.36 2009/11/10 10:13:08 dlg Exp $ */
+/* $OpenBSD: scsi_ioctl.c,v 1.37 2009/11/12 06:20:27 dlg Exp $ */
/* $NetBSD: scsi_ioctl.c,v 1.23 1996/10/12 23:23:17 christos Exp $ */
/*
@@ -52,7 +52,22 @@
#include <scsi/scsiconf.h>
#include <sys/scsiio.h>
-int scsi_ioc_cmd(struct scsi_link *, scsireq_t *);
+struct scsi_ioctl {
+ LIST_ENTRY(scsi_ioctl) si_list;
+ struct buf si_bp;
+ struct uio si_uio;
+ struct iovec si_iov;
+ scsireq_t si_screq;
+ struct scsi_link *si_sc_link;
+};
+
+LIST_HEAD(, scsi_ioctl) si_head;
+
+struct scsi_ioctl *si_get(void);
+void si_free(struct scsi_ioctl *);
+struct scsi_ioctl *si_find(struct buf *);
+void scsistrategy(struct buf *);
+void scsiminphys(struct buf *);
const unsigned char scsi_readsafe_cmd[256] = {
[0x00] = 1, /* TEST UNIT READY */
@@ -95,98 +110,237 @@ const unsigned char scsi_readsafe_cmd[256] = {
[0xbe] = 1 /* READ CD */
};
-int
-scsi_ioc_cmd(struct scsi_link *link, scsireq_t *screq)
+struct scsi_ioctl *
+si_get(void)
{
- struct scsi_xfer *xs;
- int err = 0;
- int s;
+ struct scsi_ioctl *si;
+ int s;
- if (screq->cmdlen > sizeof(struct scsi_generic))
- return (EFAULT);
+ si = malloc(sizeof(*si), M_TEMP, M_WAITOK | M_ZERO);
+ s = splbio();
+ LIST_INSERT_HEAD(&si_head, si, si_list);
+ splx(s);
+ return (si);
+}
- xs = scsi_xs_get(link, 0);
- if (xs == NULL)
- return (ENOMEM);
+void
+si_free(struct scsi_ioctl *si)
+{
+ int s;
- memcpy(xs->cmd, screq->cmd, screq->cmdlen);
- xs->cmdlen = screq->cmdlen;
+ s = splbio();
+ LIST_REMOVE(si, si_list);
+ splx(s);
+ free(si, M_TEMP);
+}
+
+struct scsi_ioctl *
+si_find(struct buf *bp)
+{
+ struct scsi_ioctl *si;
+ int s;
- if (screq->datalen > 0) {
- xs->data = malloc(screq->datalen, M_TEMP, M_WAITOK);
- xs->datalen = screq->datalen;
+ s = splbio();
+ LIST_FOREACH(si, &si_head, si_list) {
+ if (bp == &si->si_bp)
+ break;
}
+ splx(s);
- if (screq->flags & SCCMD_READ)
- xs->flags |= SCSI_DATA_IN;
- if (screq->flags & SCCMD_WRITE) {
- if (screq->datalen > 0) {
- err = copyin(screq->databuf, xs->data, screq->datalen);
- if (err != 0)
- goto err;
- }
+ return (si);
+}
- xs->flags |= SCSI_DATA_OUT;
- }
+/*
+ * We let the user interpret his own sense in the generic scsi world.
+ * This routine is called at interrupt time if the SCSI_USER bit was set
+ * in the flags passed to scsi_scsi_cmd(). No other completion processing
+ * takes place, even if we are running over another device driver.
+ * The lower level routines that call us here, will free the xs and restart
+ * the device's queue if such exists.
+ */
+void
+scsi_user_done(struct scsi_xfer *xs)
+{
+ struct buf *bp;
+ struct scsi_ioctl *si;
+ scsireq_t *screq;
+ struct scsi_link *sc_link;
- xs->timeout = screq->timeout;
- xs->retries = 0; /* user must do the retries *//* ignored */
+ splassert(IPL_BIO);
- xs->done = (void (*)(struct scsi_xfer *))wakeup;
+ bp = xs->bp;
+ if (bp == NULL) { /* ALL user requests must have a buf */
+ sc_print_addr(xs->sc_link);
+ printf("User command with no buf\n");
+ return;
+ }
- scsi_xs_exec(xs);
- s = splbio();
- while (!ISSET(xs->flags, ITSDONE))
- tsleep(xs, PRIBIO, "scsiioc", 0);
- splx(s);
+ si = si_find(bp);
+ if (si == NULL) {
+ sc_print_addr(xs->sc_link);
+ printf("User command with no ioctl\n");
+ return;
+ }
+
+ screq = &si->si_screq;
+ sc_link = si->si_sc_link;
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("user-done\n"));
screq->retsts = 0;
screq->status = xs->status;
switch (xs->error) {
case XS_NOERROR:
+ SC_DEBUG(sc_link, SDEV_DB3, ("no error\n"));
/* probably rubbish */
screq->datalen_used = xs->datalen - xs->resid;
screq->retsts = SCCMD_OK;
break;
case XS_SENSE:
- screq->senselen_used = min(sizeof(xs->sense),
- sizeof(screq->sense));
- bcopy(&xs->sense, screq->sense, screq->senselen_used);
+ SC_DEBUG(sc_link, SDEV_DB3, ("have sense\n"));
+ screq->senselen_used = min(sizeof(xs->sense), SENSEBUFLEN);
+ bcopy(&xs->sense, screq->sense, screq->senselen);
screq->retsts = SCCMD_SENSE;
break;
case XS_SHORTSENSE:
- printf("XS_SHORTSENSE\n");
- screq->senselen_used = min(sizeof(xs->sense),
- sizeof(screq->sense));
- bcopy(&xs->sense, screq->sense, screq->senselen_used);
+ SC_DEBUG(sc_link, SDEV_DB3, ("have short sense\n"));
+ screq->senselen_used = min(sizeof(xs->sense), SENSEBUFLEN);
+ bcopy(&xs->sense, screq->sense, screq->senselen);
screq->retsts = SCCMD_UNKNOWN;
break;
case XS_DRIVER_STUFFUP:
+ sc_print_addr(sc_link);
+ printf("host adapter code inconsistency\n");
screq->retsts = SCCMD_UNKNOWN;
break;
case XS_TIMEOUT:
+ SC_DEBUG(sc_link, SDEV_DB3, ("timeout\n"));
screq->retsts = SCCMD_TIMEOUT;
break;
case XS_BUSY:
+ SC_DEBUG(sc_link, SDEV_DB3, ("busy\n"));
screq->retsts = SCCMD_BUSY;
break;
default:
+ sc_print_addr(sc_link);
+ printf("unknown error category (0x%x) from host adapter code\n",
+ xs->error);
screq->retsts = SCCMD_UNKNOWN;
break;
}
- if (screq->datalen > 0 && screq->flags & SCCMD_READ) {
- err = copyout(xs->data, screq->databuf, screq->datalen);
- if (err != 0)
- goto err;
+ biodone(bp); /* we're waiting on it in scsi_strategy() */
+}
+
+
+/* Pseudo strategy function
+ * Called by scsi_do_ioctl() via physio/physstrat if there is to
+ * be data transferred, and directly if there is no data transfer.
+ *
+ * Should I reorganize this so it returns to physio instead
+ * of sleeping in scsiio_scsi_cmd? Is there any advantage, other
+ * than avoiding the probable duplicate wakeup in iodone? [PD]
+ *
+ * No, seems ok to me... [JRE]
+ * (I don't see any duplicate wakeups)
+ *
+ * Can't be used with block devices or raw_read/raw_write directly
+ * from the cdevsw/bdevsw tables because they couldn't have added
+ * the screq structure. [JRE]
+ */
+void
+scsistrategy(struct buf *bp)
+{
+ struct scsi_ioctl *si;
+ scsireq_t *screq;
+ struct scsi_link *sc_link;
+ int error;
+ int flags = 0;
+ int s;
+
+ si = si_find(bp);
+ if (si == NULL) {
+ printf("user_strat: No ioctl\n");
+ error = EINVAL;
+ goto bad;
+ }
+
+ screq = &si->si_screq;
+ sc_link = si->si_sc_link;
+ SC_DEBUG(sc_link, SDEV_DB2, ("user_strategy\n"));
+
+ /*
+ * We're in trouble if physio tried to break up the transfer.
+ */
+ if (bp->b_bcount != screq->datalen) {
+ sc_print_addr(sc_link);
+ printf("physio split the request.. cannot proceed\n");
+ error = EIO;
+ goto bad;
+ }
+
+ if (screq->timeout == 0) {
+ error = EINVAL;
+ goto bad;
}
-err:
- if (screq->datalen > 0)
- free(xs->data, M_TEMP);
- scsi_xs_put(xs);
+ if (screq->cmdlen > sizeof(struct scsi_generic)) {
+ sc_print_addr(sc_link);
+ printf("cmdlen too big\n");
+ error = EFAULT;
+ goto bad;
+ }
+
+ if (screq->flags & SCCMD_READ)
+ flags |= SCSI_DATA_IN;
+ if (screq->flags & SCCMD_WRITE)
+ flags |= SCSI_DATA_OUT;
+ if (screq->flags & SCCMD_TARGET)
+ flags |= SCSI_TARGET;
+ if (screq->flags & SCCMD_ESCAPE)
+ flags |= SCSI_ESCAPE;
+
+ error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)screq->cmd,
+ screq->cmdlen, (u_char *)bp->b_data, screq->datalen,
+ 0, /* user must do the retries *//* ignored */
+ screq->timeout, bp, flags | SCSI_USER | SCSI_NOSLEEP);
+
+ /* because there is a bp, scsi_scsi_cmd will return immediately */
+ if (error)
+ goto bad;
+
+ SC_DEBUG(sc_link, SDEV_DB3, ("about to sleep\n"));
+ s = splbio();
+ while ((bp->b_flags & B_DONE) == 0)
+ tsleep(bp, PRIBIO, "scistr", 0);
+ splx(s);
+ SC_DEBUG(sc_link, SDEV_DB3, ("back from sleep\n"));
+
+ return;
+
+bad:
+ bp->b_flags |= B_ERROR;
+ bp->b_error = error;
+ s = splbio();
+ biodone(bp);
+ splx(s);
+}
+
+void
+scsiminphys(struct buf *bp)
+{
+ struct scsi_ioctl *si;
+ struct scsi_link *sc_link;
+
+ si = si_find(bp);
+ if (si == NULL) {
+ /* should not happen */
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EINVAL;
+ return;
+ }
- return (err);
+ sc_link = si->si_sc_link;
+ (*sc_link->adapter->scsi_minphys)(bp, sc_link);
}
/*
@@ -200,6 +354,8 @@ int
scsi_do_ioctl(struct scsi_link *sc_link, dev_t dev, u_long cmd, caddr_t addr,
int flag, struct proc *p)
{
+ int error;
+
SC_DEBUG(sc_link, SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd));
switch(cmd) {
@@ -222,6 +378,7 @@ scsi_do_ioctl(struct scsi_link *sc_link, dev_t dev, u_long cmd, caddr_t addr,
break;
/* FALLTHROUGH */
case SCIOCDEBUG:
+ case SCIOCRESET:
if ((flag & FWRITE) == 0)
return (EPERM);
break;
@@ -234,8 +391,41 @@ scsi_do_ioctl(struct scsi_link *sc_link, dev_t dev, u_long cmd, caddr_t addr,
}
switch(cmd) {
- case SCIOCCOMMAND:
- return (scsi_ioc_cmd(sc_link, (scsireq_t *)addr));
+ case SCIOCCOMMAND: {
+ scsireq_t *screq = (scsireq_t *)addr;
+ struct scsi_ioctl *si;
+
+ si = si_get();
+ si->si_screq = *screq;
+ si->si_sc_link = sc_link;
+ if (screq->datalen) {
+ si->si_iov.iov_base = screq->databuf;
+ si->si_iov.iov_len = screq->datalen;
+ si->si_uio.uio_iov = &si->si_iov;
+ si->si_uio.uio_iovcnt = 1;
+ si->si_uio.uio_resid = screq->datalen;
+ si->si_uio.uio_offset = 0;
+ si->si_uio.uio_segflg = UIO_USERSPACE;
+ si->si_uio.uio_rw =
+ (screq->flags & SCCMD_READ) ? UIO_READ : UIO_WRITE;
+ si->si_uio.uio_procp = p;
+ error = physio(scsistrategy, &si->si_bp, dev,
+ (screq->flags & SCCMD_READ) ? B_READ : B_WRITE,
+ scsiminphys, &si->si_uio);
+ } else {
+ /* if no data, no need to translate it.. */
+ si->si_bp.b_flags = 0;
+ si->si_bp.b_data = 0;
+ si->si_bp.b_bcount = 0;
+ si->si_bp.b_dev = dev;
+ si->si_bp.b_proc = p;
+ scsistrategy(&si->si_bp);
+ error = si->si_bp.b_error;
+ }
+ *screq = si->si_screq;
+ si_free(si);
+ return (error);
+ }
case SCIOCDEBUG: {
int level = *((int *)addr);
@@ -251,6 +441,11 @@ scsi_do_ioctl(struct scsi_link *sc_link, dev_t dev, u_long cmd, caddr_t addr,
sc_link->flags |= SDEV_DB4;
return (0);
}
+ case SCIOCRESET: {
+ scsi_scsi_cmd(sc_link, 0, 0, 0, 0, GENRETRY, 2000, NULL,
+ SCSI_RESET);
+ return (0);
+ }
default:
#ifdef DIAGNOSTIC
panic("scsi_do_ioctl: impossible cmd (%#lx)", cmd);
diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c
index f801a1d5d53..58d0f609d22 100644
--- a/sys/scsi/scsiconf.c
+++ b/sys/scsi/scsiconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsiconf.c,v 1.150 2009/11/10 10:34:07 dlg Exp $ */
+/* $OpenBSD: scsiconf.c,v 1.151 2009/11/12 06:20:27 dlg Exp $ */
/* $NetBSD: scsiconf.c,v 1.57 1996/05/02 01:09:01 neil Exp $ */
/*
@@ -113,10 +113,6 @@ int scsi_autoconf = SCSI_AUTOCONF;
int scsibusprint(void *, const char *);
void scsibus_printlink(struct scsi_link *);
-void scsi_activate_bus(struct scsibus_softc *, int);
-void scsi_activate_target(struct scsibus_softc *, int, int);
-void scsi_activate_lun(struct scsibus_softc *, int, int, int);
-
const u_int8_t version_to_spc [] = {
0, /* 0x00: The device does not claim conformance to any standard. */
1, /* 0x01: (Obsolete) SCSI-1 in olden times. */
@@ -203,99 +199,30 @@ scsibusattach(struct device *parent, struct device *self, void *aux)
int
scsibusactivate(struct device *dev, int act)
{
- struct scsibus_softc *sc = (struct scsibus_softc *)dev;
-
- scsi_activate(sc, -1, -1, act);
-
- return (0);
-}
-
-void
-scsi_activate(struct scsibus_softc *sc, int target, int lun, int act)
-{
- if (target == -1 && lun == -1)
- scsi_activate_bus(sc, act);
-
- if (target == -1)
- return;
-
- if (lun == -1)
- scsi_activate_target(sc, target, act);
-
- scsi_activate_lun(sc, target, lun, act);
-}
-
-void
-scsi_activate_bus(struct scsibus_softc *sc, int act)
-{
- int target;
-
- for (target = 0; target < sc->sc_buswidth; target++)
- scsi_activate_target(sc, target, act);
-}
-
-void
-scsi_activate_target(struct scsibus_softc *sc, int target, int act)
-{
- int lun;
-
- for (lun = 0; lun < sc->adapter_link->luns; lun++)
- scsi_activate_lun(sc, target, lun, act);
-}
-
-void
-scsi_activate_lun(struct scsibus_softc *sc, int target, int lun, int act)
-{
- struct scsi_link *link = sc->sc_link[target][lun];
- struct device *dev;
-
- if (link == NULL)
- return;
-
- dev = link->device_softc;
- switch (act) {
- case DVACT_ACTIVATE:
-#if NMPATH > 0
- if (dev == NULL)
- mpath_path_activate(link);
- else
-#endif /* NMPATH */
- config_activate(dev);
- break;
-
- case DVACT_DEACTIVATE:
-#if NMPATH > 0
- if (dev == NULL)
- mpath_path_deactivate(link);
- else
-#endif /* NMPATH */
- config_deactivate(dev);
- break;
- default:
-#ifdef DIAGNOSTIC
- printf("%s: unsupported act %d\n", sc->sc_dev.dv_xname, act);
-#endif
- break;
- }
+ return (config_activate_children(dev, act));
}
int
scsibusdetach(struct device *dev, int type)
{
struct scsibus_softc *sb = (struct scsibus_softc *)dev;
- int i, error;
+ int i, j, error;
#if NBIO > 0
bio_unregister(&sb->sc_dev);
#endif
- error = scsi_detach_bus(sb, type);
- if (error != 0)
+ if ((error = config_detach_children(dev, type)) != 0)
return (error);
for (i = 0; i < sb->sc_buswidth; i++) {
- if (sb->sc_link[i] != NULL)
+ if (sb->sc_link[i] != NULL) {
+ for (j = 0; j < sb->adapter_link->luns; j++) {
+ if (sb->sc_link[i][j] != NULL)
+ free(sb->sc_link[i][j], M_DEVBUF);
+ }
free(sb->sc_link[i], M_DEVBUF);
+ }
}
free(sb->sc_link, M_DEVBUF);
@@ -347,9 +274,6 @@ scsibus_bioctl(struct device *dev, u_long cmd, caddr_t addr)
case SBIOCDETACH:
sdev = (struct sbioc_device *)addr;
- if (sdev->sd_target == -1 && sdev->sd_lun == -1)
- return (scsi_detach_bus(sc, 0));
-
if (sdev->sd_target == -1)
return (EINVAL);
@@ -455,22 +379,19 @@ int
scsi_detach_bus(struct scsibus_softc *sc, int flags)
{
struct scsi_link *alink = sc->adapter_link;
- int i, err, rv = 0;
+ int i;
- for (i = 0; i < alink->adapter_buswidth; i++) {
- err = scsi_detach_target(sc, i, flags);
- if (err != 0 && err != ENXIO)
- rv = err;
- }
+ for (i = 0; i < alink->adapter_buswidth; i++)
+ scsi_detach_target(sc, i, flags);
- return (rv);
+ return (0);
}
int
scsi_detach_target(struct scsibus_softc *sc, int target, int flags)
{
struct scsi_link *alink = sc->adapter_link;
- int i, err, rv = 0;
+ int i, err, rv = 0, detached = 0;
if (target < 0 || target >= alink->adapter_buswidth ||
target == alink->adapter_target)
@@ -484,11 +405,12 @@ scsi_detach_target(struct scsibus_softc *sc, int target, int flags)
continue;
err = scsi_detach_lun(sc, target, i, flags);
- if (err != 0 && err != ENXIO)
+ if (err != 0)
rv = err;
+ detached = 1;
}
- return (rv);
+ return (detached ? rv : ENXIO);
}
int
@@ -531,8 +453,6 @@ scsi_detach_lun(struct scsibus_softc *sc, int target, int lun, int flags)
alink->adapter->dev_free(link);
/* 3. free up its state in the midlayer */
- if (link->id != NULL)
- devid_free(link->id);
free(link, M_DEVBUF);
sc->sc_link[target][lun] = NULL;
@@ -765,42 +685,6 @@ scsibus_printlink(struct scsi_link *link)
printf("SCSI%d", SCSISPC(inqbuf->version));
printf(" %d/%s %s%s", type, dtype, removable ? "removable" : "fixed",
qtype);
-
-#if NMPATH > 0
- if (link->id != NULL && link->id->d_type != DEVID_NONE) {
- u_int8_t *id = (u_int8_t *)(link->id + 1);
- int i;
-
- switch (link->id->d_type) {
- case DEVID_NAA:
- printf(" naa.");
- break;
- case DEVID_EUI:
- printf(" eui.");
- break;
- case DEVID_T10:
- printf(" t10.");
- break;
- }
-
- if (ISSET(link->id->d_flags, DEVID_F_PRINT)) {
- for (i = 0; i < link->id->d_len; i++) {
- if (id[i] == '\0' || id[i] == ' ')
- printf("_");
- else if (id[i] < 0x20 || id[i] >= 0x80) {
- /* non-printable characters */
- printf("~");
- } else {
- /* normal characters */
- printf("%c", id[i]);
- }
- }
- } else {
- for (i = 0; i < link->id->d_len; i++)
- printf("%02x", id[i]);
- }
- }
-#endif /* NMPATH > 0 */
}
/*
@@ -854,7 +738,6 @@ scsi_probedev(struct scsibus_softc *scsi, int target, int lun)
sc_link->target = target;
sc_link->lun = lun;
sc_link->device = &probe_switch;
- mtx_init(&sc_link->mtx, IPL_BIO);
inqbuf = &sc_link->inqdata;
SC_DEBUG(sc_link, SDEV_DB2, ("scsi_link created.\n"));
@@ -927,15 +810,15 @@ scsi_probedev(struct scsibus_softc *scsi, int target, int lun)
;
else if (sc_link->flags & SDEV_UMASS)
;
- else if (sc_link->id != NULL &&
- !DEVID_CMP(scsi->sc_link[target][0]->id, sc_link->id))
+ else if (sc_link->id.d_type != DEVID_NONE &&
+ !DEVID_CMP(&scsi->sc_link[target][0]->id, &sc_link->id))
;
else if (memcmp(inqbuf, &scsi->sc_link[target][0]->inqdata,
sizeof(*inqbuf)) == 0) {
/* The device doesn't distinguish between LUNs. */
SC_DEBUG(sc_link, SDEV_DB1, ("IDENTIFY not supported.\n"));
rslt = EINVAL;
- goto free_devid;
+ goto bad;
}
#if NMPATH > 0
@@ -989,7 +872,7 @@ scsi_probedev(struct scsibus_softc *scsi, int target, int lun)
&sa)) == 0) {
scsibusprint(&sa, scsi->sc_dev.dv_xname);
printf(" not configured\n");
- goto free_devid;
+ goto bad;
}
/*
@@ -1026,9 +909,6 @@ scsi_probedev(struct scsibus_softc *scsi, int target, int lun)
return (0);
-free_devid:
- if (sc_link->id)
- devid_free(sc_link->id);
bad:
if (scsi->adapter_link->adapter->dev_free != NULL)
scsi->adapter_link->adapter->dev_free(sc_link);
@@ -1099,9 +979,6 @@ scsi_devid(struct scsi_link *link)
} __packed pg;
int pg80 = 0, pg83 = 0, i;
- if (link->id != NULL)
- return;
-
if (SCSISPC(link->inqdata.version) >= 2) {
if (scsi_inquire_vpd(link, &pg, sizeof(pg), SI_PG_SUPPORTED,
scsi_autoconf) != 0)
@@ -1131,10 +1008,9 @@ int
scsi_devid_pg83(struct scsi_link *link)
{
struct scsi_vpd_hdr hdr;
- struct scsi_vpd_devid_hdr dhdr, chdr;
+ struct scsi_vpd_devid_hdr dhdr;
u_int8_t *pg, *id;
- int type, idtype = 0;
- u_char idflags;
+ int type, idtype = 0, idlen;
int len, pos;
int rv;
@@ -1172,8 +1048,7 @@ scsi_devid_pg83(struct scsi_link *link)
case VPD_DEVID_TYPE_T10:
if (type >= idtype) {
idtype = type;
-
- chdr = dhdr;
+ idlen = dhdr.len;
id = &pg[pos];
}
break;
@@ -1188,27 +1063,21 @@ scsi_devid_pg83(struct scsi_link *link)
} while (idtype != VPD_DEVID_TYPE_NAA && len != pos);
if (idtype > 0) {
- switch (VPD_DEVID_TYPE(chdr.flags)) {
+ link->id.d_id = malloc(idlen, M_DEVBUF, M_WAITOK);
+
+ switch (idtype) {
case VPD_DEVID_TYPE_NAA:
- idtype = DEVID_NAA;
+ link->id.d_type = DEVID_NAA;
break;
case VPD_DEVID_TYPE_EUI64:
- idtype = DEVID_EUI;
+ link->id.d_type = DEVID_EUI;
break;
case VPD_DEVID_TYPE_T10:
- idtype = DEVID_T10;
+ link->id.d_type = DEVID_T10;
break;
}
- switch (VPD_DEVID_CODE(chdr.pi_code)) {
- case VPD_DEVID_CODE_ASCII:
- case VPD_DEVID_CODE_UTF8:
- idflags = DEVID_F_PRINT;
- break;
- default:
- idflags = 0;
- break;
- }
- link->id = devid_alloc(idtype, idflags, chdr.len, id);
+ link->id.d_len = idlen;
+ memcpy(link->id.d_id, id, idlen);
} else
rv = ENODEV;
@@ -1226,35 +1095,3 @@ scsi_minphys(struct buf *bp, struct scsi_link *sl)
{
minphys(bp);
}
-
-struct devid *
-devid_alloc(u_int8_t type, u_int8_t flags, u_int8_t len, u_int8_t *id)
-{
- struct devid *d;
-
- d = malloc(sizeof(*d) + len, M_DEVBUF, M_WAITOK|M_CANFAIL);
- if (d == NULL)
- return (NULL);
-
- d->d_type = type;
- d->d_flags = flags;
- d->d_len = len;
- d->d_refcount = 1;
- memcpy(d + 1, id, len);
-
- return (d);
-}
-
-struct devid *
-devid_copy(struct devid *d)
-{
- d->d_refcount++;
- return (d);
-}
-
-void
-devid_free(struct devid *d)
-{
- if (--d->d_refcount == 0)
- free(d, M_DEVBUF);
-}
diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h
index 8e115ccab3c..be4d14053dc 100644
--- a/sys/scsi/scsiconf.h
+++ b/sys/scsi/scsiconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsiconf.h,v 1.108 2009/11/10 10:18:59 dlg Exp $ */
+/* $OpenBSD: scsiconf.h,v 1.109 2009/11/12 06:20:27 dlg Exp $ */
/* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */
/*
@@ -53,7 +53,6 @@
#include <sys/queue.h>
#include <sys/timeout.h>
#include <sys/workq.h>
-#include <sys/mutex.h>
#include <machine/cpu.h>
#include <scsi/scsi_debug.h>
@@ -235,31 +234,20 @@ _4ltol(u_int8_t *bytes)
#define DEVID_T10 3
struct devid {
- u_int8_t d_type;
- u_int8_t d_flags;
-#define DEVID_F_PRINT (1<<0)
- u_int8_t d_refcount;
- u_int8_t d_len;
-
- /*
- * the devid struct is basically a header, the actual id is allocated
- * immediately after it.
- */
+ int d_type;
+ u_int d_len;
+ u_int8_t *d_id;
};
-#define DEVID_CMP(_a, _b) ( \
- (_a) != NULL && (_b) != NULL && \
- ((_a) == (_b) || \
- ((_a)->d_type != DEVID_NONE && \
- (_a)->d_type == (_b)->d_type && \
- (_a)->d_len == (_b)->d_len && \
- bcmp((_a) + 1, (_b) + 1, (_a)->d_len) == 0)) \
+#define DEVID_CMP(_a, _b) ( \
+ (_a) != NULL && \
+ (_b) != NULL && \
+ (_a)->d_type != DEVID_NONE && \
+ (_a)->d_type == (_b)->d_type && \
+ (_a)->d_len == (_b)->d_len && \
+ bcmp((_a)->d_id, (_b)->d_id, (_a)->d_len) == 0 \
)
-struct devid * devid_alloc(u_int8_t, u_int8_t, u_int8_t, u_int8_t *);
-struct devid * devid_copy(struct devid *);
-void devid_free(struct devid *);
-
/*
* The following documentation tries to describe the relationship between the
* various structures defined in this file:
@@ -351,6 +339,7 @@ struct scsi_link {
u_int64_t node_wwn; /* world wide name of node */
u_int16_t adapter_target; /* what are we on the scsi bus */
u_int16_t adapter_buswidth; /* 8 (regular) or 16 (wide). (0 becomes 8) */
+ u_int16_t active; /* operations in progress */
u_int16_t flags; /* flags that all devices have */
#define SDEV_REMOVABLE 0x0001 /* media is removable */
#define SDEV_MEDIA_LOADED 0x0002 /* device figures are still valid */
@@ -379,8 +368,7 @@ struct scsi_link {
void *adapter_softc; /* needed for call to foo_scsi_cmd */
struct scsibus_softc *bus; /* link to the scsibus we're on */
struct scsi_inquiry_data inqdata; /* copy of INQUIRY data from probe */
- struct devid *id;
- struct mutex mtx;
+ struct devid id;
};
int scsiprint(void *, const char *);
@@ -456,8 +444,6 @@ struct scsi_xfer {
* timeout structure for hba's to use for a command
*/
struct timeout stimeout;
- void *cookie;
- void (*done)(struct scsi_xfer *);
};
/*
@@ -500,7 +486,6 @@ struct scsi_xfer {
#define XS_BUSY 5 /* The device busy, try again later? */
#define XS_SHORTSENSE 6 /* Check the ATAPI sense for the error */
#define XS_RESET 8 /* bus was reset; possible retry command */
-#define XS_NO_CCB 9 /* device should requeue io and retry */
/*
* Possible retries for scsi_test_unit_ready()
@@ -572,23 +557,14 @@ int scsi_detach_lun(struct scsibus_softc *, int, int, int);
int scsi_req_probe(struct scsibus_softc *, int, int);
int scsi_req_detach(struct scsibus_softc *, int, int, int);
-void scsi_activate(struct scsibus_softc *, int, int, int);
-
extern const u_int8_t version_to_spc[];
#define SCSISPC(x)(version_to_spc[(x) & SID_ANSII])
-struct scsi_xfer * scsi_xs_get(struct scsi_link *, int);
-void scsi_xs_exec(struct scsi_xfer *);
-void scsi_xs_put(struct scsi_xfer *);
-
/*
* Entrypoints for multipathing
*/
int mpath_path_attach(struct scsi_link *);
int mpath_path_detach(struct scsi_link *, int);
-void mpath_path_activate(struct scsi_link *);
-void mpath_path_deactivate(struct scsi_link *);
-
#endif /* _KERNEL */
#endif /* SCSI_SCSICONF_H */
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c
index 4ab8afe13d4..baf354d80b0 100644
--- a/sys/scsi/sd.c
+++ b/sys/scsi/sd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sd.c,v 1.163 2009/11/10 10:18:59 dlg Exp $ */
+/* $OpenBSD: sd.c,v 1.164 2009/11/12 06:20:27 dlg Exp $ */
/* $NetBSD: sd.c,v 1.111 1997/04/02 02:29:41 mycroft Exp $ */
/*-
@@ -83,7 +83,10 @@ int sddetach(struct device *, int);
void sdminphys(struct buf *);
int sdgetdisklabel(dev_t, struct sd_softc *, struct disklabel *, int);
void sdstart(void *);
+void sdrestart(void *);
+void sddone(struct scsi_xfer *);
void sd_shutdown(void *);
+int sd_reassign_blocks(struct sd_softc *, u_long);
int sd_interpret_sense(struct scsi_xfer *);
int sd_get_parms(struct sd_softc *, struct disk_parms *, int);
void sd_flush(struct sd_softc *, int);
@@ -93,16 +96,6 @@ void viscpy(u_char *, u_char *, int);
int sd_ioctl_inquiry(struct sd_softc *, struct dk_inquiry *);
-struct buf *sd_buf_dequeue(struct sd_softc *);
-void sd_buf_requeue(struct sd_softc *, struct buf *);
-
-void sd_cmd_rw6(struct scsi_xfer *, int, daddr64_t, u_int);
-void sd_cmd_rw10(struct scsi_xfer *, int, daddr64_t, u_int);
-void sd_cmd_rw12(struct scsi_xfer *, int, daddr64_t, u_int);
-void sd_cmd_rw16(struct scsi_xfer *, int, daddr64_t, u_int);
-
-void sd_buf_done(struct scsi_xfer *);
-
struct cfattach sd_ca = {
sizeof(struct sd_softc), sdmatch, sdattach,
sddetach, sdactivate
@@ -118,7 +111,7 @@ struct scsi_device sd_switch = {
sd_interpret_sense, /* check out error handler first */
sdstart, /* have a queue, served by this */
NULL, /* have no async handler */
- NULL, /* have no done handler */
+ sddone, /* deal with stats at interrupt time */
};
const struct scsi_inquiry_pattern sd_patterns[] = {
@@ -170,8 +163,6 @@ sdattach(struct device *parent, struct device *self, void *aux)
SC_DEBUG(sc_link, SDEV_DB2, ("sdattach:\n"));
- mtx_init(&sd->sc_buf_mtx, IPL_BIO);
-
/*
* Store information needed to contact our base driver
*/
@@ -206,7 +197,7 @@ sdattach(struct device *parent, struct device *self, void *aux)
*/
printf("\n");
- timeout_set(&sd->sc_timeout, sdstart, sd);
+ timeout_set(&sd->sc_timeout, sdrestart, sd);
/* Spin up non-UMASS devices ready or not. */
if ((sd->sc_link->flags & SDEV_UMASS) == 0)
@@ -560,12 +551,12 @@ sdstrategy(struct buf *bp)
(sd->flags & (SDF_WLABEL|SDF_LABELLING)) != 0) <= 0)
goto done;
+ s = splbio();
+
/*
* Place it in the queue of disk activities for this disk
*/
- mtx_enter(&sd->sc_buf_mtx);
- disksort(&sd->sc_buf_queue, bp);
- mtx_leave(&sd->sc_buf_mtx);
+ disksort(&sd->buf_queue, bp);
/*
* Tell the device to get going on the transfer if it's
@@ -573,6 +564,8 @@ sdstrategy(struct buf *bp)
*/
sdstart(sd);
+ splx(s);
+
device_unref(&sd->sc_dev);
return;
@@ -590,77 +583,6 @@ done:
device_unref(&sd->sc_dev);
}
-struct buf *
-sd_buf_dequeue(struct sd_softc *sc)
-{
- struct buf *bp;
-
- mtx_enter(&sc->sc_buf_mtx);
- bp = sc->sc_buf_queue.b_actf;
- if (bp != NULL)
- sc->sc_buf_queue.b_actf = bp->b_actf;
- mtx_leave(&sc->sc_buf_mtx);
-
- return (bp);
-}
-
-void
-sd_buf_requeue(struct sd_softc *sc, struct buf *bp)
-{
- mtx_enter(&sc->sc_buf_mtx);
- bp->b_actf = sc->sc_buf_queue.b_actf;
- sc->sc_buf_queue.b_actf = bp;
- mtx_leave(&sc->sc_buf_mtx);
-}
-
-void
-sd_cmd_rw6(struct scsi_xfer *xs, int read, daddr64_t blkno, u_int nblks)
-{
- struct scsi_rw *cmd = (struct scsi_rw *)xs->cmd;
-
- cmd->opcode = read ? READ_COMMAND : WRITE_COMMAND;
- _lto3b(blkno, cmd->addr);
- cmd->length = nblks;
-
- xs->cmdlen = sizeof(*cmd);
-}
-
-void
-sd_cmd_rw10(struct scsi_xfer *xs, int read, daddr64_t blkno, u_int nblks)
-{
- struct scsi_rw_big *cmd = (struct scsi_rw_big *)xs->cmd;
-
- cmd->opcode = read ? READ_BIG : WRITE_BIG;
- _lto4b(blkno, cmd->addr);
- _lto2b(nblks, cmd->length);
-
- xs->cmdlen = sizeof(*cmd);
-}
-
-void
-sd_cmd_rw12(struct scsi_xfer *xs, int read, daddr64_t blkno, u_int nblks)
-{
- struct scsi_rw_12 *cmd = (struct scsi_rw_12 *)xs->cmd;
-
- cmd->opcode = read ? READ_12 : WRITE_12;
- _lto4b(blkno, cmd->addr);
- _lto4b(nblks, cmd->length);
-
- xs->cmdlen = sizeof(*cmd);
-}
-
-void
-sd_cmd_rw16(struct scsi_xfer *xs, int read, daddr64_t blkno, u_int nblks)
-{
- struct scsi_rw_16 *cmd = (struct scsi_rw_16 *)xs->cmd;
-
- cmd->opcode = read ? READ_16 : WRITE_16;
- _lto8b(blkno, cmd->addr);
- _lto4b(nblks, cmd->length);
-
- xs->cmdlen = sizeof(*cmd);
-}
-
/*
* sdstart looks to see if there is a buf waiting for the device
* and that the device is not already busy. If both are true,
@@ -673,33 +595,62 @@ sd_cmd_rw16(struct scsi_xfer *xs, int read, daddr64_t blkno, u_int nblks)
* This routine is also called after other non-queued requests
* have been made of the scsi driver, to ensure that the queue
* continues to be drained.
+ *
+ * must be called at the correct (highish) spl level
+ * sdstart() is called at splbio from sdstrategy, sdrestart and scsi_done
*/
void
sdstart(void *v)
{
- struct sd_softc *sc = (struct sd_softc *)v;
- struct scsi_link *link = sc->sc_link;
- struct scsi_xfer *xs;
- struct buf *bp;
+ struct sd_softc *sd = (struct sd_softc *)v;
+ struct scsi_link *sc_link = sd->sc_link;
+ struct buf *bp = 0;
+ struct buf *dp;
+ struct scsi_rw_big cmd_big;
+ struct scsi_rw_12 cmd_12;
+ struct scsi_rw_16 cmd_16;
+ struct scsi_rw cmd_small;
+ struct scsi_generic *cmdp;
daddr64_t blkno;
- int nblks;
- int read;
+ int nblks, cmdlen, error;
struct partition *p;
- if (sc->flags & SDF_DYING)
+ if (sd->flags & SDF_DYING)
return;
SC_DEBUG(sc_link, SDEV_DB2, ("sdstart\n"));
- CLR(sc->flags, SDF_WAITING);
- while (!ISSET(sc->flags, SDF_WAITING) &&
- (bp = sd_buf_dequeue(sc)) != NULL) {
+ splassert(IPL_BIO);
+
+ /*
+ * Check if the device has room for another command
+ */
+ while (sc_link->openings > 0) {
+ /*
+ * there is excess capacity, but a special waits
+ * It'll need the adapter as soon as we clear out of the
+ * way and let it run (user level wait).
+ */
+ if (sc_link->flags & SDEV_WAITING) {
+ sc_link->flags &= ~SDEV_WAITING;
+ wakeup((caddr_t)sc_link);
+ return;
+ }
+
+ /*
+ * See if there is a buf with work for us to do..
+ */
+ dp = &sd->buf_queue;
+ if ((bp = dp->b_actf) == NULL) /* yes, an assign */
+ return;
+ dp->b_actf = bp->b_actf;
+
/*
* If the device has become invalid, abort all the
* reads and writes until all files have been closed and
* re-opened
*/
- if ((link->flags & SDEV_MEDIA_LOADED) == 0) {
+ if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
bp->b_resid = bp->b_bcount;
@@ -707,86 +658,129 @@ sdstart(void *v)
continue;
}
- xs = scsi_xs_get(link, SCSI_NOSLEEP);
- if (xs == NULL) {
- sd_buf_requeue(sc, bp);
- return;
- }
-
+ /*
+ * We have a buf, now we should make a command
+ *
+ * First, translate the block to absolute and put it in terms
+ * of the logical blocksize of the device.
+ */
blkno =
- bp->b_blkno / (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE);
- p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
+ bp->b_blkno / (sd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
+ p = &sd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
blkno += DL_GETPOFFSET(p);
- nblks = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize);
- read = bp->b_flags & B_READ;
+ nblks = howmany(bp->b_bcount, sd->sc_dk.dk_label->d_secsize);
/*
* Fill out the scsi command. If the transfer will
* fit in a "small" cdb, use it.
*/
- if (!(link->flags & SDEV_ATAPI) &&
- !(link->quirks & SDEV_ONLYBIG) &&
+ if (!(sc_link->flags & SDEV_ATAPI) &&
+ !(sc_link->quirks & SDEV_ONLYBIG) &&
((blkno & 0x1fffff) == blkno) &&
- ((nblks & 0xff) == nblks))
- sd_cmd_rw6(xs, read, blkno, nblks);
- else if (((blkno & 0xffffffff) == blkno) &&
- ((nblks & 0xffff) == nblks))
- sd_cmd_rw10(xs, read, blkno, nblks);
- else if (((blkno & 0xffffffff) == blkno) &&
- ((nblks & 0xffffffff) == nblks))
- sd_cmd_rw12(xs, read, blkno, nblks);
- else
- sd_cmd_rw16(xs, read, blkno, nblks);
-
- xs->flags |= (read ? SCSI_DATA_IN : SCSI_DATA_OUT);
- xs->timeout = 60000;
- xs->data = bp->b_data;
- xs->datalen = bp->b_bcount;
-
- xs->done = sd_buf_done;
- xs->cookie = bp;
+ ((nblks & 0xff) == nblks)) {
+ /*
+ * We can fit in a 6 byte cdb.
+ */
+ bzero(&cmd_small, sizeof(cmd_small));
+ cmd_small.opcode = (bp->b_flags & B_READ) ?
+ READ_COMMAND : WRITE_COMMAND;
+ _lto3b(blkno, cmd_small.addr);
+ cmd_small.length = nblks;
+ cmdlen = sizeof(cmd_small);
+ cmdp = (struct scsi_generic *)&cmd_small;
+ } else if (((blkno & 0xffffffff) == blkno) &&
+ ((nblks & 0xffff) == nblks)) {
+ /*
+ * We can fit in a 10 byte cdb.
+ */
+ bzero(&cmd_big, sizeof(cmd_big));
+ cmd_big.opcode = (bp->b_flags & B_READ) ?
+ READ_BIG : WRITE_BIG;
+ _lto4b(blkno, cmd_big.addr);
+ _lto2b(nblks, cmd_big.length);
+ cmdlen = sizeof(cmd_big);
+ cmdp = (struct scsi_generic *)&cmd_big;
+ } else if (((blkno & 0xffffffff) == blkno) &&
+ ((nblks & 0xffffffff) == nblks)) {
+ /*
+ * We can fit in a 12 byte cdb.
+ */
+ bzero(&cmd_12, sizeof(cmd_12));
+ cmd_12.opcode = (bp->b_flags & B_READ) ?
+ READ_12 : WRITE_12;
+ _lto4b(blkno, cmd_12.addr);
+ _lto4b(nblks, cmd_12.length);
+ cmdlen = sizeof(cmd_12);
+ cmdp = (struct scsi_generic *)&cmd_12;
+ } else {
+ /*
+ * Need a 16 byte cdb. There's nothing bigger.
+ */
+ bzero(&cmd_16, sizeof(cmd_16));
+ cmd_16.opcode = (bp->b_flags & B_READ) ?
+ READ_16 : WRITE_16;
+ _lto8b(blkno, cmd_16.addr);
+ _lto4b(nblks, cmd_16.length);
+ cmdlen = sizeof(cmd_16);
+ cmdp = (struct scsi_generic *)&cmd_16;
+ }
/* Instrumentation. */
- disk_busy(&sc->sc_dk);
- scsi_xs_exec(xs);
+ disk_busy(&sd->sc_dk);
+
+ /*
+ * Call the routine that chats with the adapter.
+ * Note: we cannot sleep as we may be an interrupt
+ */
+ error = scsi_scsi_cmd(sc_link, cmdp, cmdlen,
+ (u_char *)bp->b_data, bp->b_bcount,
+ SCSI_RETRIES, 60000, bp, SCSI_NOSLEEP |
+ ((bp->b_flags & B_READ) ? SCSI_DATA_IN : SCSI_DATA_OUT));
+ switch (error) {
+ case 0:
+ /*
+ * Mark the disk dirty so that the cache will be
+ * flushed on close.
+ */
+ if ((bp->b_flags & B_READ) == 0)
+ sd->flags |= SDF_DIRTY;
+ timeout_del(&sd->sc_timeout);
+ break;
+ case EAGAIN:
+ /*
+ * The device can't start another i/o. Try again later.
+ */
+ dp->b_actf = bp;
+ disk_unbusy(&sd->sc_dk, 0, 0);
+ timeout_add(&sd->sc_timeout, 1);
+ return;
+ default:
+ disk_unbusy(&sd->sc_dk, 0, 0);
+ printf("%s: not queued, error %d\n",
+ sd->sc_dev.dv_xname, error);
+ break;
+ }
}
}
void
-sd_buf_done(struct scsi_xfer *xs)
+sdrestart(void *v)
{
- struct sd_softc *sc = xs->sc_link->device_softc;
- struct buf *bp = xs->cookie;
-
- splassert(IPL_BIO);
-
- disk_unbusy(&sc->sc_dk, bp->b_bcount - xs->resid,
- bp->b_flags & B_READ);
-
- switch (xs->error) {
- case XS_NOERROR:
- bp->b_error = 0;
- bp->b_resid = xs->resid;
- break;
+ int s;
- case XS_NO_CCB:
- /* The hardware is busy, requeue the buf and try it later. */
- sd_buf_requeue(sc, bp);
- scsi_xs_put(xs);
- SET(sc->flags, SDF_WAITING); /* break out of sdstart loop */
- timeout_add(&sc->sc_timeout, 1);
- return;
+ s = splbio();
+ sdstart(v);
+ splx(s);
+}
- default:
- bp->b_error = EIO;
- bp->b_flags |= B_ERROR;
- bp->b_resid = bp->b_bcount;
- break;
- }
+void
+sddone(struct scsi_xfer *xs)
+{
+ struct sd_softc *sd = xs->sc_link->device_softc;
- biodone(bp);
- scsi_xs_put(xs);
- sdstart(sc); /* restart io */
+ if (xs->bp != NULL)
+ disk_unbusy(&sd->sc_dk, (xs->bp->b_bcount - xs->bp->b_resid),
+ (xs->bp->b_flags & B_READ));
}
void
@@ -1087,6 +1081,27 @@ sd_shutdown(void *arg)
}
/*
+ * Tell the device to map out a defective block
+ */
+int
+sd_reassign_blocks(struct sd_softc *sd, u_long blkno)
+{
+ struct scsi_reassign_blocks scsi_cmd;
+ struct scsi_reassign_blocks_data rbdata;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ bzero(&rbdata, sizeof(rbdata));
+ scsi_cmd.opcode = REASSIGN_BLOCKS;
+
+ _lto2b(sizeof(rbdata.defect_descriptor[0]), rbdata.length);
+ _lto4b(blkno, rbdata.defect_descriptor[0].dlbaddr);
+
+ return scsi_scsi_cmd(sd->sc_link, (struct scsi_generic *)&scsi_cmd,
+ sizeof(scsi_cmd), (u_char *)&rbdata, sizeof(rbdata), SCSI_RETRIES,
+ 5000, NULL, SCSI_DATA_OUT);
+}
+
+/*
* Check Errors
*/
int
@@ -1171,6 +1186,7 @@ sdsize(dev_t dev)
}
/* #define SD_DUMP_NOT_TRUSTED if you just want to watch */
+static struct scsi_xfer sx;
static int sddoingadump;
/*
@@ -1180,7 +1196,7 @@ static int sddoingadump;
int
sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
{
- struct sd_softc *sc; /* disk unit to do the I/O */
+ struct sd_softc *sd; /* disk unit to do the I/O */
struct disklabel *lp; /* disk's disklabel */
int unit, part;
int sectorsize; /* size of a disk sector */
@@ -1188,7 +1204,9 @@ sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
daddr64_t sectoff; /* sector offset of partition */
int totwrt; /* total number of sectors left to write */
int nwrt; /* current number of sectors to write */
+ struct scsi_rw_big cmd; /* write command */
struct scsi_xfer *xs; /* ... convenience */
+ int retval;
/* Check if recursive dump; if so, punt. */
if (sddoingadump)
@@ -1201,7 +1219,7 @@ sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
part = DISKPART(dev);
/* Check for acceptable drive number. */
- if (unit >= sd_cd.cd_ndevs || (sc = sd_cd.cd_devs[unit]) == NULL)
+ if (unit >= sd_cd.cd_ndevs || (sd = sd_cd.cd_devs[unit]) == NULL)
return ENXIO;
/*
@@ -1211,12 +1229,12 @@ sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
*/
#if 0
/* Make sure it was initialized. */
- if ((sc->sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED)
+ if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED)
return ENXIO;
#endif
/* Convert to disk sectors. Request must be a multiple of size. */
- lp = sc->sc_dk.dk_label;
+ lp = sd->sc_dk.dk_label;
sectorsize = lp->d_secsize;
if ((size % sectorsize) != 0)
return EFAULT;
@@ -1233,25 +1251,43 @@ sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
/* Offset block number to start of partition. */
blkno += sectoff;
+ xs = &sx;
+
while (totwrt > 0) {
nwrt = totwrt; /* XXX */
-
#ifndef SD_DUMP_NOT_TRUSTED
- xs = scsi_xs_get(sc->sc_link, SCSI_NOSLEEP);
- if (xs == NULL)
- return (ENOMEM);
-
- xs->timeout = 10000;
- xs->flags = SCSI_POLL | SCSI_NOSLEEP | SCSI_DATA_OUT;
+ /*
+ * Fill out the scsi command
+ */
+ bzero(&cmd, sizeof(cmd));
+ cmd.opcode = WRITE_BIG;
+ _lto4b(blkno, cmd.addr);
+ _lto2b(nwrt, cmd.length);
+ /*
+ * Fill out the scsi_xfer structure
+ * Note: we cannot sleep as we may be an interrupt
+ * don't use scsi_scsi_cmd() as it may want
+ * to wait for an xs.
+ */
+ bzero(xs, sizeof(sx));
+ xs->flags |= SCSI_AUTOCONF | SCSI_DATA_OUT;
+ xs->sc_link = sd->sc_link;
+ xs->retries = SCSI_RETRIES;
+ xs->timeout = 10000; /* 10000 millisecs for a disk ! */
+ xs->cmd = (struct scsi_generic *)&cmd;
+ xs->cmdlen = sizeof(cmd);
+ xs->resid = nwrt * sectorsize;
+ xs->error = XS_NOERROR;
+ xs->bp = NULL;
xs->data = va;
xs->datalen = nwrt * sectorsize;
- sd_cmd_rw10(xs, 0, blkno, nwrt); /* XXX */
-
- scsi_xs_exec(xs);
- if (xs->error != XS_NOERROR)
- return (ENXIO);
- scsi_xs_put(xs);
+ /*
+ * Pass all this info to the scsi driver.
+ */
+ retval = (*(sd->sc_link->adapter->scsi_cmd)) (xs);
+ if (retval != COMPLETE)
+ return ENXIO;
#else /* SD_DUMP_NOT_TRUSTED */
/* Let's just talk about this first... */
printf("sd%d: dump addr 0x%x, blk %d\n", unit, va, blkno);
@@ -1263,10 +1299,8 @@ sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
blkno += nwrt;
va += sectorsize * nwrt;
}
-
sddoingadump = 0;
-
- return (0);
+ return 0;
}
/*
@@ -1435,17 +1469,14 @@ validate:
return (SDGP_RESULT_OK);
}
-void
-sd_flush_done(struct scsi_xfer *xs);
void
-sd_flush(struct sd_softc *sc, int flags)
+sd_flush(struct sd_softc *sd, int flags)
{
- struct scsi_link *link = sc->sc_link;
- struct scsi_xfer *xs;
- struct scsi_synchronize_cache *cmd;
+ struct scsi_link *sc_link = sd->sc_link;
+ struct scsi_synchronize_cache cmd;
- if (link->quirks & SDEV_NOSYNCCACHE)
+ if (sc_link->quirks & SDEV_NOSYNCCACHE)
return;
/*
@@ -1454,40 +1485,15 @@ sd_flush(struct sd_softc *sc, int flags)
* that the command is not supported by the device.
*/
- xs = scsi_xs_get(link, flags);
- if (xs == NULL) {
- SC_DEBUG(sc_link, SDEV_DB1, ("cache sync failed to get xs\n"));
- return;
- }
-
- cmd = (struct scsi_synchronize_cache *)xs->cmd;
- cmd->opcode = SYNCHRONIZE_CACHE;
-
- xs->timeout = 100000;
-
- xs->done = sd_flush_done;
-
- do {
- scsi_xs_exec(xs);
- if (!ISSET(xs->flags, SCSI_POLL)) {
- while (!ISSET(xs->flags, ITSDONE))
- tsleep(xs, PRIBIO, "sdflush", 0);
- }
- } while (xs->status == XS_NO_CCB);
-
- if (xs->error != XS_NOERROR)
+ bzero(&cmd, sizeof(cmd));
+ cmd.opcode = SYNCHRONIZE_CACHE;
+
+ if (scsi_scsi_cmd(sc_link, (struct scsi_generic *)&cmd, sizeof(cmd),
+ NULL, 0, SCSI_RETRIES, 100000, NULL,
+ flags | SCSI_IGNORE_ILLEGAL_REQUEST)) {
SC_DEBUG(sc_link, SDEV_DB1, ("cache sync failed\n"));
- else
- sc->flags &= ~SDF_DIRTY;
-
- scsi_xs_put(xs);
-}
-
-void
-sd_flush_done(struct scsi_xfer *xs)
-{
- if (!ISSET(xs->flags, SCSI_POLL))
- wakeup_one(xs);
+ } else
+ sd->flags &= ~SDF_DIRTY;
}
/*
@@ -1496,11 +1502,16 @@ sd_flush_done(struct scsi_xfer *xs)
void
sd_kill_buffers(struct sd_softc *sd)
{
- struct buf *bp;
+ struct buf *dp, *bp;
+ int s;
+
+ s = splbio();
+ for (dp = &sd->buf_queue; (bp = dp->b_actf) != NULL; ) {
+ dp->b_actf = bp->b_actf;
- while ((bp = sd_buf_dequeue(sd)) != NULL) {
bp->b_error = ENXIO;
bp->b_flags |= B_ERROR;
biodone(bp);
}
+ splx(s);
}
diff --git a/sys/scsi/sdvar.h b/sys/scsi/sdvar.h
index d848c5554f0..7147b6f6f0e 100644
--- a/sys/scsi/sdvar.h
+++ b/sys/scsi/sdvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdvar.h,v 1.22 2009/11/10 10:18:59 dlg Exp $ */
+/* $OpenBSD: sdvar.h,v 1.23 2009/11/12 06:20:27 dlg Exp $ */
/* $NetBSD: sdvar.h,v 1.7 1998/08/17 00:49:03 mycroft Exp $ */
/*-
@@ -49,10 +49,10 @@
#ifdef _KERNEL
struct sd_softc {
- struct device sc_dev;
- struct disk sc_dk;
+ struct device sc_dev;
+ struct disk sc_dk;
- int flags;
+ int flags;
#define SDF_LOCKED 0x01
#define SDF_WANTED 0x02
#define SDF_WLABEL 0x04 /* label is writable */
@@ -60,8 +60,7 @@ struct sd_softc {
#define SDF_ANCIENT 0x10 /* disk is ancient; for minphys */
#define SDF_DIRTY 0x20 /* disk is dirty; needs cache flush */
#define SDF_DYING 0x40 /* dying, when deactivated */
-#define SDF_WAITING 0x80 /* bus is busy, try again later */
- struct scsi_link *sc_link; /* contains our targ, lun, etc. */
+ struct scsi_link *sc_link; /* contains our targ, lun, etc. */
struct disk_parms {
u_long heads; /* number of heads */
u_long cyls; /* number of cylinders */
@@ -70,11 +69,9 @@ struct sd_softc {
u_long rot_rate; /* rotational rate, in RPM */
daddr64_t disksize; /* total number sectors */
} params;
- struct mutex sc_buf_mtx;
- struct buf sc_buf_queue;
+ struct buf buf_queue;
void *sc_sdhook; /* our shutdown hook */
struct timeout sc_timeout;
-
};
#define SDGP_RESULT_OK 0 /* parameters obtained */