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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 (void) probe_scsi(); 549 550 nsa = scsi_get_adapter_count(); 551 for (i = 0; i < nsa; i++) 552 if ((sa = scsi_get_adapter(i))) 553 (void) scan_bus(sa, add_lib, (void *)&nlibs); 554 555 NDMP_LOG(LOG_DEBUG, "nlibs %d", nlibs); 556 557 /* Search through all SCSI adapters, look for tape drives. */ 558 vlibs = 0; 559 for (i = 0; i < nsa; i++) 560 if ((sa = scsi_get_adapter(i))) 561 (void) scan_bus(sa, add_drv, (void *)&vlibs); 562 563 NDMP_LOG(LOG_DEBUG, "vlibs %d", 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 NDMP_LOG(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 NDMP_LOG(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 } 603