summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2014-04-03 04:02:51 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2014-04-03 04:02:51 +0000
commit98fc7bec44a16edda7dba0c21559c283b7244bea (patch)
tree53a0587d052aba0d69703c47546ac21d42767e20
parent247bb93f271273afc9be4bced92297210061f4ec (diff)
massage the preferred path detection to happen when mpath asks for
a paths status, rather than on attach. the status it returns depends on the type of device you have. hds provides two types of arrays, symmetric and asymmetric. on a symmetric device you can shove io down any path to any port on any controller and it will work. on symmetric devices we say all paths are part of the same group, and unconditionally return active path status to any check request. on asymmetric devices we group paths by which controller in teh array they connect to. the controllers return whether theyre providing a preferred path via a couple of status bits in a hds specific vpd page, so we query that and return the state of the bits. unfortunately hds arrays dont report change of lun ownership in any way, so we dont currently have any way of failing over at the moment. ill have to think about the least worst way to handle that. tested by deraadt@ on hppa
-rw-r--r--sys/scsi/mpath_hds.c106
1 files changed, 60 insertions, 46 deletions
diff --git a/sys/scsi/mpath_hds.c b/sys/scsi/mpath_hds.c
index 9348b49a65d..b2a593ba409 100644
--- a/sys/scsi/mpath_hds.c
+++ b/sys/scsi/mpath_hds.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mpath_hds.c,v 1.14 2013/12/06 21:03:02 deraadt Exp $ */
+/* $OpenBSD: mpath_hds.c,v 1.15 2014/04/03 04:02:50 dlg Exp $ */
/*
* Copyright (c) 2011 David Gwynne <dlg@openbsd.org>
@@ -47,7 +47,7 @@
#define HDS_VPD 0xe0
struct hds_vpd {
- struct scsi_vpd_hdr hdr; /* HDS_VPD */
+ struct scsi_vpd_hdr hdr; /* HDS_VPD */
u_int8_t state;
#define HDS_VPD_VALID 0x80
#define HDS_VPD_PREFERRED 0x40
@@ -61,7 +61,10 @@ struct hds_vpd {
struct hds_softc {
struct device sc_dev;
struct mpath_path sc_path;
+ struct scsi_xshandler sc_xsh;
+ struct hds_vpd *sc_vpd;
int sc_mode;
+ int sc_ctrl;
};
#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
@@ -101,7 +104,9 @@ struct hds_device {
int hds_inquiry(struct scsi_link *, int *);
int hds_info(struct hds_softc *);
-int hds_preferred(struct hds_softc *, int *);
+
+void hds_status(struct scsi_xfer *);
+void hds_status_done(struct scsi_xfer *);
struct hds_device hds_devices[] = {
/* " vendor " " device " */
@@ -140,7 +145,6 @@ hds_attach(struct device *parent, struct device *self, void *aux)
struct hds_softc *sc = (struct hds_softc *)self;
struct scsi_attach_args *sa = aux;
struct scsi_link *link = sa->sa_sc_link;
- int preferred = 1;
printf("\n");
@@ -151,6 +155,10 @@ hds_attach(struct device *parent, struct device *self, void *aux)
scsi_xsh_set(&sc->sc_path.p_xsh, link, hds_mpath_start);
sc->sc_path.p_link = link;
+ /* init status handler */
+ scsi_xsh_set(&sc->sc_xsh, link, hds_status);
+ sc->sc_vpd = dma_alloc(sizeof(*sc->sc_vpd), PR_WAITOK);
+
if (hds_inquiry(link, &sc->sc_mode) != 0) {
printf("%s: unable to query controller mode\n", DEVNAME(sc));
return;
@@ -161,22 +169,19 @@ hds_attach(struct device *parent, struct device *self, void *aux)
return;
}
- if (hds_preferred(sc, &preferred) != 0) {
- printf("%s: unable to query preferred path\n", DEVNAME(sc));
- return;
- }
-
- if (!preferred)
- return;
-
- /* XXX id isnt real, needs to come from hds_info */
- if (mpath_path_attach(&sc->sc_path, 0, &hds_mpath_ops) != 0)
+ if (mpath_path_attach(&sc->sc_path,
+ (sc->sc_mode == HDS_SYMMETRIC) ? 0 : sc->sc_ctrl,
+ &hds_mpath_ops) != 0)
printf("%s: unable to attach path\n", DEVNAME(sc));
}
int
hds_detach(struct device *self, int flags)
{
+ struct hds_softc *sc = (struct hds_softc *)self;
+
+ dma_free(sc->sc_vpd, sizeof(*sc->sc_vpd));
+
return (0);
}
@@ -214,7 +219,45 @@ hds_mpath_status(struct scsi_link *link)
{
struct hds_softc *sc = link->device_softc;
- mpath_path_status(&sc->sc_path, MPATH_S_UNKNOWN);
+ if (sc->sc_mode == HDS_SYMMETRIC)
+ mpath_path_status(&sc->sc_path, MPATH_S_ACTIVE);
+ else
+ scsi_xsh_add(&sc->sc_xsh);
+}
+
+void
+hds_status(struct scsi_xfer *xs)
+{
+ struct scsi_link *link = xs->sc_link;
+ struct hds_softc *sc = link->device_softc;
+
+ scsi_init_inquiry(xs, SI_EVPD, HDS_VPD,
+ sc->sc_vpd, sizeof(*sc->sc_vpd));
+
+ xs->done = hds_status_done;
+
+ scsi_xs_exec(xs);
+}
+
+void
+hds_status_done(struct scsi_xfer *xs)
+{
+ struct scsi_link *link = xs->sc_link;
+ struct hds_softc *sc = link->device_softc;
+ struct hds_vpd *vpd = sc->sc_vpd;
+ int status;
+
+ scsi_xs_put(xs);
+
+ if (_2btol(vpd->hdr.page_length) < sizeof(vpd->state) ||
+ !ISSET(vpd->state, HDS_VPD_VALID))
+ status = MPATH_S_UNKNOWN;
+ else if (ISSET(vpd->state, HDS_VPD_PREFERRED))
+ status = MPATH_S_ACTIVE;
+ else
+ status = MPATH_S_PASSIVE;
+
+ mpath_path_status(&sc->sc_path, status);
}
int
@@ -281,6 +324,8 @@ hds_info(struct hds_softc *sc)
printf("%s: ldev %s, controller %c, port %c, %s\n",
DEVNAME(sc), ldev, ctrl, port,
sc->sc_mode == HDS_SYMMETRIC ? "symmetric" : "asymmetric");
+
+ sc->sc_ctrl = ctrl;
} else
error = ENXIO;
@@ -288,34 +333,3 @@ done:
dma_free(buf, len);
return (error);
}
-
-int
-hds_preferred(struct hds_softc *sc, int *preferred)
-{
- struct scsi_link *link = sc->sc_path.p_link;
- struct hds_vpd *pg;
- int error;
-
- if (sc->sc_mode == HDS_SYMMETRIC) {
- *preferred = 1;
- return (0);
- }
-
- pg = dma_alloc(sizeof(*pg), PR_WAITOK);
-
- error = scsi_inquire_vpd(link, pg, sizeof(*pg), HDS_VPD, scsi_autoconf);
- if (error)
- goto done;
-
- if (_2btol(pg->hdr.page_length) < sizeof(pg->state) ||
- !ISSET(pg->state, HDS_VPD_VALID)) {
- error = ENXIO;
- goto done;
- }
-
- *preferred = ISSET(pg->state, HDS_VPD_PREFERRED);
-
-done:
- dma_free(pg, sizeof(*pg));
- return (error);
-}