this is based on the solaris code. its a lot less arbitrary than
the stupid linux code.

if this works i'll add back the printing of the physical path, it can be useful 
when debugging wiring issues.

cheers,
dlg

Index: mpath_hds.c
===================================================================
RCS file: /cvs/src/sys/scsi/mpath_hds.c,v
retrieving revision 1.2
diff -u -p -r1.2 mpath_hds.c
--- mpath_hds.c 28 Apr 2011 10:43:36 -0000      1.2
+++ mpath_hds.c 14 Jun 2011 05:34:00 -0000
@@ -37,6 +37,17 @@
 #include <scsi/scsiconf.h>
 #include <scsi/mpathvar.h>
 
+#define HDS_VPD                        0xe0
+
+struct hds_vpd {
+        struct scsi_vpd_hdr    hdr; /* HDS_VPD */
+       u_int8_t                state;
+#define HDS_VPD_VALID                  0x80
+#define HDS_VPD_PREFERRED              0x40
+
+       /* followed by lots of unknown stuff */
+};
+
 struct hds_softc {
        struct device           sc_dev;
        struct mpath_path       sc_path;
@@ -80,7 +91,7 @@ struct hds_device {
        char *product;
 };
 
-int            hds_priority(struct hds_softc *);
+int            hds_preferred(struct scsi_link *, int *);
 
 struct hds_device hds_devices[] = {
 /*       " vendor "  "     device     " */
@@ -94,8 +105,9 @@ hds_match(struct device *parent, void *m
 {
        struct scsi_attach_args *sa = aux;
        struct scsi_inquiry_data *inq = sa->sa_inqbuf;
+       struct scsi_link *link = sa->sa_sc_link;
        struct hds_device *s;
-       int i;
+       int i, preferred;
 
        if (mpath_path_probe(sa->sa_sc_link) != 0)
                return (0);
@@ -104,8 +116,11 @@ hds_match(struct device *parent, void *m
                s = &hds_devices[i];
 
                if (bcmp(s->vendor, inq->vendor, strlen(s->vendor)) == 0 &&
-                   bcmp(s->product, inq->product, strlen(s->product)) == 0)
-                       return (3);
+                   bcmp(s->product, inq->product, strlen(s->product)) == 0 &&
+                   hds_preferred(link, &preferred) == 0) {
+                       /* match above sym(4) */
+                       return (4);
+               }
        }
 
        return (0);
@@ -128,7 +143,7 @@ hds_attach(struct device *parent, struct
        sc->sc_path.p_link = link;
        sc->sc_path.p_ops = &hds_mpath_ops;
 
-       if (hds_priority(sc) != 0)
+       if (hds_preferred(link, &sc->sc_active) != 0)
                return;
 
        if (!sc->sc_active)
@@ -190,68 +205,26 @@ hds_mpath_offline(struct scsi_link *link
 }
 
 int
-hds_priority(struct hds_softc *sc)
+hds_preferred(struct scsi_link *link, int *preferred)
 {
-       u_int8_t *buffer;
-       struct scsi_inquiry *cdb;
-       struct scsi_xfer *xs;
-       size_t length;
-       u_int8_t ldev[9];
-       u_int8_t ctrl;
-       u_int8_t port;
-       int p, c;
+       struct hds_vpd *pg;
        int error;
 
-       length = MIN(sc->sc_path.p_link->inqdata.additional_length + 5, 255);
-       if (length < 51)
-               return (EIO);
-
-       buffer = dma_alloc(length, PR_WAITOK);
-
-       xs = scsi_xs_get(sc->sc_path.p_link, scsi_autoconf);
-       if (xs == NULL) {
-               error = EBUSY;
-               goto done;
-       }
-
-       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;
+       pg = dma_alloc(sizeof(*pg), PR_WAITOK);
 
-       error = scsi_xs_sync(xs);
-       scsi_xs_put(xs);
-
-       if (error != 0)
+       error = scsi_inquire_vpd(link, pg, sizeof(*pg), HDS_VPD, scsi_autoconf);
+       if (error)
                goto done;
 
-       /* XXX magical */
-       bzero(ldev, sizeof(ldev));
-       scsi_strvis(ldev, buffer + 44, 4);
-       ctrl = buffer[49];
-       port = buffer[50];
-
-       if (strlen(ldev) > 4 || ldev[3] < '0' || ldev[3] > 'F' ||
-           ctrl < '0' || ctrl > '9' ||
-           port < 'A' || port > 'B') {
-               error = EIO;
+       if (_2btol(pg->hdr.page_length) < sizeof(pg->state) ||
+            !ISSET(pg->state, HDS_VPD_VALID)) {
+               error = ENXIO;
                goto done;
        }
 
-       c = ctrl - '0';
-       p = port - 'A';
-       if ((c & 0x1) == (p & 0x1))
-               sc->sc_active = 1;
-
-       printf("%s: ldev %s, controller %c, port %c\n", DEVNAME(sc), ldev,
-           ctrl, port);
+       *preferred = ISSET(pg->state, HDS_VPD_PREFERRED);
 
-       error = 0;
 done:
-       dma_free(buffer, length);
+       dma_free(pg, sizeof(*pg));
        return (error);
 }

Reply via email to