12654012fSReza Sabdar /* 2e461e790SRandall Ralphs * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 32654012fSReza Sabdar */ 42654012fSReza Sabdar 52654012fSReza Sabdar /* 62654012fSReza Sabdar * BSD 3 Clause License 72654012fSReza Sabdar * 82654012fSReza Sabdar * Copyright (c) 2007, The Storage Networking Industry Association. 92654012fSReza Sabdar * 102654012fSReza Sabdar * Redistribution and use in source and binary forms, with or without 112654012fSReza Sabdar * modification, are permitted provided that the following conditions 122654012fSReza Sabdar * are met: 132654012fSReza Sabdar * - Redistributions of source code must retain the above copyright 142654012fSReza Sabdar * notice, this list of conditions and the following disclaimer. 152654012fSReza Sabdar * 162654012fSReza Sabdar * - Redistributions in binary form must reproduce the above copyright 172654012fSReza Sabdar * notice, this list of conditions and the following disclaimer in 182654012fSReza Sabdar * the documentation and/or other materials provided with the 192654012fSReza Sabdar * distribution. 202654012fSReza Sabdar * 212654012fSReza Sabdar * - Neither the name of The Storage Networking Industry Association (SNIA) 222654012fSReza Sabdar * nor the names of its contributors may be used to endorse or promote 232654012fSReza Sabdar * products derived from this software without specific prior written 242654012fSReza Sabdar * permission. 252654012fSReza Sabdar * 262654012fSReza Sabdar * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 272654012fSReza Sabdar * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 282654012fSReza Sabdar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 292654012fSReza Sabdar * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 302654012fSReza Sabdar * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 312654012fSReza Sabdar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 322654012fSReza Sabdar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 332654012fSReza Sabdar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 342654012fSReza Sabdar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 352654012fSReza Sabdar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 362654012fSReza Sabdar * POSSIBILITY OF SUCH DAMAGE. 372654012fSReza Sabdar */ 382654012fSReza Sabdar #include <sys/errno.h> 392654012fSReza Sabdar #include <sys/types.h> 402654012fSReza Sabdar #include <stdlib.h> 412654012fSReza Sabdar #include <unistd.h> 42e461e790SRandall Ralphs #include <ctype.h> 43e461e790SRandall Ralphs #include <sys/byteorder.h> 442654012fSReza Sabdar #include <sys/scsi/impl/uscsi.h> 452654012fSReza Sabdar #include <sys/scsi/scsi.h> 462654012fSReza Sabdar #include <tlm.h> 472654012fSReza Sabdar #include <pthread.h> 482654012fSReza Sabdar #include "tlm_proto.h" 492654012fSReza Sabdar 502654012fSReza Sabdar /* 512654012fSReza Sabdar * generic routine to read a SCSI page 522654012fSReza Sabdar */ 532654012fSReza Sabdar int 542654012fSReza Sabdar read_scsi_page(scsi_link_t *slink, union scsi_cdb *cdb, 552654012fSReza Sabdar int command_size, caddr_t data, int size) 562654012fSReza Sabdar { 572654012fSReza Sabdar struct uscsi_cmd uscsi_cmd; 582654012fSReza Sabdar char *dname; 592654012fSReza Sabdar int dev; 602654012fSReza Sabdar 612654012fSReza Sabdar if (slink == 0 || slink->sl_sa == 0) 622654012fSReza Sabdar return (EINVAL); 632654012fSReza Sabdar 642654012fSReza Sabdar (void) memset(&uscsi_cmd, 0, sizeof (uscsi_cmd)); 652654012fSReza Sabdar 662654012fSReza Sabdar /* Lun is in the 5th bit */ 672654012fSReza Sabdar cdb->scc_lun = slink->sl_lun; 682654012fSReza Sabdar uscsi_cmd.uscsi_flags |= USCSI_READ | USCSI_ISOLATE; 692654012fSReza Sabdar uscsi_cmd.uscsi_bufaddr = data; 702654012fSReza Sabdar uscsi_cmd.uscsi_buflen = size; 712654012fSReza Sabdar uscsi_cmd.uscsi_timeout = 1000; 722654012fSReza Sabdar uscsi_cmd.uscsi_cdb = (char *)cdb; 732654012fSReza Sabdar 742654012fSReza Sabdar if (cdb->scc_cmd == SCMD_READ_ELEMENT_STATUS) { 752654012fSReza Sabdar uscsi_cmd.uscsi_flags |= USCSI_RQENABLE; 762654012fSReza Sabdar uscsi_cmd.uscsi_rqbuf = data; 772654012fSReza Sabdar uscsi_cmd.uscsi_rqlen = size; 782654012fSReza Sabdar } 792654012fSReza Sabdar uscsi_cmd.uscsi_cdblen = command_size; 802654012fSReza Sabdar 812654012fSReza Sabdar dname = sasd_slink_name(slink); 822654012fSReza Sabdar dev = open(dname, O_RDWR | O_NDELAY); 832654012fSReza Sabdar if (dev == -1) { 842654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Open failed for %s err=%d", 852654012fSReza Sabdar dname, errno); 862654012fSReza Sabdar return (errno); 872654012fSReza Sabdar } 882654012fSReza Sabdar if (tlm_ioctl(dev, USCSICMD, &uscsi_cmd) < 0) { 892654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "SCSI cmd %d failed for %s err=%d", 902654012fSReza Sabdar cdb->scc_cmd, dname, errno); 912654012fSReza Sabdar (void) close(dev); 922654012fSReza Sabdar return (errno); 932654012fSReza Sabdar } 942654012fSReza Sabdar (void) close(dev); 952654012fSReza Sabdar return (uscsi_cmd.uscsi_status); 962654012fSReza Sabdar } 972654012fSReza Sabdar 982654012fSReza Sabdar /* 992654012fSReza Sabdar * Read the Inquiry Page. 1002654012fSReza Sabdar */ 1012654012fSReza Sabdar static int 1022654012fSReza Sabdar read_inquiry_page(scsi_link_t *slink, struct scsi_inquiry *inq) 1032654012fSReza Sabdar { 1042654012fSReza Sabdar union scsi_cdb cdb; 1052654012fSReza Sabdar 1062654012fSReza Sabdar (void) memset(&cdb, 0, sizeof (union scsi_cdb)); 1072654012fSReza Sabdar cdb.scc_cmd = SCMD_INQUIRY; 1082654012fSReza Sabdar cdb.g0_count0 = sizeof (struct scsi_inquiry); 1092654012fSReza Sabdar 1102654012fSReza Sabdar return (read_scsi_page(slink, &cdb, CDB_GROUP0, 1112654012fSReza Sabdar (caddr_t)inq, sizeof (*inq)) ? -1 : 0); 1122654012fSReza Sabdar } 1132654012fSReza Sabdar 1142654012fSReza Sabdar /* 1157bc22e45SReza Sabdar * Read the Product Data Page. 1167bc22e45SReza Sabdar */ 1177bc22e45SReza Sabdar static int 1187bc22e45SReza Sabdar read_data_page(scsi_link_t *slink, int pcode, char *snum, int size) 1197bc22e45SReza Sabdar { 1207bc22e45SReza Sabdar char cmd[CDB_GROUP0]; 1217bc22e45SReza Sabdar 1227bc22e45SReza Sabdar (void) memset(cmd, 0, sizeof (cmd)); 1237bc22e45SReza Sabdar 1247bc22e45SReza Sabdar cmd[0] = SCMD_INQUIRY; 1257bc22e45SReza Sabdar cmd[1] = pcode ? 0x01 : 0x00; 1267bc22e45SReza Sabdar cmd[2] = pcode; 1277bc22e45SReza Sabdar cmd[4] = size; 1287bc22e45SReza Sabdar 1297bc22e45SReza Sabdar /* LINTED improper alignment */ 1307bc22e45SReza Sabdar return (read_scsi_page(slink, (union scsi_cdb *)&cmd, CDB_GROUP0, 1317bc22e45SReza Sabdar (caddr_t)snum, size) == -1 ? -1 : 0); 1327bc22e45SReza Sabdar } 1337bc22e45SReza Sabdar 1347bc22e45SReza Sabdar 1357bc22e45SReza Sabdar /* 1367bc22e45SReza Sabdar * Read the Serial Number Page. 1377bc22e45SReza Sabdar */ 1387bc22e45SReza Sabdar static int 1397bc22e45SReza Sabdar read_serial_num_page(scsi_link_t *slink, char *snum, int size) 1407bc22e45SReza Sabdar { 1417bc22e45SReza Sabdar scsi_serial_t serial; 1427bc22e45SReza Sabdar int rv; 1437bc22e45SReza Sabdar 1447bc22e45SReza Sabdar (void) memset(&serial, 0, sizeof (scsi_serial_t)); 1457bc22e45SReza Sabdar rv = read_data_page(slink, SCSI_SERIAL_PAGE, (caddr_t)&serial, 1467bc22e45SReza Sabdar sizeof (scsi_serial_t)); 1477bc22e45SReza Sabdar (void) strlcpy(snum, serial.sr_num, size); 1487bc22e45SReza Sabdar 1497bc22e45SReza Sabdar return (rv == -1 ? -1 : 0); 1507bc22e45SReza Sabdar } 1517bc22e45SReza Sabdar 1527bc22e45SReza Sabdar 1537bc22e45SReza Sabdar /* 1547bc22e45SReza Sabdar * Read the Device Name Page. 1557bc22e45SReza Sabdar */ 1567bc22e45SReza Sabdar static int 157e461e790SRandall Ralphs read_dev_name_page(scsi_link_t *slink, device_ident_header_t *devp, int len) 1587bc22e45SReza Sabdar { 159e461e790SRandall Ralphs (void) memset(devp, 0, len); 1607bc22e45SReza Sabdar 1617bc22e45SReza Sabdar if (read_data_page(slink, SCSI_DEVICE_IDENT_PAGE, (caddr_t)devp, 162e461e790SRandall Ralphs len) == -1) 1637bc22e45SReza Sabdar return (-1); 1647bc22e45SReza Sabdar 165e461e790SRandall Ralphs if (devp->di_page_code != SCSI_DEVICE_IDENT_PAGE) 1667bc22e45SReza Sabdar return (-1); 167e461e790SRandall Ralphs 168e461e790SRandall Ralphs return (0); 1697bc22e45SReza Sabdar } 1707bc22e45SReza Sabdar 1717bc22e45SReza Sabdar /* 1727bc22e45SReza Sabdar * Formatted print of WWN 1737bc22e45SReza Sabdar */ 174e461e790SRandall Ralphs static void 1757bc22e45SReza Sabdar snprintf_wwn(char *buf, int size, uint8_t *wwn) 1767bc22e45SReza Sabdar { 1777bc22e45SReza Sabdar if (wwn == NULL || buf == NULL) 178e461e790SRandall Ralphs return; 1797bc22e45SReza Sabdar 1807bc22e45SReza Sabdar (void) snprintf(buf, size, "0x%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", 1817bc22e45SReza Sabdar wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]); 1827bc22e45SReza Sabdar } 1837bc22e45SReza Sabdar 1847bc22e45SReza Sabdar 1857bc22e45SReza Sabdar /* 1867bc22e45SReza Sabdar * Extract and print the world wide name (WWN) 1877bc22e45SReza Sabdar */ 1887bc22e45SReza Sabdar int 1897bc22e45SReza Sabdar read_device_wwn(scsi_link_t *slink, char *wwnp, int wsize) 1907bc22e45SReza Sabdar { 191e461e790SRandall Ralphs device_ident_header_t *header; 192e461e790SRandall Ralphs name_ident_t *ident; 193e461e790SRandall Ralphs uint16_t page_len = sizeof (device_ident_header_t); 194e461e790SRandall Ralphs uint16_t act_len; 195e461e790SRandall Ralphs int accessed; 196e461e790SRandall Ralphs uint8_t *designator_data; 1977bc22e45SReza Sabdar 1987bc22e45SReza Sabdar (void) memset(wwnp, 0, wsize); 199e461e790SRandall Ralphs resize: 200e461e790SRandall Ralphs header = malloc(page_len); 201e461e790SRandall Ralphs if (header == NULL) 2027bc22e45SReza Sabdar return (-1); 2037bc22e45SReza Sabdar 204e461e790SRandall Ralphs if (read_dev_name_page(slink, header, page_len) == -1) { 205e461e790SRandall Ralphs free(header); 206e461e790SRandall Ralphs return (-1); 2077bc22e45SReza Sabdar } 208e461e790SRandall Ralphs 209e461e790SRandall Ralphs act_len = BE_16(header->di_page_length); 210e461e790SRandall Ralphs if (act_len > page_len) { 211e461e790SRandall Ralphs free(header); 212e461e790SRandall Ralphs page_len = act_len; 213e461e790SRandall Ralphs goto resize; 2147bc22e45SReza Sabdar } 215e461e790SRandall Ralphs 216e461e790SRandall Ralphs ident = (name_ident_t *)&header[1]; 217e461e790SRandall Ralphs accessed = sizeof (device_ident_header_t); 218e461e790SRandall Ralphs 219e461e790SRandall Ralphs while (accessed < act_len) { 220e461e790SRandall Ralphs 221e461e790SRandall Ralphs accessed += sizeof (name_ident_t); 222e461e790SRandall Ralphs accessed += ident->ni_ident_length; 223e461e790SRandall Ralphs designator_data = (uint8_t *)&ident[1]; 224e461e790SRandall Ralphs /* 225e461e790SRandall Ralphs * Looking for code set 1 (Binary) ident type NAA 64 bit 226e461e790SRandall Ralphs * address that is associated with the node (0). 227e461e790SRandall Ralphs */ 228e461e790SRandall Ralphs if ((ident->ni_code_set == 1) && 229e461e790SRandall Ralphs (ident->ni_ident_type == 3)) { 230e461e790SRandall Ralphs snprintf_wwn(wwnp, wsize, designator_data); 231e461e790SRandall Ralphs /* 232e461e790SRandall Ralphs * If assc is zero (Node) this is the one we want. 233e461e790SRandall Ralphs * If we find that we're done. 234e461e790SRandall Ralphs */ 235e461e790SRandall Ralphs if (ident->ni_asso == 0) 236e461e790SRandall Ralphs break; 237e461e790SRandall Ralphs } 238e461e790SRandall Ralphs /* 239e461e790SRandall Ralphs * If we find a EUI-64 we can use that also. 240e461e790SRandall Ralphs */ 241e461e790SRandall Ralphs if ((ident->ni_code_set == 2) && 242e461e790SRandall Ralphs (ident->ni_ident_type == 1) && 243e461e790SRandall Ralphs (ident->ni_asso == 0) && 244e461e790SRandall Ralphs (isprint(wwnp[0] == 0))) { /* Don't overwrite */ 245e461e790SRandall Ralphs /* 246e461e790SRandall Ralphs * This isn't our first choice but we'll print it 247e461e790SRandall Ralphs * in case there is nothing else to use. 248e461e790SRandall Ralphs */ 2497bc22e45SReza Sabdar (void) snprintf(wwnp, wsize, "%.*s", 250e461e790SRandall Ralphs ident->ni_ident_length, designator_data); 2517bc22e45SReza Sabdar } 252e461e790SRandall Ralphs ident = 253e461e790SRandall Ralphs (name_ident_t *)&designator_data[ident->ni_ident_length]; 2547bc22e45SReza Sabdar } 255e461e790SRandall Ralphs free(header); 256e461e790SRandall Ralphs /* 257e461e790SRandall Ralphs * See if we found something. 258e461e790SRandall Ralphs * Memset above would leave wwnp not printable. 259e461e790SRandall Ralphs */ 260e461e790SRandall Ralphs if (isprint(wwnp[0])) 261e461e790SRandall Ralphs return (0); 2627bc22e45SReza Sabdar return (-1); 2637bc22e45SReza Sabdar } 2647bc22e45SReza Sabdar 2657bc22e45SReza Sabdar /* 2662654012fSReza Sabdar * Add the tape library call back function (used while scanning the bus) 2672654012fSReza Sabdar */ 2682654012fSReza Sabdar static int 2692654012fSReza Sabdar add_lib(scsi_link_t *slink, struct scsi_inquiry *sd, void *arg) 2702654012fSReza Sabdar { 2712654012fSReza Sabdar int l; 2722654012fSReza Sabdar int *nlp; /* pointer to library counter */ 2732654012fSReza Sabdar sasd_drive_t *ssd; 2742654012fSReza Sabdar 2752654012fSReza Sabdar if (!slink || !sd) { 2762654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Invalid argument %x %x %x", 2772654012fSReza Sabdar slink, sd, arg); 2782654012fSReza Sabdar return (-TLM_INVALID); 2792654012fSReza Sabdar } 2802654012fSReza Sabdar 2812654012fSReza Sabdar if (sd->inq_dtype == DTYPE_CHANGER) { 2822654012fSReza Sabdar /* This is a robot, which means this is also a library */ 2832654012fSReza Sabdar nlp = (int *)arg; 2842654012fSReza Sabdar (*nlp)++; 2852654012fSReza Sabdar l = tlm_insert_new_library(slink); 2862654012fSReza Sabdar tlm_enable_barcode(l); 2872654012fSReza Sabdar 2882654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "lib %d sid %d lun %d", 2892654012fSReza Sabdar l, slink->sl_sid, slink->sl_lun); 2902654012fSReza Sabdar 2912654012fSReza Sabdar if ((ssd = sasd_slink_drive(slink)) != NULL) { 2922654012fSReza Sabdar (void) strlcpy(ssd->sd_vendor, sd->inq_vid, 2932654012fSReza Sabdar sizeof (ssd->sd_vendor)); 2942654012fSReza Sabdar (void) strlcpy(ssd->sd_id, sd->inq_pid, 2952654012fSReza Sabdar sizeof (ssd->sd_id)); 2962654012fSReza Sabdar (void) strlcpy(ssd->sd_rev, sd->inq_revision, 2972654012fSReza Sabdar sizeof (ssd->sd_rev)); 2987bc22e45SReza Sabdar (void) read_serial_num_page(slink, ssd->sd_serial, 2997bc22e45SReza Sabdar sizeof (ssd->sd_serial)); 3007bc22e45SReza Sabdar (void) read_device_wwn(slink, ssd->sd_wwn, 3017bc22e45SReza Sabdar sizeof (ssd->sd_wwn)); 3022654012fSReza Sabdar } 3032654012fSReza Sabdar } 3042654012fSReza Sabdar 3052654012fSReza Sabdar return (TLM_NO_ERRORS); 3062654012fSReza Sabdar } 3072654012fSReza Sabdar 3082654012fSReza Sabdar /* 3092654012fSReza Sabdar * Create some virutal slots 3102654012fSReza Sabdar */ 3112654012fSReza Sabdar static int 3122654012fSReza Sabdar make_virtual_slot(int l, tlm_drive_t *dp) 3132654012fSReza Sabdar { 3142654012fSReza Sabdar int s; 3152654012fSReza Sabdar tlm_slot_t *sp; 3162654012fSReza Sabdar 3172654012fSReza Sabdar if (l <= 0 || !dp) { 3182654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Invalid argument %d, %x", l, dp); 3192654012fSReza Sabdar return (-TLM_INVALID); 3202654012fSReza Sabdar } 3212654012fSReza Sabdar 3222654012fSReza Sabdar if ((s = tlm_insert_new_slot(l)) <= 0) 3232654012fSReza Sabdar return (-TLM_NO_MEMORY); 3242654012fSReza Sabdar 3252654012fSReza Sabdar if (!(sp = tlm_slot(l, s))) { 3262654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Internal error: slot not found %d", s); 3272654012fSReza Sabdar return (-TLM_ERROR_INTERNAL); 3282654012fSReza Sabdar } 3292654012fSReza Sabdar /* 3302654012fSReza Sabdar * For virtual slots element number is 0 and they are always full. 3312654012fSReza Sabdar */ 3322654012fSReza Sabdar sp->ts_element = 0; 3332654012fSReza Sabdar sp->ts_status_full = TRUE; 3342654012fSReza Sabdar return (TLM_NO_ERRORS); 3352654012fSReza Sabdar } 3362654012fSReza Sabdar 3372654012fSReza Sabdar /* 3382654012fSReza Sabdar * Make the tape drive not part of a tape library (stand alone) 3392654012fSReza Sabdar */ 3402654012fSReza Sabdar static int 3412654012fSReza Sabdar make_stand_alone_drive(scsi_link_t *slink, int l) 3422654012fSReza Sabdar { 3432654012fSReza Sabdar int d; 3442654012fSReza Sabdar tlm_drive_t *dp; 3452654012fSReza Sabdar 3462654012fSReza Sabdar if (!slink || l <= 0) { 3472654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Invalid argument %x %d", slink, l); 3482654012fSReza Sabdar return (-TLM_INVALID); 3492654012fSReza Sabdar } 3502654012fSReza Sabdar 3512654012fSReza Sabdar d = tlm_insert_new_drive(l); 3522654012fSReza Sabdar if (!(dp = tlm_drive(l, d))) { 3532654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Internal error: drive not found %d", d); 3542654012fSReza Sabdar return (-TLM_ERROR_INTERNAL); 3552654012fSReza Sabdar } 3562654012fSReza Sabdar 3572654012fSReza Sabdar /* For stand-alone drives, the element number is the drive number. */ 3582654012fSReza Sabdar dp->td_element = d; 3592654012fSReza Sabdar dp->td_slink = slink; 3602654012fSReza Sabdar dp->td_scsi_id = slink->sl_sid; 3612654012fSReza Sabdar dp->td_lun = slink->sl_lun; 3622654012fSReza Sabdar dp->td_exists = TRUE; 3632654012fSReza Sabdar 3642654012fSReza Sabdar /* 3652654012fSReza Sabdar * Note: There is no way to remove library elements. We cannot clean 3662654012fSReza Sabdar * up if make_virtual_slot() fails. 3672654012fSReza Sabdar */ 3682654012fSReza Sabdar (void) make_virtual_slot(l, dp); 3692654012fSReza Sabdar return (d); 3702654012fSReza Sabdar } 3712654012fSReza Sabdar 3722654012fSReza Sabdar /* 3732654012fSReza Sabdar * Find the LIBRARY structure that has control of this DRIVE. 3742654012fSReza Sabdar */ 3752654012fSReza Sabdar static int 3762654012fSReza Sabdar new_drive(scsi_link_t *slink, int *lib) 3772654012fSReza Sabdar { 3782654012fSReza Sabdar int d; 3792654012fSReza Sabdar tlm_drive_t *dp; 3802654012fSReza Sabdar tlm_library_t *lp; 3812654012fSReza Sabdar 3822654012fSReza Sabdar /* Walk through all libraries. */ 3832654012fSReza Sabdar for (*lib = 1; *lib <= tlm_library_count(); (*lib)++) { 3842654012fSReza Sabdar if (!(lp = tlm_library(*lib))) 3852654012fSReza Sabdar continue; 3862654012fSReza Sabdar /* Walk through drives that are already found. */ 3872654012fSReza Sabdar for (d = 1; d <= lp->tl_drive_count; d++) { 3882654012fSReza Sabdar if (!(dp = tlm_drive(*lib, d))) 3892654012fSReza Sabdar continue; 3902654012fSReza Sabdar if (dp->td_scsi_id == slink->sl_sid && 3912654012fSReza Sabdar dp->td_lun == slink->sl_lun) 3922654012fSReza Sabdar return (d); 3932654012fSReza Sabdar } 3942654012fSReza Sabdar } 3952654012fSReza Sabdar 3962654012fSReza Sabdar /* Not part of any library, this is a newly found tape drive. */ 3972654012fSReza Sabdar return (0); 3982654012fSReza Sabdar } 3992654012fSReza Sabdar 4007bc22e45SReza Sabdar 4012654012fSReza Sabdar /* 4022654012fSReza Sabdar * Add the tape library call back function (used while scanning the bus) 4032654012fSReza Sabdar */ 4042654012fSReza Sabdar static int 4052654012fSReza Sabdar add_drv(scsi_link_t *slink, struct scsi_inquiry *sd, void *arg) 4062654012fSReza Sabdar { 4072654012fSReza Sabdar int l, d; 4082654012fSReza Sabdar int *vlp; /* pointer to virtual library number */ 4092654012fSReza Sabdar sasd_drive_t *ssd; 4102654012fSReza Sabdar tlm_library_t *library; 4112654012fSReza Sabdar tlm_drive_t *drive; 4122654012fSReza Sabdar 4132654012fSReza Sabdar if (!slink || !sd) { 4142654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Invalid argument %x %x %x", 4152654012fSReza Sabdar slink, sd, arg); 4162654012fSReza Sabdar return (-TLM_INVALID); 4172654012fSReza Sabdar } 4182654012fSReza Sabdar 4192654012fSReza Sabdar if (sd->inq_dtype == DTYPE_SEQUENTIAL) { 4202654012fSReza Sabdar vlp = (int *)arg; 4212654012fSReza Sabdar d = new_drive(slink, &l); 4222654012fSReza Sabdar if (d == 0) { 4232654012fSReza Sabdar /* This tape drive was not found inside any robot. */ 4242654012fSReza Sabdar if (*vlp == 0) { 4252654012fSReza Sabdar /* 4262654012fSReza Sabdar * First, create a virtual library if it's not 4272654012fSReza Sabdar * done yet. 4282654012fSReza Sabdar */ 4292654012fSReza Sabdar *vlp = tlm_insert_new_library(slink); 4302654012fSReza Sabdar if ((library = tlm_library(*vlp)) != NULL) 4312654012fSReza Sabdar library->tl_capability_robot = FALSE; 4322654012fSReza Sabdar } 4332654012fSReza Sabdar if ((d = make_stand_alone_drive(slink, *vlp)) < 0) { 4342654012fSReza Sabdar /* sorry, we can not clean up the vlib now * */ 4352654012fSReza Sabdar return (-TLM_INVALID); 4362654012fSReza Sabdar } 4372654012fSReza Sabdar l = *vlp; 4382654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "vlib(%d, %d) sid %d lun %d", 4392654012fSReza Sabdar l, d, slink->sl_sid, slink->sl_lun); 4402654012fSReza Sabdar } else 4412654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "(%d, %d) sid %d lun %d", 4422654012fSReza Sabdar l, d, slink->sl_sid, slink->sl_lun); 4432654012fSReza Sabdar 4442654012fSReza Sabdar if ((drive = tlm_drive(l, d)) != NULL) { 4452654012fSReza Sabdar drive->td_exists = TRUE; 4462654012fSReza Sabdar drive->td_slink = slink; 4472654012fSReza Sabdar } 4482654012fSReza Sabdar if ((ssd = sasd_slink_drive(slink)) != NULL) { 4492654012fSReza Sabdar (void) strlcpy(ssd->sd_vendor, 4502654012fSReza Sabdar sd->inq_vid, sizeof (ssd->sd_vendor)); 4512654012fSReza Sabdar (void) strlcpy(ssd->sd_id, sd->inq_pid, 4522654012fSReza Sabdar sizeof (ssd->sd_id)); 4532654012fSReza Sabdar (void) strlcpy(ssd->sd_rev, sd->inq_revision, 4542654012fSReza Sabdar sizeof (ssd->sd_rev)); 4557bc22e45SReza Sabdar (void) read_serial_num_page(slink, ssd->sd_serial, 4567bc22e45SReza Sabdar sizeof (ssd->sd_serial)); 4577bc22e45SReza Sabdar (void) read_device_wwn(slink, ssd->sd_wwn, 4587bc22e45SReza Sabdar sizeof (ssd->sd_wwn)); 4592654012fSReza Sabdar } 4602654012fSReza Sabdar } 4612654012fSReza Sabdar 4622654012fSReza Sabdar return (TLM_NO_ERRORS); 4632654012fSReza Sabdar } 4642654012fSReza Sabdar 4652654012fSReza Sabdar /* 4662654012fSReza Sabdar * Scan the specified bus and call the handler function. 4672654012fSReza Sabdar */ 4682654012fSReza Sabdar static int 4692654012fSReza Sabdar scan_bus(scsi_adapter_t *sa, int(*hndlr)(), void *args) 4702654012fSReza Sabdar { 4712654012fSReza Sabdar int nerr; 4722654012fSReza Sabdar scsi_link_t *slink; 4732654012fSReza Sabdar struct scsi_inquiry scsi_data; 4742654012fSReza Sabdar 4752654012fSReza Sabdar nerr = 0; 4762654012fSReza Sabdar slink = sa->sa_link_head.sl_next; 4772654012fSReza Sabdar for (; slink != &sa->sa_link_head; slink = slink->sl_next) { 4782654012fSReza Sabdar (void) memset(&scsi_data, 0, sizeof (struct scsi_inquiry)); 4792654012fSReza Sabdar if (read_inquiry_page(slink, &scsi_data) == -1) 4802654012fSReza Sabdar nerr++; 4812654012fSReza Sabdar else 4822654012fSReza Sabdar if ((*hndlr)(slink, &scsi_data, args) != TLM_NO_ERRORS) 4832654012fSReza Sabdar nerr++; 4842654012fSReza Sabdar } 4852654012fSReza Sabdar 4862654012fSReza Sabdar return (nerr); 4872654012fSReza Sabdar } 4882654012fSReza Sabdar 4892654012fSReza Sabdar /* 4902654012fSReza Sabdar * Marks the library/slots inaccessible if there are not enough drives 4912654012fSReza Sabdar * available on the library 4922654012fSReza Sabdar */ 4932654012fSReza Sabdar static void 4942654012fSReza Sabdar inaccbl_drv_warn(int start, int max) 4952654012fSReza Sabdar { 4962654012fSReza Sabdar char *dname; 4972654012fSReza Sabdar int l, d; 4982654012fSReza Sabdar tlm_library_t *lp; 4992654012fSReza Sabdar 5002654012fSReza Sabdar for (l = start; l < max; l++) { 5012654012fSReza Sabdar if (!(lp = tlm_library(l))) 5022654012fSReza Sabdar continue; 5032654012fSReza Sabdar if (lp->tl_drive_count <= 0) 5042654012fSReza Sabdar continue; 5052654012fSReza Sabdar 5062654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 5072654012fSReza Sabdar "Warning: The following drives are not accessible:"); 5082654012fSReza Sabdar for (d = 1; d <= lp->tl_drive_count; d++) 5092654012fSReza Sabdar if (!(dname = tlm_get_tape_name(l, d))) { 5102654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 5112654012fSReza Sabdar "Error getting drive(%d, %d)", l, d); 5122654012fSReza Sabdar } else 5132654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "%s", dname); 5142654012fSReza Sabdar 5152654012fSReza Sabdar /* 5162654012fSReza Sabdar * Note: Make the slots inaccessible to prevent running 5172654012fSReza Sabdar * discovery on these libraries. The better idea is 5182654012fSReza Sabdar * removing these libraries, but we don't have that 5192654012fSReza Sabdar * feature available now. 5202654012fSReza Sabdar */ 5212654012fSReza Sabdar lp->tl_slot_count = 0; 5222654012fSReza Sabdar } 5232654012fSReza Sabdar } 5242654012fSReza Sabdar 5252654012fSReza Sabdar /* 5262654012fSReza Sabdar * Initialize the tape library data structure, asks the libraries what 5272654012fSReza Sabdar * equipments they have. 5282654012fSReza Sabdar */ 5292654012fSReza Sabdar int 5302654012fSReza Sabdar tlm_init(void) 5312654012fSReza Sabdar { 5322654012fSReza Sabdar static int nlibs; /* number of found libraries */ 5332654012fSReza Sabdar int i, nsa; 5342654012fSReza Sabdar int l, vlibs, d; 5352654012fSReza Sabdar int rv; 5362654012fSReza Sabdar scsi_adapter_t *sa; 5372654012fSReza Sabdar tlm_library_t *lp; 5382654012fSReza Sabdar tlm_drive_t *dp; 5392654012fSReza Sabdar 5402654012fSReza Sabdar /* Search through all SCSI adapters, look for tape robots. */ 5412654012fSReza Sabdar nlibs = 0; 5422654012fSReza Sabdar 5432654012fSReza Sabdar /* 5442654012fSReza Sabdar * We probe both changers and tape drives here 5452654012fSReza Sabdar * but later on this needs to be removed as the 5462654012fSReza Sabdar * probe will happen somewhere else. 5472654012fSReza Sabdar */ 548*1e05b03fSJanice Chang if (probe_scsi() < 0) 549*1e05b03fSJanice Chang return (-1); 5502654012fSReza Sabdar 5512654012fSReza Sabdar nsa = scsi_get_adapter_count(); 5522654012fSReza Sabdar for (i = 0; i < nsa; i++) 5532654012fSReza Sabdar if ((sa = scsi_get_adapter(i))) 5542654012fSReza Sabdar (void) scan_bus(sa, add_lib, (void *)&nlibs); 5552654012fSReza Sabdar 5562654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "nlibs %d", nlibs); 5572654012fSReza Sabdar 5582654012fSReza Sabdar /* Search through all SCSI adapters, look for tape drives. */ 5592654012fSReza Sabdar vlibs = 0; 5602654012fSReza Sabdar for (i = 0; i < nsa; i++) 5612654012fSReza Sabdar if ((sa = scsi_get_adapter(i))) 5622654012fSReza Sabdar (void) scan_bus(sa, add_drv, (void *)&vlibs); 5632654012fSReza Sabdar 5642654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "vlibs %d", vlibs); 5652654012fSReza Sabdar 5662654012fSReza Sabdar if (nlibs > 0 && vlibs > 0) 5672654012fSReza Sabdar inaccbl_drv_warn(nlibs + 1, vlibs + nlibs + 1); 5682654012fSReza Sabdar 5692654012fSReza Sabdar for (l = 1; l <= tlm_library_count(); l++) { 5702654012fSReza Sabdar if (!(lp = tlm_library(l))) { 5712654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "can't find lib %d", l); 5722654012fSReza Sabdar continue; 5732654012fSReza Sabdar } 5742654012fSReza Sabdar 5752654012fSReza Sabdar /* 5762654012fSReza Sabdar * Make sure all libraries have tape drives. 5772654012fSReza Sabdar */ 5782654012fSReza Sabdar if (lp->tl_drive_count == 0) 5792654012fSReza Sabdar continue; 5802654012fSReza Sabdar 5812654012fSReza Sabdar /* 5822654012fSReza Sabdar * Make sure all tape drives exist. A drive that is not 5832654012fSReza Sabdar * linked into the SCSI chain will be seen by the library 5842654012fSReza Sabdar * but we cannot talk to it. 5852654012fSReza Sabdar */ 5862654012fSReza Sabdar for (d = 1; d <= lp->tl_drive_count; d++) { 5872654012fSReza Sabdar dp = tlm_drive(l, d); 5882654012fSReza Sabdar if (dp && !dp->td_exists) { 5892654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Ghost drive found %d.%d", 5902654012fSReza Sabdar l, d); 5912654012fSReza Sabdar lp->tl_ghost_drives = TRUE; 5922654012fSReza Sabdar continue; 5932654012fSReza Sabdar } 5942654012fSReza Sabdar } 5952654012fSReza Sabdar } 5962654012fSReza Sabdar 5972654012fSReza Sabdar if (nlibs > 0) 5982654012fSReza Sabdar rv = (vlibs > 0) ? 0 : nlibs; 5992654012fSReza Sabdar else 6002654012fSReza Sabdar rv = vlibs; 6012654012fSReza Sabdar 6022654012fSReza Sabdar return (rv); 6032654012fSReza Sabdar } 604