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