1 /*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4
5 /*
6 * BSD 3 Clause License
7 *
8 * Copyright (c) 2007, The Storage Networking Industry Association.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * - Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * - Neither the name of The Storage Networking Industry Association (SNIA)
22 * nor the names of its contributors may be used to endorse or promote
23 * products derived from this software without specific prior written
24 * permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38 #include <sys/errno.h>
39 #include <sys/types.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <ctype.h>
43 #include <sys/byteorder.h>
44 #include <sys/scsi/impl/uscsi.h>
45 #include <sys/scsi/scsi.h>
46 #include <tlm.h>
47 #include <pthread.h>
48 #include "tlm_proto.h"
49
50 /*
51 * generic routine to read a SCSI page
52 */
53 int
read_scsi_page(scsi_link_t * slink,union scsi_cdb * cdb,int command_size,caddr_t data,int size)54 read_scsi_page(scsi_link_t *slink, union scsi_cdb *cdb,
55 int command_size, caddr_t data, int size)
56 {
57 struct uscsi_cmd uscsi_cmd;
58 char *dname;
59 int dev;
60
61 if (slink == 0 || slink->sl_sa == 0)
62 return (EINVAL);
63
64 (void) memset(&uscsi_cmd, 0, sizeof (uscsi_cmd));
65
66 /* Lun is in the 5th bit */
67 cdb->scc_lun = slink->sl_lun;
68 uscsi_cmd.uscsi_flags |= USCSI_READ | USCSI_ISOLATE;
69 uscsi_cmd.uscsi_bufaddr = data;
70 uscsi_cmd.uscsi_buflen = size;
71 uscsi_cmd.uscsi_timeout = 1000;
72 uscsi_cmd.uscsi_cdb = (char *)cdb;
73
74 if (cdb->scc_cmd == SCMD_READ_ELEMENT_STATUS) {
75 uscsi_cmd.uscsi_flags |= USCSI_RQENABLE;
76 uscsi_cmd.uscsi_rqbuf = data;
77 uscsi_cmd.uscsi_rqlen = size;
78 }
79 uscsi_cmd.uscsi_cdblen = command_size;
80
81 dname = sasd_slink_name(slink);
82 dev = open(dname, O_RDWR | O_NDELAY);
83 if (dev == -1) {
84 NDMP_LOG(LOG_DEBUG, "Open failed for %s err=%d",
85 dname, errno);
86 return (errno);
87 }
88 if (tlm_ioctl(dev, USCSICMD, &uscsi_cmd) < 0) {
89 NDMP_LOG(LOG_DEBUG, "SCSI cmd %d failed for %s err=%d",
90 cdb->scc_cmd, dname, errno);
91 (void) close(dev);
92 return (errno);
93 }
94 (void) close(dev);
95 return (uscsi_cmd.uscsi_status);
96 }
97
98 /*
99 * Read the Inquiry Page.
100 */
101 static int
read_inquiry_page(scsi_link_t * slink,struct scsi_inquiry * inq)102 read_inquiry_page(scsi_link_t *slink, struct scsi_inquiry *inq)
103 {
104 union scsi_cdb cdb;
105
106 (void) memset(&cdb, 0, sizeof (union scsi_cdb));
107 cdb.scc_cmd = SCMD_INQUIRY;
108 cdb.g0_count0 = sizeof (struct scsi_inquiry);
109
110 return (read_scsi_page(slink, &cdb, CDB_GROUP0,
111 (caddr_t)inq, sizeof (*inq)) ? -1 : 0);
112 }
113
114 /*
115 * Read the Product Data Page.
116 */
117 static int
read_data_page(scsi_link_t * slink,int pcode,char * snum,int size)118 read_data_page(scsi_link_t *slink, int pcode, char *snum, int size)
119 {
120 char cmd[CDB_GROUP0];
121
122 (void) memset(cmd, 0, sizeof (cmd));
123
124 cmd[0] = SCMD_INQUIRY;
125 cmd[1] = pcode ? 0x01 : 0x00;
126 cmd[2] = pcode;
127 cmd[4] = size;
128
129 /* LINTED improper alignment */
130 return (read_scsi_page(slink, (union scsi_cdb *)&cmd, CDB_GROUP0,
131 (caddr_t)snum, size) == -1 ? -1 : 0);
132 }
133
134
135 /*
136 * Read the Serial Number Page.
137 */
138 static int
read_serial_num_page(scsi_link_t * slink,char * snum,int size)139 read_serial_num_page(scsi_link_t *slink, char *snum, int size)
140 {
141 scsi_serial_t serial;
142 int rv;
143
144 (void) memset(&serial, 0, sizeof (scsi_serial_t));
145 rv = read_data_page(slink, SCSI_SERIAL_PAGE, (caddr_t)&serial,
146 sizeof (scsi_serial_t));
147 (void) strlcpy(snum, serial.sr_num, size);
148
149 return (rv == -1 ? -1 : 0);
150 }
151
152
153 /*
154 * Read the Device Name Page.
155 */
156 static int
read_dev_name_page(scsi_link_t * slink,device_ident_header_t * devp,int len)157 read_dev_name_page(scsi_link_t *slink, device_ident_header_t *devp, int len)
158 {
159 (void) memset(devp, 0, len);
160
161 if (read_data_page(slink, SCSI_DEVICE_IDENT_PAGE, (caddr_t)devp,
162 len) == -1)
163 return (-1);
164
165 if (devp->di_page_code != SCSI_DEVICE_IDENT_PAGE)
166 return (-1);
167
168 return (0);
169 }
170
171 /*
172 * Formatted print of WWN
173 */
174 static void
snprintf_wwn(char * buf,int size,uint8_t * wwn)175 snprintf_wwn(char *buf, int size, uint8_t *wwn)
176 {
177 if (wwn == NULL || buf == NULL)
178 return;
179
180 (void) snprintf(buf, size, "0x%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
181 wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
182 }
183
184
185 /*
186 * Extract and print the world wide name (WWN)
187 */
188 int
read_device_wwn(scsi_link_t * slink,char * wwnp,int wsize)189 read_device_wwn(scsi_link_t *slink, char *wwnp, int wsize)
190 {
191 device_ident_header_t *header;
192 name_ident_t *ident;
193 uint16_t page_len = sizeof (device_ident_header_t);
194 uint16_t act_len;
195 int accessed;
196 uint8_t *designator_data;
197
198 (void) memset(wwnp, 0, wsize);
199 resize:
200 header = malloc(page_len);
201 if (header == NULL)
202 return (-1);
203
204 if (read_dev_name_page(slink, header, page_len) == -1) {
205 free(header);
206 return (-1);
207 }
208
209 act_len = BE_16(header->di_page_length);
210 if (act_len > page_len) {
211 free(header);
212 page_len = act_len;
213 goto resize;
214 }
215
216 ident = (name_ident_t *)&header[1];
217 accessed = sizeof (device_ident_header_t);
218
219 while (accessed < act_len) {
220
221 accessed += sizeof (name_ident_t);
222 accessed += ident->ni_ident_length;
223 designator_data = (uint8_t *)&ident[1];
224 /*
225 * Looking for code set 1 (Binary) ident type NAA 64 bit
226 * address that is associated with the node (0).
227 */
228 if ((ident->ni_code_set == 1) &&
229 (ident->ni_ident_type == 3)) {
230 snprintf_wwn(wwnp, wsize, designator_data);
231 /*
232 * If assc is zero (Node) this is the one we want.
233 * If we find that we're done.
234 */
235 if (ident->ni_asso == 0)
236 break;
237 }
238 /*
239 * If we find a EUI-64 we can use that also.
240 */
241 if ((ident->ni_code_set == 2) &&
242 (ident->ni_ident_type == 1) &&
243 (ident->ni_asso == 0) &&
244 (isprint(wwnp[0] == 0))) { /* Don't overwrite */
245 /*
246 * This isn't our first choice but we'll print it
247 * in case there is nothing else to use.
248 */
249 (void) snprintf(wwnp, wsize, "%.*s",
250 ident->ni_ident_length, designator_data);
251 }
252 ident =
253 (name_ident_t *)&designator_data[ident->ni_ident_length];
254 }
255 free(header);
256 /*
257 * See if we found something.
258 * Memset above would leave wwnp not printable.
259 */
260 if (isprint(wwnp[0]))
261 return (0);
262 return (-1);
263 }
264
265 /*
266 * Add the tape library call back function (used while scanning the bus)
267 */
268 static int
add_lib(scsi_link_t * slink,struct scsi_inquiry * sd,void * arg)269 add_lib(scsi_link_t *slink, struct scsi_inquiry *sd, void *arg)
270 {
271 int l;
272 int *nlp; /* pointer to library counter */
273 sasd_drive_t *ssd;
274
275 if (!slink || !sd) {
276 NDMP_LOG(LOG_DEBUG, "Invalid argument %x %x %x",
277 slink, sd, arg);
278 return (-TLM_INVALID);
279 }
280
281 if (sd->inq_dtype == DTYPE_CHANGER) {
282 /* This is a robot, which means this is also a library */
283 nlp = (int *)arg;
284 (*nlp)++;
285 l = tlm_insert_new_library(slink);
286 tlm_enable_barcode(l);
287
288 NDMP_LOG(LOG_DEBUG, "lib %d sid %d lun %d",
289 l, slink->sl_sid, slink->sl_lun);
290
291 if ((ssd = sasd_slink_drive(slink)) != NULL) {
292 (void) strlcpy(ssd->sd_vendor, sd->inq_vid,
293 sizeof (ssd->sd_vendor));
294 (void) strlcpy(ssd->sd_id, sd->inq_pid,
295 sizeof (ssd->sd_id));
296 (void) strlcpy(ssd->sd_rev, sd->inq_revision,
297 sizeof (ssd->sd_rev));
298 (void) read_serial_num_page(slink, ssd->sd_serial,
299 sizeof (ssd->sd_serial));
300 (void) read_device_wwn(slink, ssd->sd_wwn,
301 sizeof (ssd->sd_wwn));
302 }
303 }
304
305 return (TLM_NO_ERRORS);
306 }
307
308 /*
309 * Create some virutal slots
310 */
311 static int
make_virtual_slot(int l,tlm_drive_t * dp)312 make_virtual_slot(int l, tlm_drive_t *dp)
313 {
314 int s;
315 tlm_slot_t *sp;
316
317 if (l <= 0 || !dp) {
318 NDMP_LOG(LOG_DEBUG, "Invalid argument %d, %x", l, dp);
319 return (-TLM_INVALID);
320 }
321
322 if ((s = tlm_insert_new_slot(l)) <= 0)
323 return (-TLM_NO_MEMORY);
324
325 if (!(sp = tlm_slot(l, s))) {
326 NDMP_LOG(LOG_DEBUG, "Internal error: slot not found %d", s);
327 return (-TLM_ERROR_INTERNAL);
328 }
329 /*
330 * For virtual slots element number is 0 and they are always full.
331 */
332 sp->ts_element = 0;
333 sp->ts_status_full = TRUE;
334 return (TLM_NO_ERRORS);
335 }
336
337 /*
338 * Make the tape drive not part of a tape library (stand alone)
339 */
340 static int
make_stand_alone_drive(scsi_link_t * slink,int l)341 make_stand_alone_drive(scsi_link_t *slink, int l)
342 {
343 int d;
344 tlm_drive_t *dp;
345
346 if (!slink || l <= 0) {
347 NDMP_LOG(LOG_DEBUG, "Invalid argument %x %d", slink, l);
348 return (-TLM_INVALID);
349 }
350
351 d = tlm_insert_new_drive(l);
352 if (!(dp = tlm_drive(l, d))) {
353 NDMP_LOG(LOG_DEBUG, "Internal error: drive not found %d", d);
354 return (-TLM_ERROR_INTERNAL);
355 }
356
357 /* For stand-alone drives, the element number is the drive number. */
358 dp->td_element = d;
359 dp->td_slink = slink;
360 dp->td_scsi_id = slink->sl_sid;
361 dp->td_lun = slink->sl_lun;
362 dp->td_exists = TRUE;
363
364 /*
365 * Note: There is no way to remove library elements. We cannot clean
366 * up if make_virtual_slot() fails.
367 */
368 (void) make_virtual_slot(l, dp);
369 return (d);
370 }
371
372 /*
373 * Find the LIBRARY structure that has control of this DRIVE.
374 */
375 static int
new_drive(scsi_link_t * slink,int * lib)376 new_drive(scsi_link_t *slink, int *lib)
377 {
378 int d;
379 tlm_drive_t *dp;
380 tlm_library_t *lp;
381
382 /* Walk through all libraries. */
383 for (*lib = 1; *lib <= tlm_library_count(); (*lib)++) {
384 if (!(lp = tlm_library(*lib)))
385 continue;
386 /* Walk through drives that are already found. */
387 for (d = 1; d <= lp->tl_drive_count; d++) {
388 if (!(dp = tlm_drive(*lib, d)))
389 continue;
390 if (dp->td_scsi_id == slink->sl_sid &&
391 dp->td_lun == slink->sl_lun)
392 return (d);
393 }
394 }
395
396 /* Not part of any library, this is a newly found tape drive. */
397 return (0);
398 }
399
400
401 /*
402 * Add the tape library call back function (used while scanning the bus)
403 */
404 static int
add_drv(scsi_link_t * slink,struct scsi_inquiry * sd,void * arg)405 add_drv(scsi_link_t *slink, struct scsi_inquiry *sd, void *arg)
406 {
407 int l, d;
408 int *vlp; /* pointer to virtual library number */
409 sasd_drive_t *ssd;
410 tlm_library_t *library;
411 tlm_drive_t *drive;
412
413 if (!slink || !sd) {
414 NDMP_LOG(LOG_DEBUG, "Invalid argument %x %x %x",
415 slink, sd, arg);
416 return (-TLM_INVALID);
417 }
418
419 if (sd->inq_dtype == DTYPE_SEQUENTIAL) {
420 vlp = (int *)arg;
421 d = new_drive(slink, &l);
422 if (d == 0) {
423 /* This tape drive was not found inside any robot. */
424 if (*vlp == 0) {
425 /*
426 * First, create a virtual library if it's not
427 * done yet.
428 */
429 *vlp = tlm_insert_new_library(slink);
430 if ((library = tlm_library(*vlp)) != NULL)
431 library->tl_capability_robot = FALSE;
432 }
433 if ((d = make_stand_alone_drive(slink, *vlp)) < 0) {
434 /* sorry, we can not clean up the vlib now * */
435 return (-TLM_INVALID);
436 }
437 l = *vlp;
438 NDMP_LOG(LOG_DEBUG, "vlib(%d, %d) sid %d lun %d",
439 l, d, slink->sl_sid, slink->sl_lun);
440 } else
441 NDMP_LOG(LOG_DEBUG, "(%d, %d) sid %d lun %d",
442 l, d, slink->sl_sid, slink->sl_lun);
443
444 if ((drive = tlm_drive(l, d)) != NULL) {
445 drive->td_exists = TRUE;
446 drive->td_slink = slink;
447 }
448 if ((ssd = sasd_slink_drive(slink)) != NULL) {
449 (void) strlcpy(ssd->sd_vendor,
450 sd->inq_vid, sizeof (ssd->sd_vendor));
451 (void) strlcpy(ssd->sd_id, sd->inq_pid,
452 sizeof (ssd->sd_id));
453 (void) strlcpy(ssd->sd_rev, sd->inq_revision,
454 sizeof (ssd->sd_rev));
455 (void) read_serial_num_page(slink, ssd->sd_serial,
456 sizeof (ssd->sd_serial));
457 (void) read_device_wwn(slink, ssd->sd_wwn,
458 sizeof (ssd->sd_wwn));
459 }
460 }
461
462 return (TLM_NO_ERRORS);
463 }
464
465 /*
466 * Scan the specified bus and call the handler function.
467 */
468 static int
scan_bus(scsi_adapter_t * sa,int (* hndlr)(),void * args)469 scan_bus(scsi_adapter_t *sa, int(*hndlr)(), void *args)
470 {
471 int nerr;
472 scsi_link_t *slink;
473 struct scsi_inquiry scsi_data;
474
475 nerr = 0;
476 slink = sa->sa_link_head.sl_next;
477 for (; slink != &sa->sa_link_head; slink = slink->sl_next) {
478 (void) memset(&scsi_data, 0, sizeof (struct scsi_inquiry));
479 if (read_inquiry_page(slink, &scsi_data) == -1)
480 nerr++;
481 else
482 if ((*hndlr)(slink, &scsi_data, args) != TLM_NO_ERRORS)
483 nerr++;
484 }
485
486 return (nerr);
487 }
488
489 /*
490 * Marks the library/slots inaccessible if there are not enough drives
491 * available on the library
492 */
493 static void
inaccbl_drv_warn(int start,int max)494 inaccbl_drv_warn(int start, int max)
495 {
496 char *dname;
497 int l, d;
498 tlm_library_t *lp;
499
500 for (l = start; l < max; l++) {
501 if (!(lp = tlm_library(l)))
502 continue;
503 if (lp->tl_drive_count <= 0)
504 continue;
505
506 NDMP_LOG(LOG_DEBUG,
507 "Warning: The following drives are not accessible:");
508 for (d = 1; d <= lp->tl_drive_count; d++)
509 if (!(dname = tlm_get_tape_name(l, d))) {
510 NDMP_LOG(LOG_DEBUG,
511 "Error getting drive(%d, %d)", l, d);
512 } else
513 NDMP_LOG(LOG_DEBUG, "%s", dname);
514
515 /*
516 * Note: Make the slots inaccessible to prevent running
517 * discovery on these libraries. The better idea is
518 * removing these libraries, but we don't have that
519 * feature available now.
520 */
521 lp->tl_slot_count = 0;
522 }
523 }
524
525 /*
526 * Initialize the tape library data structure, asks the libraries what
527 * equipments they have.
528 */
529 int
tlm_init(void)530 tlm_init(void)
531 {
532 static int nlibs; /* number of found libraries */
533 int i, nsa;
534 int l, vlibs, d;
535 int rv;
536 scsi_adapter_t *sa;
537 tlm_library_t *lp;
538 tlm_drive_t *dp;
539
540 /* Search through all SCSI adapters, look for tape robots. */
541 nlibs = 0;
542
543 /*
544 * We probe both changers and tape drives here
545 * but later on this needs to be removed as the
546 * probe will happen somewhere else.
547 */
548 if (probe_scsi() < 0)
549 return (-1);
550
551 nsa = scsi_get_adapter_count();
552 for (i = 0; i < nsa; i++)
553 if ((sa = scsi_get_adapter(i)))
554 (void) scan_bus(sa, add_lib, (void *)&nlibs);
555
556 NDMP_LOG(LOG_DEBUG, "nlibs %d", nlibs);
557
558 /* Search through all SCSI adapters, look for tape drives. */
559 vlibs = 0;
560 for (i = 0; i < nsa; i++)
561 if ((sa = scsi_get_adapter(i)))
562 (void) scan_bus(sa, add_drv, (void *)&vlibs);
563
564 NDMP_LOG(LOG_DEBUG, "vlibs %d", vlibs);
565
566 if (nlibs > 0 && vlibs > 0)
567 inaccbl_drv_warn(nlibs + 1, vlibs + nlibs + 1);
568
569 for (l = 1; l <= tlm_library_count(); l++) {
570 if (!(lp = tlm_library(l))) {
571 NDMP_LOG(LOG_DEBUG, "can't find lib %d", l);
572 continue;
573 }
574
575 /*
576 * Make sure all libraries have tape drives.
577 */
578 if (lp->tl_drive_count == 0)
579 continue;
580
581 /*
582 * Make sure all tape drives exist. A drive that is not
583 * linked into the SCSI chain will be seen by the library
584 * but we cannot talk to it.
585 */
586 for (d = 1; d <= lp->tl_drive_count; d++) {
587 dp = tlm_drive(l, d);
588 if (dp && !dp->td_exists) {
589 NDMP_LOG(LOG_DEBUG, "Ghost drive found %d.%d",
590 l, d);
591 lp->tl_ghost_drives = TRUE;
592 continue;
593 }
594 }
595 }
596
597 if (nlibs > 0)
598 rv = (vlibs > 0) ? 0 : nlibs;
599 else
600 rv = vlibs;
601
602 return (rv);
603 }
604