summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2010-09-13 07:48:13 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2010-09-13 07:48:13 +0000
commit81c0e6ff49f3bda87db8333a87cd5a0ef375526a (patch)
treebc54eb9b39937e841b4b4a46724c26443b977d3e /sys/dev
parent42612cd7f11ebee7a11be4efd3ae883c760903cb (diff)
if a busy sas device is unplugged, the pending io on that device will
never complete. when we get a detach event from the firmware, we currently deactivate the device and then request the scsi midlayer attempt to detach the device. this diff now deactivates the device and then resets the target, forcing the ioc to complete the pending operations. once the reset has completed we then request a detach of the kernel device. this lets me hotplug busy sas disks without leaking scsi_xfers or bufs or anything.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/mpi.c113
-rw-r--r--sys/dev/ic/mpivar.h6
2 files changed, 105 insertions, 14 deletions
diff --git a/sys/dev/ic/mpi.c b/sys/dev/ic/mpi.c
index 0a16fe2e38f..5366cbc3205 100644
--- a/sys/dev/ic/mpi.c
+++ b/sys/dev/ic/mpi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mpi.c,v 1.160 2010/09/13 07:11:47 dlg Exp $ */
+/* $OpenBSD: mpi.c,v 1.161 2010/09/13 07:48:12 dlg Exp $ */
/*
* Copyright (c) 2005, 2006, 2009 David Gwynne <dlg@openbsd.org>
@@ -137,9 +137,13 @@ int mpi_scsi_probe_virtual(struct scsi_link *);
int mpi_eventnotify(struct mpi_softc *);
void mpi_eventnotify_done(struct mpi_ccb *);
+void mpi_eventnotify_free(struct mpi_softc *,
+ struct mpi_rcb *);
void mpi_eventack(void *, void *);
void mpi_eventack_done(struct mpi_ccb *);
-void mpi_evt_sas(struct mpi_softc *, struct mpi_rcb *);
+int mpi_evt_sas(struct mpi_softc *, struct mpi_rcb *);
+void mpi_evt_sas_detach(void *, void *);
+void mpi_evt_sas_detach_done(struct mpi_ccb *);
void mpi_evt_fc_rescan(struct mpi_softc *);
void mpi_fc_rescan(void *, void *);
@@ -260,8 +264,13 @@ mpi_attach(struct mpi_softc *sc)
}
switch (sc->sc_porttype) {
- case MPI_PORTFACTS_PORTTYPE_FC:
case MPI_PORTFACTS_PORTTYPE_SAS:
+ SIMPLEQ_INIT(&sc->sc_evt_scan_queue);
+ mtx_init(&sc->sc_evt_scan_mtx, IPL_BIO);
+ scsi_ioh_set(&sc->sc_evt_scan_handler, &sc->sc_iopool,
+ mpi_evt_sas_detach, sc);
+ /* FALLTHROUGH */
+ case MPI_PORTFACTS_PORTTYPE_FC:
if (mpi_eventnotify(sc) != 0) {
printf("%s: unable to enable events\n", DEVNAME(sc));
goto free_replies;
@@ -2240,7 +2249,10 @@ mpi_eventnotify_done(struct mpi_ccb *ccb)
if (sc->sc_scsibus == NULL)
break;
- mpi_evt_sas(sc, rcb);
+ if (mpi_evt_sas(sc, rcb) != 0) {
+ /* reply is freed later on */
+ return;
+ }
break;
case MPI_EVENT_RESCAN:
@@ -2255,16 +2267,24 @@ mpi_eventnotify_done(struct mpi_ccb *ccb)
break;
}
+ mpi_eventnotify_free(sc, rcb);
+}
+
+void
+mpi_eventnotify_free(struct mpi_softc *sc, struct mpi_rcb *rcb)
+{
+ struct mpi_msg_event_reply *enp = rcb->rcb_reply;
+
if (enp->ack_required) {
mtx_enter(&sc->sc_evt_ack_mtx);
SIMPLEQ_INSERT_TAIL(&sc->sc_evt_ack_queue, rcb, rcb_link);
mtx_leave(&sc->sc_evt_ack_mtx);
scsi_ioh_add(&sc->sc_evt_ack_handler);
} else
- mpi_push_reply(sc, ccb->ccb_rcb);
+ mpi_push_reply(sc, rcb);
}
-void
+int
mpi_evt_sas(struct mpi_softc *sc, struct mpi_rcb *rcb)
{
struct mpi_evt_sas_change *ch;
@@ -2275,7 +2295,7 @@ mpi_evt_sas(struct mpi_softc *sc, struct mpi_rcb *rcb)
ch = (struct mpi_evt_sas_change *)data;
if (ch->bus != 0)
- return;
+ return (0);
switch (ch->reason) {
case MPI_EVT_SASCH_REASON_ADDED:
@@ -2288,12 +2308,14 @@ mpi_evt_sas(struct mpi_softc *sc, struct mpi_rcb *rcb)
case MPI_EVT_SASCH_REASON_NOT_RESPONDING:
scsi_activate(sc->sc_scsibus, ch->target, -1, DVACT_DEACTIVATE);
- if (scsi_req_detach(sc->sc_scsibus, ch->target, -1,
- DETACH_FORCE) != 0) {
- printf("%s: unable to request detach of %d\n",
- DEVNAME(sc), ch->target);
- }
- break;
+
+ mtx_enter(&sc->sc_evt_scan_mtx);
+ SIMPLEQ_INSERT_TAIL(&sc->sc_evt_scan_queue, rcb, rcb_link);
+ mtx_leave(&sc->sc_evt_scan_mtx);
+ scsi_ioh_add(&sc->sc_evt_scan_handler);
+
+ /* we'll handle event ack later on */
+ return (1);
case MPI_EVT_SASCH_REASON_SMART_DATA:
case MPI_EVT_SASCH_REASON_UNSUPPORTED:
@@ -2304,6 +2326,71 @@ mpi_evt_sas(struct mpi_softc *sc, struct mpi_rcb *rcb)
"0x%02x\n", DEVNAME(sc), ch->reason);
break;
}
+
+ return (0);
+}
+
+void
+mpi_evt_sas_detach(void *cookie, void *io)
+{
+ struct mpi_softc *sc = cookie;
+ struct mpi_ccb *ccb = io;
+ struct mpi_rcb *rcb, *next;
+ struct mpi_msg_event_reply *enp;
+ struct mpi_evt_sas_change *ch;
+ struct mpi_msg_scsi_task_request *str;
+
+ DNPRINTF(MPI_D_EVT, "%s: event sas detach handler\n", DEVNAME(sc));
+
+ mtx_enter(&sc->sc_evt_scan_mtx);
+ rcb = SIMPLEQ_FIRST(&sc->sc_evt_scan_queue);
+ if (rcb != NULL) {
+ next = SIMPLEQ_NEXT(rcb, rcb_link);
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_evt_scan_queue, rcb_link);
+ }
+ mtx_leave(&sc->sc_evt_scan_mtx);
+
+ if (rcb == NULL) {
+ scsi_io_put(&sc->sc_iopool, ccb);
+ return;
+ }
+
+ enp = rcb->rcb_reply;
+ ch = (struct mpi_evt_sas_change *)(enp + 1);
+
+ ccb->ccb_done = mpi_evt_sas_detach_done;
+ str = ccb->ccb_cmd;
+
+ str->target_id = ch->target;
+ str->bus = 0;
+ str->function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+ str->task_type = MPI_MSG_SCSI_TASK_TYPE_TARGET_RESET;
+
+ str->msg_context = htole32(ccb->ccb_id);
+
+ mpi_eventnotify_free(sc, rcb);
+
+ mpi_start(sc, ccb);
+
+ if (next != NULL)
+ scsi_ioh_add(&sc->sc_evt_scan_handler);
+}
+
+void
+mpi_evt_sas_detach_done(struct mpi_ccb *ccb)
+{
+ struct mpi_softc *sc = ccb->ccb_sc;
+ struct mpi_msg_scsi_task_reply *r = ccb->ccb_rcb->rcb_reply;
+
+ if (scsi_req_detach(sc->sc_scsibus, r->target_id, -1,
+ DETACH_FORCE) != 0) {
+ printf("%s: unable to request detach of %d\n",
+ DEVNAME(sc), r->target_id);
+ }
+
+ mpi_push_reply(sc, ccb->ccb_rcb);
+ scsi_io_put(&sc->sc_iopool, ccb);
}
void
diff --git a/sys/dev/ic/mpivar.h b/sys/dev/ic/mpivar.h
index d06f7c70151..911217d1a82 100644
--- a/sys/dev/ic/mpivar.h
+++ b/sys/dev/ic/mpivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mpivar.h,v 1.34 2010/09/13 06:53:43 dlg Exp $ */
+/* $OpenBSD: mpivar.h,v 1.35 2010/09/13 07:48:12 dlg Exp $ */
/*
* Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
@@ -140,6 +140,10 @@ struct mpi_softc {
struct mutex sc_evt_ack_mtx;
struct scsi_iohandler sc_evt_ack_handler;
+ struct mpi_rcb_list sc_evt_scan_queue;
+ struct mutex sc_evt_scan_mtx;
+ struct scsi_iohandler sc_evt_scan_handler;
+
struct workq_task sc_evt_rescan;
struct mutex sc_evt_rescan_mtx;
u_int sc_evt_rescan_sem;