1*9593dc34Smglocker /* $OpenBSD: scsiconf.c,v 1.254 2024/09/04 07:54:53 mglocker Exp $ */ 27f8fc37fSderaadt /* $NetBSD: scsiconf.c,v 1.57 1996/05/02 01:09:01 neil Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /* 5df930be7Sderaadt * Copyright (c) 1994 Charles Hannum. All rights reserved. 6df930be7Sderaadt * 7df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 8df930be7Sderaadt * modification, are permitted provided that the following conditions 9df930be7Sderaadt * are met: 10df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 11df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 12df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 13df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 14df930be7Sderaadt * documentation and/or other materials provided with the distribution. 15df930be7Sderaadt * 3. All advertising materials mentioning features or use of this software 16df930be7Sderaadt * must display the following acknowledgement: 17df930be7Sderaadt * This product includes software developed by Charles Hannum. 18df930be7Sderaadt * 4. The name of the author may not be used to endorse or promote products 19df930be7Sderaadt * derived from this software without specific prior written permission. 20df930be7Sderaadt * 21df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22df930be7Sderaadt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23df930be7Sderaadt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24df930be7Sderaadt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25df930be7Sderaadt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26df930be7Sderaadt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27df930be7Sderaadt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28df930be7Sderaadt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29df930be7Sderaadt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30df930be7Sderaadt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31df930be7Sderaadt */ 32df930be7Sderaadt 33df930be7Sderaadt /* 34df930be7Sderaadt * Originally written by Julian Elischer (julian@tfs.com) 35df930be7Sderaadt * for TRW Financial Systems for use under the MACH(2.5) operating system. 36df930be7Sderaadt * 37df930be7Sderaadt * TRW Financial Systems, in accordance with their agreement with Carnegie 38df930be7Sderaadt * Mellon University, makes this software available to CMU to distribute 39df930be7Sderaadt * or use in any manner that they see fit as long as this message is kept with 40df930be7Sderaadt * the software. For this reason TFS also grants any other persons or 41df930be7Sderaadt * organisations permission to use or modify this software. 42df930be7Sderaadt * 43df930be7Sderaadt * TFS supplies this software to be publicly redistributed 44df930be7Sderaadt * on the understanding that TFS is not responsible for the correct 45df930be7Sderaadt * functioning of this software in any circumstances. 46df930be7Sderaadt * 47df930be7Sderaadt * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 48df930be7Sderaadt */ 49df930be7Sderaadt 506e420380Sdlg #include "bio.h" 5181efa114Sdlg #include "mpath.h" 526e420380Sdlg 53df930be7Sderaadt #include <sys/param.h> 54df930be7Sderaadt #include <sys/systm.h> 55df930be7Sderaadt #include <sys/malloc.h> 565c0b007dSderaadt #include <sys/pool.h> 57df930be7Sderaadt #include <sys/device.h> 5801355dc1Smiod #include <sys/buf.h> 5933bc13e6Sdlg #include <sys/atomic.h> 60df930be7Sderaadt 61df930be7Sderaadt #include <scsi/scsi_all.h> 62bba39a67Skrw #include <scsi/scsi_debug.h> 63df930be7Sderaadt #include <scsi/scsiconf.h> 64df930be7Sderaadt 659c2a17abSkrw int scsibusmatch(struct device *, void *, void *); 669c2a17abSkrw void scsibusattach(struct device *, struct device *, void *); 679c2a17abSkrw int scsibusactivate(struct device *, int); 689c2a17abSkrw int scsibusdetach(struct device *, int); 699c2a17abSkrw int scsibussubmatch(struct device *, void *, void *); 70ae7c6741Skrw int scsibussubprint(void *, const char *); 716e420380Sdlg #if NBIO > 0 72f080b2c3Sdlg #include <sys/ioctl.h> 73f080b2c3Sdlg #include <sys/scsiio.h> 746e420380Sdlg #include <dev/biovar.h> 759c2a17abSkrw int scsibusbioctl(struct device *, u_long, caddr_t); 76364ebb70Skrw #endif /* NBIO > 0 */ 776e420380Sdlg 7845653f8bSkrw void scsi_get_target_luns(struct scsibus_softc *, int, 7945653f8bSkrw struct scsi_lun_array *); 80cdca80fcSkrw void scsi_add_link(struct scsi_link *); 81cdca80fcSkrw void scsi_remove_link(struct scsi_link *); 8214832242Skrw void scsi_print_link(struct scsi_link *); 8314832242Skrw int scsi_probe_link(struct scsibus_softc *, int, int, int); 84cdca80fcSkrw int scsi_activate_link(struct scsi_link *, int); 85cdca80fcSkrw int scsi_detach_link(struct scsi_link *, int); 8658fa39c1Skrw int scsi_detach_bus(struct scsibus_softc *, int); 87df930be7Sderaadt 88758476e4Sdlg void scsi_devid(struct scsi_link *); 895b0d6b70Sdlg int scsi_devid_pg80(struct scsi_link *); 90758476e4Sdlg int scsi_devid_pg83(struct scsi_link *); 914d409963Sdlg int scsi_devid_wwn(struct scsi_link *); 92758476e4Sdlg 9314832242Skrw int scsi_activate_bus(struct scsibus_softc *, int); 9414832242Skrw int scsi_activate_target(struct scsibus_softc *, int, int); 9514832242Skrw int scsi_activate_lun(struct scsibus_softc *, int, int, int); 96df930be7Sderaadt 9714832242Skrw int scsi_autoconf = SCSI_AUTOCONF; 9814832242Skrw 999eaf72d1Smpi const struct cfattach scsibus_ca = { 1001e7162a8Scsapuntz sizeof(struct scsibus_softc), scsibusmatch, scsibusattach, 101a23d39c4Smiod scsibusdetach, scsibusactivate 102d724e01aSderaadt }; 103d724e01aSderaadt 104d724e01aSderaadt struct cfdriver scsibus_cd = { 105d724e01aSderaadt NULL, "scsibus", DV_DULL 106df930be7Sderaadt }; 107df930be7Sderaadt 10814832242Skrw struct scsi_quirk_inquiry_pattern { 10914832242Skrw struct scsi_inquiry_pattern pattern; 11014832242Skrw u_int16_t quirks; 11114832242Skrw }; 112c8de565eScsapuntz 11314832242Skrw const struct scsi_quirk_inquiry_pattern scsi_quirk_patterns[] = { 11414832242Skrw {{T_CDROM, T_REMOV, 11514832242Skrw "PLEXTOR", "CD-ROM PX-40TS", "1.01"}, SDEV_NOSYNC}, 1160c0430f8Sniklas 11714832242Skrw {{T_DIRECT, T_FIXED, 11814832242Skrw "MICROP ", "1588-15MBSUN0669", ""}, SDEV_AUTOSAVE}, 11914832242Skrw {{T_DIRECT, T_FIXED, 12014832242Skrw "DEC ", "RZ55 (C) DEC", ""}, SDEV_AUTOSAVE}, 12114832242Skrw {{T_DIRECT, T_FIXED, 12214832242Skrw "EMULEX ", "MD21/S2 ESDI", "A00"}, SDEV_AUTOSAVE}, 12314832242Skrw {{T_DIRECT, T_FIXED, 12414832242Skrw "IBMRAID ", "0662S", ""}, SDEV_AUTOSAVE}, 12514832242Skrw {{T_DIRECT, T_FIXED, 12614832242Skrw "IBM ", "0663H", ""}, SDEV_AUTOSAVE}, 12714832242Skrw {{T_DIRECT, T_FIXED, 12814832242Skrw "IBM", "0664", ""}, SDEV_AUTOSAVE}, 12914832242Skrw {{T_DIRECT, T_FIXED, 13014832242Skrw "IBM ", "H3171-S2", ""}, SDEV_AUTOSAVE}, 13114832242Skrw {{T_DIRECT, T_FIXED, 13214832242Skrw "IBM ", "KZ-C", ""}, SDEV_AUTOSAVE}, 13314832242Skrw /* Broken IBM disk */ 13414832242Skrw {{T_DIRECT, T_FIXED, 13514832242Skrw "" , "DFRSS2F", ""}, SDEV_AUTOSAVE}, 13614832242Skrw {{T_DIRECT, T_FIXED, 13714832242Skrw "QUANTUM ", "ELS85S ", ""}, SDEV_AUTOSAVE}, 13814832242Skrw {{T_DIRECT, T_REMOV, 13914832242Skrw "iomega", "jaz 1GB", ""}, SDEV_NOTAGS}, 14014832242Skrw {{T_DIRECT, T_FIXED, 14114832242Skrw "MICROP", "4421-07", ""}, SDEV_NOTAGS}, 14214832242Skrw {{T_DIRECT, T_FIXED, 14314832242Skrw "SEAGATE", "ST150176LW", "0002"}, SDEV_NOTAGS}, 14414832242Skrw {{T_DIRECT, T_FIXED, 14514832242Skrw "HP", "C3725S", ""}, SDEV_NOTAGS}, 14614832242Skrw {{T_DIRECT, T_FIXED, 14714832242Skrw "IBM", "DCAS", ""}, SDEV_NOTAGS}, 14814832242Skrw 14914832242Skrw {{T_SEQUENTIAL, T_REMOV, 15014832242Skrw "SONY ", "SDT-5000 ", "3."}, SDEV_NOSYNC|SDEV_NOWIDE}, 15114832242Skrw {{T_SEQUENTIAL, T_REMOV, 15214832242Skrw "WangDAT ", "Model 1300 ", "02.4"}, SDEV_NOSYNC|SDEV_NOWIDE}, 15314832242Skrw {{T_SEQUENTIAL, T_REMOV, 15414832242Skrw "WangDAT ", "Model 2600 ", "01.7"}, SDEV_NOSYNC|SDEV_NOWIDE}, 15514832242Skrw {{T_SEQUENTIAL, T_REMOV, 15614832242Skrw "WangDAT ", "Model 3200 ", "02.2"}, SDEV_NOSYNC|SDEV_NOWIDE}, 15714832242Skrw 15814832242Skrw /* ATAPI device quirks */ 15914832242Skrw {{T_CDROM, T_REMOV, 16014832242Skrw "CR-2801TE", "", "1.07"}, ADEV_NOSENSE}, 16114832242Skrw {{T_CDROM, T_REMOV, 16214832242Skrw "CREATIVECD3630E", "", "AC101"}, ADEV_NOSENSE}, 16314832242Skrw {{T_CDROM, T_REMOV, 16414832242Skrw "FX320S", "", "q01"}, ADEV_NOSENSE}, 16514832242Skrw {{T_CDROM, T_REMOV, 16614832242Skrw "GCD-R580B", "", "1.00"}, ADEV_LITTLETOC}, 16714832242Skrw {{T_CDROM, T_REMOV, 16814832242Skrw "MATSHITA CR-574", "", "1.02"}, ADEV_NOCAPACITY}, 16914832242Skrw {{T_CDROM, T_REMOV, 17014832242Skrw "MATSHITA CR-574", "", "1.06"}, ADEV_NOCAPACITY}, 17114832242Skrw {{T_CDROM, T_REMOV, 17214832242Skrw "Memorex CRW-2642", "", "1.0g"}, ADEV_NOSENSE}, 17314832242Skrw {{T_CDROM, T_REMOV, 17414832242Skrw "SANYO CRD-256P", "", "1.02"}, ADEV_NOCAPACITY}, 17514832242Skrw {{T_CDROM, T_REMOV, 17614832242Skrw "SANYO CRD-254P", "", "1.02"}, ADEV_NOCAPACITY}, 17714832242Skrw {{T_CDROM, T_REMOV, 17814832242Skrw "SANYO CRD-S54P", "", "1.08"}, ADEV_NOCAPACITY}, 17914832242Skrw {{T_CDROM, T_REMOV, 18014832242Skrw "CD-ROM CDR-S1", "", "1.70"}, ADEV_NOCAPACITY}, /* Sanyo */ 18114832242Skrw {{T_CDROM, T_REMOV, 18214832242Skrw "CD-ROM CDR-N16", "", "1.25"}, ADEV_NOCAPACITY}, /* Sanyo */ 18314832242Skrw {{T_CDROM, T_REMOV, 18414832242Skrw "UJDCD8730", "", "1.14"}, ADEV_NODOORLOCK}, /* Acer */ 18514832242Skrw }; 186864c175eSdlg 187df930be7Sderaadt int 18831cd24eeSdlg scsiprint(void *aux, const char *pnp) 18916b5b5baSmaja { 190ce9fc84eSkrw /* Only "scsibus"es can attach to "scsi"s. */ 19116b5b5baSmaja if (pnp) 19216b5b5baSmaja printf("scsibus at %s", pnp); 19316b5b5baSmaja 194ce9fc84eSkrw return UNCONF; 19516b5b5baSmaja } 19616b5b5baSmaja 19716b5b5baSmaja int 19831cd24eeSdlg scsibusmatch(struct device *parent, void *match, void *aux) 199df930be7Sderaadt { 200ce9fc84eSkrw return 1; 201df930be7Sderaadt } 202df930be7Sderaadt 203df930be7Sderaadt /* 204df930be7Sderaadt * The routine called by the adapter boards to get all their 205df930be7Sderaadt * devices configured in. 206df930be7Sderaadt */ 207df930be7Sderaadt void 20831cd24eeSdlg scsibusattach(struct device *parent, struct device *self, void *aux) 209df930be7Sderaadt { 210df930be7Sderaadt struct scsibus_softc *sb = (struct scsibus_softc *)self; 21173d09fc5Sdlg struct scsibus_attach_args *saa = aux; 212c8de565eScsapuntz 213c8de565eScsapuntz if (!cold) 214c8de565eScsapuntz scsi_autoconf = 0; 215df930be7Sderaadt 21641e86d54Skrw SLIST_INIT(&sb->sc_link_list); 217ead808c4Skrw sb->sb_adapter_softc = saa->saa_adapter_softc; 218ead808c4Skrw sb->sb_adapter = saa->saa_adapter; 219e5eae15dSkrw sb->sb_pool = saa->saa_pool; 220e5eae15dSkrw sb->sb_quirks = saa->saa_quirks; 221e5eae15dSkrw sb->sb_flags = saa->saa_flags; 222e5eae15dSkrw sb->sb_openings = saa->saa_openings; 223ead808c4Skrw sb->sb_adapter_buswidth = saa->saa_adapter_buswidth; 224ead808c4Skrw sb->sb_adapter_target = saa->saa_adapter_target; 225ead808c4Skrw sb->sb_luns = saa->saa_luns; 2267e60ace3Sderaadt 22741e86d54Skrw if (sb->sb_adapter_buswidth == 0) 22841e86d54Skrw sb->sb_adapter_buswidth = 8; 22941e86d54Skrw if (sb->sb_luns == 0) 23041e86d54Skrw sb->sb_luns = 8; 23141e86d54Skrw 23241e86d54Skrw printf(": %d targets", sb->sb_adapter_buswidth); 23341e86d54Skrw if (sb->sb_adapter_target < sb->sb_adapter_buswidth) 23441e86d54Skrw printf(", initiator %d", sb->sb_adapter_target); 235e5eae15dSkrw if (saa->saa_wwpn != 0x0 && saa->saa_wwnn != 0x0) { 236e5eae15dSkrw printf(", WWPN %016llx, WWNN %016llx", saa->saa_wwpn, 237e5eae15dSkrw saa->saa_wwnn); 238700bc256Sdlg } 239ea0c10dfSdlg printf("\n"); 2407e60ace3Sderaadt 241731fd99bSfgsch /* Initialize shared data. */ 242731fd99bSfgsch scsi_init(); 243731fd99bSfgsch 24420f90945Skrw SLIST_INIT(&sb->sc_link_list); 245df930be7Sderaadt 2466e420380Sdlg #if NBIO > 0 2479c2a17abSkrw if (bio_register(&sb->sc_dev, scsibusbioctl) != 0) 2486e420380Sdlg printf("%s: unable to register bio\n", sb->sc_dev.dv_xname); 249364ebb70Skrw #endif /* NBIO > 0 */ 2506e420380Sdlg 25158fa39c1Skrw scsi_probe_bus(sb); 252df930be7Sderaadt } 253df930be7Sderaadt 2541e7162a8Scsapuntz int 255e78728c7Spirofti scsibusactivate(struct device *dev, int act) 2561e7162a8Scsapuntz { 25720f90945Skrw struct scsibus_softc *sb = (struct scsibus_softc *)dev; 258864c175eSdlg 25958fa39c1Skrw return scsi_activate_bus(sb, act); 260864c175eSdlg } 261864c175eSdlg 262c42815b3Sdlg int 2639c2a17abSkrw scsibusdetach(struct device *dev, int type) 2649c2a17abSkrw { 2659c2a17abSkrw struct scsibus_softc *sb = (struct scsibus_softc *)dev; 2669c2a17abSkrw int error; 2679c2a17abSkrw 2689c2a17abSkrw #if NBIO > 0 2699c2a17abSkrw bio_unregister(&sb->sc_dev); 2709c2a17abSkrw #endif /* NBIO > 0 */ 2719c2a17abSkrw 27258fa39c1Skrw error = scsi_detach_bus(sb, type); 2739c2a17abSkrw if (error != 0) 2749c2a17abSkrw return error; 2759c2a17abSkrw 2769c2a17abSkrw KASSERT(SLIST_EMPTY(&sb->sc_link_list)); 2779c2a17abSkrw 2789c2a17abSkrw return 0; 2799c2a17abSkrw } 2809c2a17abSkrw 2819c2a17abSkrw int 2829c2a17abSkrw scsibussubmatch(struct device *parent, void *match, void *aux) 2839c2a17abSkrw { 2849c2a17abSkrw struct cfdata *cf = match; 2859c2a17abSkrw struct scsi_attach_args *sa = aux; 2869c2a17abSkrw struct scsi_link *link = sa->sa_sc_link; 2879c2a17abSkrw 2889c2a17abSkrw if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != link->target) 2899c2a17abSkrw return 0; 2909c2a17abSkrw if (cf->cf_loc[1] != -1 && cf->cf_loc[1] != link->lun) 2919c2a17abSkrw return 0; 2929c2a17abSkrw 2939c2a17abSkrw return (*cf->cf_attach->ca_match)(parent, match, aux); 2949c2a17abSkrw } 2959c2a17abSkrw 2969c2a17abSkrw /* 2979c2a17abSkrw * Print out autoconfiguration information for a subdevice. 2989c2a17abSkrw * 2999c2a17abSkrw * This is a slight abuse of 'standard' autoconfiguration semantics, 3009c2a17abSkrw * because 'print' functions don't normally print the colon and 3019c2a17abSkrw * device information. However, in this case that's better than 3029c2a17abSkrw * either printing redundant information before the attach message, 3039c2a17abSkrw * or having the device driver call a special function to print out 3049c2a17abSkrw * the standard device information. 3059c2a17abSkrw */ 3069c2a17abSkrw int 307ae7c6741Skrw scsibussubprint(void *aux, const char *pnp) 3089c2a17abSkrw { 3099c2a17abSkrw struct scsi_attach_args *sa = aux; 3109c2a17abSkrw 3119c2a17abSkrw if (pnp != NULL) 3129c2a17abSkrw printf("%s", pnp); 3139c2a17abSkrw 3149c2a17abSkrw scsi_print_link(sa->sa_sc_link); 3159c2a17abSkrw 3169c2a17abSkrw return UNCONF; 3179c2a17abSkrw } 3189c2a17abSkrw 3199c2a17abSkrw #if NBIO > 0 3209c2a17abSkrw int 3219c2a17abSkrw scsibusbioctl(struct device *dev, u_long cmd, caddr_t addr) 3229c2a17abSkrw { 3239c2a17abSkrw struct scsibus_softc *sb = (struct scsibus_softc *)dev; 3249c2a17abSkrw struct sbioc_device *sdev; 3259c2a17abSkrw 3269c2a17abSkrw switch (cmd) { 3279c2a17abSkrw case SBIOCPROBE: 3289c2a17abSkrw sdev = (struct sbioc_device *)addr; 3299c2a17abSkrw return scsi_probe(sb, sdev->sd_target, sdev->sd_lun); 3309c2a17abSkrw 3319c2a17abSkrw case SBIOCDETACH: 3329c2a17abSkrw sdev = (struct sbioc_device *)addr; 3339c2a17abSkrw return scsi_detach(sb, sdev->sd_target, sdev->sd_lun, 0); 3349c2a17abSkrw 3359c2a17abSkrw default: 3369c2a17abSkrw return ENOTTY; 3379c2a17abSkrw } 3389c2a17abSkrw } 3399c2a17abSkrw #endif /* NBIO > 0 */ 3409c2a17abSkrw 3419c2a17abSkrw int 34220f90945Skrw scsi_activate(struct scsibus_softc *sb, int target, int lun, int act) 343864c175eSdlg { 344864c175eSdlg if (target == -1 && lun == -1) 34520f90945Skrw return scsi_activate_bus(sb, act); 34658fa39c1Skrw else if (lun == -1) 34720f90945Skrw return scsi_activate_target(sb, target, act); 34858fa39c1Skrw else 34920f90945Skrw return scsi_activate_lun(sb, target, lun, act); 350864c175eSdlg } 351864c175eSdlg 352c42815b3Sdlg int 35320f90945Skrw scsi_activate_bus(struct scsibus_softc *sb, int act) 354864c175eSdlg { 35558fa39c1Skrw struct scsi_link *link; 35658fa39c1Skrw int r, rv = 0; 357864c175eSdlg 35858fa39c1Skrw /* Activate all links on the bus. */ 35958fa39c1Skrw SLIST_FOREACH(link, &sb->sc_link_list, bus_list) { 36058fa39c1Skrw r = scsi_activate_link(link, act); 361c42815b3Sdlg if (r) 362c42815b3Sdlg rv = r; 363c42815b3Sdlg } 364ce9fc84eSkrw return rv; 365864c175eSdlg } 366864c175eSdlg 367c42815b3Sdlg int 36820f90945Skrw scsi_activate_target(struct scsibus_softc *sb, int target, int act) 369864c175eSdlg { 3706ca8192cSkrw struct scsi_link *link; 3716ca8192cSkrw int r, rv = 0; 372864c175eSdlg 37358fa39c1Skrw /* Activate all links on the target. */ 3746ca8192cSkrw SLIST_FOREACH(link, &sb->sc_link_list, bus_list) { 3756ca8192cSkrw if (link->target == target) { 376cdca80fcSkrw r = scsi_activate_link(link, act); 377c42815b3Sdlg if (r) 378c42815b3Sdlg rv = r; 379c42815b3Sdlg } 3806ca8192cSkrw } 381ce9fc84eSkrw return rv; 382864c175eSdlg } 383864c175eSdlg 384c42815b3Sdlg int 38520f90945Skrw scsi_activate_lun(struct scsibus_softc *sb, int target, int lun, int act) 386864c175eSdlg { 387a0870786Smatthew struct scsi_link *link; 388864c175eSdlg 38958fa39c1Skrw /* Activate the (target, lun) link.*/ 39020f90945Skrw link = scsi_get_link(sb, target, lun); 391864c175eSdlg if (link == NULL) 392ce9fc84eSkrw return 0; 393864c175eSdlg 394cdca80fcSkrw return scsi_activate_link(link, act); 3956ca8192cSkrw } 3966ca8192cSkrw 3976ca8192cSkrw int 398cdca80fcSkrw scsi_activate_link(struct scsi_link *link, int act) 3996ca8192cSkrw { 4006ca8192cSkrw struct device *dev; 4016ca8192cSkrw int rv = 0; 4026ca8192cSkrw 403864c175eSdlg dev = link->device_softc; 404864c175eSdlg switch (act) { 405864c175eSdlg case DVACT_DEACTIVATE: 4062f10112bSdlg atomic_setbits_int(&link->state, SDEV_S_DYING); 407864c175eSdlg config_deactivate(dev); 408864c175eSdlg break; 409864c175eSdlg default: 41037ecb596Sderaadt rv = config_suspend(dev, act); 411864c175eSdlg break; 412864c175eSdlg } 413ce9fc84eSkrw return rv; 4141e7162a8Scsapuntz } 4151e7162a8Scsapuntz 416bc9adaf2Skrw int 41720f90945Skrw scsi_probe(struct scsibus_softc *sb, int target, int lun) 418b0b58169Sdlg { 41958fa39c1Skrw if (target == -1 && lun == -1) 42058fa39c1Skrw return scsi_probe_bus(sb); 42158fa39c1Skrw else if (lun == -1) 42258fa39c1Skrw return scsi_probe_target(sb, target); 42358fa39c1Skrw else 42458fa39c1Skrw return scsi_probe_lun(sb, target, lun); 42558fa39c1Skrw } 426bc9adaf2Skrw 42758fa39c1Skrw int 42858fa39c1Skrw scsi_probe_bus(struct scsibus_softc *sb) 42958fa39c1Skrw { 43058fa39c1Skrw int target, r, rv = 0; 43158fa39c1Skrw 43258fa39c1Skrw /* Probe all possible targets on bus. */ 43358fa39c1Skrw for (target = 0; target < sb->sb_adapter_buswidth; target++) { 43458fa39c1Skrw r = scsi_probe_target(sb, target); 435bc9adaf2Skrw if (r != 0 && r != EINVAL) 436bc9adaf2Skrw rv = r; 437bc9adaf2Skrw } 438bc9adaf2Skrw return rv; 439288889b9Skrw } 440b0b58169Sdlg 44158fa39c1Skrw int 44258fa39c1Skrw scsi_probe_target(struct scsibus_softc *sb, int target) 44358fa39c1Skrw { 44458fa39c1Skrw struct scsi_lun_array lunarray; 44558fa39c1Skrw int i, r, rv = 0; 44658fa39c1Skrw 44758fa39c1Skrw if (target < 0 || target == sb->sb_adapter_target) 448bc9adaf2Skrw return EINVAL; 449b0b58169Sdlg 45045653f8bSkrw scsi_get_target_luns(sb, target, &lunarray); 45145653f8bSkrw if (lunarray.count == 0) 452bc9adaf2Skrw return EINVAL; 45345653f8bSkrw 454bc9adaf2Skrw for (i = 0; i < lunarray.count; i++) { 45514832242Skrw r = scsi_probe_link(sb, target, lunarray.luns[i], 456bc9adaf2Skrw lunarray.dumbscan); 457bc9adaf2Skrw if (r == EINVAL && lunarray.dumbscan == 1) 458bc9adaf2Skrw return 0; 459bc9adaf2Skrw if (r != 0 && r != EINVAL) 460bc9adaf2Skrw rv = r; 461bc9adaf2Skrw } 462bc9adaf2Skrw return rv; 463bc9adaf2Skrw } 464b0b58169Sdlg 465b0b58169Sdlg int 46620f90945Skrw scsi_probe_lun(struct scsibus_softc *sb, int target, int lun) 4671a0657b7Sdlg { 46858fa39c1Skrw if (target < 0 || target == sb->sb_adapter_target || lun < 0) 469bc9adaf2Skrw return EINVAL; 47058fa39c1Skrw 47158fa39c1Skrw /* Probe lun on target. *NOT* a dumbscan! */ 47258fa39c1Skrw return scsi_probe_link(sb, target, lun, 0); 4731a0657b7Sdlg } 4741a0657b7Sdlg 475f565022dSkrw int 476f565022dSkrw scsi_probe_link(struct scsibus_softc *sb, int target, int lun, int dumbscan) 477df930be7Sderaadt { 478f565022dSkrw struct scsi_attach_args sa; 479f565022dSkrw const struct scsi_quirk_inquiry_pattern *finger; 480f565022dSkrw struct scsi_inquiry_data *inqbuf, *usbinqbuf; 481f565022dSkrw struct scsi_link *link, *link0; 482f565022dSkrw struct cfdata *cf; 483f565022dSkrw int inqbytes, priority, rslt = 0; 484f565022dSkrw u_int16_t devquirks; 485f565022dSkrw 486f565022dSkrw /* Skip this slot if it is already attached and try the next LUN. */ 487f565022dSkrw if (scsi_get_link(sb, target, lun) != NULL) 488f565022dSkrw return 0; 489df930be7Sderaadt 4906d4b3493Skrw link = malloc(sizeof(*link), M_DEVBUF, M_NOWAIT); 49194c54771Skrw if (link == NULL) { 4927d920e80Skrw SC_DEBUG(link, SDEV_DB2, ("malloc(scsi_link) failed.\n")); 493f565022dSkrw return EINVAL; 49494c54771Skrw } 495b7a5bd96Skrw 49641e86d54Skrw link->state = 0; 4976d4b3493Skrw link->target = target; 4986d4b3493Skrw link->lun = lun; 49941e86d54Skrw link->openings = sb->sb_openings; 5006d4b3493Skrw link->node_wwn = link->port_wwn = 0; 50141e86d54Skrw link->flags = sb->sb_flags; 50241e86d54Skrw link->quirks = sb->sb_quirks; 50341e86d54Skrw link->interpret_sense = scsi_interpret_sense; 50441e86d54Skrw link->device_softc = NULL; 50541e86d54Skrw link->bus = sb; 50641e86d54Skrw memset(&link->inqdata, 0, sizeof(link->inqdata)); 50741e86d54Skrw link->id = NULL; 5086d4b3493Skrw TAILQ_INIT(&link->queue); 50941e86d54Skrw link->running = 0; 51041e86d54Skrw link->pending = 0; 51141e86d54Skrw link->pool = sb->sb_pool; 512df930be7Sderaadt 5136d4b3493Skrw SC_DEBUG(link, SDEV_DB2, ("scsi_link created.\n")); 514b7a5bd96Skrw 515ce9fc84eSkrw /* Ask the adapter if this will be a valid device. */ 51641e86d54Skrw if (sb->sb_adapter->dev_probe != NULL && 51741e86d54Skrw sb->sb_adapter->dev_probe(link) != 0) { 51894c54771Skrw if (lun == 0) { 5197d920e80Skrw SC_DEBUG(link, SDEV_DB2, ("dev_probe(link) failed.\n")); 520cf78f4e9Sdlg rslt = EINVAL; 52194c54771Skrw } 522974883aaSkrw free(link, M_DEVBUF, sizeof(*link)); 523974883aaSkrw return rslt; 524cf78f4e9Sdlg } 525cf78f4e9Sdlg 526df930be7Sderaadt /* 527*9593dc34Smglocker * If we haven't been given an io pool by now then fall back to 528f565022dSkrw * using link->openings. 529f565022dSkrw */ 530f565022dSkrw if (link->pool == NULL) { 531eab44964Skrw link->pool = malloc(sizeof(*link->pool), M_DEVBUF, M_NOWAIT); 532f565022dSkrw if (link->pool == NULL) { 533f565022dSkrw SC_DEBUG(link, SDEV_DB2, ("malloc(pool) failed.\n")); 534f565022dSkrw rslt = ENOMEM; 535f565022dSkrw goto bad; 536f565022dSkrw } 537eab44964Skrw scsi_iopool_init(link->pool, link, scsi_default_get, 538eab44964Skrw scsi_default_put); 539f565022dSkrw 540f565022dSkrw SET(link->flags, SDEV_OWN_IOPL); 541f565022dSkrw } 542f565022dSkrw 543f565022dSkrw /* 544b7a5bd96Skrw * Tell drivers that are paying attention to avoid sync/wide/tags until 545b7a5bd96Skrw * INQUIRY data has been processed and the quirks information is 546b7a5bd96Skrw * complete. Some drivers set bits in quirks before we get here, so 547b7a5bd96Skrw * just add NOTAGS, NOWIDE and NOSYNC. 54860b1a1deSkrw */ 549b3df7069Skrw devquirks = link->quirks; 550dacf4336Skrw SET(link->quirks, SDEV_NOSYNC | SDEV_NOWIDE | SDEV_NOTAGS); 551f565022dSkrw 552f565022dSkrw /* 553f565022dSkrw * Ask the device what it is. 554f565022dSkrw */ 555f565022dSkrw #ifdef SCSIDEBUG 556f565022dSkrw if (((sb->sc_dev.dv_unit < 32) && 557f565022dSkrw ((1U << sb->sc_dev.dv_unit) & scsidebug_buses)) && 558f565022dSkrw ((target < 32) && ((1U << target) & scsidebug_targets)) && 559f565022dSkrw ((lun < 32) && ((1U << lun) & scsidebug_luns))) 560f565022dSkrw SET(link->flags, scsidebug_level); 561f565022dSkrw #endif /* SCSIDEBUG */ 562f565022dSkrw 56332e33df8Sderaadt if (lun == 0) { 56459e50368Skrw /* Clear any outstanding errors. */ 5656d4b3493Skrw scsi_test_unit_ready(link, TEST_READY_RETRIES, 56632e33df8Sderaadt scsi_autoconf | SCSI_IGNORE_ILLEGAL_REQUEST | 56732e33df8Sderaadt SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE); 56832e33df8Sderaadt } 56932e33df8Sderaadt 570df930be7Sderaadt /* Now go ask the device all about itself. */ 5712866d547Sdlg inqbuf = dma_alloc(sizeof(*inqbuf), PR_NOWAIT | PR_ZERO); 5722866d547Sdlg if (inqbuf == NULL) { 5737d920e80Skrw SC_DEBUG(link, SDEV_DB2, ("dma_alloc(inqbuf) failed.\n")); 5742866d547Sdlg rslt = ENOMEM; 5752866d547Sdlg goto bad; 5762866d547Sdlg } 5772866d547Sdlg 5786d4b3493Skrw rslt = scsi_inquire(link, inqbuf, scsi_autoconf | SCSI_SILENT); 579004599b4Skrw if (rslt != 0) { 5807d920e80Skrw if (lun == 0) 581b7a5bd96Skrw rslt = EINVAL; 5826b0aba5fSkrw dma_free(inqbuf, sizeof(*inqbuf)); 583b7a5bd96Skrw goto bad; 5844147c8c3Skrw } 5856b0aba5fSkrw inqbytes = SID_SCSI2_HDRLEN + inqbuf->additional_length; 5866b0aba5fSkrw memcpy(&link->inqdata, inqbuf, inqbytes); 5876b0aba5fSkrw dma_free(inqbuf, sizeof(*inqbuf)); 5886d4b3493Skrw inqbuf = &link->inqdata; 5896b0aba5fSkrw if (inqbytes < offsetof(struct scsi_inquiry_data, vendor)) 5906b0aba5fSkrw memset(inqbuf->vendor, ' ', sizeof(inqbuf->vendor)); 5916b0aba5fSkrw if (inqbytes < offsetof(struct scsi_inquiry_data, product)) 5926b0aba5fSkrw memset(inqbuf->product, ' ', sizeof(inqbuf->product)); 5936b0aba5fSkrw if (inqbytes < offsetof(struct scsi_inquiry_data, revision)) 5946b0aba5fSkrw memset(inqbuf->revision, ' ', sizeof(inqbuf->revision)); 5956b0aba5fSkrw if (inqbytes < offsetof(struct scsi_inquiry_data, extra)) 5966b0aba5fSkrw memset(inqbuf->extra, ' ', sizeof(inqbuf->extra)); 5974147c8c3Skrw 5986baa3d5cSdlg switch (inqbuf->device & SID_QUAL) { 599a1080618Skrw case SID_QUAL_RSVD: 600a1080618Skrw case SID_QUAL_BAD_LU: 601ed3e5711Skrw goto bad; 602a1080618Skrw case SID_QUAL_LU_OFFLINE: 603ed3e5711Skrw if (lun == 0 && (inqbuf->device & SID_TYPE) == T_NODEVICE) 604ed3e5711Skrw break; 605a1080618Skrw goto bad; 606a1080618Skrw case SID_QUAL_LU_OK: 6079b0b1e37Skrw default: 6087d920e80Skrw if ((inqbuf->device & SID_TYPE) == T_NODEVICE) 609a1080618Skrw goto bad; 610ed3e5711Skrw break; 611ed3e5711Skrw } 612df930be7Sderaadt 6136d4b3493Skrw scsi_devid(link); 614758476e4Sdlg 61520f90945Skrw link0 = scsi_get_link(sb, target, 0); 616a0870786Smatthew if (lun == 0 || link0 == NULL) 6178993c085Skrw ; 618c3094a8aSkrw else if (ISSET(link->flags, SDEV_UMASS)) 6194cdd8c64Skrw ; 6206d4b3493Skrw else if (link->id != NULL && !DEVID_CMP(link0->id, link->id)) 621758476e4Sdlg ; 622bc9adaf2Skrw else if (dumbscan == 1 && memcmp(inqbuf, &link0->inqdata, 623bc9adaf2Skrw sizeof(*inqbuf)) == 0) { 624478a8574Skrw /* The device doesn't distinguish between LUNs. */ 6257d920e80Skrw SC_DEBUG(link, SDEV_DB1, ("IDENTIFY not supported.\n")); 626478a8574Skrw rslt = EINVAL; 627974883aaSkrw goto bad; 628478a8574Skrw } 629478a8574Skrw 630b3df7069Skrw link->quirks = devquirks; /* Restore what the device wanted. */ 631b3df7069Skrw 632697fee68Smickey finger = (const struct scsi_quirk_inquiry_pattern *)scsi_inqmatch( 6336baa3d5cSdlg inqbuf, scsi_quirk_patterns, 634e61a197cSjasper nitems(scsi_quirk_patterns), 635df930be7Sderaadt sizeof(scsi_quirk_patterns[0]), &priority); 636df930be7Sderaadt if (priority != 0) 637dacf4336Skrw SET(link->quirks, finger->quirks); 638df930be7Sderaadt 639b3df7069Skrw switch (SID_ANSII_REV(inqbuf)) { 640b3df7069Skrw case SCSI_REV_0: 641b3df7069Skrw case SCSI_REV_1: 642b3df7069Skrw SET(link->quirks, SDEV_NOTAGS | SDEV_NOSYNC | SDEV_NOWIDE | 643b3df7069Skrw SDEV_NOSYNCCACHE); 644b3df7069Skrw break; 645b3df7069Skrw case SCSI_REV_2: 646b3df7069Skrw case SCSI_REV_SPC: 647b3df7069Skrw case SCSI_REV_SPC2: 648b3df7069Skrw if (!ISSET(inqbuf->flags, SID_CmdQue)) 649b3df7069Skrw SET(link->quirks, SDEV_NOTAGS); 650b3df7069Skrw if (!ISSET(inqbuf->flags, SID_Sync)) 651b3df7069Skrw SET(link->quirks, SDEV_NOSYNC); 652b3df7069Skrw if (!ISSET(inqbuf->flags, SID_WBus16)) 653b3df7069Skrw SET(link->quirks, SDEV_NOWIDE); 654b3df7069Skrw break; 655b3df7069Skrw case SCSI_REV_SPC3: 656b3df7069Skrw case SCSI_REV_SPC4: 657b3df7069Skrw case SCSI_REV_SPC5: 658b3df7069Skrw /* By this time SID_Sync and SID_WBus16 were obsolete. */ 659b3df7069Skrw if (!ISSET(inqbuf->flags, SID_CmdQue)) 660b3df7069Skrw SET(link->quirks, SDEV_NOTAGS); 661b3df7069Skrw break; 662b3df7069Skrw default: 663b3df7069Skrw break; 664b3df7069Skrw } 665b3df7069Skrw 666df930be7Sderaadt /* 6671fa0cb04Skrw * If the device can't use tags, >1 opening may confuse it. 6681fa0cb04Skrw */ 6696d4b3493Skrw if (ISSET(link->quirks, SDEV_NOTAGS)) 6706d4b3493Skrw link->openings = 1; 6711fa0cb04Skrw 6721fa0cb04Skrw /* 673df930be7Sderaadt * note what BASIC type of device it is 674df930be7Sderaadt */ 675c3094a8aSkrw if (ISSET(inqbuf->dev_qual2, SID_REMOVABLE)) 676dacf4336Skrw SET(link->flags, SDEV_REMOVABLE); 677df930be7Sderaadt 6786d4b3493Skrw sa.sa_sc_link = link; 679df930be7Sderaadt 6806db5dbffSkrw cf = config_search(scsibussubmatch, (struct device *)sb, &sa); 6816db5dbffSkrw if (cf == NULL) { 682ae7c6741Skrw scsibussubprint(&sa, sb->sc_dev.dv_xname); 6830c0430f8Sniklas printf(" not configured\n"); 684974883aaSkrw goto bad; 6850c0430f8Sniklas } 686df930be7Sderaadt 687dcd6245dSkrw /* 688dcd6245dSkrw * Braindead USB devices, especially some x-in-1 media readers, try to 689dcd6245dSkrw * 'help' by pretending any LUN is actually LUN 0 until they see a 690dcd6245dSkrw * different LUN used in a command. So do an INQUIRY on LUN 1 at this 691114dc81eSdlg * point to prevent such helpfulness before it causes confusion. 692dcd6245dSkrw */ 693c3094a8aSkrw if (lun == 0 && ISSET(link->flags, SDEV_UMASS) && 69467c3123bSkrw scsi_get_link(sb, target, 1) == NULL && sb->sb_luns > 1 && 6952866d547Sdlg (usbinqbuf = dma_alloc(sizeof(*usbinqbuf), M_NOWAIT)) != NULL) { 696114dc81eSdlg 6976d4b3493Skrw link->lun = 1; 6986d4b3493Skrw scsi_inquire(link, usbinqbuf, scsi_autoconf | SCSI_SILENT); 6996d4b3493Skrw link->lun = 0; 7002866d547Sdlg 7012866d547Sdlg dma_free(usbinqbuf, sizeof(*usbinqbuf)); 702dcd6245dSkrw } 703dcd6245dSkrw 704cdca80fcSkrw scsi_add_link(link); 70560b1a1deSkrw 70660b1a1deSkrw /* 707b7a5bd96Skrw * Generate a TEST_UNIT_READY command. This gives drivers waiting for 708b7a5bd96Skrw * valid quirks data a chance to set wide/sync/tag options 709b7a5bd96Skrw * appropriately. It also clears any outstanding ACA conditions that 710b7a5bd96Skrw * INQUIRY may leave behind. 711b7a5bd96Skrw * 712b7a5bd96Skrw * Do this now so that any messages generated by config_attach() do not 713b7a5bd96Skrw * have negotiation messages inserted into their midst. 71460b1a1deSkrw */ 7156d4b3493Skrw scsi_test_unit_ready(link, TEST_READY_RETRIES, 716b7a5bd96Skrw scsi_autoconf | SCSI_IGNORE_ILLEGAL_REQUEST | 717b7a5bd96Skrw SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE); 71860b1a1deSkrw 719ae7c6741Skrw config_attach((struct device *)sb, cf, &sa, scsibussubprint); 720ce9fc84eSkrw return 0; 721df930be7Sderaadt 722df930be7Sderaadt bad: 723974883aaSkrw scsi_detach_link(link, DETACH_FORCE); 724ce9fc84eSkrw return rslt; 725df930be7Sderaadt } 726df930be7Sderaadt 72714832242Skrw int 72814832242Skrw scsi_detach(struct scsibus_softc *sb, int target, int lun, int flags) 72914832242Skrw { 73058fa39c1Skrw if (target == -1 && lun == -1) 73158fa39c1Skrw return scsi_detach_bus(sb, flags); 73258fa39c1Skrw else if (lun == -1) 73358fa39c1Skrw return scsi_detach_target(sb, target, flags); 73458fa39c1Skrw else 73558fa39c1Skrw return scsi_detach_lun(sb, target, lun, flags); 73658fa39c1Skrw } 73758fa39c1Skrw 73858fa39c1Skrw int 73958fa39c1Skrw scsi_detach_bus(struct scsibus_softc *sb, int flags) 74058fa39c1Skrw { 741f803c2f9Skrw struct scsi_link *link, *tmp; 74214832242Skrw int r, rv = 0; 74314832242Skrw 74414832242Skrw /* Detach all links from bus. */ 745f803c2f9Skrw SLIST_FOREACH_SAFE(link, &sb->sc_link_list, bus_list, tmp) { 74614832242Skrw r = scsi_detach_link(link, flags); 74714832242Skrw if (r != 0 && r != ENXIO) 74814832242Skrw rv = r; 74914832242Skrw } 75014832242Skrw return rv; 75114832242Skrw } 75214832242Skrw 75358fa39c1Skrw int 75458fa39c1Skrw scsi_detach_target(struct scsibus_softc *sb, int target, int flags) 75558fa39c1Skrw { 75658fa39c1Skrw struct scsi_link *link, *tmp; 75758fa39c1Skrw int r, rv = 0; 75814832242Skrw 75914832242Skrw /* Detach all links from target. */ 76014832242Skrw SLIST_FOREACH_SAFE(link, &sb->sc_link_list, bus_list, tmp) { 76114832242Skrw if (link->target == target) { 76214832242Skrw r = scsi_detach_link(link, flags); 76314832242Skrw if (r != 0 && r != ENXIO) 76414832242Skrw rv = r; 76514832242Skrw } 76614832242Skrw } 76714832242Skrw return rv; 76814832242Skrw } 76914832242Skrw 77014832242Skrw int 77114832242Skrw scsi_detach_lun(struct scsibus_softc *sb, int target, int lun, int flags) 77214832242Skrw { 77358fa39c1Skrw struct scsi_link *link; 77458fa39c1Skrw 77558fa39c1Skrw /* Detach (target, lun) link. */ 77658fa39c1Skrw link = scsi_get_link(sb, target, lun); 77758fa39c1Skrw if (link == NULL) 77814832242Skrw return EINVAL; 77958fa39c1Skrw 78058fa39c1Skrw return scsi_detach_link(link, flags); 78114832242Skrw } 78214832242Skrw 78314832242Skrw int 78414832242Skrw scsi_detach_link(struct scsi_link *link, int flags) 78514832242Skrw { 78614832242Skrw struct scsibus_softc *sb = link->bus; 78714832242Skrw int rv; 78814832242Skrw 78914832242Skrw if (!ISSET(flags, DETACH_FORCE) && ISSET(link->flags, SDEV_OPEN)) 79014832242Skrw return EBUSY; 79114832242Skrw 79214832242Skrw /* Detaching a device from scsibus is a five step process. */ 79314832242Skrw 79414832242Skrw /* 1. Wake up processes sleeping for an xs. */ 79522d8fe70Skrw if (link->pool != NULL) 79614832242Skrw scsi_link_shutdown(link); 79714832242Skrw 79814832242Skrw /* 2. Detach the device. */ 79922d8fe70Skrw if (link->device_softc != NULL) { 80014832242Skrw rv = config_detach(link->device_softc, flags); 80114832242Skrw if (rv != 0) 80214832242Skrw return rv; 80322d8fe70Skrw } 80414832242Skrw 80514832242Skrw /* 3. If it's using the openings io allocator, clean that up. */ 80634ceb667Skrw if (link->pool != NULL && ISSET(link->flags, SDEV_OWN_IOPL)) { 80714832242Skrw scsi_iopool_destroy(link->pool); 80814832242Skrw free(link->pool, M_DEVBUF, sizeof(*link->pool)); 80914832242Skrw } 81014832242Skrw 81114832242Skrw /* 4. Free up its state in the adapter. */ 81214832242Skrw if (sb->sb_adapter->dev_free != NULL) 81314832242Skrw sb->sb_adapter->dev_free(link); 81414832242Skrw 81514832242Skrw /* 5. Free up its state in the midlayer. */ 81614832242Skrw if (link->id != NULL) 81714832242Skrw devid_free(link->id); 81814832242Skrw scsi_remove_link(link); 81914832242Skrw free(link, M_DEVBUF, sizeof(*link)); 82014832242Skrw 82114832242Skrw return 0; 82214832242Skrw } 82314832242Skrw 82414832242Skrw struct scsi_link * 82514832242Skrw scsi_get_link(struct scsibus_softc *sb, int target, int lun) 82614832242Skrw { 82714832242Skrw struct scsi_link *link; 82814832242Skrw 82914832242Skrw SLIST_FOREACH(link, &sb->sc_link_list, bus_list) { 83014832242Skrw if (link->target == target && link->lun == lun) 83114832242Skrw return link; 83214832242Skrw } 83314832242Skrw 83414832242Skrw return NULL; 83514832242Skrw } 83614832242Skrw 83714832242Skrw void 83814832242Skrw scsi_add_link(struct scsi_link *link) 83914832242Skrw { 84014832242Skrw SLIST_INSERT_HEAD(&link->bus->sc_link_list, link, bus_list); 84114832242Skrw } 84214832242Skrw 84314832242Skrw void 84414832242Skrw scsi_remove_link(struct scsi_link *link) 84514832242Skrw { 8466b0fbbfdSkrw struct scsibus_softc *sb = link->bus; 84729220739Skrw struct scsi_link *elm, *prev = NULL; 8486b0fbbfdSkrw 84929220739Skrw SLIST_FOREACH(elm, &sb->sc_link_list, bus_list) { 8506b0fbbfdSkrw if (elm == link) { 85129220739Skrw if (prev == NULL) 85229220739Skrw SLIST_REMOVE_HEAD(&sb->sc_link_list, bus_list); 85329220739Skrw else 85429220739Skrw SLIST_REMOVE_AFTER(prev, bus_list); 8556b0fbbfdSkrw break; 8566b0fbbfdSkrw } 85729220739Skrw prev = elm; 8586b0fbbfdSkrw } 85914832242Skrw } 86014832242Skrw 86114832242Skrw void 86245653f8bSkrw scsi_get_target_luns(struct scsibus_softc *sb, int target, 86345653f8bSkrw struct scsi_lun_array *lunarray) 864ae7c6741Skrw { 865ae7c6741Skrw struct scsi_report_luns_data *report; 86645653f8bSkrw struct scsi_link *link0; 867ae7c6741Skrw int i, nluns, rv = 0; 868ae7c6741Skrw 86945653f8bSkrw /* LUN 0 *must* be present. */ 87045653f8bSkrw scsi_probe_link(sb, target, 0, 0); 87145653f8bSkrw link0 = scsi_get_link(sb, target, 0); 87245653f8bSkrw if (link0 == NULL) { 87345653f8bSkrw lunarray->count = 0; 87445653f8bSkrw return; 87545653f8bSkrw } 87645653f8bSkrw 877ae7c6741Skrw /* Initialize dumbscan result. Just in case. */ 878ae7c6741Skrw report = NULL; 879ae7c6741Skrw for (i = 0; i < link0->bus->sb_luns; i++) 880ae7c6741Skrw lunarray->luns[i] = i; 881ae7c6741Skrw lunarray->count = link0->bus->sb_luns; 882ae7c6741Skrw lunarray->dumbscan = 1; 883ae7c6741Skrw 884ae7c6741Skrw /* 885ae7c6741Skrw * ATAPI, USB and pre-SPC (i.e. pre-SCSI-3) devices can't ask 886ae7c6741Skrw * for a report of valid LUNs. 887ae7c6741Skrw */ 888ae7c6741Skrw if ((link0->flags & (SDEV_UMASS | SDEV_ATAPI)) != 0 || 889ae7c6741Skrw SID_ANSII_REV(&link0->inqdata) < SCSI_REV_SPC) 890ae7c6741Skrw goto dumbscan; 891ae7c6741Skrw 892ae7c6741Skrw report = dma_alloc(sizeof(*report), PR_WAITOK); 893ae7c6741Skrw if (report == NULL) 894ae7c6741Skrw goto dumbscan; 895ae7c6741Skrw 896ae7c6741Skrw rv = scsi_report_luns(link0, REPORT_NORMAL, report, 897ae7c6741Skrw sizeof(*report), scsi_autoconf | SCSI_SILENT | 898ae7c6741Skrw SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY | 899ae7c6741Skrw SCSI_IGNORE_MEDIA_CHANGE, 10000); 900ae7c6741Skrw if (rv != 0) 901ae7c6741Skrw goto dumbscan; 902ae7c6741Skrw 903ae7c6741Skrw /* 904ae7c6741Skrw * XXX In theory we should check if data is full, which 905ae7c6741Skrw * would indicate it needs to be enlarged and REPORT 906ae7c6741Skrw * LUNS tried again. Solaris tries up to 3 times with 907ae7c6741Skrw * larger sizes for data. 908ae7c6741Skrw */ 909ae7c6741Skrw 910ae7c6741Skrw /* Return the reported Type-0 LUNs. Type-0 only! */ 911ae7c6741Skrw lunarray->count = 0; 912ae7c6741Skrw lunarray->dumbscan = 0; 913ae7c6741Skrw nluns = _4btol(report->length) / RPL_LUNDATA_SIZE; 914ae7c6741Skrw for (i = 0; i < nluns; i++) { 915ae7c6741Skrw if (report->luns[i].lundata[0] != 0) 916ae7c6741Skrw continue; 917ae7c6741Skrw lunarray->luns[lunarray->count++] = 918ae7c6741Skrw report->luns[i].lundata[RPL_LUNDATA_T0LUN]; 919ae7c6741Skrw } 920ae7c6741Skrw 921ae7c6741Skrw dumbscan: 922ae7c6741Skrw if (report != NULL) 923ae7c6741Skrw dma_free(report, sizeof(*report)); 924ae7c6741Skrw } 925ae7c6741Skrw 926ae7c6741Skrw void 92714832242Skrw scsi_strvis(u_char *dst, u_char *src, int len) 92814832242Skrw { 92914832242Skrw u_char last; 93014832242Skrw 93114832242Skrw /* Trim leading and trailing whitespace and NULs. */ 93214832242Skrw while (len > 0 && (src[0] == ' ' || src[0] == '\t' || src[0] == '\n' || 93314832242Skrw src[0] == '\0' || src[0] == 0xff)) 93414832242Skrw ++src, --len; 93514832242Skrw while (len > 0 && (src[len-1] == ' ' || src[len-1] == '\t' || 93614832242Skrw src[len-1] == '\n' || src[len-1] == '\0' || src[len-1] == 0xff)) 93714832242Skrw --len; 93814832242Skrw 93914832242Skrw last = 0xff; 94014832242Skrw while (len > 0) { 94114832242Skrw switch (*src) { 94214832242Skrw case ' ': 94314832242Skrw case '\t': 94414832242Skrw case '\n': 94514832242Skrw case '\0': 94614832242Skrw case 0xff: 94714832242Skrw /* Collapse whitespace and NULs to a single space. */ 94814832242Skrw if (last != ' ') 94914832242Skrw *dst++ = ' '; 95014832242Skrw last = ' '; 95114832242Skrw break; 95214832242Skrw case '\\': 95314832242Skrw /* Quote backslashes. */ 95414832242Skrw *dst++ = '\\'; 95514832242Skrw *dst++ = '\\'; 95614832242Skrw last = '\\'; 95714832242Skrw break; 95814832242Skrw default: 95914832242Skrw if (*src < 0x20 || *src >= 0x80) { 96014832242Skrw /* Non-printable characters to octal. */ 96114832242Skrw *dst++ = '\\'; 96214832242Skrw *dst++ = ((*src & 0300) >> 6) + '0'; 96314832242Skrw *dst++ = ((*src & 0070) >> 3) + '0'; 96414832242Skrw *dst++ = ((*src & 0007) >> 0) + '0'; 96514832242Skrw } else { 96614832242Skrw /* Copy normal characters. */ 96714832242Skrw *dst++ = *src; 96814832242Skrw } 96914832242Skrw last = *src; 97014832242Skrw break; 97114832242Skrw } 97214832242Skrw ++src, --len; 97314832242Skrw } 97414832242Skrw 97514832242Skrw *dst++ = 0; 97614832242Skrw } 97714832242Skrw 97814832242Skrw void 9799c2a17abSkrw scsi_print_link(struct scsi_link *link) 98014832242Skrw { 98114832242Skrw char visbuf[65]; 98214832242Skrw struct scsi_inquiry_data *inqbuf; 98314832242Skrw u_int8_t *id; 98414832242Skrw int i; 98514832242Skrw 98614832242Skrw printf(" targ %d lun %d: ", link->target, link->lun); 98714832242Skrw 98814832242Skrw inqbuf = &link->inqdata; 98914832242Skrw 99014832242Skrw scsi_strvis(visbuf, inqbuf->vendor, 8); 99114832242Skrw printf("<%s, ", visbuf); 99214832242Skrw scsi_strvis(visbuf, inqbuf->product, 16); 99314832242Skrw printf("%s, ", visbuf); 99414832242Skrw scsi_strvis(visbuf, inqbuf->revision, 4); 99514832242Skrw printf("%s>", visbuf); 99614832242Skrw 99714832242Skrw #ifdef SCSIDEBUG 99814832242Skrw if (ISSET(link->flags, SDEV_ATAPI)) 99914832242Skrw printf(" ATAPI"); 100014832242Skrw else if (SID_ANSII_REV(inqbuf) < SCSI_REV_SPC) 100114832242Skrw printf(" SCSI/%d", SID_ANSII_REV(inqbuf)); 100214832242Skrw else if (SID_ANSII_REV(inqbuf) == SCSI_REV_SPC) 100314832242Skrw printf(" SCSI/SPC"); 100414832242Skrw else 100514832242Skrw printf(" SCSI/SPC-%d", SID_ANSII_REV(inqbuf) - 2); 100614832242Skrw #endif /* SCSIDEBUG */ 100714832242Skrw 100814832242Skrw if (ISSET(link->flags, SDEV_REMOVABLE)) 100914832242Skrw printf(" removable"); 101014832242Skrw 101114832242Skrw if (link->id != NULL && link->id->d_type != DEVID_NONE) { 101214832242Skrw id = (u_int8_t *)(link->id + 1); 101314832242Skrw switch (link->id->d_type) { 101414832242Skrw case DEVID_NAA: 101514832242Skrw printf(" naa."); 101614832242Skrw break; 101714832242Skrw case DEVID_EUI: 101814832242Skrw printf(" eui."); 101914832242Skrw break; 102014832242Skrw case DEVID_T10: 102114832242Skrw printf(" t10."); 102214832242Skrw break; 102314832242Skrw case DEVID_SERIAL: 102414832242Skrw printf(" serial."); 102514832242Skrw break; 102614832242Skrw case DEVID_WWN: 102714832242Skrw printf(" wwn."); 102814832242Skrw break; 102914832242Skrw } 103014832242Skrw 103114832242Skrw if (ISSET(link->id->d_flags, DEVID_F_PRINT)) { 103214832242Skrw for (i = 0; i < link->id->d_len; i++) { 103314832242Skrw if (id[i] == '\0' || id[i] == ' ') { 103414832242Skrw /* skip leading blanks */ 103514832242Skrw /* collapse multiple blanks into one */ 103614832242Skrw if (i > 0 && id[i-1] != id[i]) 103714832242Skrw printf("_"); 103814832242Skrw } else if (id[i] < 0x20 || id[i] >= 0x80) { 103914832242Skrw /* non-printable characters */ 104014832242Skrw printf("~"); 104114832242Skrw } else { 104214832242Skrw /* normal characters */ 104314832242Skrw printf("%c", id[i]); 104414832242Skrw } 104514832242Skrw } 104614832242Skrw } else { 104714832242Skrw for (i = 0; i < link->id->d_len; i++) 104814832242Skrw printf("%02x", id[i]); 104914832242Skrw } 105014832242Skrw } 105114832242Skrw #ifdef SCSIDEBUG 105214832242Skrw printf("\n"); 105314832242Skrw sc_print_addr(link); 105414832242Skrw printf("state %u, luns %u, openings %u\n", 105514832242Skrw link->state, link->bus->sb_luns, link->openings); 105614832242Skrw 105714832242Skrw sc_print_addr(link); 105814832242Skrw printf("flags (0x%04x) ", link->flags); 105914832242Skrw scsi_show_flags(link->flags, flagnames); 106014832242Skrw printf("\n"); 106114832242Skrw 106214832242Skrw sc_print_addr(link); 106314832242Skrw printf("quirks (0x%04x) ", link->quirks); 106414832242Skrw scsi_show_flags(link->quirks, quirknames); 106514832242Skrw #endif /* SCSIDEBUG */ 106614832242Skrw } 106714832242Skrw 106814832242Skrw /* 1069df930be7Sderaadt * Return a priority based on how much of the inquiry data matches 1070df930be7Sderaadt * the patterns for the particular driver. 1071df930be7Sderaadt */ 1072697fee68Smickey const void * 10733957c1c0Spedro scsi_inqmatch(struct scsi_inquiry_data *inqbuf, const void *_base, 10743957c1c0Spedro int nmatches, int matchsize, int *bestpriority) 1075df930be7Sderaadt { 10763957c1c0Spedro const unsigned char *base = (const unsigned char *)_base; 10779b0b1e37Skrw const void *bestmatch; 10789b0b1e37Skrw int removable; 1079df930be7Sderaadt 1080df930be7Sderaadt /* Include the qualifier to catch vendor-unique types. */ 1081c3094a8aSkrw removable = ISSET(inqbuf->dev_qual2, SID_REMOVABLE) ? T_REMOV : T_FIXED; 1082df930be7Sderaadt 1083df930be7Sderaadt for (*bestpriority = 0, bestmatch = 0; nmatches--; base += matchsize) { 1084df930be7Sderaadt struct scsi_inquiry_pattern *match = (void *)base; 1085df930be7Sderaadt int priority, len; 1086df930be7Sderaadt 10879b0b1e37Skrw if (inqbuf->device != match->type) 1088df930be7Sderaadt continue; 1089df930be7Sderaadt if (removable != match->removable) 1090df930be7Sderaadt continue; 1091df930be7Sderaadt priority = 2; 1092df930be7Sderaadt len = strlen(match->vendor); 1093df930be7Sderaadt if (bcmp(inqbuf->vendor, match->vendor, len)) 1094df930be7Sderaadt continue; 1095df930be7Sderaadt priority += len; 1096df930be7Sderaadt len = strlen(match->product); 1097df930be7Sderaadt if (bcmp(inqbuf->product, match->product, len)) 1098df930be7Sderaadt continue; 1099df930be7Sderaadt priority += len; 1100df930be7Sderaadt len = strlen(match->revision); 1101df930be7Sderaadt if (bcmp(inqbuf->revision, match->revision, len)) 1102df930be7Sderaadt continue; 1103df930be7Sderaadt priority += len; 1104df930be7Sderaadt 110525efb03fSjsg #ifdef SCSIDEBUG 11069b0b1e37Skrw printf("scsi_inqmatch: "); 11079b0b1e37Skrw if (_base == &scsi_quirk_patterns) 11089b0b1e37Skrw printf(" quirk "); 11099b0b1e37Skrw else 11109b0b1e37Skrw printf(" match "); 11119b0b1e37Skrw 1112173a6623Skrw printf("priority %d. %s %s <\"%s\", \"%s\", \"%s\">", priority, 11132a40f7e1Skrw devicetypenames[(match->type & SID_TYPE)], 1114173a6623Skrw (match->removable == T_FIXED) ? "T_FIXED" : "T_REMOV", 1115df930be7Sderaadt match->vendor, match->product, match->revision); 11169b0b1e37Skrw 11179b0b1e37Skrw if (_base == &scsi_quirk_patterns) 11189b0b1e37Skrw printf(" quirks: 0x%04x", 1119ce9fc84eSkrw ((struct scsi_quirk_inquiry_pattern *)match)->quirks 1120ce9fc84eSkrw ); 11219b0b1e37Skrw 11229b0b1e37Skrw printf("\n"); 11239b0b1e37Skrw #endif /* SCSIDEBUG */ 1124df930be7Sderaadt if (priority > *bestpriority) { 1125df930be7Sderaadt *bestpriority = priority; 1126df930be7Sderaadt bestmatch = base; 1127df930be7Sderaadt } 1128df930be7Sderaadt } 1129df930be7Sderaadt 1130ce9fc84eSkrw return bestmatch; 1131df930be7Sderaadt } 1132758476e4Sdlg 1133758476e4Sdlg void 1134758476e4Sdlg scsi_devid(struct scsi_link *link) 1135758476e4Sdlg { 1136758476e4Sdlg struct { 1137758476e4Sdlg struct scsi_vpd_hdr hdr; 1138758476e4Sdlg u_int8_t list[32]; 11395c0b007dSderaadt } __packed *pg; 1140c6c609d5Sdlg size_t len; 1141ce9fc84eSkrw int pg80 = 0, pg83 = 0, i; 1142758476e4Sdlg 1143864c175eSdlg if (link->id != NULL) 1144864c175eSdlg return; 1145864c175eSdlg 11465c0b007dSderaadt pg = dma_alloc(sizeof(*pg), PR_WAITOK | PR_ZERO); 1147758476e4Sdlg 11487b732f28Skrw if (SID_ANSII_REV(&link->inqdata) >= SCSI_REV_2) { 11495c0b007dSderaadt if (scsi_inquire_vpd(link, pg, sizeof(*pg), SI_PG_SUPPORTED, 11505c0b007dSderaadt scsi_autoconf) != 0) 11514d409963Sdlg goto wwn; 11525c0b007dSderaadt 11535c0b007dSderaadt len = MIN(sizeof(pg->list), _2btol(pg->hdr.page_length)); 1154c6c609d5Sdlg for (i = 0; i < len; i++) { 11555c0b007dSderaadt switch (pg->list[i]) { 1156758476e4Sdlg case SI_PG_SERIAL: 1157758476e4Sdlg pg80 = 1; 1158758476e4Sdlg break; 1159758476e4Sdlg case SI_PG_DEVID: 1160758476e4Sdlg pg83 = 1; 1161758476e4Sdlg break; 1162758476e4Sdlg } 1163758476e4Sdlg } 1164758476e4Sdlg 1165758476e4Sdlg if (pg83 && scsi_devid_pg83(link) == 0) 11665c0b007dSderaadt goto done; 1167758476e4Sdlg if (pg80 && scsi_devid_pg80(link) == 0) 11685c0b007dSderaadt goto done; 1169758476e4Sdlg } 11704d409963Sdlg 11714d409963Sdlg wwn: 11724d409963Sdlg scsi_devid_wwn(link); 11735c0b007dSderaadt done: 11745c0b007dSderaadt dma_free(pg, sizeof(*pg)); 1175758476e4Sdlg } 1176758476e4Sdlg 1177758476e4Sdlg int 1178758476e4Sdlg scsi_devid_pg83(struct scsi_link *link) 1179758476e4Sdlg { 1180864c175eSdlg struct scsi_vpd_devid_hdr dhdr, chdr; 1181ce9fc84eSkrw struct scsi_vpd_hdr *hdr = NULL; 11825c0b007dSderaadt u_int8_t *pg = NULL, *id; 1183ce9fc84eSkrw int len, pos, rv, type; 1184ce9fc84eSkrw int idtype = 0; 1185864c175eSdlg u_char idflags; 1186758476e4Sdlg 11875c0b007dSderaadt hdr = dma_alloc(sizeof(*hdr), PR_WAITOK | PR_ZERO); 11885c0b007dSderaadt 11895c0b007dSderaadt rv = scsi_inquire_vpd(link, hdr, sizeof(*hdr), SI_PG_DEVID, 1190758476e4Sdlg scsi_autoconf); 1191758476e4Sdlg if (rv != 0) 11925c0b007dSderaadt goto done; 1193758476e4Sdlg 11945c0b007dSderaadt len = sizeof(*hdr) + _2btol(hdr->page_length); 11955c0b007dSderaadt pg = dma_alloc(len, PR_WAITOK | PR_ZERO); 1196758476e4Sdlg 1197758476e4Sdlg rv = scsi_inquire_vpd(link, pg, len, SI_PG_DEVID, scsi_autoconf); 1198758476e4Sdlg if (rv != 0) 11995c0b007dSderaadt goto done; 1200758476e4Sdlg 12015c0b007dSderaadt pos = sizeof(*hdr); 1202758476e4Sdlg 1203758476e4Sdlg do { 1204758476e4Sdlg if (len - pos < sizeof(dhdr)) { 1205758476e4Sdlg rv = EIO; 12065c0b007dSderaadt goto done; 1207758476e4Sdlg } 1208758476e4Sdlg memcpy(&dhdr, &pg[pos], sizeof(dhdr)); 1209758476e4Sdlg pos += sizeof(dhdr); 1210758476e4Sdlg if (len - pos < dhdr.len) { 1211758476e4Sdlg rv = EIO; 12125c0b007dSderaadt goto done; 1213758476e4Sdlg } 1214758476e4Sdlg 1215758476e4Sdlg if (VPD_DEVID_ASSOC(dhdr.flags) == VPD_DEVID_ASSOC_LU) { 1216758476e4Sdlg type = VPD_DEVID_TYPE(dhdr.flags); 1217758476e4Sdlg switch (type) { 1218758476e4Sdlg case VPD_DEVID_TYPE_NAA: 1219758476e4Sdlg case VPD_DEVID_TYPE_EUI64: 1220758476e4Sdlg case VPD_DEVID_TYPE_T10: 1221758476e4Sdlg if (type >= idtype) { 1222758476e4Sdlg idtype = type; 1223864c175eSdlg 1224864c175eSdlg chdr = dhdr; 1225758476e4Sdlg id = &pg[pos]; 1226758476e4Sdlg } 1227758476e4Sdlg break; 1228758476e4Sdlg 1229758476e4Sdlg default: 1230758476e4Sdlg /* skip */ 1231758476e4Sdlg break; 1232758476e4Sdlg } 1233758476e4Sdlg } 1234758476e4Sdlg 1235758476e4Sdlg pos += dhdr.len; 1236758476e4Sdlg } while (idtype != VPD_DEVID_TYPE_NAA && len != pos); 1237758476e4Sdlg 1238758476e4Sdlg if (idtype > 0) { 1239864c175eSdlg switch (VPD_DEVID_TYPE(chdr.flags)) { 1240758476e4Sdlg case VPD_DEVID_TYPE_NAA: 1241864c175eSdlg idtype = DEVID_NAA; 1242758476e4Sdlg break; 1243758476e4Sdlg case VPD_DEVID_TYPE_EUI64: 1244864c175eSdlg idtype = DEVID_EUI; 1245758476e4Sdlg break; 1246758476e4Sdlg case VPD_DEVID_TYPE_T10: 1247864c175eSdlg idtype = DEVID_T10; 1248758476e4Sdlg break; 1249758476e4Sdlg } 1250864c175eSdlg switch (VPD_DEVID_CODE(chdr.pi_code)) { 1251864c175eSdlg case VPD_DEVID_CODE_ASCII: 1252864c175eSdlg case VPD_DEVID_CODE_UTF8: 1253864c175eSdlg idflags = DEVID_F_PRINT; 1254864c175eSdlg break; 1255864c175eSdlg default: 1256864c175eSdlg idflags = 0; 1257864c175eSdlg break; 1258864c175eSdlg } 1259864c175eSdlg link->id = devid_alloc(idtype, idflags, chdr.len, id); 1260758476e4Sdlg } else 1261758476e4Sdlg rv = ENODEV; 1262758476e4Sdlg 12635c0b007dSderaadt done: 12645c0b007dSderaadt if (pg) 12655c0b007dSderaadt dma_free(pg, len); 12665c0b007dSderaadt if (hdr) 12675c0b007dSderaadt dma_free(hdr, sizeof(*hdr)); 1268ce9fc84eSkrw return rv; 1269758476e4Sdlg } 127001355dc1Smiod 12715b0d6b70Sdlg int 12725b0d6b70Sdlg scsi_devid_pg80(struct scsi_link *link) 12735b0d6b70Sdlg { 12745b0d6b70Sdlg struct scsi_vpd_hdr *hdr = NULL; 12755b0d6b70Sdlg u_int8_t *pg = NULL; 12765b0d6b70Sdlg char *id; 1277a67129dbStedu size_t idlen; 1278ce9fc84eSkrw int len, pglen, rv; 12795b0d6b70Sdlg 12805b0d6b70Sdlg hdr = dma_alloc(sizeof(*hdr), PR_WAITOK | PR_ZERO); 12815b0d6b70Sdlg 12825b0d6b70Sdlg rv = scsi_inquire_vpd(link, hdr, sizeof(*hdr), SI_PG_SERIAL, 12835b0d6b70Sdlg scsi_autoconf); 12845b0d6b70Sdlg if (rv != 0) 12855b0d6b70Sdlg goto freehdr; 12865b0d6b70Sdlg 12875b0d6b70Sdlg len = _2btol(hdr->page_length); 12885b0d6b70Sdlg if (len == 0) { 12895b0d6b70Sdlg rv = EINVAL; 12905b0d6b70Sdlg goto freehdr; 12915b0d6b70Sdlg } 12925b0d6b70Sdlg 12935b0d6b70Sdlg pglen = sizeof(*hdr) + len; 12945b0d6b70Sdlg pg = dma_alloc(pglen, PR_WAITOK | PR_ZERO); 12955b0d6b70Sdlg 12965b0d6b70Sdlg rv = scsi_inquire_vpd(link, pg, pglen, SI_PG_SERIAL, scsi_autoconf); 12975b0d6b70Sdlg if (rv != 0) 12985b0d6b70Sdlg goto free; 12995b0d6b70Sdlg 1300a67129dbStedu idlen = sizeof(link->inqdata.vendor) + 1301a67129dbStedu sizeof(link->inqdata.product) + len; 1302a67129dbStedu id = malloc(idlen, M_TEMP, M_WAITOK); 13035b0d6b70Sdlg memcpy(id, link->inqdata.vendor, sizeof(link->inqdata.vendor)); 13045b0d6b70Sdlg memcpy(id + sizeof(link->inqdata.vendor), link->inqdata.product, 13055b0d6b70Sdlg sizeof(link->inqdata.product)); 13065b0d6b70Sdlg memcpy(id + sizeof(link->inqdata.vendor) + 13075b0d6b70Sdlg sizeof(link->inqdata.product), pg + sizeof(*hdr), len); 13085b0d6b70Sdlg 13095b0d6b70Sdlg link->id = devid_alloc(DEVID_SERIAL, DEVID_F_PRINT, 13105b0d6b70Sdlg sizeof(link->inqdata.vendor) + sizeof(link->inqdata.product) + len, 13115b0d6b70Sdlg id); 13125b0d6b70Sdlg 1313a67129dbStedu free(id, M_TEMP, idlen); 13145b0d6b70Sdlg 13155b0d6b70Sdlg free: 13165b0d6b70Sdlg dma_free(pg, pglen); 13175b0d6b70Sdlg freehdr: 13185b0d6b70Sdlg dma_free(hdr, sizeof(*hdr)); 1319ce9fc84eSkrw return rv; 13205b0d6b70Sdlg } 13215b0d6b70Sdlg 13224d409963Sdlg int 13234d409963Sdlg scsi_devid_wwn(struct scsi_link *link) 13244d409963Sdlg { 13254d409963Sdlg u_int64_t wwnn; 13264d409963Sdlg 13274d409963Sdlg if (link->lun != 0 || link->node_wwn == 0) 1328ce9fc84eSkrw return EOPNOTSUPP; 13294d409963Sdlg 13304d409963Sdlg wwnn = htobe64(link->node_wwn); 13314d409963Sdlg link->id = devid_alloc(DEVID_WWN, 0, sizeof(wwnn), (u_int8_t *)&wwnn); 13324d409963Sdlg 1333ce9fc84eSkrw return 0; 13344d409963Sdlg } 13354d409963Sdlg 1336864c175eSdlg struct devid * 1337864c175eSdlg devid_alloc(u_int8_t type, u_int8_t flags, u_int8_t len, u_int8_t *id) 1338864c175eSdlg { 1339864c175eSdlg struct devid *d; 1340864c175eSdlg 1341864c175eSdlg d = malloc(sizeof(*d) + len, M_DEVBUF, M_WAITOK|M_CANFAIL); 1342864c175eSdlg if (d == NULL) 1343ce9fc84eSkrw return NULL; 1344864c175eSdlg 1345864c175eSdlg d->d_type = type; 1346864c175eSdlg d->d_flags = flags; 1347864c175eSdlg d->d_len = len; 1348864c175eSdlg d->d_refcount = 1; 1349864c175eSdlg memcpy(d + 1, id, len); 1350864c175eSdlg 1351ce9fc84eSkrw return d; 1352864c175eSdlg } 1353864c175eSdlg 1354864c175eSdlg struct devid * 1355864c175eSdlg devid_copy(struct devid *d) 1356864c175eSdlg { 1357864c175eSdlg d->d_refcount++; 1358ce9fc84eSkrw return d; 1359864c175eSdlg } 1360864c175eSdlg 1361864c175eSdlg void 1362864c175eSdlg devid_free(struct devid *d) 1363864c175eSdlg { 1364864c175eSdlg if (--d->d_refcount == 0) 1365a67129dbStedu free(d, M_DEVBUF, sizeof(*d) + d->d_len); 1366864c175eSdlg } 1367