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