The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/scsi/scsiconf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: scsiconf.c,v 1.253 2022/04/06 17:39:13 krw Exp $      */
    2 /*      $NetBSD: scsiconf.c,v 1.57 1996/05/02 01:09:01 neil Exp $       */
    3 
    4 /*
    5  * Copyright (c) 1994 Charles Hannum.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Charles Hannum.
   18  * 4. The name of the author may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * Originally written by Julian Elischer (julian@tfs.com)
   35  * for TRW Financial Systems for use under the MACH(2.5) operating system.
   36  *
   37  * TRW Financial Systems, in accordance with their agreement with Carnegie
   38  * Mellon University, makes this software available to CMU to distribute
   39  * or use in any manner that they see fit as long as this message is kept with
   40  * the software. For this reason TFS also grants any other persons or
   41  * organisations permission to use or modify this software.
   42  *
   43  * TFS supplies this software to be publicly redistributed
   44  * on the understanding that TFS is not responsible for the correct
   45  * functioning of this software in any circumstances.
   46  *
   47  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
   48  */
   49 
   50 #include "bio.h"
   51 #include "mpath.h"
   52 
   53 #include <sys/param.h>
   54 #include <sys/systm.h>
   55 #include <sys/malloc.h>
   56 #include <sys/pool.h>
   57 #include <sys/device.h>
   58 #include <sys/buf.h>
   59 #include <sys/atomic.h>
   60 
   61 #include <scsi/scsi_all.h>
   62 #include <scsi/scsi_debug.h>
   63 #include <scsi/scsiconf.h>
   64 
   65 int     scsibusmatch(struct device *, void *, void *);
   66 void    scsibusattach(struct device *, struct device *, void *);
   67 int     scsibusactivate(struct device *, int);
   68 int     scsibusdetach(struct device *, int);
   69 int     scsibussubmatch(struct device *, void *, void *);
   70 int     scsibussubprint(void *, const char *);
   71 #if NBIO > 0
   72 #include <sys/ioctl.h>
   73 #include <sys/scsiio.h>
   74 #include <dev/biovar.h>
   75 int     scsibusbioctl(struct device *, u_long, caddr_t);
   76 #endif /* NBIO > 0 */
   77 
   78 void    scsi_get_target_luns(struct scsibus_softc *, int,
   79     struct scsi_lun_array *);
   80 void    scsi_add_link(struct scsi_link *);
   81 void    scsi_remove_link(struct scsi_link *);
   82 void    scsi_print_link(struct scsi_link *);
   83 int     scsi_probe_link(struct scsibus_softc *, int, int, int);
   84 int     scsi_activate_link(struct scsi_link *, int);
   85 int     scsi_detach_link(struct scsi_link *, int);
   86 int     scsi_detach_bus(struct scsibus_softc *, int);
   87 
   88 void    scsi_devid(struct scsi_link *);
   89 int     scsi_devid_pg80(struct scsi_link *);
   90 int     scsi_devid_pg83(struct scsi_link *);
   91 int     scsi_devid_wwn(struct scsi_link *);
   92 
   93 int     scsi_activate_bus(struct scsibus_softc *, int);
   94 int     scsi_activate_target(struct scsibus_softc *, int, int);
   95 int     scsi_activate_lun(struct scsibus_softc *, int, int, int);
   96 
   97 int     scsi_autoconf = SCSI_AUTOCONF;
   98 
   99 const struct cfattach scsibus_ca = {
  100         sizeof(struct scsibus_softc), scsibusmatch, scsibusattach,
  101         scsibusdetach, scsibusactivate
  102 };
  103 
  104 struct cfdriver scsibus_cd = {
  105         NULL, "scsibus", DV_DULL
  106 };
  107 
  108 struct scsi_quirk_inquiry_pattern {
  109         struct scsi_inquiry_pattern     pattern;
  110         u_int16_t                       quirks;
  111 };
  112 
  113 const struct scsi_quirk_inquiry_pattern scsi_quirk_patterns[] = {
  114         {{T_CDROM, T_REMOV,
  115          "PLEXTOR", "CD-ROM PX-40TS", "1.01"},    SDEV_NOSYNC},
  116 
  117         {{T_DIRECT, T_FIXED,
  118          "MICROP  ", "1588-15MBSUN0669", ""},     SDEV_AUTOSAVE},
  119         {{T_DIRECT, T_FIXED,
  120          "DEC     ", "RZ55     (C) DEC", ""},     SDEV_AUTOSAVE},
  121         {{T_DIRECT, T_FIXED,
  122          "EMULEX  ", "MD21/S2     ESDI", "A00"},  SDEV_AUTOSAVE},
  123         {{T_DIRECT, T_FIXED,
  124          "IBMRAID ", "0662S",            ""},     SDEV_AUTOSAVE},
  125         {{T_DIRECT, T_FIXED,
  126          "IBM     ", "0663H",            ""},     SDEV_AUTOSAVE},
  127         {{T_DIRECT, T_FIXED,
  128          "IBM",   "0664",                ""},     SDEV_AUTOSAVE},
  129         {{T_DIRECT, T_FIXED,
  130          "IBM     ", "H3171-S2",         ""},     SDEV_AUTOSAVE},
  131         {{T_DIRECT, T_FIXED,
  132          "IBM     ", "KZ-C",             ""},     SDEV_AUTOSAVE},
  133         /* Broken IBM disk */
  134         {{T_DIRECT, T_FIXED,
  135          ""        , "DFRSS2F",          ""},     SDEV_AUTOSAVE},
  136         {{T_DIRECT, T_FIXED,
  137          "QUANTUM ", "ELS85S          ", ""},     SDEV_AUTOSAVE},
  138         {{T_DIRECT, T_REMOV,
  139          "iomega", "jaz 1GB",            ""},     SDEV_NOTAGS},
  140         {{T_DIRECT, T_FIXED,
  141          "MICROP", "4421-07",            ""},     SDEV_NOTAGS},
  142         {{T_DIRECT, T_FIXED,
  143          "SEAGATE", "ST150176LW",        "0002"}, SDEV_NOTAGS},
  144         {{T_DIRECT, T_FIXED,
  145          "HP", "C3725S",                 ""},     SDEV_NOTAGS},
  146         {{T_DIRECT, T_FIXED,
  147          "IBM", "DCAS",                  ""},     SDEV_NOTAGS},
  148 
  149         {{T_SEQUENTIAL, T_REMOV,
  150          "SONY    ", "SDT-5000        ", "3."},   SDEV_NOSYNC|SDEV_NOWIDE},
  151         {{T_SEQUENTIAL, T_REMOV,
  152          "WangDAT ", "Model 1300      ", "02.4"}, SDEV_NOSYNC|SDEV_NOWIDE},
  153         {{T_SEQUENTIAL, T_REMOV,
  154          "WangDAT ", "Model 2600      ", "01.7"}, SDEV_NOSYNC|SDEV_NOWIDE},
  155         {{T_SEQUENTIAL, T_REMOV,
  156          "WangDAT ", "Model 3200      ", "02.2"}, SDEV_NOSYNC|SDEV_NOWIDE},
  157 
  158         /* ATAPI device quirks */
  159         {{T_CDROM, T_REMOV,
  160          "CR-2801TE", "", "1.07"},              ADEV_NOSENSE},
  161         {{T_CDROM, T_REMOV,
  162          "CREATIVECD3630E", "", "AC101"},       ADEV_NOSENSE},
  163         {{T_CDROM, T_REMOV,
  164          "FX320S", "", "q01"},                  ADEV_NOSENSE},
  165         {{T_CDROM, T_REMOV,
  166          "GCD-R580B", "", "1.00"},              ADEV_LITTLETOC},
  167         {{T_CDROM, T_REMOV,
  168          "MATSHITA CR-574", "", "1.02"},        ADEV_NOCAPACITY},
  169         {{T_CDROM, T_REMOV,
  170          "MATSHITA CR-574", "", "1.06"},        ADEV_NOCAPACITY},
  171         {{T_CDROM, T_REMOV,
  172          "Memorex CRW-2642", "", "1.0g"},       ADEV_NOSENSE},
  173         {{T_CDROM, T_REMOV,
  174          "SANYO CRD-256P", "", "1.02"},         ADEV_NOCAPACITY},
  175         {{T_CDROM, T_REMOV,
  176          "SANYO CRD-254P", "", "1.02"},         ADEV_NOCAPACITY},
  177         {{T_CDROM, T_REMOV,
  178          "SANYO CRD-S54P", "", "1.08"},         ADEV_NOCAPACITY},
  179         {{T_CDROM, T_REMOV,
  180          "CD-ROM  CDR-S1", "", "1.70"},         ADEV_NOCAPACITY}, /* Sanyo */
  181         {{T_CDROM, T_REMOV,
  182          "CD-ROM  CDR-N16", "", "1.25"},        ADEV_NOCAPACITY}, /* Sanyo */
  183         {{T_CDROM, T_REMOV,
  184          "UJDCD8730", "", "1.14"},              ADEV_NODOORLOCK}, /* Acer */
  185 };
  186 
  187 int
  188 scsiprint(void *aux, const char *pnp)
  189 {
  190         /* Only "scsibus"es can attach to "scsi"s. */
  191         if (pnp)
  192                 printf("scsibus at %s", pnp);
  193 
  194         return UNCONF;
  195 }
  196 
  197 int
  198 scsibusmatch(struct device *parent, void *match, void *aux)
  199 {
  200         return 1;
  201 }
  202 
  203 /*
  204  * The routine called by the adapter boards to get all their
  205  * devices configured in.
  206  */
  207 void
  208 scsibusattach(struct device *parent, struct device *self, void *aux)
  209 {
  210         struct scsibus_softc            *sb = (struct scsibus_softc *)self;
  211         struct scsibus_attach_args      *saa = aux;
  212 
  213         if (!cold)
  214                 scsi_autoconf = 0;
  215 
  216         SLIST_INIT(&sb->sc_link_list);
  217         sb->sb_adapter_softc = saa->saa_adapter_softc;
  218         sb->sb_adapter = saa->saa_adapter;
  219         sb->sb_pool = saa->saa_pool;
  220         sb->sb_quirks = saa->saa_quirks;
  221         sb->sb_flags = saa->saa_flags;
  222         sb->sb_openings = saa->saa_openings;
  223         sb->sb_adapter_buswidth = saa->saa_adapter_buswidth;
  224         sb->sb_adapter_target = saa->saa_adapter_target;
  225         sb->sb_luns = saa->saa_luns;
  226 
  227         if (sb->sb_adapter_buswidth == 0)
  228                 sb->sb_adapter_buswidth = 8;
  229         if (sb->sb_luns == 0)
  230                 sb->sb_luns = 8;
  231 
  232         printf(": %d targets", sb->sb_adapter_buswidth);
  233         if (sb->sb_adapter_target < sb->sb_adapter_buswidth)
  234                 printf(", initiator %d", sb->sb_adapter_target);
  235         if (saa->saa_wwpn != 0x0 && saa->saa_wwnn != 0x0) {
  236                 printf(", WWPN %016llx, WWNN %016llx", saa->saa_wwpn,
  237                     saa->saa_wwnn);
  238         }
  239         printf("\n");
  240 
  241         /* Initialize shared data. */
  242         scsi_init();
  243 
  244         SLIST_INIT(&sb->sc_link_list);
  245 
  246 #if NBIO > 0
  247         if (bio_register(&sb->sc_dev, scsibusbioctl) != 0)
  248                 printf("%s: unable to register bio\n", sb->sc_dev.dv_xname);
  249 #endif /* NBIO > 0 */
  250 
  251         scsi_probe_bus(sb);
  252 }
  253 
  254 int
  255 scsibusactivate(struct device *dev, int act)
  256 {
  257         struct scsibus_softc *sb = (struct scsibus_softc *)dev;
  258 
  259         return scsi_activate_bus(sb, act);
  260 }
  261 
  262 int
  263 scsibusdetach(struct device *dev, int type)
  264 {
  265         struct scsibus_softc            *sb = (struct scsibus_softc *)dev;
  266         int                              error;
  267 
  268 #if NBIO > 0
  269         bio_unregister(&sb->sc_dev);
  270 #endif /* NBIO > 0 */
  271 
  272         error = scsi_detach_bus(sb, type);
  273         if (error != 0)
  274                 return error;
  275 
  276         KASSERT(SLIST_EMPTY(&sb->sc_link_list));
  277 
  278         return 0;
  279 }
  280 
  281 int
  282 scsibussubmatch(struct device *parent, void *match, void *aux)
  283 {
  284         struct cfdata                   *cf = match;
  285         struct scsi_attach_args         *sa = aux;
  286         struct scsi_link                *link = sa->sa_sc_link;
  287 
  288         if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != link->target)
  289                 return 0;
  290         if (cf->cf_loc[1] != -1 && cf->cf_loc[1] != link->lun)
  291                 return 0;
  292 
  293         return (*cf->cf_attach->ca_match)(parent, match, aux);
  294 }
  295 
  296 /*
  297  * Print out autoconfiguration information for a subdevice.
  298  *
  299  * This is a slight abuse of 'standard' autoconfiguration semantics,
  300  * because 'print' functions don't normally print the colon and
  301  * device information.  However, in this case that's better than
  302  * either printing redundant information before the attach message,
  303  * or having the device driver call a special function to print out
  304  * the standard device information.
  305  */
  306 int
  307 scsibussubprint(void *aux, const char *pnp)
  308 {
  309         struct scsi_attach_args         *sa = aux;
  310 
  311         if (pnp != NULL)
  312                 printf("%s", pnp);
  313 
  314         scsi_print_link(sa->sa_sc_link);
  315 
  316         return UNCONF;
  317 }
  318 
  319 #if NBIO > 0
  320 int
  321 scsibusbioctl(struct device *dev, u_long cmd, caddr_t addr)
  322 {
  323         struct scsibus_softc            *sb = (struct scsibus_softc *)dev;
  324         struct sbioc_device             *sdev;
  325 
  326         switch (cmd) {
  327         case SBIOCPROBE:
  328                 sdev = (struct sbioc_device *)addr;
  329                 return scsi_probe(sb, sdev->sd_target, sdev->sd_lun);
  330 
  331         case SBIOCDETACH:
  332                 sdev = (struct sbioc_device *)addr;
  333                 return scsi_detach(sb, sdev->sd_target, sdev->sd_lun, 0);
  334 
  335         default:
  336                 return ENOTTY;
  337         }
  338 }
  339 #endif /* NBIO > 0 */
  340 
  341 int
  342 scsi_activate(struct scsibus_softc *sb, int target, int lun, int act)
  343 {
  344         if (target == -1 && lun == -1)
  345                 return scsi_activate_bus(sb, act);
  346         else if (lun == -1)
  347                 return scsi_activate_target(sb, target, act);
  348         else
  349                 return scsi_activate_lun(sb, target, lun, act);
  350 }
  351 
  352 int
  353 scsi_activate_bus(struct scsibus_softc *sb, int act)
  354 {
  355         struct scsi_link                *link;
  356         int                              r, rv = 0;
  357 
  358         /*  Activate all links on the bus. */
  359         SLIST_FOREACH(link, &sb->sc_link_list, bus_list) {
  360                 r = scsi_activate_link(link, act);
  361                 if (r)
  362                         rv = r;
  363         }
  364         return rv;
  365 }
  366 
  367 int
  368 scsi_activate_target(struct scsibus_softc *sb, int target, int act)
  369 {
  370         struct scsi_link                *link;
  371         int                              r, rv = 0;
  372 
  373         /*  Activate all links on the target. */
  374         SLIST_FOREACH(link, &sb->sc_link_list, bus_list) {
  375                 if (link->target == target) {
  376                         r = scsi_activate_link(link, act);
  377                         if (r)
  378                                 rv = r;
  379                 }
  380         }
  381         return rv;
  382 }
  383 
  384 int
  385 scsi_activate_lun(struct scsibus_softc *sb, int target, int lun, int act)
  386 {
  387         struct scsi_link *link;
  388 
  389         /*  Activate the (target, lun) link.*/
  390         link = scsi_get_link(sb, target, lun);
  391         if (link == NULL)
  392                 return 0;
  393 
  394         return scsi_activate_link(link, act);
  395 }
  396 
  397 int
  398 scsi_activate_link(struct scsi_link *link, int act)
  399 {
  400         struct device                   *dev;
  401         int                              rv = 0;
  402 
  403         dev = link->device_softc;
  404         switch (act) {
  405         case DVACT_DEACTIVATE:
  406                 atomic_setbits_int(&link->state, SDEV_S_DYING);
  407                 config_deactivate(dev);
  408                 break;
  409         default:
  410                 rv = config_suspend(dev, act);
  411                 break;
  412         }
  413         return rv;
  414 }
  415 
  416 int
  417 scsi_probe(struct scsibus_softc *sb, int target, int lun)
  418 {
  419         if (target == -1 && lun == -1)
  420                 return scsi_probe_bus(sb);
  421         else if (lun == -1)
  422                 return scsi_probe_target(sb, target);
  423         else
  424                 return scsi_probe_lun(sb, target, lun);
  425 }
  426 
  427 int
  428 scsi_probe_bus(struct scsibus_softc *sb)
  429 {
  430         int             target, r, rv = 0;
  431 
  432         /* Probe all possible targets on bus. */
  433         for (target = 0; target < sb->sb_adapter_buswidth; target++) {
  434                 r = scsi_probe_target(sb, target);
  435                 if (r != 0 && r != EINVAL)
  436                         rv = r;
  437         }
  438         return rv;
  439 }
  440 
  441 int
  442 scsi_probe_target(struct scsibus_softc *sb, int target)
  443 {
  444         struct scsi_lun_array            lunarray;
  445         int                              i, r, rv = 0;
  446 
  447         if (target < 0 || target == sb->sb_adapter_target)
  448                 return EINVAL;
  449 
  450         scsi_get_target_luns(sb, target, &lunarray);
  451         if (lunarray.count == 0)
  452                 return EINVAL;
  453 
  454         for (i = 0; i < lunarray.count; i++) {
  455                 r = scsi_probe_link(sb, target, lunarray.luns[i],
  456                     lunarray.dumbscan);
  457                 if (r == EINVAL && lunarray.dumbscan == 1)
  458                         return 0;
  459                 if (r != 0 && r != EINVAL)
  460                         rv = r;
  461         }
  462         return rv;
  463 }
  464 
  465 int
  466 scsi_probe_lun(struct scsibus_softc *sb, int target, int lun)
  467 {
  468         if (target < 0 || target == sb->sb_adapter_target || lun < 0)
  469                 return EINVAL;
  470 
  471         /* Probe lun on target. *NOT* a dumbscan! */
  472         return scsi_probe_link(sb, target, lun, 0);
  473 }
  474 
  475 int
  476 scsi_probe_link(struct scsibus_softc *sb, int target, int lun, int dumbscan)
  477 {
  478         struct scsi_attach_args                  sa;
  479         const struct scsi_quirk_inquiry_pattern *finger;
  480         struct scsi_inquiry_data                *inqbuf, *usbinqbuf;
  481         struct scsi_link                        *link, *link0;
  482         struct cfdata                           *cf;
  483         int                                      inqbytes, priority, rslt = 0;
  484         u_int16_t                                devquirks;
  485 
  486         /* Skip this slot if it is already attached and try the next LUN. */
  487         if (scsi_get_link(sb, target, lun) != NULL)
  488                 return 0;
  489 
  490         link = malloc(sizeof(*link), M_DEVBUF, M_NOWAIT);
  491         if (link == NULL) {
  492                 SC_DEBUG(link, SDEV_DB2, ("malloc(scsi_link) failed.\n"));
  493                 return EINVAL;
  494         }
  495 
  496         link->state = 0;
  497         link->target = target;
  498         link->lun = lun;
  499         link->openings = sb->sb_openings;
  500         link->node_wwn = link->port_wwn = 0;
  501         link->flags = sb->sb_flags;
  502         link->quirks = sb->sb_quirks;
  503         link->interpret_sense = scsi_interpret_sense;
  504         link->device_softc = NULL;
  505         link->bus = sb;
  506         memset(&link->inqdata, 0, sizeof(link->inqdata));
  507         link->id = NULL;
  508         TAILQ_INIT(&link->queue);
  509         link->running = 0;
  510         link->pending = 0;
  511         link->pool = sb->sb_pool;
  512 
  513         SC_DEBUG(link, SDEV_DB2, ("scsi_link created.\n"));
  514 
  515         /* Ask the adapter if this will be a valid device. */
  516         if (sb->sb_adapter->dev_probe != NULL &&
  517             sb->sb_adapter->dev_probe(link) != 0) {
  518                 if (lun == 0) {
  519                         SC_DEBUG(link, SDEV_DB2, ("dev_probe(link) failed.\n"));
  520                         rslt = EINVAL;
  521                 }
  522                 free(link, M_DEVBUF, sizeof(*link));
  523                 return rslt;
  524         }
  525 
  526         /*
  527          * If we havent been given an io pool by now then fall back to
  528          * using link->openings.
  529          */
  530         if (link->pool == NULL) {
  531                 link->pool = malloc(sizeof(*link->pool), M_DEVBUF, M_NOWAIT);
  532                 if (link->pool == NULL) {
  533                         SC_DEBUG(link, SDEV_DB2, ("malloc(pool) failed.\n"));
  534                         rslt = ENOMEM;
  535                         goto bad;
  536                 }
  537                 scsi_iopool_init(link->pool, link, scsi_default_get,
  538                     scsi_default_put);
  539 
  540                 SET(link->flags, SDEV_OWN_IOPL);
  541         }
  542 
  543         /*
  544          * Tell drivers that are paying attention to avoid sync/wide/tags until
  545          * INQUIRY data has been processed and the quirks information is
  546          * complete. Some drivers set bits in quirks before we get here, so
  547          * just add NOTAGS, NOWIDE and NOSYNC.
  548          */
  549         devquirks = link->quirks;
  550         SET(link->quirks, SDEV_NOSYNC | SDEV_NOWIDE | SDEV_NOTAGS);
  551 
  552         /*
  553          * Ask the device what it is.
  554          */
  555 #ifdef SCSIDEBUG
  556         if (((sb->sc_dev.dv_unit < 32) &&
  557             ((1U << sb->sc_dev.dv_unit) & scsidebug_buses)) &&
  558             ((target < 32) && ((1U << target) & scsidebug_targets)) &&
  559             ((lun < 32) && ((1U << lun) & scsidebug_luns)))
  560                 SET(link->flags, scsidebug_level);
  561 #endif /* SCSIDEBUG */
  562 
  563         if (lun == 0) {
  564                 /* Clear any outstanding errors. */
  565                 scsi_test_unit_ready(link, TEST_READY_RETRIES,
  566                     scsi_autoconf | SCSI_IGNORE_ILLEGAL_REQUEST |
  567                     SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE);
  568         }
  569 
  570         /* Now go ask the device all about itself. */
  571         inqbuf = dma_alloc(sizeof(*inqbuf), PR_NOWAIT | PR_ZERO);
  572         if (inqbuf == NULL) {
  573                 SC_DEBUG(link, SDEV_DB2, ("dma_alloc(inqbuf) failed.\n"));
  574                 rslt = ENOMEM;
  575                 goto bad;
  576         }
  577 
  578         rslt = scsi_inquire(link, inqbuf, scsi_autoconf | SCSI_SILENT);
  579         if (rslt != 0) {
  580                 if (lun == 0)
  581                         rslt = EINVAL;
  582                 dma_free(inqbuf, sizeof(*inqbuf));
  583                 goto bad;
  584         }
  585         inqbytes = SID_SCSI2_HDRLEN + inqbuf->additional_length;
  586         memcpy(&link->inqdata, inqbuf, inqbytes);
  587         dma_free(inqbuf, sizeof(*inqbuf));
  588         inqbuf = &link->inqdata;
  589         if (inqbytes < offsetof(struct scsi_inquiry_data, vendor))
  590                 memset(inqbuf->vendor, ' ', sizeof(inqbuf->vendor));
  591         if (inqbytes < offsetof(struct scsi_inquiry_data, product))
  592                 memset(inqbuf->product, ' ', sizeof(inqbuf->product));
  593         if (inqbytes < offsetof(struct scsi_inquiry_data, revision))
  594                 memset(inqbuf->revision, ' ', sizeof(inqbuf->revision));
  595         if (inqbytes < offsetof(struct scsi_inquiry_data, extra))
  596                 memset(inqbuf->extra, ' ', sizeof(inqbuf->extra));
  597 
  598         switch (inqbuf->device & SID_QUAL) {
  599         case SID_QUAL_RSVD:
  600         case SID_QUAL_BAD_LU:
  601                 goto bad;
  602         case SID_QUAL_LU_OFFLINE:
  603                 if (lun == 0 && (inqbuf->device & SID_TYPE) == T_NODEVICE)
  604                         break;
  605                 goto bad;
  606         case SID_QUAL_LU_OK:
  607         default:
  608                 if ((inqbuf->device & SID_TYPE) == T_NODEVICE)
  609                         goto bad;
  610                 break;
  611         }
  612 
  613         scsi_devid(link);
  614 
  615         link0 = scsi_get_link(sb, target, 0);
  616         if (lun == 0 || link0 == NULL)
  617                 ;
  618         else if (ISSET(link->flags, SDEV_UMASS))
  619                 ;
  620         else if (link->id != NULL && !DEVID_CMP(link0->id, link->id))
  621                 ;
  622         else if (dumbscan == 1 && memcmp(inqbuf, &link0->inqdata,
  623             sizeof(*inqbuf)) == 0) {
  624                 /* The device doesn't distinguish between LUNs. */
  625                 SC_DEBUG(link, SDEV_DB1, ("IDENTIFY not supported.\n"));
  626                 rslt = EINVAL;
  627                 goto bad;
  628         }
  629 
  630         link->quirks = devquirks;       /* Restore what the device wanted. */
  631 
  632         finger = (const struct scsi_quirk_inquiry_pattern *)scsi_inqmatch(
  633             inqbuf, scsi_quirk_patterns,
  634             nitems(scsi_quirk_patterns),
  635             sizeof(scsi_quirk_patterns[0]), &priority);
  636         if (priority != 0)
  637                 SET(link->quirks, finger->quirks);
  638 
  639         switch (SID_ANSII_REV(inqbuf)) {
  640         case SCSI_REV_0:
  641         case SCSI_REV_1:
  642                 SET(link->quirks, SDEV_NOTAGS | SDEV_NOSYNC | SDEV_NOWIDE |
  643                     SDEV_NOSYNCCACHE);
  644                 break;
  645         case SCSI_REV_2:
  646         case SCSI_REV_SPC:
  647         case SCSI_REV_SPC2:
  648                 if (!ISSET(inqbuf->flags, SID_CmdQue))
  649                         SET(link->quirks, SDEV_NOTAGS);
  650                 if (!ISSET(inqbuf->flags, SID_Sync))
  651                         SET(link->quirks, SDEV_NOSYNC);
  652                 if (!ISSET(inqbuf->flags, SID_WBus16))
  653                         SET(link->quirks, SDEV_NOWIDE);
  654                 break;
  655         case SCSI_REV_SPC3:
  656         case SCSI_REV_SPC4:
  657         case SCSI_REV_SPC5:
  658                 /* By this time SID_Sync and SID_WBus16 were obsolete. */
  659                 if (!ISSET(inqbuf->flags, SID_CmdQue))
  660                         SET(link->quirks, SDEV_NOTAGS);
  661                 break;
  662         default:
  663                 break;
  664         }
  665 
  666         /*
  667          * If the device can't use tags, >1 opening may confuse it.
  668          */
  669         if (ISSET(link->quirks, SDEV_NOTAGS))
  670                 link->openings = 1;
  671 
  672         /*
  673          * note what BASIC type of device it is
  674          */
  675         if (ISSET(inqbuf->dev_qual2, SID_REMOVABLE))
  676                 SET(link->flags, SDEV_REMOVABLE);
  677 
  678         sa.sa_sc_link = link;
  679 
  680         cf = config_search(scsibussubmatch, (struct device *)sb, &sa);
  681         if (cf == NULL) {
  682                 scsibussubprint(&sa, sb->sc_dev.dv_xname);
  683                 printf(" not configured\n");
  684                 goto bad;
  685         }
  686 
  687         /*
  688          * Braindead USB devices, especially some x-in-1 media readers, try to
  689          * 'help' by pretending any LUN is actually LUN 0 until they see a
  690          * different LUN used in a command. So do an INQUIRY on LUN 1 at this
  691          * point to prevent such helpfulness before it causes confusion.
  692          */
  693         if (lun == 0 && ISSET(link->flags, SDEV_UMASS) &&
  694             scsi_get_link(sb, target, 1) == NULL && sb->sb_luns > 1 &&
  695             (usbinqbuf = dma_alloc(sizeof(*usbinqbuf), M_NOWAIT)) != NULL) {
  696 
  697                 link->lun = 1;
  698                 scsi_inquire(link, usbinqbuf, scsi_autoconf | SCSI_SILENT);
  699                 link->lun = 0;
  700 
  701                 dma_free(usbinqbuf, sizeof(*usbinqbuf));
  702         }
  703 
  704         scsi_add_link(link);
  705 
  706         /*
  707          * Generate a TEST_UNIT_READY command. This gives drivers waiting for
  708          * valid quirks data a chance to set wide/sync/tag options
  709          * appropriately. It also clears any outstanding ACA conditions that
  710          * INQUIRY may leave behind.
  711          *
  712          * Do this now so that any messages generated by config_attach() do not
  713          * have negotiation messages inserted into their midst.
  714          */
  715         scsi_test_unit_ready(link, TEST_READY_RETRIES,
  716             scsi_autoconf | SCSI_IGNORE_ILLEGAL_REQUEST |
  717             SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE);
  718 
  719         config_attach((struct device *)sb, cf, &sa, scsibussubprint);
  720         return 0;
  721 
  722 bad:
  723         scsi_detach_link(link, DETACH_FORCE);
  724         return rslt;
  725 }
  726 
  727 int
  728 scsi_detach(struct scsibus_softc *sb, int target, int lun, int flags)
  729 {
  730         if (target == -1 && lun == -1)
  731                 return scsi_detach_bus(sb, flags);
  732         else if (lun == -1)
  733                 return scsi_detach_target(sb, target, flags);
  734         else
  735                 return scsi_detach_lun(sb, target, lun, flags);
  736 }
  737 
  738 int
  739 scsi_detach_bus(struct scsibus_softc *sb, int flags)
  740 {
  741         struct scsi_link        *link, *tmp;
  742         int                      r, rv = 0;
  743 
  744         /* Detach all links from bus. */
  745         SLIST_FOREACH_SAFE(link, &sb->sc_link_list, bus_list, tmp) {
  746                 r = scsi_detach_link(link, flags);
  747                 if (r != 0 && r != ENXIO)
  748                         rv = r;
  749         }
  750         return rv;
  751 }
  752 
  753 int
  754 scsi_detach_target(struct scsibus_softc *sb, int target, int flags)
  755 {
  756         struct scsi_link        *link, *tmp;
  757         int                      r, rv = 0;
  758 
  759         /* Detach all links from target. */
  760         SLIST_FOREACH_SAFE(link, &sb->sc_link_list, bus_list, tmp) {
  761                 if (link->target == target) {
  762                         r = scsi_detach_link(link, flags);
  763                         if (r != 0 && r != ENXIO)
  764                                 rv = r;
  765                 }
  766         }
  767         return rv;
  768 }
  769 
  770 int
  771 scsi_detach_lun(struct scsibus_softc *sb, int target, int lun, int flags)
  772 {
  773         struct scsi_link        *link;
  774 
  775         /* Detach (target, lun) link. */
  776         link = scsi_get_link(sb, target, lun);
  777         if (link == NULL)
  778                 return EINVAL;
  779 
  780         return scsi_detach_link(link, flags);
  781 }
  782 
  783 int
  784 scsi_detach_link(struct scsi_link *link, int flags)
  785 {
  786         struct scsibus_softc            *sb = link->bus;
  787         int                              rv;
  788 
  789         if (!ISSET(flags, DETACH_FORCE) && ISSET(link->flags, SDEV_OPEN))
  790                 return EBUSY;
  791 
  792         /* Detaching a device from scsibus is a five step process. */
  793 
  794         /* 1. Wake up processes sleeping for an xs. */
  795         if (link->pool != NULL)
  796                 scsi_link_shutdown(link);
  797 
  798         /* 2. Detach the device. */
  799         if (link->device_softc != NULL) {
  800                 rv = config_detach(link->device_softc, flags);
  801                 if (rv != 0)
  802                         return rv;
  803         }
  804 
  805         /* 3. If it's using the openings io allocator, clean that up. */
  806         if (link->pool != NULL && ISSET(link->flags, SDEV_OWN_IOPL)) {
  807                 scsi_iopool_destroy(link->pool);
  808                 free(link->pool, M_DEVBUF, sizeof(*link->pool));
  809         }
  810 
  811         /* 4. Free up its state in the adapter. */
  812         if (sb->sb_adapter->dev_free != NULL)
  813                 sb->sb_adapter->dev_free(link);
  814 
  815         /* 5. Free up its state in the midlayer. */
  816         if (link->id != NULL)
  817                 devid_free(link->id);
  818         scsi_remove_link(link);
  819         free(link, M_DEVBUF, sizeof(*link));
  820 
  821         return 0;
  822 }
  823 
  824 struct scsi_link *
  825 scsi_get_link(struct scsibus_softc *sb, int target, int lun)
  826 {
  827         struct scsi_link *link;
  828 
  829         SLIST_FOREACH(link, &sb->sc_link_list, bus_list) {
  830                 if (link->target == target && link->lun == lun)
  831                         return link;
  832         }
  833 
  834         return NULL;
  835 }
  836 
  837 void
  838 scsi_add_link(struct scsi_link *link)
  839 {
  840         SLIST_INSERT_HEAD(&link->bus->sc_link_list, link, bus_list);
  841 }
  842 
  843 void
  844 scsi_remove_link(struct scsi_link *link)
  845 {
  846         struct scsibus_softc    *sb = link->bus;
  847         struct scsi_link        *elm, *prev = NULL;
  848 
  849         SLIST_FOREACH(elm, &sb->sc_link_list, bus_list) {
  850                 if (elm == link) {
  851                         if (prev == NULL)
  852                                 SLIST_REMOVE_HEAD(&sb->sc_link_list, bus_list);
  853                         else
  854                                 SLIST_REMOVE_AFTER(prev, bus_list);
  855                         break;
  856                 }
  857                 prev = elm;
  858         }
  859 }
  860 
  861 void
  862 scsi_get_target_luns(struct scsibus_softc *sb, int target,
  863     struct scsi_lun_array *lunarray)
  864 {
  865         struct scsi_report_luns_data    *report;
  866         struct scsi_link                *link0;
  867         int                              i, nluns, rv = 0;
  868 
  869         /* LUN 0 *must* be present. */
  870         scsi_probe_link(sb, target, 0, 0);
  871         link0 = scsi_get_link(sb, target, 0);
  872         if (link0 == NULL) {
  873                 lunarray->count = 0;
  874                 return;
  875         }
  876 
  877         /* Initialize dumbscan result. Just in case. */
  878         report = NULL;
  879         for (i = 0; i < link0->bus->sb_luns; i++)
  880                 lunarray->luns[i] = i;
  881         lunarray->count = link0->bus->sb_luns;
  882         lunarray->dumbscan = 1;
  883 
  884         /*
  885          * ATAPI, USB and pre-SPC (i.e. pre-SCSI-3) devices can't ask
  886          * for a report of valid LUNs.
  887          */
  888         if ((link0->flags & (SDEV_UMASS | SDEV_ATAPI)) != 0 ||
  889             SID_ANSII_REV(&link0->inqdata) < SCSI_REV_SPC)
  890                 goto dumbscan;
  891 
  892         report = dma_alloc(sizeof(*report), PR_WAITOK);
  893         if (report == NULL)
  894                 goto dumbscan;
  895 
  896         rv = scsi_report_luns(link0, REPORT_NORMAL, report,
  897             sizeof(*report), scsi_autoconf | SCSI_SILENT |
  898             SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY |
  899             SCSI_IGNORE_MEDIA_CHANGE, 10000);
  900         if (rv != 0)
  901                 goto dumbscan;
  902 
  903         /*
  904          * XXX In theory we should check if data is full, which
  905          * would indicate it needs to be enlarged and REPORT
  906          * LUNS tried again. Solaris tries up to 3 times with
  907          * larger sizes for data.
  908          */
  909 
  910         /* Return the reported Type-0 LUNs. Type-0 only! */
  911         lunarray->count = 0;
  912         lunarray->dumbscan = 0;
  913         nluns = _4btol(report->length) / RPL_LUNDATA_SIZE;
  914         for (i = 0; i < nluns; i++) {
  915                 if (report->luns[i].lundata[0] != 0)
  916                         continue;
  917                 lunarray->luns[lunarray->count++] =
  918                     report->luns[i].lundata[RPL_LUNDATA_T0LUN];
  919         }
  920 
  921 dumbscan:
  922         if (report != NULL)
  923                 dma_free(report, sizeof(*report));
  924 }
  925 
  926 void
  927 scsi_strvis(u_char *dst, u_char *src, int len)
  928 {
  929         u_char                          last;
  930 
  931         /* Trim leading and trailing whitespace and NULs. */
  932         while (len > 0 && (src[0] == ' ' || src[0] == '\t' || src[0] == '\n' ||
  933             src[0] == '\0' || src[0] == 0xff))
  934                 ++src, --len;
  935         while (len > 0 && (src[len-1] == ' ' || src[len-1] == '\t' ||
  936             src[len-1] == '\n' || src[len-1] == '\0' || src[len-1] == 0xff))
  937                 --len;
  938 
  939         last = 0xff;
  940         while (len > 0) {
  941                 switch (*src) {
  942                 case ' ':
  943                 case '\t':
  944                 case '\n':
  945                 case '\0':
  946                 case 0xff:
  947                         /* Collapse whitespace and NULs to a single space. */
  948                         if (last != ' ')
  949                                 *dst++ = ' ';
  950                         last = ' ';
  951                         break;
  952                 case '\\':
  953                         /* Quote backslashes. */
  954                         *dst++ = '\\';
  955                         *dst++ = '\\';
  956                         last = '\\';
  957                         break;
  958                 default:
  959                         if (*src < 0x20 || *src >= 0x80) {
  960                                 /* Non-printable characters to octal. */
  961                                 *dst++ = '\\';
  962                                 *dst++ = ((*src & 0300) >> 6) + '';
  963                                 *dst++ = ((*src & 0070) >> 3) + '';
  964                                 *dst++ = ((*src & 0007) >> 0) + '';
  965                         } else {
  966                                 /* Copy normal characters. */
  967                                 *dst++ = *src;
  968                         }
  969                         last = *src;
  970                         break;
  971                 }
  972                 ++src, --len;
  973         }
  974 
  975         *dst++ = 0;
  976 }
  977 
  978 void
  979 scsi_print_link(struct scsi_link *link)
  980 {
  981         char                             visbuf[65];
  982         struct scsi_inquiry_data        *inqbuf;
  983         u_int8_t                        *id;
  984         int                              i;
  985 
  986         printf(" targ %d lun %d: ", link->target, link->lun);
  987 
  988         inqbuf = &link->inqdata;
  989 
  990         scsi_strvis(visbuf, inqbuf->vendor, 8);
  991         printf("<%s, ", visbuf);
  992         scsi_strvis(visbuf, inqbuf->product, 16);
  993         printf("%s, ", visbuf);
  994         scsi_strvis(visbuf, inqbuf->revision, 4);
  995         printf("%s>", visbuf);
  996 
  997 #ifdef SCSIDEBUG
  998         if (ISSET(link->flags, SDEV_ATAPI))
  999                 printf(" ATAPI");
 1000         else if (SID_ANSII_REV(inqbuf) < SCSI_REV_SPC)
 1001                 printf(" SCSI/%d", SID_ANSII_REV(inqbuf));
 1002         else if (SID_ANSII_REV(inqbuf) == SCSI_REV_SPC)
 1003                 printf(" SCSI/SPC");
 1004         else
 1005                 printf(" SCSI/SPC-%d", SID_ANSII_REV(inqbuf) - 2);
 1006 #endif /* SCSIDEBUG */
 1007 
 1008         if (ISSET(link->flags, SDEV_REMOVABLE))
 1009                 printf(" removable");
 1010 
 1011         if (link->id != NULL && link->id->d_type != DEVID_NONE) {
 1012                 id = (u_int8_t *)(link->id + 1);
 1013                 switch (link->id->d_type) {
 1014                 case DEVID_NAA:
 1015                         printf(" naa.");
 1016                         break;
 1017                 case DEVID_EUI:
 1018                         printf(" eui.");
 1019                         break;
 1020                 case DEVID_T10:
 1021                         printf(" t10.");
 1022                         break;
 1023                 case DEVID_SERIAL:
 1024                         printf(" serial.");
 1025                         break;
 1026                 case DEVID_WWN:
 1027                         printf(" wwn.");
 1028                         break;
 1029                 }
 1030 
 1031                 if (ISSET(link->id->d_flags, DEVID_F_PRINT)) {
 1032                         for (i = 0; i < link->id->d_len; i++) {
 1033                                 if (id[i] == '\0' || id[i] == ' ') {
 1034                                         /* skip leading blanks */
 1035                                         /* collapse multiple blanks into one */
 1036                                         if (i > 0 && id[i-1] != id[i])
 1037                                                 printf("_");
 1038                                 } else if (id[i] < 0x20 || id[i] >= 0x80) {
 1039                                         /* non-printable characters */
 1040                                         printf("~");
 1041                                 } else {
 1042                                         /* normal characters */
 1043                                         printf("%c", id[i]);
 1044                                 }
 1045                         }
 1046                 } else {
 1047                         for (i = 0; i < link->id->d_len; i++)
 1048                                 printf("%02x", id[i]);
 1049                 }
 1050         }
 1051 #ifdef SCSIDEBUG
 1052         printf("\n");
 1053         sc_print_addr(link);
 1054         printf("state %u, luns %u, openings %u\n",
 1055             link->state, link->bus->sb_luns, link->openings);
 1056 
 1057         sc_print_addr(link);
 1058         printf("flags (0x%04x) ", link->flags);
 1059         scsi_show_flags(link->flags, flagnames);
 1060         printf("\n");
 1061 
 1062         sc_print_addr(link);
 1063         printf("quirks (0x%04x) ", link->quirks);
 1064         scsi_show_flags(link->quirks, quirknames);
 1065 #endif /* SCSIDEBUG */
 1066 }
 1067 
 1068 /*
 1069  * Return a priority based on how much of the inquiry data matches
 1070  * the patterns for the particular driver.
 1071  */
 1072 const void *
 1073 scsi_inqmatch(struct scsi_inquiry_data *inqbuf, const void *_base,
 1074     int nmatches, int matchsize, int *bestpriority)
 1075 {
 1076         const unsigned char             *base = (const unsigned char *)_base;
 1077         const void                      *bestmatch;
 1078         int                              removable;
 1079 
 1080         /* Include the qualifier to catch vendor-unique types. */
 1081         removable = ISSET(inqbuf->dev_qual2, SID_REMOVABLE) ? T_REMOV : T_FIXED;
 1082 
 1083         for (*bestpriority = 0, bestmatch = 0; nmatches--; base += matchsize) {
 1084                 struct scsi_inquiry_pattern *match = (void *)base;
 1085                 int priority, len;
 1086 
 1087                 if (inqbuf->device != match->type)
 1088                         continue;
 1089                 if (removable != match->removable)
 1090                         continue;
 1091                 priority = 2;
 1092                 len = strlen(match->vendor);
 1093                 if (bcmp(inqbuf->vendor, match->vendor, len))
 1094                         continue;
 1095                 priority += len;
 1096                 len = strlen(match->product);
 1097                 if (bcmp(inqbuf->product, match->product, len))
 1098                         continue;
 1099                 priority += len;
 1100                 len = strlen(match->revision);
 1101                 if (bcmp(inqbuf->revision, match->revision, len))
 1102                         continue;
 1103                 priority += len;
 1104 
 1105 #ifdef SCSIDEBUG
 1106                 printf("scsi_inqmatch: ");
 1107                 if (_base == &scsi_quirk_patterns)
 1108                         printf(" quirk ");
 1109                 else
 1110                         printf(" match ");
 1111 
 1112                 printf("priority %d. %s %s <\"%s\", \"%s\", \"%s\">", priority,
 1113                     devicetypenames[(match->type & SID_TYPE)],
 1114                     (match->removable == T_FIXED) ? "T_FIXED" : "T_REMOV",
 1115                     match->vendor, match->product, match->revision);
 1116 
 1117                 if (_base == &scsi_quirk_patterns)
 1118                         printf(" quirks: 0x%04x",
 1119                             ((struct scsi_quirk_inquiry_pattern *)match)->quirks
 1120                         );
 1121 
 1122                 printf("\n");
 1123 #endif /* SCSIDEBUG */
 1124                 if (priority > *bestpriority) {
 1125                         *bestpriority = priority;
 1126                         bestmatch = base;
 1127                 }
 1128         }
 1129 
 1130         return bestmatch;
 1131 }
 1132 
 1133 void
 1134 scsi_devid(struct scsi_link *link)
 1135 {
 1136         struct {
 1137                 struct scsi_vpd_hdr hdr;
 1138                 u_int8_t list[32];
 1139         } __packed                      *pg;
 1140         size_t                           len;
 1141         int                              pg80 = 0, pg83 = 0, i;
 1142 
 1143         if (link->id != NULL)
 1144                 return;
 1145 
 1146         pg = dma_alloc(sizeof(*pg), PR_WAITOK | PR_ZERO);
 1147 
 1148         if (SID_ANSII_REV(&link->inqdata) >= SCSI_REV_2) {
 1149                 if (scsi_inquire_vpd(link, pg, sizeof(*pg), SI_PG_SUPPORTED,
 1150                     scsi_autoconf) != 0)
 1151                         goto wwn;
 1152 
 1153                 len = MIN(sizeof(pg->list), _2btol(pg->hdr.page_length));
 1154                 for (i = 0; i < len; i++) {
 1155                         switch (pg->list[i]) {
 1156                         case SI_PG_SERIAL:
 1157                                 pg80 = 1;
 1158                                 break;
 1159                         case SI_PG_DEVID:
 1160                                 pg83 = 1;
 1161                                 break;
 1162                         }
 1163                 }
 1164 
 1165                 if (pg83 && scsi_devid_pg83(link) == 0)
 1166                         goto done;
 1167                 if (pg80 && scsi_devid_pg80(link) == 0)
 1168                         goto done;
 1169         }
 1170 
 1171 wwn:
 1172         scsi_devid_wwn(link);
 1173 done:
 1174         dma_free(pg, sizeof(*pg));
 1175 }
 1176 
 1177 int
 1178 scsi_devid_pg83(struct scsi_link *link)
 1179 {
 1180         struct scsi_vpd_devid_hdr        dhdr, chdr;
 1181         struct scsi_vpd_hdr             *hdr = NULL;
 1182         u_int8_t                        *pg = NULL, *id;
 1183         int                              len, pos, rv, type;
 1184         int                              idtype = 0;
 1185         u_char                           idflags;
 1186 
 1187         hdr = dma_alloc(sizeof(*hdr), PR_WAITOK | PR_ZERO);
 1188 
 1189         rv = scsi_inquire_vpd(link, hdr, sizeof(*hdr), SI_PG_DEVID,
 1190             scsi_autoconf);
 1191         if (rv != 0)
 1192                 goto done;
 1193 
 1194         len = sizeof(*hdr) + _2btol(hdr->page_length);
 1195         pg = dma_alloc(len, PR_WAITOK | PR_ZERO);
 1196 
 1197         rv = scsi_inquire_vpd(link, pg, len, SI_PG_DEVID, scsi_autoconf);
 1198         if (rv != 0)
 1199                 goto done;
 1200 
 1201         pos = sizeof(*hdr);
 1202 
 1203         do {
 1204                 if (len - pos < sizeof(dhdr)) {
 1205                         rv = EIO;
 1206                         goto done;
 1207                 }
 1208                 memcpy(&dhdr, &pg[pos], sizeof(dhdr));
 1209                 pos += sizeof(dhdr);
 1210                 if (len - pos < dhdr.len) {
 1211                         rv = EIO;
 1212                         goto done;
 1213                 }
 1214 
 1215                 if (VPD_DEVID_ASSOC(dhdr.flags) == VPD_DEVID_ASSOC_LU) {
 1216                         type = VPD_DEVID_TYPE(dhdr.flags);
 1217                         switch (type) {
 1218                         case VPD_DEVID_TYPE_NAA:
 1219                         case VPD_DEVID_TYPE_EUI64:
 1220                         case VPD_DEVID_TYPE_T10:
 1221                                 if (type >= idtype) {
 1222                                         idtype = type;
 1223 
 1224                                         chdr = dhdr;
 1225                                         id = &pg[pos];
 1226                                 }
 1227                                 break;
 1228 
 1229                         default:
 1230                                 /* skip */
 1231                                 break;
 1232                         }
 1233                 }
 1234 
 1235                 pos += dhdr.len;
 1236         } while (idtype != VPD_DEVID_TYPE_NAA && len != pos);
 1237 
 1238         if (idtype > 0) {
 1239                 switch (VPD_DEVID_TYPE(chdr.flags)) {
 1240                 case VPD_DEVID_TYPE_NAA:
 1241                         idtype = DEVID_NAA;
 1242                         break;
 1243                 case VPD_DEVID_TYPE_EUI64:
 1244                         idtype = DEVID_EUI;
 1245                         break;
 1246                 case VPD_DEVID_TYPE_T10:
 1247                         idtype = DEVID_T10;
 1248                         break;
 1249                 }
 1250                 switch (VPD_DEVID_CODE(chdr.pi_code)) {
 1251                 case VPD_DEVID_CODE_ASCII:
 1252                 case VPD_DEVID_CODE_UTF8:
 1253                         idflags = DEVID_F_PRINT;
 1254                         break;
 1255                 default:
 1256                         idflags = 0;
 1257                         break;
 1258                 }
 1259                 link->id = devid_alloc(idtype, idflags, chdr.len, id);
 1260         } else
 1261                 rv = ENODEV;
 1262 
 1263 done:
 1264         if (pg)
 1265                 dma_free(pg, len);
 1266         if (hdr)
 1267                 dma_free(hdr, sizeof(*hdr));
 1268         return rv;
 1269 }
 1270 
 1271 int
 1272 scsi_devid_pg80(struct scsi_link *link)
 1273 {
 1274         struct scsi_vpd_hdr             *hdr = NULL;
 1275         u_int8_t                        *pg = NULL;
 1276         char                            *id;
 1277         size_t                           idlen;
 1278         int                              len, pglen, rv;
 1279 
 1280         hdr = dma_alloc(sizeof(*hdr), PR_WAITOK | PR_ZERO);
 1281 
 1282         rv = scsi_inquire_vpd(link, hdr, sizeof(*hdr), SI_PG_SERIAL,
 1283             scsi_autoconf);
 1284         if (rv != 0)
 1285                 goto freehdr;
 1286 
 1287         len = _2btol(hdr->page_length);
 1288         if (len == 0) {
 1289                 rv = EINVAL;
 1290                 goto freehdr;
 1291         }
 1292 
 1293         pglen = sizeof(*hdr) + len;
 1294         pg = dma_alloc(pglen, PR_WAITOK | PR_ZERO);
 1295 
 1296         rv = scsi_inquire_vpd(link, pg, pglen, SI_PG_SERIAL, scsi_autoconf);
 1297         if (rv != 0)
 1298                 goto free;
 1299 
 1300         idlen = sizeof(link->inqdata.vendor) +
 1301             sizeof(link->inqdata.product) + len;
 1302         id = malloc(idlen, M_TEMP, M_WAITOK);
 1303         memcpy(id, link->inqdata.vendor, sizeof(link->inqdata.vendor));
 1304         memcpy(id + sizeof(link->inqdata.vendor), link->inqdata.product,
 1305             sizeof(link->inqdata.product));
 1306         memcpy(id + sizeof(link->inqdata.vendor) +
 1307             sizeof(link->inqdata.product), pg + sizeof(*hdr), len);
 1308 
 1309         link->id = devid_alloc(DEVID_SERIAL, DEVID_F_PRINT,
 1310             sizeof(link->inqdata.vendor) + sizeof(link->inqdata.product) + len,
 1311             id);
 1312 
 1313         free(id, M_TEMP, idlen);
 1314 
 1315 free:
 1316         dma_free(pg, pglen);
 1317 freehdr:
 1318         dma_free(hdr, sizeof(*hdr));
 1319         return rv;
 1320 }
 1321 
 1322 int
 1323 scsi_devid_wwn(struct scsi_link *link)
 1324 {
 1325         u_int64_t wwnn;
 1326 
 1327         if (link->lun != 0 || link->node_wwn == 0)
 1328                 return EOPNOTSUPP;
 1329 
 1330         wwnn = htobe64(link->node_wwn);
 1331         link->id = devid_alloc(DEVID_WWN, 0, sizeof(wwnn), (u_int8_t *)&wwnn);
 1332 
 1333         return 0;
 1334 }
 1335 
 1336 struct devid *
 1337 devid_alloc(u_int8_t type, u_int8_t flags, u_int8_t len, u_int8_t *id)
 1338 {
 1339         struct devid *d;
 1340 
 1341         d = malloc(sizeof(*d) + len, M_DEVBUF, M_WAITOK|M_CANFAIL);
 1342         if (d == NULL)
 1343                 return NULL;
 1344 
 1345         d->d_type = type;
 1346         d->d_flags = flags;
 1347         d->d_len = len;
 1348         d->d_refcount = 1;
 1349         memcpy(d + 1, id, len);
 1350 
 1351         return d;
 1352 }
 1353 
 1354 struct devid *
 1355 devid_copy(struct devid *d)
 1356 {
 1357         d->d_refcount++;
 1358         return d;
 1359 }
 1360 
 1361 void
 1362 devid_free(struct devid *d)
 1363 {
 1364         if (--d->d_refcount == 0)
 1365                 free(d, M_DEVBUF, sizeof(*d) + d->d_len);
 1366 }

Cache object: f7f75893b2ce861feb4faa5f62f77b2d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.