summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2011-04-05 14:25:43 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2011-04-05 14:25:43 +0000
commit6894d524815751209e596eb2888fc36dcdadc461 (patch)
treed8a9ea654578c297b377d0d406e592d7cf3749ad /sys
parent09931756bf164ec239559a8c39bd52706b27241e (diff)
move forward with scsi multipathing.
the big change is how paths between mpath capable devices and the kernel are managed. originally the midlayer would steal the links to the devices and hide them behind mpath. all the changes an adapter made to a link (eg activate or detach), the midlayer had to test if it was an mpath link and then call special mpath code to handle it. the original code also assumed that all paths behaved the same, but the reality is that different devices have different command sets and behaviours. figuring out which behaviour to pick and prioritising them is basically the same job autoconf does with match and attach. rather than special casing mpath in the midlayer and reimplimenting autoconf, this turns paths into actual device drivers with match and attach routines. after they figure out if the path is active, they then give it to mpath(4) to use as a backend. i have written drivers for symmetric access devices (sym(4)) where all paths to the same logical unit are as good as each other, lsi/engenio arrays (rdac(4), and emc arrays (emc(4)). the rdac and emc drivers only detect active paths at attach time, the do not cope if the controller changes state unless you unplug the path and plug it in again to retest the active state. they also do not have support for directing array failover. operating and hoplugging has been tested with mpii(4), fc and sas mpi(4), and iscsi via vscsi (claudio did this too). ok krw@ deraadt@
Diffstat (limited to 'sys')
-rw-r--r--sys/scsi/files.scsi15
-rw-r--r--sys/scsi/mpath.c348
-rw-r--r--sys/scsi/mpath_emc.c298
-rw-r--r--sys/scsi/mpath_rdac.c335
-rw-r--r--sys/scsi/mpath_sym.c179
-rw-r--r--sys/scsi/mpathvar.h55
-rw-r--r--sys/scsi/scsiconf.c36
-rw-r--r--sys/scsi/scsiconf.h11
8 files changed, 1153 insertions, 124 deletions
diff --git a/sys/scsi/files.scsi b/sys/scsi/files.scsi
index 2066b8f9579..e5e5a70ba5a 100644
--- a/sys/scsi/files.scsi
+++ b/sys/scsi/files.scsi
@@ -1,4 +1,4 @@
-# $OpenBSD: files.scsi,v 1.22 2010/07/03 03:59:17 krw Exp $
+# $OpenBSD: files.scsi,v 1.23 2011/04/05 14:25:42 dlg Exp $
# $NetBSD: files.scsi,v 1.4 1996/05/16 04:01:08 mycroft Exp $
#
# Config.new file and device description for machine-independent SCSI code.
@@ -39,3 +39,16 @@ file scsi/safte.c safte needs-flag
device ses: disk
attach ses at scsibus
file scsi/ses.c ses needs-flag
+
+
+device sym
+attach sym at scsibus
+file scsi/mpath_sym.c sym
+
+device rdac
+attach rdac at scsibus
+file scsi/mpath_rdac.c rdac
+
+device emc
+attach emc at scsibus
+file scsi/mpath_emc.c emc
diff --git a/sys/scsi/mpath.c b/sys/scsi/mpath.c
index 239b2bb5c09..02389cb518b 100644
--- a/sys/scsi/mpath.c
+++ b/sys/scsi/mpath.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mpath.c,v 1.18 2010/07/21 21:34:12 todd Exp $ */
+/* $OpenBSD: mpath.c,v 1.19 2011/04/05 14:25:42 dlg Exp $ */
/*
* Copyright (c) 2009 David Gwynne <dlg@openbsd.org>
@@ -33,6 +33,7 @@
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
+#include <scsi/mpathvar.h>
#define MPATH_BUSWIDTH 256
@@ -40,27 +41,37 @@ int mpath_match(struct device *, void *, void *);
void mpath_attach(struct device *, struct device *, void *);
void mpath_shutdown(void *);
-struct mpath_path {
- struct scsi_link *path_link;
- TAILQ_ENTRY(mpath_path) path_entry;
-};
TAILQ_HEAD(mpath_paths, mpath_path);
-struct mpath_node {
- struct devid *node_id;
- struct mpath_paths node_paths;
+struct mpath_ccb {
+ struct scsi_xfer *c_xs;
+ SIMPLEQ_ENTRY(mpath_ccb) c_entry;
+};
+SIMPLEQ_HEAD(mpath_ccbs, mpath_ccb);
+
+struct mpath_dev {
+ struct mutex d_mtx;
+
+ struct mpath_ccbs d_ccbs;
+ struct mpath_paths d_paths;
+ struct mpath_path *d_next_path;
+
+ u_int d_path_count;
+
+ struct devid *d_id;
};
struct mpath_softc {
struct device sc_dev;
struct scsi_link sc_link;
+ struct pool sc_ccb_pool;
+ struct scsi_iopool sc_iopool;
struct scsibus_softc *sc_scsibus;
};
+#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
struct mpath_softc *mpath;
-struct mpath_node *mpath_nodes[MPATH_BUSWIDTH];
-
-#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
+struct mpath_dev *mpath_devs[MPATH_BUSWIDTH];
struct cfattach mpath_ca = {
sizeof(struct mpath_softc),
@@ -78,17 +89,20 @@ void mpath_cmd(struct scsi_xfer *);
void mpath_minphys(struct buf *, struct scsi_link *);
int mpath_probe(struct scsi_link *);
+struct mpath_path *mpath_next_path(struct mpath_dev *);
void mpath_done(struct scsi_xfer *);
struct scsi_adapter mpath_switch = {
mpath_cmd,
scsi_minphys,
- mpath_probe,
- NULL
+ mpath_probe
};
void mpath_xs_stuffup(struct scsi_xfer *);
+void * mpath_ccb_get(void *);
+void mpath_ccb_put(void *, void *);
+
int
mpath_match(struct device *parent, void *match, void *aux)
{
@@ -105,11 +119,19 @@ mpath_attach(struct device *parent, struct device *self, void *aux)
printf("\n");
+ pool_init(&sc->sc_ccb_pool, sizeof(struct mpath_ccb), 0, 0, 0,
+ "mpathccb", NULL);
+ pool_setipl(&sc->sc_ccb_pool, IPL_BIO);
+
+ scsi_iopool_init(&sc->sc_iopool, sc, mpath_ccb_get, mpath_ccb_put);
+
sc->sc_link.adapter = &mpath_switch;
sc->sc_link.adapter_softc = sc;
sc->sc_link.adapter_target = MPATH_BUSWIDTH;
sc->sc_link.adapter_buswidth = MPATH_BUSWIDTH;
- sc->sc_link.openings = 1;
+ sc->sc_link.luns = 1;
+ sc->sc_link.openings = 1024; /* XXX magical */
+ sc->sc_link.pool = &sc->sc_iopool;
bzero(&saa, sizeof(saa));
saa.saa_sc_link = &sc->sc_link;
@@ -128,34 +150,119 @@ mpath_xs_stuffup(struct scsi_xfer *xs)
int
mpath_probe(struct scsi_link *link)
{
- struct mpath_node *n = mpath_nodes[link->target];
+ struct mpath_dev *d = mpath_devs[link->target];
- if (link->lun != 0 || n == NULL)
+ if (link->lun != 0 || d == NULL)
return (ENXIO);
- link->id = devid_copy(n->node_id);
+ link->id = devid_copy(d->d_id);
return (0);
}
+struct mpath_path *
+mpath_next_path(struct mpath_dev *d)
+{
+ struct mpath_path *p;
+
+ if (d == NULL)
+ panic("%s: d is NULL", __func__);
+
+ p = d->d_next_path;
+ if (p != NULL) {
+ d->d_next_path = TAILQ_NEXT(p, p_entry);
+ if (d->d_next_path == NULL)
+ d->d_next_path = TAILQ_FIRST(&d->d_paths);
+ }
+
+ return (p);
+}
+
void
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 mpath_dev *d = mpath_devs[link->target];
+ struct mpath_ccb *ccb = xs->io;
+ struct mpath_path *p;
struct scsi_xfer *mxs;
- if (n == NULL || p == NULL) {
- mpath_xs_stuffup(xs);
+#ifdef DIAGNOSTIC
+ if (d == NULL)
+ panic("mpath_cmd issued against nonexistant device");
+#endif
+
+ if (ISSET(xs->flags, SCSI_POLL)) {
+ mtx_enter(&d->d_mtx);
+ p = mpath_next_path(d);
+ mtx_leave(&d->d_mtx);
+ if (p == NULL) {
+ mpath_xs_stuffup(xs);
+ return;
+ }
+
+ mxs = scsi_xs_get(p->p_link, xs->flags);
+ if (mxs == NULL) {
+ mpath_xs_stuffup(xs);
+ return;
+ }
+
+ 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->bp = xs->bp;
+
+ scsi_xs_sync(mxs);
+
+ xs->error = mxs->error;
+ xs->status = mxs->status;
+ xs->resid = mxs->resid;
+
+ memcpy(&xs->sense, &mxs->sense, sizeof(xs->sense));
+
+ scsi_xs_put(mxs);
+ scsi_done(xs);
return;
}
- mxs = scsi_xs_get(p->path_link, xs->flags);
- if (mxs == NULL) {
- mpath_xs_stuffup(xs);
- return;
+ ccb->c_xs = xs;
+
+ mtx_enter(&d->d_mtx);
+ SIMPLEQ_INSERT_TAIL(&d->d_ccbs, ccb, c_entry);
+ p = mpath_next_path(d);
+ mtx_leave(&d->d_mtx);
+
+ if (p != NULL)
+ scsi_xsh_add(&p->p_xsh);
+}
+
+void
+mpath_start(struct mpath_path *p, struct scsi_xfer *mxs)
+{
+ struct mpath_dev *d = p->p_dev;
+ struct mpath_ccb *ccb;
+ struct scsi_xfer *xs;
+ int addxsh = 0;
+
+ if (ISSET(p->p_link->state, SDEV_S_DYING) || d == NULL)
+ goto fail;
+
+ mtx_enter(&d->d_mtx);
+ ccb = SIMPLEQ_FIRST(&d->d_ccbs);
+ if (ccb != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&d->d_ccbs, c_entry);
+ if (!SIMPLEQ_EMPTY(&d->d_ccbs))
+ addxsh = 1;
}
+ mtx_leave(&d->d_mtx);
+
+ if (ccb == NULL)
+ goto fail;
+
+ xs = ccb->c_xs;
memcpy(mxs->cmd, xs->cmd, xs->cmdlen);
mxs->cmdlen = xs->cmdlen;
@@ -164,21 +271,46 @@ mpath_cmd(struct scsi_xfer *xs)
mxs->retries = xs->retries;
mxs->timeout = xs->timeout;
mxs->bp = xs->bp;
+ mxs->flags = xs->flags;
mxs->cookie = xs;
mxs->done = mpath_done;
scsi_xs_exec(mxs);
+
+ if (addxsh)
+ scsi_xsh_add(&p->p_xsh);
+
+ return;
+fail:
+ scsi_xs_put(mxs);
}
void
mpath_done(struct scsi_xfer *mxs)
{
struct scsi_xfer *xs = mxs->cookie;
+ struct scsi_link *link = xs->sc_link;
+ struct mpath_ccb *ccb = xs->io;
+ struct mpath_dev *d = mpath_devs[link->target];
+ struct mpath_path *p;
+
+ if (mxs->error == XS_RESET) {
+ mtx_enter(&d->d_mtx);
+ SIMPLEQ_INSERT_HEAD(&d->d_ccbs, ccb, c_entry);
+ p = mpath_next_path(d);
+ mtx_leave(&d->d_mtx);
+
+ scsi_xs_put(mxs);
+
+ if (p != NULL)
+ scsi_xsh_add(&p->p_xsh);
+
+ return;
+ }
xs->error = mxs->error;
xs->status = mxs->status;
- xs->flags = mxs->flags;
xs->resid = mxs->resid;
memcpy(&xs->sense, &mxs->sense, sizeof(xs->sense));
@@ -191,56 +323,74 @@ mpath_done(struct scsi_xfer *mxs)
void
mpath_minphys(struct buf *bp, struct scsi_link *link)
{
- struct mpath_node *n = mpath_nodes[link->target];
+ struct mpath_dev *d = mpath_devs[link->target];
struct mpath_path *p;
- if (n == NULL)
- return;
+#ifdef DIAGNOSTIC
+ if (d == NULL)
+ panic("mpath_minphys against nonexistant device");
+#endif
- TAILQ_FOREACH(p, &n->node_paths, path_entry)
- p->path_link->adapter->scsi_minphys(bp, p->path_link);
+ TAILQ_FOREACH(p, &d->d_paths, p_entry)
+ p->p_link->adapter->scsi_minphys(bp, p->p_link);
}
int
-mpath_path_attach(struct scsi_link *link)
+mpath_path_probe(struct scsi_link *link)
{
- struct mpath_node *n;
- struct mpath_path *p;
- int probe = 0;
- int target;
-
- if (mpath != NULL && link->adapter_softc == mpath)
- return (ENODEV);
+ if (link->id == NULL)
+ return (EINVAL);
- /* XXX this is dumb. should check inq shizz */
- if (ISSET(link->flags, SDEV_VIRTUAL) || link->id == NULL)
+ if (mpath != NULL && mpath == link->adapter_softc)
return (ENXIO);
+ return (0);
+}
+
+int
+mpath_path_attach(struct mpath_path *p)
+{
+ struct scsi_link *link = p->p_link;
+ struct mpath_dev *d = NULL;
+ int newdev = 0, addxsh = 0;
+ int target;
+
+#ifdef DIAGNOSTIC
+ if (p->p_link == NULL)
+ panic("mpath_path_attach: NULL link");
+ if (p->p_dev != NULL)
+ panic("mpath_path_attach: dev is not NULL");
+#endif
+
for (target = 0; target < MPATH_BUSWIDTH; target++) {
- if ((n = mpath_nodes[target]) == NULL)
+ if ((d = mpath_devs[target]) == NULL)
continue;
- if (DEVID_CMP(n->node_id, link->id))
+ if (DEVID_CMP(d->d_id, link->id))
break;
- n = NULL;
+ d = NULL;
}
- if (n == NULL) {
+ if (d == NULL) {
for (target = 0; target < MPATH_BUSWIDTH; target++) {
- if (mpath_nodes[target] == NULL)
+ if (mpath_devs[target] == NULL)
break;
}
if (target >= MPATH_BUSWIDTH)
return (ENXIO);
- n = malloc(sizeof(*n), M_DEVBUF, M_WAITOK | M_ZERO);
- TAILQ_INIT(&n->node_paths);
+ d = malloc(sizeof(*d), M_DEVBUF, M_WAITOK | M_ZERO);
+ if (d == NULL)
+ return (ENOMEM);
- n->node_id = devid_copy(link->id);
+ mtx_init(&d->d_mtx, IPL_BIO);
+ TAILQ_INIT(&d->d_paths);
+ SIMPLEQ_INIT(&d->d_ccbs);
+ d->d_id = devid_copy(link->id);
- mpath_nodes[target] = n;
- probe = 1;
+ mpath_devs[target] = d;
+ newdev = 1;
} else {
/*
* instead of carrying identical values in different devid
@@ -248,60 +398,94 @@ mpath_path_attach(struct scsi_link *link)
* the new scsi_link.
*/
devid_free(link->id);
- link->id = devid_copy(n->node_id);
+ link->id = devid_copy(d->d_id);
}
- p = malloc(sizeof(*p), M_DEVBUF, M_WAITOK);
-
- p->path_link = link;
- TAILQ_INSERT_TAIL(&n->node_paths, p, path_entry);
-
- if (mpath != NULL && probe)
+ p->p_dev = d;
+ mtx_enter(&d->d_mtx);
+ if (TAILQ_EMPTY(&d->d_paths))
+ d->d_next_path = p;
+ TAILQ_INSERT_TAIL(&d->d_paths, p, p_entry);
+ d->d_path_count++;
+ if (!SIMPLEQ_EMPTY(&d->d_ccbs))
+ addxsh = 1;
+ mtx_leave(&d->d_mtx);
+
+ if (newdev && mpath != NULL)
scsi_probe_target(mpath->sc_scsibus, target);
+ else if (addxsh)
+ scsi_xsh_add(&p->p_xsh);
return (0);
}
int
-mpath_path_detach(struct scsi_link *link, int flags)
+mpath_path_detach(struct mpath_path *p)
{
- struct mpath_node *n;
- struct mpath_path *p;
- int target;
+ struct mpath_dev *d = p->p_dev;
+ struct mpath_path *np = NULL;
- for (target = 0; target < MPATH_BUSWIDTH; target++) {
- if ((n = mpath_nodes[target]) == NULL)
- continue;
+#ifdef DIAGNOSTIC
+ if (d == NULL)
+ panic("mpath: detaching a path from a nonexistant bus");
+#endif
+ p->p_dev = NULL;
- if (DEVID_CMP(n->node_id, link->id))
- break;
+ mtx_enter(&d->d_mtx);
+ TAILQ_REMOVE(&d->d_paths, p, p_entry);
+ if (d->d_next_path == p)
+ d->d_next_path = TAILQ_FIRST(&d->d_paths);
- n = NULL;
- }
+ d->d_path_count--;
+ if (!SIMPLEQ_EMPTY(&d->d_ccbs))
+ np = d->d_next_path;
+ mtx_leave(&d->d_mtx);
- if (n == NULL)
- panic("mpath: detaching a path from a nonexistant bus");
+ scsi_xsh_del(&p->p_xsh);
- TAILQ_FOREACH(p, &n->node_paths, path_entry) {
- if (p->path_link == link) {
- TAILQ_REMOVE(&n->node_paths, p, path_entry);
- free(p, M_DEVBUF);
- return (0);
- }
- }
+ if (np != NULL)
+ scsi_xsh_add(&np->p_xsh);
- panic("mpath: unable to locate path for detach");
+ return (0);
}
-void
-mpath_path_activate(struct scsi_link *link)
+void *
+mpath_ccb_get(void *cookie)
{
+ struct mpath_softc *sc = cookie;
+ return (pool_get(&sc->sc_ccb_pool, PR_NOWAIT));
}
void
-mpath_path_deactivate(struct scsi_link *link)
+mpath_ccb_put(void *cookie, void *io)
{
+ struct mpath_softc *sc = cookie;
+ pool_put(&sc->sc_ccb_pool, io);
}
+struct device *
+mpath_bootdv(struct device *dev)
+{
+ struct mpath_dev *d;
+ struct mpath_path *p;
+ int target;
+
+ if (mpath == NULL)
+ return (dev);
+
+ for (target = 0; target < MPATH_BUSWIDTH; target++) {
+ if ((d = mpath_devs[target]) == NULL)
+ continue;
+
+ TAILQ_FOREACH(p, &d->d_paths, p_entry) {
+ if (p->p_link->device_softc == dev) {
+ return (scsi_get_link(mpath->sc_scsibus,
+ target, 0)->device_softc);
+ }
+ }
+ }
+
+ return (dev);
+}
diff --git a/sys/scsi/mpath_emc.c b/sys/scsi/mpath_emc.c
new file mode 100644
index 00000000000..cb77e0c079b
--- /dev/null
+++ b/sys/scsi/mpath_emc.c
@@ -0,0 +1,298 @@
+/* $OpenBSD: mpath_emc.c,v 1.1 2011/04/05 14:25:42 dlg Exp $ */
+
+/*
+ * Copyright (c) 2011 David Gwynne <dlg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* EMC CLARiiON AX/CX support for mpath(4) */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/queue.h>
+#include <sys/rwlock.h>
+#include <sys/pool.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/selinfo.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <scsi/mpathvar.h>
+
+#define EMC_VPD_SP_INFO 0xc0
+
+struct emc_vpd_sp_info {
+ struct scsi_vpd_hdr hdr; /* EMC_VPD_SP_INFO */
+
+ u_int8_t lun_state;
+#define EMC_SP_INFO_LUN_STATE_UNBOUND 0x00
+#define EMC_SP_INFO_LUN_STATE_BOUND 0x01
+#define EMC_SP_INFO_LUN_STATE_OWNED 0x02
+ u_int8_t default_sp;
+ u_int8_t _reserved1[1];
+ u_int8_t port;
+ u_int8_t current_sp;
+ u_int8_t _reserved2[1];
+ u_int8_t unique_id[16];
+ u_int8_t _reserved3[1];
+ u_int8_t type;
+ u_int8_t failover_mode;
+ u_int8_t _reserved4[21];
+ u_int8_t serial[16];
+} __packed;
+
+struct emc_softc {
+ struct device sc_dev;
+ struct mpath_path sc_path;
+ u_int sc_flags;
+ u_int8_t sc_sp;
+ u_int8_t sc_port;
+ u_int8_t sc_lun_state;
+
+};
+#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
+
+int emc_match(struct device *, void *, void *);
+void emc_attach(struct device *, struct device *, void *);
+int emc_detach(struct device *, int);
+int emc_activate(struct device *, int);
+
+struct cfattach emc_ca = {
+ sizeof(struct emc_softc),
+ emc_match,
+ emc_attach,
+ emc_detach,
+ emc_activate
+};
+
+struct cfdriver emc_cd = {
+ NULL,
+ "emc",
+ DV_DULL
+};
+
+void emc_mpath_start(struct scsi_xfer *);
+int emc_mpath_checksense(struct scsi_xfer *);
+int emc_mpath_online(struct scsi_link *);
+int emc_mpath_offline(struct scsi_link *);
+
+struct mpath_ops emc_mpath_ops = {
+ "emc",
+ emc_mpath_start,
+ emc_mpath_checksense,
+ emc_mpath_online,
+ emc_mpath_offline,
+};
+
+struct emc_device {
+ char *vendor;
+ char *product;
+};
+
+int emc_inquiry(struct emc_softc *, char *, char *);
+int emc_sp_info(struct emc_softc *);
+
+struct emc_device emc_devices[] = {
+/* " vendor " " device " */
+/* "01234567" "0123456789012345" */
+ { "DGC ", "LUNZ" },
+ { "DGC ", "RAID" },
+ { "DGC ", "DISK" },
+ { "DGC ", "VRAID" }
+};
+
+int
+emc_match(struct device *parent, void *match, void *aux)
+{
+ struct scsi_attach_args *sa = aux;
+ struct scsi_inquiry_data *inq = sa->sa_inqbuf;
+ struct emc_device *s;
+ int i;
+
+ if (mpath_path_probe(sa->sa_sc_link) != 0)
+ return (0);
+
+ for (i = 0; i < nitems(emc_devices); i++) {
+ s = &emc_devices[i];
+
+ if (bcmp(s->vendor, inq->vendor, strlen(s->vendor)) == 0 &&
+ bcmp(s->product, inq->product, strlen(s->product)) == 0)
+ return (3);
+ }
+
+ return (0);
+}
+
+void
+emc_attach(struct device *parent, struct device *self, void *aux)
+{
+ char model[256], serial[256];
+ struct emc_softc *sc = (struct emc_softc *)self;
+ struct scsi_attach_args *sa = aux;
+ struct scsi_link *link = sa->sa_sc_link;
+
+ printf("\n");
+
+ /* init link */
+ link->device_softc = sc;
+
+ /* init path */
+ scsi_xsh_set(&sc->sc_path.p_xsh, link, emc_mpath_start);
+ sc->sc_path.p_link = link;
+ sc->sc_path.p_ops = &emc_mpath_ops;
+
+ if (emc_sp_info(sc)) {
+ printf("%s: unable to get sp info\n", DEVNAME(sc));
+ return;
+ }
+
+ if (emc_inquiry(sc, model, serial) != 0) {
+ printf("%s: unable to get inquiry data\n", DEVNAME(sc));
+ return;
+ }
+
+ printf("%s: %s %s SP-%c port %d\n", DEVNAME(sc), model, serial,
+ sc->sc_sp + 'A', sc->sc_port);
+
+ if (sc->sc_lun_state == EMC_SP_INFO_LUN_STATE_OWNED) {
+ if (mpath_path_attach(&sc->sc_path) != 0)
+ printf("%s: unable to attach path\n", DEVNAME(sc));
+ }
+}
+
+int
+emc_detach(struct device *self, int flags)
+{
+ return (0);
+}
+
+int
+emc_activate(struct device *self, int act)
+{
+ struct emc_softc *sc = (struct emc_softc *)self;
+ int rv = 0;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ case DVACT_SUSPEND:
+ case DVACT_RESUME:
+ break;
+ case DVACT_DEACTIVATE:
+ if (sc->sc_path.p_dev != NULL)
+ mpath_path_detach(&sc->sc_path);
+ break;
+ }
+ return (rv);
+}
+
+void
+emc_mpath_start(struct scsi_xfer *xs)
+{
+ struct emc_softc *sc = xs->sc_link->device_softc;
+
+ mpath_start(&sc->sc_path, xs);
+}
+
+int
+emc_mpath_checksense(struct scsi_xfer *xs)
+{
+ return (0);
+}
+
+int
+emc_mpath_online(struct scsi_link *link)
+{
+ return (0);
+}
+
+int
+emc_mpath_offline(struct scsi_link *link)
+{
+ return (0);
+}
+
+int
+emc_inquiry(struct emc_softc *sc, char *model, char *serial)
+{
+ u_int8_t buffer[255];
+ struct scsi_inquiry *cdb;
+ struct scsi_xfer *xs;
+ size_t length;
+ int error;
+ u_int8_t slen, mlen;
+
+ length = MIN(sc->sc_path.p_link->inqdata.additional_length + 5,
+ sizeof(buffer));
+ if (length < 160) {
+ printf("%s: FC (Legacy)\n");
+ return (0);
+ }
+
+ xs = scsi_xs_get(sc->sc_path.p_link, scsi_autoconf);
+ if (xs == NULL)
+ return (EBUSY);
+
+ cdb = (struct scsi_inquiry *)xs->cmd;
+ cdb->opcode = INQUIRY;
+ _lto2b(length, cdb->length);
+
+ xs->cmdlen = sizeof(*cdb);
+ xs->flags |= SCSI_DATA_IN;
+ xs->data = buffer;
+ xs->datalen = length;
+
+ error = scsi_xs_sync(xs);
+ scsi_xs_put(xs);
+
+ if (error != 0)
+ return (error);
+
+ slen = buffer[160];
+ if (slen == 0 || slen + 161 > length)
+ return (EIO);
+
+ mlen = buffer[99];
+ if (mlen == 0 || slen + mlen + 161 > length)
+ return (EIO);
+
+ scsi_strvis(serial, buffer + 161, slen);
+ scsi_strvis(model, buffer + 161 + slen, mlen);
+
+ return (0);
+}
+
+int
+emc_sp_info(struct emc_softc *sc)
+{
+ struct emc_vpd_sp_info pg;
+ int error;
+
+ error = scsi_inquire_vpd(sc->sc_path.p_link, &pg, sizeof(pg),
+ EMC_VPD_SP_INFO, scsi_autoconf);
+ if (error != 0)
+ return (error);
+
+ sc->sc_sp = pg.current_sp;
+ sc->sc_port = pg.port;
+ sc->sc_lun_state = pg.lun_state;
+
+ return (0);
+}
diff --git a/sys/scsi/mpath_rdac.c b/sys/scsi/mpath_rdac.c
new file mode 100644
index 00000000000..493912ead7e
--- /dev/null
+++ b/sys/scsi/mpath_rdac.c
@@ -0,0 +1,335 @@
+/* $OpenBSD: mpath_rdac.c,v 1.1 2011/04/05 14:25:42 dlg Exp $ */
+
+/*
+ * Copyright (c) 2010 David Gwynne <dlg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Redundant Disk Array Controller support for mpath(4) */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/queue.h>
+#include <sys/rwlock.h>
+#include <sys/pool.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/selinfo.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <scsi/mpathvar.h>
+
+struct rdac_common_mode_page {
+ u_int8_t controller_serial[16];
+ u_int8_t alt_controller_serial[16];
+ u_int8_t mode[2];
+ u_int8_t alt_mode[2];
+ u_int8_t timeout;
+ u_int8_t options;
+};
+
+/*
+ * RDAC VPD pages
+ */
+#define RDAC_VPD_HDWVER 0xc0 /* Hardware Version */
+#define RDAC_VPD_SERNUM 0xc1 /* Serial Numbers */
+#define RDAC_VPD_SFWVER 0xc2
+#define RDAC_VPD_FEAPAR 0xc3 /* Feature Parameters */
+#define RDAC_VPD_SUBSYS 0xc4
+#define RDAC_VPD_HSTINT 0xc5
+#define RDAC_VPD_DGM 0xc6
+#define RDAC_VPD_HSTINT2 0xc7
+#define RDAC_VPD_EXTDEVID 0xc8
+#define RDAC_VPD_VOLACCESSCTL 0xc9
+
+struct rdac_vpd_hdwver {
+ struct scsi_vpd_hdr hdr; /* RDAC_VPD_HDWVER */
+ u_int8_t pg_id[4];
+#define RDAC_VPD_ID_HDWVER 0x68777234 /* "hwr4" */
+ u_int8_t num_channels;
+ u_int8_t flags;
+ u_int8_t proc_memory_size;
+ u_int8_t _reserved1[5];
+ u_int8_t board_name[64];
+ u_int8_t board_part_number[16];
+ u_int8_t schematic_number[12];
+ u_int8_t schematic_revision[4];
+ u_int8_t serial_number[16];
+ u_int8_t _reserved2[16];
+ u_int8_t date_manufactured[8];
+ u_int8_t board_revision[2];
+ u_int8_t board_identifier[4];
+};
+
+struct rdac_vpd_subsys {
+ struct scsi_vpd_hdr hdr; /* RDAC_VPD_SUBSYS */
+ u_int8_t pg_id[4];
+#define RDAC_VPD_ID_SUBSYS 0x73756273 /* "subs" */
+ u_int8_t subsystem_id[16];
+ u_int8_t subsystem_revision[4];
+ u_int8_t controller_slot_id[2];
+ u_int8_t _reserved[2];
+};
+
+struct rdac_vpd_extdevid {
+ struct scsi_vpd_hdr hdr; /* RDAC_VPD_EXTDEVID */
+ u_int8_t pg_id[4];
+#define RDAC_VPD_ID_EXTDEVID 0x65646964 /* "edid" */
+ u_int8_t _reserved[3];
+ u_int8_t vol_id_len;
+ u_int8_t vol_id[16];
+ u_int8_t vol_label_len;
+ u_int8_t vol_label[60];
+ u_int8_t array_id_len;
+ u_int8_t array_id[16];
+ u_int8_t array_label_len;
+ u_int8_t array_label[60];
+ u_int8_t lun[8];
+};
+
+struct rdac_vpd_volaccessctl {
+ struct scsi_vpd_hdr hdr; /* RDAC_VPD_VOLACCESSCTL */
+ u_int8_t pg_id[4];
+#define RDAC_VPD_ID_VOLACCESSCTL 0x76616331 /* "vac1" */
+ u_int8_t avtcvp;
+#define RDAC_VOLACCESSCTL_OWNER 0x01
+#define RDAC_VOLACCESSCTL_AVT 0x70
+ u_int8_t path_priority;
+ u_int8_t _reserved[38];
+};
+
+struct rdac_softc {
+ struct device sc_dev;
+ struct mpath_path sc_path;
+};
+#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
+
+int rdac_match(struct device *, void *, void *);
+void rdac_attach(struct device *, struct device *, void *);
+int rdac_detach(struct device *, int);
+int rdac_activate(struct device *, int);
+
+struct cfattach rdac_ca = {
+ sizeof(struct rdac_softc),
+ rdac_match,
+ rdac_attach,
+ rdac_detach,
+ rdac_activate
+};
+
+struct cfdriver rdac_cd = {
+ NULL,
+ "rdac",
+ DV_DULL
+};
+
+void rdac_mpath_start(struct scsi_xfer *);
+int rdac_mpath_checksense(struct scsi_xfer *);
+int rdac_mpath_online(struct scsi_link *);
+int rdac_mpath_offline(struct scsi_link *);
+
+struct mpath_ops rdac_mpath_ops = {
+ "rdac",
+ rdac_mpath_start,
+ rdac_mpath_checksense,
+ rdac_mpath_online,
+ rdac_mpath_offline,
+};
+
+int rdac_c8(struct rdac_softc *);
+int rdac_c9(struct rdac_softc *);
+
+struct rdac_device {
+ char *vendor;
+ char *product;
+};
+
+struct rdac_device rdac_devices[] = {
+/* " vendor " " device " */
+/* "01234567" "0123456789012345" */
+ { "SUN ", "CSM200_" },
+ { "DELL ", "MD3000i " }
+};
+
+int
+rdac_match(struct device *parent, void *match, void *aux)
+{
+ struct scsi_attach_args *sa = aux;
+ struct scsi_inquiry_data *inq = sa->sa_inqbuf;
+ struct rdac_device *s;
+ int i;
+
+ if (mpath_path_probe(sa->sa_sc_link) != 0)
+ return (0);
+
+ for (i = 0; i < nitems(rdac_devices); i++) {
+ s = &rdac_devices[i];
+
+ if (bcmp(s->vendor, inq->vendor, strlen(s->vendor)) == 0 &&
+ bcmp(s->product, inq->product, strlen(s->product)) == 0)
+ return (3);
+ }
+
+ return (0);
+}
+
+void
+rdac_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct rdac_softc *sc = (struct rdac_softc *)self;
+ struct scsi_attach_args *sa = aux;
+ struct scsi_link *link = sa->sa_sc_link;
+
+ printf("\n");
+
+ /* init link */
+ link->device_softc = sc;
+
+ /* init path */
+ scsi_xsh_set(&sc->sc_path.p_xsh, link, rdac_mpath_start);
+ sc->sc_path.p_link = link;
+ sc->sc_path.p_ops = &rdac_mpath_ops;
+
+ if (rdac_c8(sc) != 0)
+ return;
+
+ if (rdac_c9(sc) != 0)
+ return;
+
+ if (mpath_path_attach(&sc->sc_path) != 0)
+ printf("%s: unable to attach path\n", DEVNAME(sc));
+}
+
+int
+rdac_detach(struct device *self, int flags)
+{
+ return (0);
+}
+
+int
+rdac_activate(struct device *self, int act)
+{
+ struct rdac_softc *sc = (struct rdac_softc *)self;
+ int rv = 0;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ case DVACT_SUSPEND:
+ case DVACT_RESUME:
+ break;
+ case DVACT_DEACTIVATE:
+ if (sc->sc_path.p_dev != NULL)
+ mpath_path_detach(&sc->sc_path);
+ break;
+ }
+ return (rv);
+
+}
+
+void
+rdac_mpath_start(struct scsi_xfer *xs)
+{
+ struct rdac_softc *sc = xs->sc_link->device_softc;
+
+ mpath_start(&sc->sc_path, xs);
+}
+
+int
+rdac_mpath_checksense(struct scsi_xfer *xs)
+{
+ return (0);
+}
+
+int
+rdac_mpath_online(struct scsi_link *link)
+{
+ return (0);
+}
+
+int
+rdac_mpath_offline(struct scsi_link *link)
+{
+ return (0);
+}
+
+int
+rdac_c8(struct rdac_softc *sc)
+{
+ struct rdac_vpd_extdevid pg;
+ char array[31];
+ char vol[31];
+ int i;
+
+ if (scsi_inquire_vpd(sc->sc_path.p_link, &pg, sizeof(pg), 0xc8,
+ scsi_autoconf) != 0) {
+ printf("%s: unable to fetch vpd page c8\n", DEVNAME(sc));
+ return (1);
+ }
+
+ if (_4btol(pg.pg_id) != RDAC_VPD_ID_EXTDEVID) {
+ printf("%s: extended hardware id page is invalid\n",
+ DEVNAME(sc));
+ return (1);
+ }
+
+ memset(array, 0, sizeof(array));
+ for (i = 0; i < sizeof(pg.array_label) / 2; i++)
+ array[i] = pg.array_label[i * 2 + 1];
+
+ memset(vol, 0, sizeof(vol));
+ for (i = 0; i < sizeof(pg.vol_label) / 2; i++)
+ vol[i] = pg.vol_label[i * 2 + 1];
+
+ printf("%s: array %s, volume %s\n", DEVNAME(sc), array, vol);
+
+ return (0);
+}
+
+int
+rdac_c9(struct rdac_softc *sc)
+{
+ struct rdac_vpd_volaccessctl pg;
+
+ if (scsi_inquire_vpd(sc->sc_path.p_link, &pg, sizeof(pg),
+ RDAC_VPD_VOLACCESSCTL, scsi_autoconf) != 0) {
+ printf("%s: unable to fetch vpd page c9\n", DEVNAME(sc));
+ return (1);
+ }
+
+ if (_4btol(pg.pg_id) != RDAC_VPD_ID_VOLACCESSCTL) {
+ printf("%s: volume access control page id is invalid\n",
+ DEVNAME(sc));
+ return (1);
+ }
+
+ if (ISSET(pg.avtcvp, RDAC_VOLACCESSCTL_AVT)) {
+ printf("%s: avt\n", DEVNAME(sc));
+ return (0);
+ }
+ if (ISSET(pg.avtcvp, RDAC_VOLACCESSCTL_OWNER)) {
+ printf("%s: owner\n", DEVNAME(sc));
+ return (0);
+ }
+
+ printf("%s: unowned\n", DEVNAME(sc));
+ return (1);
+}
+
diff --git a/sys/scsi/mpath_sym.c b/sys/scsi/mpath_sym.c
new file mode 100644
index 00000000000..8eb5ecaefdf
--- /dev/null
+++ b/sys/scsi/mpath_sym.c
@@ -0,0 +1,179 @@
+/* $OpenBSD: mpath_sym.c,v 1.1 2011/04/05 14:25:42 dlg Exp $ */
+
+/*
+ * Copyright (c) 2010 David Gwynne <dlg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/queue.h>
+#include <sys/rwlock.h>
+#include <sys/pool.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/selinfo.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <scsi/mpathvar.h>
+
+struct sym_softc {
+ struct device sc_dev;
+ struct mpath_path sc_path;
+};
+#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
+
+int sym_match(struct device *, void *, void *);
+void sym_attach(struct device *, struct device *, void *);
+int sym_detach(struct device *, int);
+int sym_activate(struct device *, int);
+
+struct cfattach sym_ca = {
+ sizeof(struct sym_softc),
+ sym_match,
+ sym_attach,
+ sym_detach,
+ sym_activate
+};
+
+struct cfdriver sym_cd = {
+ NULL,
+ "sym",
+ DV_DULL
+};
+
+void sym_mpath_start(struct scsi_xfer *);
+int sym_mpath_checksense(struct scsi_xfer *);
+int sym_mpath_online(struct scsi_link *);
+int sym_mpath_offline(struct scsi_link *);
+
+struct mpath_ops sym_mpath_ops = {
+ "sym",
+ sym_mpath_start,
+ sym_mpath_checksense,
+ sym_mpath_online,
+ sym_mpath_offline
+};
+
+struct sym_device {
+ char *vendor;
+ char *product;
+};
+
+struct sym_device sym_devices[] = {
+/* " vendor " " device " */
+/* "01234567" "0123456789012345" */
+ { "SEAGATE ", "ST" }
+};
+
+int
+sym_match(struct device *parent, void *match, void *aux)
+{
+ struct scsi_attach_args *sa = aux;
+ struct scsi_inquiry_data *inq = sa->sa_inqbuf;
+ struct sym_device *s;
+ int i;
+
+ if (mpath_path_probe(sa->sa_sc_link) != 0)
+ return (0);
+
+ for (i = 0; i < nitems(sym_devices); i++) {
+ s = &sym_devices[i];
+
+ if (bcmp(s->vendor, inq->vendor, strlen(s->vendor)) == 0 &&
+ bcmp(s->product, inq->product, strlen(s->product)) == 0)
+ return (3);
+ }
+
+ return (0);
+}
+
+void
+sym_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct sym_softc *sc = (struct sym_softc *)self;
+ struct scsi_attach_args *sa = aux;
+ struct scsi_link *link = sa->sa_sc_link;
+
+ printf("\n");
+
+ /* init link */
+ link->device_softc = sc;
+
+ /* init path */
+ scsi_xsh_set(&sc->sc_path.p_xsh, link, sym_mpath_start);
+ sc->sc_path.p_link = link;
+ sc->sc_path.p_ops = &sym_mpath_ops;
+
+ if (mpath_path_attach(&sc->sc_path) != 0)
+ printf("%s: unable to attach path\n", DEVNAME(sc));
+}
+
+int
+sym_detach(struct device *self, int flags)
+{
+ return (0);
+}
+
+int
+sym_activate(struct device *self, int act)
+{
+ struct sym_softc *sc = (struct sym_softc *)self;
+ int rv = 0;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ case DVACT_SUSPEND:
+ case DVACT_RESUME:
+ break;
+ case DVACT_DEACTIVATE:
+ if (sc->sc_path.p_dev != NULL)
+ mpath_path_detach(&sc->sc_path);
+ break;
+ }
+ return (rv);
+}
+
+void
+sym_mpath_start(struct scsi_xfer *xs)
+{
+ struct sym_softc *sc = xs->sc_link->device_softc;
+
+ mpath_start(&sc->sc_path, xs);
+}
+
+int
+sym_mpath_checksense(struct scsi_xfer *xs)
+{
+ return (0);
+}
+
+int
+sym_mpath_online(struct scsi_link *link)
+{
+ return (0);
+}
+
+int
+sym_mpath_offline(struct scsi_link *link)
+{
+ return (0);
+}
diff --git a/sys/scsi/mpathvar.h b/sys/scsi/mpathvar.h
new file mode 100644
index 00000000000..8a1357a500b
--- /dev/null
+++ b/sys/scsi/mpathvar.h
@@ -0,0 +1,55 @@
+/* $OpenBSD: mpathvar.h,v 1.1 2011/04/05 14:25:42 dlg Exp $ */
+
+/*
+ * Copyright (c) 2010 David Gwynne <dlg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SYS_SCSI_MPATH_H_
+#define _SYS_SCSI_MPATH_H_
+
+struct mpath_dev;
+struct mpath_group;
+
+struct mpath_ops {
+ char op_name[16];
+ void (*op_start)(struct scsi_xfer *);
+ int (*op_checksense)(struct scsi_xfer *);
+ int (*op_online)(struct scsi_link *);
+ int (*op_offline)(struct scsi_link *);
+};
+
+struct mpath_path {
+ /* the path driver must set these */
+ struct scsi_xshandler p_xsh;
+ struct scsi_link *p_link;
+ struct mpath_ops *p_ops;
+ int p_gid;
+
+ /* the follwoing are private to mpath.c */
+ TAILQ_ENTRY(mpath_path) p_entry;
+ struct mpath_dev *p_dev;
+ int p_state;
+};
+
+int mpath_path_probe(struct scsi_link *);
+int mpath_path_attach(struct mpath_path *);
+void mpath_path_state(struct mpath_path *, int);
+int mpath_path_detach(struct mpath_path *);
+
+void mpath_start(struct mpath_path *, struct scsi_xfer *);
+
+struct device *mpath_bootdv(struct device *);
+
+#endif /* _SYS_SCSI_MPATH_H_ */
diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c
index 9fa6900e761..778c42a701b 100644
--- a/sys/scsi/scsiconf.c
+++ b/sys/scsi/scsiconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsiconf.c,v 1.169 2011/03/31 18:42:48 jasper Exp $ */
+/* $OpenBSD: scsiconf.c,v 1.170 2011/04/05 14:25:42 dlg Exp $ */
/* $NetBSD: scsiconf.c,v 1.57 1996/05/02 01:09:01 neil Exp $ */
/*
@@ -61,6 +61,7 @@
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
+#include <scsi/mpathvar.h>
#if NBIO > 0
#include <sys/ioctl.h>
@@ -248,12 +249,7 @@ scsi_activate_lun(struct scsibus_softc *sc, int target, int lun, int act)
switch (act) {
case DVACT_ACTIVATE:
atomic_clearbits_int(&link->state, SDEV_S_DYING);
-#if NMPATH > 0
- if (dev == NULL)
- mpath_path_activate(link);
- else
-#endif /* NMPATH */
- config_activate(dev);
+ config_activate(dev);
break;
case DVACT_QUIESCE:
case DVACT_SUSPEND:
@@ -262,12 +258,7 @@ scsi_activate_lun(struct scsibus_softc *sc, int target, int lun, int act)
break;
case DVACT_DEACTIVATE:
atomic_setbits_int(&link->state, SDEV_S_DYING);
-#if NMPATH > 0
- if (dev == NULL)
- mpath_path_deactivate(link);
- else
-#endif /* NMPATH */
- config_deactivate(dev);
+ config_deactivate(dev);
break;
default:
break;
@@ -502,12 +493,7 @@ scsi_detach_lun(struct scsibus_softc *sc, int target, int lun, int flags)
scsi_link_shutdown(link);
/* 2. detach the device */
-#if NMPATH > 0
- if (link->device_softc == NULL)
- rv = mpath_path_detach(link, flags);
- else
-#endif /* NMPATH */
- rv = config_detach(link->device_softc, flags);
+ rv = config_detach(link->device_softc, flags);
if (rv != 0)
return (rv);
@@ -970,18 +956,6 @@ scsi_probedev(struct scsibus_softc *scsi, int target, int lun)
goto free_devid;
}
-#if NMPATH > 0
- /* should multipathing steal the link? */
- if (mpath_path_attach(sc_link) == 0) {
- printf("%s: path to", scsi->sc_dev.dv_xname);
- scsibus_printlink(sc_link);
- printf("\n");
-
- scsi_add_link(scsi, sc_link);
- return (0);
- }
-#endif /* NMPATH */
-
finger = (const struct scsi_quirk_inquiry_pattern *)scsi_inqmatch(
inqbuf, scsi_quirk_patterns,
nitems(scsi_quirk_patterns),
diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h
index 73a67f13c19..e9a5f80e8b5 100644
--- a/sys/scsi/scsiconf.h
+++ b/sys/scsi/scsiconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsiconf.h,v 1.142 2010/12/24 02:45:33 krw Exp $ */
+/* $OpenBSD: scsiconf.h,v 1.143 2011/04/05 14:25:42 dlg Exp $ */
/* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */
/*
@@ -627,15 +627,6 @@ void scsi_xsh_add(struct scsi_xshandler *);
void scsi_xsh_del(struct scsi_xshandler *);
/*
- * 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 *);
-
-/*
* Utility functions for SCSI HBA emulation.
*/
void scsi_cmd_rw_decode(struct scsi_generic *, u_int64_t *, u_int32_t *);