diff options
Diffstat (limited to 'sys/scsi/scsiconf.c')
-rw-r--r-- | sys/scsi/scsiconf.c | 164 |
1 files changed, 68 insertions, 96 deletions
diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c index 1aa76c9c005..3028dbe54bf 100644 --- a/sys/scsi/scsiconf.c +++ b/sys/scsi/scsiconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scsiconf.c,v 1.116 2006/10/07 23:40:07 beck Exp $ */ +/* $OpenBSD: scsiconf.c,v 1.117 2006/10/21 07:36:15 dlg Exp $ */ /* $NetBSD: scsiconf.c,v 1.57 1996/05/02 01:09:01 neil Exp $ */ /* @@ -60,7 +60,6 @@ * Declarations */ int scsi_probedev(struct scsibus_softc *, int, int); -int scsi_probe_bus(int, int, int); struct scsi_device probe_switch = { NULL, @@ -160,7 +159,7 @@ scsibusattach(struct device *parent, struct device *self, void *aux) bzero(sb->sc_link[i], nbytes); } - scsi_probe_bus(sb->sc_dev.dv_unit, -1, -1); + scsi_probe_bus(sb); } int @@ -211,118 +210,91 @@ scsibussubmatch(struct device *parent, void *match, void *aux) return ((*cf->cf_attach->ca_match)(parent, match, aux)); } -/* - * Probe the requested scsi bus. It must be already set up. - * -1 requests all set up scsi busses. - * target and lun optionally narrow the search if not -1 - */ int -scsi_probe_busses(int bus, int target, int lun) +scsi_probe_bus(struct scsibus_softc *sc) { - if (bus == -1) { - for (bus = 0; bus < scsibus_cd.cd_ndevs; bus++) - if (scsibus_cd.cd_devs[bus]) - scsi_probe_bus(bus, target, lun); - return (0); - } + struct scsi_link *alink = sc->adapter_link; + int i; - return (scsi_probe_bus(bus, target, lun)); + for (i = 0; i < alink->adapter_buswidth; i++) + scsi_probe_target(sc, i); + + return (0); } -/* - * Probe the requested scsi bus. It must be already set up. - * target and lun optionally narrow the search if not -1 - */ int -scsi_probe_bus(int bus, int target, int lun) +scsi_probe_target(struct scsibus_softc *sc, int target) { - struct scsi_report_luns_data *data = NULL; - struct scsibus_softc *scsi; - struct scsi_link *sc_link; - u_int16_t scsi_addr; - int i, luncount, maxtarget, mintarget, maxlun, minlun; + struct scsi_link *alink = sc->adapter_link; + struct scsi_link *link; + struct scsi_report_luns_data *report; + int i, nluns, lun; + + if (scsi_probe_lun(sc, target, 0) == EINVAL) + return (EINVAL); - if (bus < 0 || bus >= scsibus_cd.cd_ndevs) + link = sc->sc_link[target][0]; + if (link == NULL) return (ENXIO); - scsi = scsibus_cd.cd_devs[bus]; - if (scsi == NULL) - return ENXIO; + if ((link->flags & (SDEV_UMASS | SDEV_ATAPI)) == 0 && + SCSISPC(link->inqdata.version) > 2) { + report = malloc(sizeof(*report), M_TEMP, M_WAITOK); + if (report == NULL) + goto dumbscan; + + if (scsi_report_luns(link, REPORT_NORMAL, report, + sizeof(*report), scsi_autoconf | SCSI_SILENT | + SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY | + SCSI_IGNORE_MEDIA_CHANGE, 10000) != 0) { + free(report, M_TEMP); + goto dumbscan; + } - scsi_addr = scsi->adapter_link->adapter_target; + /* + * XXX In theory we should check if data is full, which + * would indicate it needs to be enlarged and REPORT + * LUNS tried again. Solaris tries up to 3 times with + * larger sizes for data. + */ + nluns = _4btol(report->length) / RPL_LUNDATA_SIZE; + for (i = 0; i < nluns; i++) { + if (report->luns[i].lundata[0] != 0) + continue; + lun = report->luns[i].lundata[RPL_LUNDATA_T0LUN]; + if (lun == 0) + continue; + + /* Probe the provided LUN. Don't check LUN 0. */ + sc->sc_link[target][0] = NULL; + scsi_probe_lun(sc, target, lun); + sc->sc_link[target][0] = link; + } - if (target == -1) { - maxtarget = scsi->adapter_link->adapter_buswidth - 1; - mintarget = 0; - } else { - if (target < 0 || - target >= scsi->adapter_link->adapter_buswidth) - return (EINVAL); - maxtarget = mintarget = target; + free(report, M_TEMP); + return (0); } - if (lun == -1) { - maxlun = scsi->adapter_link->luns - 1; - minlun = 0; - } else { - if (lun < 0 || lun >= scsi->adapter_link->luns) - return (EINVAL); - maxlun = lun; - if (target == -1 || scsi->sc_link[target][0] == NULL) - minlun = 0; - else - minlun = lun; +dumbscan: + for (i = 1; i < alink->luns; i++) { + if (scsi_probe_lun(sc, target, i) == EINVAL) + break; } - data = malloc(sizeof *data, M_TEMP, M_NOWAIT); - - for (target = mintarget; target <= maxtarget; target++) { - if (target == scsi_addr) - continue; - if (scsi_probedev(scsi, target, 0) == EINVAL) - continue; - - sc_link = scsi->sc_link[target][0]; - if (sc_link != NULL && data != NULL && - (sc_link->flags & (SDEV_UMASS | SDEV_ATAPI)) == 0 && - SCSISPC(sc_link->inqdata.version) > 2) { - scsi_report_luns(sc_link, REPORT_NORMAL, data, - sizeof *data, scsi_autoconf | SCSI_SILENT | - SCSI_IGNORE_ILLEGAL_REQUEST | - SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE, - 10000); - /* - * XXX In theory we should check if data is full, which - * would indicate it needs to be enlarged and REPORT - * LUNS tried again. Solaris tries up to 3 times with - * larger sizes for data. - */ - luncount = _4btol(data->length) / RPL_LUNDATA_SIZE; - for (i = 0; i < luncount; i++) { - if (data->luns[i].lundata[0] != 0) - continue; - lun = data->luns[i].lundata[RPL_LUNDATA_T0LUN]; - if (lun == 0 || lun < minlun || lun > maxlun) - continue; - /* Probe the provided LUN. Don't check LUN 0. */ - scsi->sc_link[target][0] = NULL; - scsi_probedev(scsi, target, lun); - scsi->sc_link[target][0] = sc_link; - } - if (luncount > 0) - continue; /* Next target. */ - } + return (0); +} - /* No LUN list available. Scan entire range. */ - for (lun = max(minlun, 1); lun <= maxlun; lun++) - if (scsi_probedev(scsi, target, lun) == EINVAL) - break; - } +int +scsi_probe_lun(struct scsibus_softc *sc, int target, int lun) +{ + struct scsi_link *alink = sc->adapter_link; - if (data != NULL) - free(data, M_TEMP); + if (target < 0 || target >= alink->adapter_buswidth || + target == alink->adapter_target || + lun < 0 || lun >= alink->luns) + return (ENXIO); - return (0); + return (scsi_probedev(sc, target, lun)); } void |