xref: /openbsd/sys/scsi/scsiconf.c (revision 29220739)
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
scsiprint(void * aux,const char * pnp)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
scsibusmatch(struct device * parent,void * match,void * aux)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
scsibusattach(struct device * parent,struct device * self,void * aux)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
scsibusactivate(struct device * dev,int act)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
scsibusdetach(struct device * dev,int type)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
scsibussubmatch(struct device * parent,void * match,void * aux)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
scsibussubprint(void * aux,const char * pnp)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
scsibusbioctl(struct device * dev,u_long cmd,caddr_t addr)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
scsi_activate(struct scsibus_softc * sb,int target,int lun,int act)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
scsi_activate_bus(struct scsibus_softc * sb,int act)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
scsi_activate_target(struct scsibus_softc * sb,int target,int act)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
scsi_activate_lun(struct scsibus_softc * sb,int target,int lun,int act)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
scsi_activate_link(struct scsi_link * link,int act)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
scsi_probe(struct scsibus_softc * sb,int target,int lun)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
scsi_probe_bus(struct scsibus_softc * sb)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
scsi_probe_target(struct scsibus_softc * sb,int target)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
scsi_probe_lun(struct scsibus_softc * sb,int target,int lun)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
scsi_probe_link(struct scsibus_softc * sb,int target,int lun,int dumbscan)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
scsi_detach(struct scsibus_softc * sb,int target,int lun,int flags)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
scsi_detach_bus(struct scsibus_softc * sb,int flags)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
scsi_detach_target(struct scsibus_softc * sb,int target,int flags)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
scsi_detach_lun(struct scsibus_softc * sb,int target,int lun,int flags)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
scsi_detach_link(struct scsi_link * link,int flags)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 *
scsi_get_link(struct scsibus_softc * sb,int target,int lun)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
scsi_add_link(struct scsi_link * link)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
scsi_remove_link(struct scsi_link * link)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
scsi_get_target_luns(struct scsibus_softc * sb,int target,struct scsi_lun_array * lunarray)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
scsi_strvis(u_char * dst,u_char * src,int len)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) + '0';
963 				*dst++ = ((*src & 0070) >> 3) + '0';
964 				*dst++ = ((*src & 0007) >> 0) + '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
scsi_print_link(struct scsi_link * link)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 *
scsi_inqmatch(struct scsi_inquiry_data * inqbuf,const void * _base,int nmatches,int matchsize,int * bestpriority)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
scsi_devid(struct scsi_link * link)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
scsi_devid_pg83(struct scsi_link * link)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
scsi_devid_pg80(struct scsi_link * link)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
scsi_devid_wwn(struct scsi_link * link)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 *
devid_alloc(u_int8_t type,u_int8_t flags,u_int8_t len,u_int8_t * id)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 *
devid_copy(struct devid * d)1355 devid_copy(struct devid *d)
1356 {
1357 	d->d_refcount++;
1358 	return d;
1359 }
1360 
1361 void
devid_free(struct devid * d)1362 devid_free(struct devid *d)
1363 {
1364 	if (--d->d_refcount == 0)
1365 		free(d, M_DEVBUF, sizeof(*d) + d->d_len);
1366 }
1367