summaryrefslogtreecommitdiff
path: root/sys/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'sys/scsi')
-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);
-}