From: dlg Date: Tue, 22 Jul 2008 01:01:31 +0000 (+0000) Subject: implement the fetching of a scsi devices "devid". recent hardware provides X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=758476e4008f1c5767b758f772ba935ecc17552b;p=openbsd implement the fetching of a scsi devices "devid". recent hardware provides a vpd page that uniquely identifies a device no matter what bus topology or addressing was used to find it. we have a workaround for old school scsi devices that do not differentiate between luns. if the inq data for high luns is the same as the inq data for lun 0, we assume it is one of these buggy devices. the problem with this is that things like SANs present multiple volumes as luns and they all have the same inq data. if you wanted to present more than one volume to openbsd you would only ever see the first one. devices give us a mechanism to differentiate between luns, so now i do get all my volumes attached in openbsde. review and feedback by krw@ marco@ testing by todd@ --- diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c index 4ed8783ce40..969cb16dd14 100644 --- a/sys/scsi/scsiconf.c +++ b/sys/scsi/scsiconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scsiconf.c,v 1.134 2008/07/22 00:40:37 dlg Exp $ */ +/* $OpenBSD: scsiconf.c,v 1.135 2008/07/22 01:01:31 dlg Exp $ */ /* $NetBSD: scsiconf.c,v 1.57 1996/05/02 01:09:01 neil Exp $ */ /* @@ -69,6 +69,9 @@ */ int scsi_probedev(struct scsibus_softc *, int, int); +void scsi_devid(struct scsi_link *); +int scsi_devid_pg83(struct scsi_link *); + struct scsi_device probe_switch = { NULL, NULL, @@ -700,7 +703,7 @@ int scsi_probedev(struct scsibus_softc *scsi, int target, int lun) { const struct scsi_quirk_inquiry_pattern *finger; - struct scsi_inquiry_data *inqbuf; + struct scsi_inquiry_data *inqbuf; struct scsi_attach_args sa; struct scsi_link *sc_link; struct cfdata *cf; @@ -784,10 +787,15 @@ scsi_probedev(struct scsibus_softc *scsi, int target, int lun) break; } + scsi_devid(sc_link); + if (lun == 0 || scsi->sc_link[target][0] == NULL) ; else if (sc_link->flags & SDEV_UMASS) ; + else if (sc_link->id.d_type != DEVID_NONE && + !DEVID_CMP(&scsi->sc_link[target][0]->id, &sc_link->id)) + ; else if (memcmp(inqbuf, &scsi->sc_link[target][0]->inqdata, sizeof(*inqbuf)) == 0) { /* The device doesn't distinguish between LUNs. */ @@ -932,3 +940,119 @@ scsi_inqmatch(struct scsi_inquiry_data *inqbuf, const void *_base, return (bestmatch); } + +void +scsi_devid(struct scsi_link *link) +{ + struct { + struct scsi_vpd_hdr hdr; + u_int8_t list[32]; + } __packed pg; + int pg80 = 0, pg83 = 0, i; + + if (SCSISPC(link->inqdata.version) >= 2) { + if (scsi_inquire_vpd(link, &pg, sizeof(pg), SI_PG_SUPPORTED, + scsi_autoconf) != 0) + return; + + for (i = 0; i < MIN(sizeof(pg.list), pg.hdr.page_length); i++) { + switch (pg.list[i]) { + case SI_PG_SERIAL: + pg80 = 1; + break; + case SI_PG_DEVID: + pg83 = 1; + break; + } + } + + if (pg83 && scsi_devid_pg83(link) == 0) + return; +#ifdef notyet + if (pg80 && scsi_devid_pg80(link) == 0) + return; +#endif + } +} + +int +scsi_devid_pg83(struct scsi_link *link) +{ + struct scsi_vpd_hdr hdr; + struct scsi_vpd_devid_hdr dhdr; + u_int8_t *pg, *id; + int type, idtype = 0, idlen; + int len, pos; + int rv; + + rv = scsi_inquire_vpd(link, &hdr, sizeof(hdr), SI_PG_DEVID, + scsi_autoconf); + if (rv != 0) + return (rv); + + len = sizeof(hdr) + hdr.page_length; + pg = malloc(len, M_TEMP, M_WAITOK); + + rv = scsi_inquire_vpd(link, pg, len, SI_PG_DEVID, scsi_autoconf); + if (rv != 0) + goto err; + + pos = sizeof(hdr); + + do { + if (len - pos < sizeof(dhdr)) { + rv = EIO; + goto err; + } + memcpy(&dhdr, &pg[pos], sizeof(dhdr)); + pos += sizeof(dhdr); + if (len - pos < dhdr.len) { + rv = EIO; + goto err; + } + + if (VPD_DEVID_ASSOC(dhdr.flags) == VPD_DEVID_ASSOC_LU) { + type = VPD_DEVID_TYPE(dhdr.flags); + switch (type) { + case VPD_DEVID_TYPE_NAA: + case VPD_DEVID_TYPE_EUI64: + case VPD_DEVID_TYPE_T10: + if (type >= idtype) { + idtype = type; + idlen = dhdr.len; + id = &pg[pos]; + } + break; + + default: + /* skip */ + break; + } + } + + pos += dhdr.len; + } while (idtype != VPD_DEVID_TYPE_NAA && len != pos); + + if (idtype > 0) { + link->id.d_id = malloc(idlen, M_DEVBUF, M_WAITOK); + + switch (idtype) { + case VPD_DEVID_TYPE_NAA: + link->id.d_type = DEVID_NAA; + break; + case VPD_DEVID_TYPE_EUI64: + link->id.d_type = DEVID_EUI; + break; + case VPD_DEVID_TYPE_T10: + link->id.d_type = DEVID_T10; + break; + } + link->id.d_len = idlen; + memcpy(link->id.d_id, id, idlen); + } else + rv = ENODEV; + +err: + free(pg, M_TEMP); + return (rv); +} diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h index d7e252fd042..7ab43787a12 100644 --- a/sys/scsi/scsiconf.h +++ b/sys/scsi/scsiconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scsiconf.h,v 1.93 2008/06/21 21:11:34 krw Exp $ */ +/* $OpenBSD: scsiconf.h,v 1.94 2008/07/22 01:01:31 dlg Exp $ */ /* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */ /* @@ -56,6 +56,26 @@ #include #include +#define DEVID_NONE 0 +#define DEVID_NAA 1 +#define DEVID_EUI 2 +#define DEVID_T10 3 + +struct devid { + int d_type; + u_int d_len; + u_int8_t *d_id; +}; + +#define DEVID_CMP(_a, _b) ( \ + (_a) != NULL && \ + (_b) != NULL && \ + (_a)->d_type != DEVID_NONE && \ + (_a)->d_type == (_b)->d_type && \ + (_a)->d_len == (_b)->d_len && \ + bcmp((_a)->d_id, (_b)->d_id, (_a)->d_len) == 0 \ +) + /* * The following documentation tries to describe the relationship between the * various structures defined in this file: @@ -177,6 +197,7 @@ struct scsi_link { void *adapter_softc; /* needed for call to foo_scsi_cmd */ struct scsibus_softc *bus; /* link to the scsibus we're on */ struct scsi_inquiry_data inqdata; /* copy of INQUIRY data from probe */ + struct devid id; }; int scsiprint(void *, const char *);