17917SReza.Sabdar@Sun.COM /* 27917SReza.Sabdar@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 37917SReza.Sabdar@Sun.COM * Use is subject to license terms. 47917SReza.Sabdar@Sun.COM */ 57917SReza.Sabdar@Sun.COM 67917SReza.Sabdar@Sun.COM /* 77917SReza.Sabdar@Sun.COM * BSD 3 Clause License 87917SReza.Sabdar@Sun.COM * 97917SReza.Sabdar@Sun.COM * Copyright (c) 2007, The Storage Networking Industry Association. 107917SReza.Sabdar@Sun.COM * 117917SReza.Sabdar@Sun.COM * Redistribution and use in source and binary forms, with or without 127917SReza.Sabdar@Sun.COM * modification, are permitted provided that the following conditions 137917SReza.Sabdar@Sun.COM * are met: 147917SReza.Sabdar@Sun.COM * - Redistributions of source code must retain the above copyright 157917SReza.Sabdar@Sun.COM * notice, this list of conditions and the following disclaimer. 167917SReza.Sabdar@Sun.COM * 177917SReza.Sabdar@Sun.COM * - Redistributions in binary form must reproduce the above copyright 187917SReza.Sabdar@Sun.COM * notice, this list of conditions and the following disclaimer in 197917SReza.Sabdar@Sun.COM * the documentation and/or other materials provided with the 207917SReza.Sabdar@Sun.COM * distribution. 217917SReza.Sabdar@Sun.COM * 227917SReza.Sabdar@Sun.COM * - Neither the name of The Storage Networking Industry Association (SNIA) 237917SReza.Sabdar@Sun.COM * nor the names of its contributors may be used to endorse or promote 247917SReza.Sabdar@Sun.COM * products derived from this software without specific prior written 257917SReza.Sabdar@Sun.COM * permission. 267917SReza.Sabdar@Sun.COM * 277917SReza.Sabdar@Sun.COM * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 287917SReza.Sabdar@Sun.COM * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 297917SReza.Sabdar@Sun.COM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 307917SReza.Sabdar@Sun.COM * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 317917SReza.Sabdar@Sun.COM * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 327917SReza.Sabdar@Sun.COM * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 337917SReza.Sabdar@Sun.COM * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 347917SReza.Sabdar@Sun.COM * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 357917SReza.Sabdar@Sun.COM * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 367917SReza.Sabdar@Sun.COM * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 377917SReza.Sabdar@Sun.COM * POSSIBILITY OF SUCH DAMAGE. 387917SReza.Sabdar@Sun.COM */ 397917SReza.Sabdar@Sun.COM #include <sys/errno.h> 407917SReza.Sabdar@Sun.COM #include <sys/types.h> 417917SReza.Sabdar@Sun.COM #include <stdlib.h> 427917SReza.Sabdar@Sun.COM #include <unistd.h> 437917SReza.Sabdar@Sun.COM #include <sys/scsi/impl/uscsi.h> 447917SReza.Sabdar@Sun.COM #include <sys/scsi/scsi.h> 457917SReza.Sabdar@Sun.COM #include <tlm.h> 467917SReza.Sabdar@Sun.COM #include <pthread.h> 477917SReza.Sabdar@Sun.COM #include "tlm_proto.h" 487917SReza.Sabdar@Sun.COM 497917SReza.Sabdar@Sun.COM /* 507917SReza.Sabdar@Sun.COM * generic routine to read a SCSI page 517917SReza.Sabdar@Sun.COM */ 527917SReza.Sabdar@Sun.COM int 537917SReza.Sabdar@Sun.COM read_scsi_page(scsi_link_t *slink, union scsi_cdb *cdb, 547917SReza.Sabdar@Sun.COM int command_size, caddr_t data, int size) 557917SReza.Sabdar@Sun.COM { 567917SReza.Sabdar@Sun.COM struct uscsi_cmd uscsi_cmd; 577917SReza.Sabdar@Sun.COM char *dname; 587917SReza.Sabdar@Sun.COM int dev; 597917SReza.Sabdar@Sun.COM 607917SReza.Sabdar@Sun.COM if (slink == 0 || slink->sl_sa == 0) 617917SReza.Sabdar@Sun.COM return (EINVAL); 627917SReza.Sabdar@Sun.COM 637917SReza.Sabdar@Sun.COM (void) memset(&uscsi_cmd, 0, sizeof (uscsi_cmd)); 647917SReza.Sabdar@Sun.COM 657917SReza.Sabdar@Sun.COM /* Lun is in the 5th bit */ 667917SReza.Sabdar@Sun.COM cdb->scc_lun = slink->sl_lun; 677917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_flags |= USCSI_READ | USCSI_ISOLATE; 687917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_bufaddr = data; 697917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_buflen = size; 707917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_timeout = 1000; 717917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_cdb = (char *)cdb; 727917SReza.Sabdar@Sun.COM 737917SReza.Sabdar@Sun.COM if (cdb->scc_cmd == SCMD_READ_ELEMENT_STATUS) { 747917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_flags |= USCSI_RQENABLE; 757917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_rqbuf = data; 767917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_rqlen = size; 777917SReza.Sabdar@Sun.COM } 787917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_cdblen = command_size; 797917SReza.Sabdar@Sun.COM 807917SReza.Sabdar@Sun.COM dname = sasd_slink_name(slink); 817917SReza.Sabdar@Sun.COM dev = open(dname, O_RDWR | O_NDELAY); 827917SReza.Sabdar@Sun.COM if (dev == -1) { 837917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Open failed for %s err=%d", 847917SReza.Sabdar@Sun.COM dname, errno); 857917SReza.Sabdar@Sun.COM return (errno); 867917SReza.Sabdar@Sun.COM } 877917SReza.Sabdar@Sun.COM if (tlm_ioctl(dev, USCSICMD, &uscsi_cmd) < 0) { 887917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "SCSI cmd %d failed for %s err=%d", 897917SReza.Sabdar@Sun.COM cdb->scc_cmd, dname, errno); 907917SReza.Sabdar@Sun.COM (void) close(dev); 917917SReza.Sabdar@Sun.COM return (errno); 927917SReza.Sabdar@Sun.COM } 937917SReza.Sabdar@Sun.COM (void) close(dev); 947917SReza.Sabdar@Sun.COM return (uscsi_cmd.uscsi_status); 957917SReza.Sabdar@Sun.COM } 967917SReza.Sabdar@Sun.COM 977917SReza.Sabdar@Sun.COM /* 987917SReza.Sabdar@Sun.COM * Read the Inquiry Page. 997917SReza.Sabdar@Sun.COM */ 1007917SReza.Sabdar@Sun.COM static int 1017917SReza.Sabdar@Sun.COM read_inquiry_page(scsi_link_t *slink, struct scsi_inquiry *inq) 1027917SReza.Sabdar@Sun.COM { 1037917SReza.Sabdar@Sun.COM union scsi_cdb cdb; 1047917SReza.Sabdar@Sun.COM 1057917SReza.Sabdar@Sun.COM (void) memset(&cdb, 0, sizeof (union scsi_cdb)); 1067917SReza.Sabdar@Sun.COM cdb.scc_cmd = SCMD_INQUIRY; 1077917SReza.Sabdar@Sun.COM cdb.g0_count0 = sizeof (struct scsi_inquiry); 1087917SReza.Sabdar@Sun.COM 1097917SReza.Sabdar@Sun.COM return (read_scsi_page(slink, &cdb, CDB_GROUP0, 1107917SReza.Sabdar@Sun.COM (caddr_t)inq, sizeof (*inq)) ? -1 : 0); 1117917SReza.Sabdar@Sun.COM } 1127917SReza.Sabdar@Sun.COM 1137917SReza.Sabdar@Sun.COM /* 114*8193SReza.Sabdar@Sun.COM * Read the Product Data Page. 115*8193SReza.Sabdar@Sun.COM */ 116*8193SReza.Sabdar@Sun.COM static int 117*8193SReza.Sabdar@Sun.COM read_data_page(scsi_link_t *slink, int pcode, char *snum, int size) 118*8193SReza.Sabdar@Sun.COM { 119*8193SReza.Sabdar@Sun.COM char cmd[CDB_GROUP0]; 120*8193SReza.Sabdar@Sun.COM 121*8193SReza.Sabdar@Sun.COM (void) memset(cmd, 0, sizeof (cmd)); 122*8193SReza.Sabdar@Sun.COM 123*8193SReza.Sabdar@Sun.COM cmd[0] = SCMD_INQUIRY; 124*8193SReza.Sabdar@Sun.COM cmd[1] = pcode ? 0x01 : 0x00; 125*8193SReza.Sabdar@Sun.COM cmd[2] = pcode; 126*8193SReza.Sabdar@Sun.COM cmd[4] = size; 127*8193SReza.Sabdar@Sun.COM 128*8193SReza.Sabdar@Sun.COM /* LINTED improper alignment */ 129*8193SReza.Sabdar@Sun.COM return (read_scsi_page(slink, (union scsi_cdb *)&cmd, CDB_GROUP0, 130*8193SReza.Sabdar@Sun.COM (caddr_t)snum, size) == -1 ? -1 : 0); 131*8193SReza.Sabdar@Sun.COM } 132*8193SReza.Sabdar@Sun.COM 133*8193SReza.Sabdar@Sun.COM 134*8193SReza.Sabdar@Sun.COM /* 135*8193SReza.Sabdar@Sun.COM * Read the Serial Number Page. 136*8193SReza.Sabdar@Sun.COM */ 137*8193SReza.Sabdar@Sun.COM static int 138*8193SReza.Sabdar@Sun.COM read_serial_num_page(scsi_link_t *slink, char *snum, int size) 139*8193SReza.Sabdar@Sun.COM { 140*8193SReza.Sabdar@Sun.COM scsi_serial_t serial; 141*8193SReza.Sabdar@Sun.COM int rv; 142*8193SReza.Sabdar@Sun.COM 143*8193SReza.Sabdar@Sun.COM (void) memset(&serial, 0, sizeof (scsi_serial_t)); 144*8193SReza.Sabdar@Sun.COM rv = read_data_page(slink, SCSI_SERIAL_PAGE, (caddr_t)&serial, 145*8193SReza.Sabdar@Sun.COM sizeof (scsi_serial_t)); 146*8193SReza.Sabdar@Sun.COM (void) strlcpy(snum, serial.sr_num, size); 147*8193SReza.Sabdar@Sun.COM 148*8193SReza.Sabdar@Sun.COM return (rv == -1 ? -1 : 0); 149*8193SReza.Sabdar@Sun.COM } 150*8193SReza.Sabdar@Sun.COM 151*8193SReza.Sabdar@Sun.COM 152*8193SReza.Sabdar@Sun.COM /* 153*8193SReza.Sabdar@Sun.COM * Read the Device Name Page. 154*8193SReza.Sabdar@Sun.COM */ 155*8193SReza.Sabdar@Sun.COM static int 156*8193SReza.Sabdar@Sun.COM read_dev_name_page(scsi_link_t *slink, device_name_page_t *devp) 157*8193SReza.Sabdar@Sun.COM { 158*8193SReza.Sabdar@Sun.COM (void) memset(devp, 0, sizeof (device_name_page_t)); 159*8193SReza.Sabdar@Sun.COM 160*8193SReza.Sabdar@Sun.COM if (read_data_page(slink, SCSI_DEVICE_IDENT_PAGE, (caddr_t)devp, 161*8193SReza.Sabdar@Sun.COM sizeof (device_name_page_t)) == -1) 162*8193SReza.Sabdar@Sun.COM return (-1); 163*8193SReza.Sabdar@Sun.COM 164*8193SReza.Sabdar@Sun.COM if (devp->np_header.di_page_code == SCSI_DEVICE_IDENT_PAGE && 165*8193SReza.Sabdar@Sun.COM devp->np_node.ni_code_set == 1 && 166*8193SReza.Sabdar@Sun.COM devp->np_node.ni_ident_type == 3 && 167*8193SReza.Sabdar@Sun.COM devp->np_node.ni_ident_length == 8) 168*8193SReza.Sabdar@Sun.COM return (0); 169*8193SReza.Sabdar@Sun.COM 170*8193SReza.Sabdar@Sun.COM if (devp->np_header.di_page_code == SCSI_DEVICE_IDENT_PAGE) 171*8193SReza.Sabdar@Sun.COM return (0); 172*8193SReza.Sabdar@Sun.COM 173*8193SReza.Sabdar@Sun.COM return (-1); 174*8193SReza.Sabdar@Sun.COM } 175*8193SReza.Sabdar@Sun.COM 176*8193SReza.Sabdar@Sun.COM /* 177*8193SReza.Sabdar@Sun.COM * Formatted print of WWN 178*8193SReza.Sabdar@Sun.COM */ 179*8193SReza.Sabdar@Sun.COM char * 180*8193SReza.Sabdar@Sun.COM snprintf_wwn(char *buf, int size, uint8_t *wwn) 181*8193SReza.Sabdar@Sun.COM { 182*8193SReza.Sabdar@Sun.COM if (wwn == NULL || buf == NULL) 183*8193SReza.Sabdar@Sun.COM return (0); 184*8193SReza.Sabdar@Sun.COM 185*8193SReza.Sabdar@Sun.COM (void) snprintf(buf, size, "0x%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", 186*8193SReza.Sabdar@Sun.COM wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]); 187*8193SReza.Sabdar@Sun.COM return (buf); 188*8193SReza.Sabdar@Sun.COM } 189*8193SReza.Sabdar@Sun.COM 190*8193SReza.Sabdar@Sun.COM 191*8193SReza.Sabdar@Sun.COM /* 192*8193SReza.Sabdar@Sun.COM * Extract and print the world wide name (WWN) 193*8193SReza.Sabdar@Sun.COM */ 194*8193SReza.Sabdar@Sun.COM int 195*8193SReza.Sabdar@Sun.COM read_device_wwn(scsi_link_t *slink, char *wwnp, int wsize) 196*8193SReza.Sabdar@Sun.COM { 197*8193SReza.Sabdar@Sun.COM device_name_page_t dinfo; 198*8193SReza.Sabdar@Sun.COM 199*8193SReza.Sabdar@Sun.COM (void) memset(wwnp, 0, wsize); 200*8193SReza.Sabdar@Sun.COM if (read_dev_name_page(slink, &dinfo) == -1) 201*8193SReza.Sabdar@Sun.COM return (-1); 202*8193SReza.Sabdar@Sun.COM 203*8193SReza.Sabdar@Sun.COM if (dinfo.np_port.ni_code_set == 1 && 204*8193SReza.Sabdar@Sun.COM dinfo.np_port.ni_ident_type == 3) { 205*8193SReza.Sabdar@Sun.COM (void) snprintf_wwn(wwnp, wsize, dinfo.np_port_info.d_name); 206*8193SReza.Sabdar@Sun.COM return (0); 207*8193SReza.Sabdar@Sun.COM } 208*8193SReza.Sabdar@Sun.COM if (dinfo.np_node.ni_code_set == 1 && 209*8193SReza.Sabdar@Sun.COM dinfo.np_node.ni_ident_type == 3) { 210*8193SReza.Sabdar@Sun.COM (void) snprintf_wwn(wwnp, wsize, dinfo.np_node_info.d_name); 211*8193SReza.Sabdar@Sun.COM return (0); 212*8193SReza.Sabdar@Sun.COM } 213*8193SReza.Sabdar@Sun.COM if (dinfo.np_port.ni_code_set == 2 && 214*8193SReza.Sabdar@Sun.COM dinfo.np_port.ni_ident_type == 1) { 215*8193SReza.Sabdar@Sun.COM (void) snprintf(wwnp, wsize, "%.*s", 216*8193SReza.Sabdar@Sun.COM dinfo.np_port.ni_ident_length, dinfo.np_port_info.d_name); 217*8193SReza.Sabdar@Sun.COM return (0); 218*8193SReza.Sabdar@Sun.COM } 219*8193SReza.Sabdar@Sun.COM if (dinfo.np_node.ni_code_set == 2 && 220*8193SReza.Sabdar@Sun.COM dinfo.np_node.ni_ident_type == 1) { 221*8193SReza.Sabdar@Sun.COM (void) snprintf(wwnp, wsize, "%.*s", 222*8193SReza.Sabdar@Sun.COM dinfo.np_node.ni_ident_length, dinfo.np_node_info.d_name); 223*8193SReza.Sabdar@Sun.COM return (0); 224*8193SReza.Sabdar@Sun.COM } 225*8193SReza.Sabdar@Sun.COM return (-1); 226*8193SReza.Sabdar@Sun.COM } 227*8193SReza.Sabdar@Sun.COM 228*8193SReza.Sabdar@Sun.COM /* 2297917SReza.Sabdar@Sun.COM * Add the tape library call back function (used while scanning the bus) 2307917SReza.Sabdar@Sun.COM */ 2317917SReza.Sabdar@Sun.COM static int 2327917SReza.Sabdar@Sun.COM add_lib(scsi_link_t *slink, struct scsi_inquiry *sd, void *arg) 2337917SReza.Sabdar@Sun.COM { 2347917SReza.Sabdar@Sun.COM int l; 2357917SReza.Sabdar@Sun.COM int *nlp; /* pointer to library counter */ 2367917SReza.Sabdar@Sun.COM sasd_drive_t *ssd; 2377917SReza.Sabdar@Sun.COM 2387917SReza.Sabdar@Sun.COM if (!slink || !sd) { 2397917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Invalid argument %x %x %x", 2407917SReza.Sabdar@Sun.COM slink, sd, arg); 2417917SReza.Sabdar@Sun.COM return (-TLM_INVALID); 2427917SReza.Sabdar@Sun.COM } 2437917SReza.Sabdar@Sun.COM 2447917SReza.Sabdar@Sun.COM if (sd->inq_dtype == DTYPE_CHANGER) { 2457917SReza.Sabdar@Sun.COM /* This is a robot, which means this is also a library */ 2467917SReza.Sabdar@Sun.COM nlp = (int *)arg; 2477917SReza.Sabdar@Sun.COM (*nlp)++; 2487917SReza.Sabdar@Sun.COM l = tlm_insert_new_library(slink); 2497917SReza.Sabdar@Sun.COM tlm_enable_barcode(l); 2507917SReza.Sabdar@Sun.COM 2517917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "lib %d sid %d lun %d", 2527917SReza.Sabdar@Sun.COM l, slink->sl_sid, slink->sl_lun); 2537917SReza.Sabdar@Sun.COM 2547917SReza.Sabdar@Sun.COM if ((ssd = sasd_slink_drive(slink)) != NULL) { 2557917SReza.Sabdar@Sun.COM (void) strlcpy(ssd->sd_vendor, sd->inq_vid, 2567917SReza.Sabdar@Sun.COM sizeof (ssd->sd_vendor)); 2577917SReza.Sabdar@Sun.COM (void) strlcpy(ssd->sd_id, sd->inq_pid, 2587917SReza.Sabdar@Sun.COM sizeof (ssd->sd_id)); 2597917SReza.Sabdar@Sun.COM (void) strlcpy(ssd->sd_rev, sd->inq_revision, 2607917SReza.Sabdar@Sun.COM sizeof (ssd->sd_rev)); 261*8193SReza.Sabdar@Sun.COM (void) read_serial_num_page(slink, ssd->sd_serial, 262*8193SReza.Sabdar@Sun.COM sizeof (ssd->sd_serial)); 263*8193SReza.Sabdar@Sun.COM (void) read_device_wwn(slink, ssd->sd_wwn, 264*8193SReza.Sabdar@Sun.COM sizeof (ssd->sd_wwn)); 2657917SReza.Sabdar@Sun.COM } 2667917SReza.Sabdar@Sun.COM } 2677917SReza.Sabdar@Sun.COM 2687917SReza.Sabdar@Sun.COM return (TLM_NO_ERRORS); 2697917SReza.Sabdar@Sun.COM } 2707917SReza.Sabdar@Sun.COM 2717917SReza.Sabdar@Sun.COM /* 2727917SReza.Sabdar@Sun.COM * Create some virutal slots 2737917SReza.Sabdar@Sun.COM */ 2747917SReza.Sabdar@Sun.COM static int 2757917SReza.Sabdar@Sun.COM make_virtual_slot(int l, tlm_drive_t *dp) 2767917SReza.Sabdar@Sun.COM { 2777917SReza.Sabdar@Sun.COM int s; 2787917SReza.Sabdar@Sun.COM tlm_slot_t *sp; 2797917SReza.Sabdar@Sun.COM 2807917SReza.Sabdar@Sun.COM if (l <= 0 || !dp) { 2817917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Invalid argument %d, %x", l, dp); 2827917SReza.Sabdar@Sun.COM return (-TLM_INVALID); 2837917SReza.Sabdar@Sun.COM } 2847917SReza.Sabdar@Sun.COM 2857917SReza.Sabdar@Sun.COM if ((s = tlm_insert_new_slot(l)) <= 0) 2867917SReza.Sabdar@Sun.COM return (-TLM_NO_MEMORY); 2877917SReza.Sabdar@Sun.COM 2887917SReza.Sabdar@Sun.COM if (!(sp = tlm_slot(l, s))) { 2897917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Internal error: slot not found %d", s); 2907917SReza.Sabdar@Sun.COM return (-TLM_ERROR_INTERNAL); 2917917SReza.Sabdar@Sun.COM } 2927917SReza.Sabdar@Sun.COM /* 2937917SReza.Sabdar@Sun.COM * For virtual slots element number is 0 and they are always full. 2947917SReza.Sabdar@Sun.COM */ 2957917SReza.Sabdar@Sun.COM sp->ts_element = 0; 2967917SReza.Sabdar@Sun.COM sp->ts_status_full = TRUE; 2977917SReza.Sabdar@Sun.COM return (TLM_NO_ERRORS); 2987917SReza.Sabdar@Sun.COM } 2997917SReza.Sabdar@Sun.COM 3007917SReza.Sabdar@Sun.COM /* 3017917SReza.Sabdar@Sun.COM * Make the tape drive not part of a tape library (stand alone) 3027917SReza.Sabdar@Sun.COM */ 3037917SReza.Sabdar@Sun.COM static int 3047917SReza.Sabdar@Sun.COM make_stand_alone_drive(scsi_link_t *slink, int l) 3057917SReza.Sabdar@Sun.COM { 3067917SReza.Sabdar@Sun.COM int d; 3077917SReza.Sabdar@Sun.COM tlm_drive_t *dp; 3087917SReza.Sabdar@Sun.COM 3097917SReza.Sabdar@Sun.COM if (!slink || l <= 0) { 3107917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Invalid argument %x %d", slink, l); 3117917SReza.Sabdar@Sun.COM return (-TLM_INVALID); 3127917SReza.Sabdar@Sun.COM } 3137917SReza.Sabdar@Sun.COM 3147917SReza.Sabdar@Sun.COM d = tlm_insert_new_drive(l); 3157917SReza.Sabdar@Sun.COM if (!(dp = tlm_drive(l, d))) { 3167917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Internal error: drive not found %d", d); 3177917SReza.Sabdar@Sun.COM return (-TLM_ERROR_INTERNAL); 3187917SReza.Sabdar@Sun.COM } 3197917SReza.Sabdar@Sun.COM 3207917SReza.Sabdar@Sun.COM /* For stand-alone drives, the element number is the drive number. */ 3217917SReza.Sabdar@Sun.COM dp->td_element = d; 3227917SReza.Sabdar@Sun.COM dp->td_slink = slink; 3237917SReza.Sabdar@Sun.COM dp->td_scsi_id = slink->sl_sid; 3247917SReza.Sabdar@Sun.COM dp->td_lun = slink->sl_lun; 3257917SReza.Sabdar@Sun.COM dp->td_exists = TRUE; 3267917SReza.Sabdar@Sun.COM 3277917SReza.Sabdar@Sun.COM /* 3287917SReza.Sabdar@Sun.COM * Note: There is no way to remove library elements. We cannot clean 3297917SReza.Sabdar@Sun.COM * up if make_virtual_slot() fails. 3307917SReza.Sabdar@Sun.COM */ 3317917SReza.Sabdar@Sun.COM (void) make_virtual_slot(l, dp); 3327917SReza.Sabdar@Sun.COM return (d); 3337917SReza.Sabdar@Sun.COM } 3347917SReza.Sabdar@Sun.COM 3357917SReza.Sabdar@Sun.COM /* 3367917SReza.Sabdar@Sun.COM * Find the LIBRARY structure that has control of this DRIVE. 3377917SReza.Sabdar@Sun.COM */ 3387917SReza.Sabdar@Sun.COM static int 3397917SReza.Sabdar@Sun.COM new_drive(scsi_link_t *slink, int *lib) 3407917SReza.Sabdar@Sun.COM { 3417917SReza.Sabdar@Sun.COM int d; 3427917SReza.Sabdar@Sun.COM tlm_drive_t *dp; 3437917SReza.Sabdar@Sun.COM tlm_library_t *lp; 3447917SReza.Sabdar@Sun.COM 3457917SReza.Sabdar@Sun.COM /* Walk through all libraries. */ 3467917SReza.Sabdar@Sun.COM for (*lib = 1; *lib <= tlm_library_count(); (*lib)++) { 3477917SReza.Sabdar@Sun.COM if (!(lp = tlm_library(*lib))) 3487917SReza.Sabdar@Sun.COM continue; 3497917SReza.Sabdar@Sun.COM /* Walk through drives that are already found. */ 3507917SReza.Sabdar@Sun.COM for (d = 1; d <= lp->tl_drive_count; d++) { 3517917SReza.Sabdar@Sun.COM if (!(dp = tlm_drive(*lib, d))) 3527917SReza.Sabdar@Sun.COM continue; 3537917SReza.Sabdar@Sun.COM if (dp->td_scsi_id == slink->sl_sid && 3547917SReza.Sabdar@Sun.COM dp->td_lun == slink->sl_lun) 3557917SReza.Sabdar@Sun.COM return (d); 3567917SReza.Sabdar@Sun.COM } 3577917SReza.Sabdar@Sun.COM } 3587917SReza.Sabdar@Sun.COM 3597917SReza.Sabdar@Sun.COM /* Not part of any library, this is a newly found tape drive. */ 3607917SReza.Sabdar@Sun.COM return (0); 3617917SReza.Sabdar@Sun.COM } 3627917SReza.Sabdar@Sun.COM 363*8193SReza.Sabdar@Sun.COM 3647917SReza.Sabdar@Sun.COM /* 3657917SReza.Sabdar@Sun.COM * Add the tape library call back function (used while scanning the bus) 3667917SReza.Sabdar@Sun.COM */ 3677917SReza.Sabdar@Sun.COM static int 3687917SReza.Sabdar@Sun.COM add_drv(scsi_link_t *slink, struct scsi_inquiry *sd, void *arg) 3697917SReza.Sabdar@Sun.COM { 3707917SReza.Sabdar@Sun.COM int l, d; 3717917SReza.Sabdar@Sun.COM int *vlp; /* pointer to virtual library number */ 3727917SReza.Sabdar@Sun.COM sasd_drive_t *ssd; 3737917SReza.Sabdar@Sun.COM tlm_library_t *library; 3747917SReza.Sabdar@Sun.COM tlm_drive_t *drive; 3757917SReza.Sabdar@Sun.COM 3767917SReza.Sabdar@Sun.COM if (!slink || !sd) { 3777917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Invalid argument %x %x %x", 3787917SReza.Sabdar@Sun.COM slink, sd, arg); 3797917SReza.Sabdar@Sun.COM return (-TLM_INVALID); 3807917SReza.Sabdar@Sun.COM } 3817917SReza.Sabdar@Sun.COM 3827917SReza.Sabdar@Sun.COM if (sd->inq_dtype == DTYPE_SEQUENTIAL) { 3837917SReza.Sabdar@Sun.COM vlp = (int *)arg; 3847917SReza.Sabdar@Sun.COM d = new_drive(slink, &l); 3857917SReza.Sabdar@Sun.COM if (d == 0) { 3867917SReza.Sabdar@Sun.COM /* This tape drive was not found inside any robot. */ 3877917SReza.Sabdar@Sun.COM if (*vlp == 0) { 3887917SReza.Sabdar@Sun.COM /* 3897917SReza.Sabdar@Sun.COM * First, create a virtual library if it's not 3907917SReza.Sabdar@Sun.COM * done yet. 3917917SReza.Sabdar@Sun.COM */ 3927917SReza.Sabdar@Sun.COM *vlp = tlm_insert_new_library(slink); 3937917SReza.Sabdar@Sun.COM if ((library = tlm_library(*vlp)) != NULL) 3947917SReza.Sabdar@Sun.COM library->tl_capability_robot = FALSE; 3957917SReza.Sabdar@Sun.COM } 3967917SReza.Sabdar@Sun.COM if ((d = make_stand_alone_drive(slink, *vlp)) < 0) { 3977917SReza.Sabdar@Sun.COM /* sorry, we can not clean up the vlib now * */ 3987917SReza.Sabdar@Sun.COM return (-TLM_INVALID); 3997917SReza.Sabdar@Sun.COM } 4007917SReza.Sabdar@Sun.COM l = *vlp; 4017917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "vlib(%d, %d) sid %d lun %d", 4027917SReza.Sabdar@Sun.COM l, d, slink->sl_sid, slink->sl_lun); 4037917SReza.Sabdar@Sun.COM } else 4047917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "(%d, %d) sid %d lun %d", 4057917SReza.Sabdar@Sun.COM l, d, slink->sl_sid, slink->sl_lun); 4067917SReza.Sabdar@Sun.COM 4077917SReza.Sabdar@Sun.COM if ((drive = tlm_drive(l, d)) != NULL) { 4087917SReza.Sabdar@Sun.COM drive->td_exists = TRUE; 4097917SReza.Sabdar@Sun.COM drive->td_slink = slink; 4107917SReza.Sabdar@Sun.COM } 4117917SReza.Sabdar@Sun.COM if ((ssd = sasd_slink_drive(slink)) != NULL) { 4127917SReza.Sabdar@Sun.COM (void) strlcpy(ssd->sd_vendor, 4137917SReza.Sabdar@Sun.COM sd->inq_vid, sizeof (ssd->sd_vendor)); 4147917SReza.Sabdar@Sun.COM (void) strlcpy(ssd->sd_id, sd->inq_pid, 4157917SReza.Sabdar@Sun.COM sizeof (ssd->sd_id)); 4167917SReza.Sabdar@Sun.COM (void) strlcpy(ssd->sd_rev, sd->inq_revision, 4177917SReza.Sabdar@Sun.COM sizeof (ssd->sd_rev)); 418*8193SReza.Sabdar@Sun.COM (void) read_serial_num_page(slink, ssd->sd_serial, 419*8193SReza.Sabdar@Sun.COM sizeof (ssd->sd_serial)); 420*8193SReza.Sabdar@Sun.COM (void) read_device_wwn(slink, ssd->sd_wwn, 421*8193SReza.Sabdar@Sun.COM sizeof (ssd->sd_wwn)); 4227917SReza.Sabdar@Sun.COM } 4237917SReza.Sabdar@Sun.COM } 4247917SReza.Sabdar@Sun.COM 4257917SReza.Sabdar@Sun.COM return (TLM_NO_ERRORS); 4267917SReza.Sabdar@Sun.COM } 4277917SReza.Sabdar@Sun.COM 4287917SReza.Sabdar@Sun.COM /* 4297917SReza.Sabdar@Sun.COM * Scan the specified bus and call the handler function. 4307917SReza.Sabdar@Sun.COM */ 4317917SReza.Sabdar@Sun.COM static int 4327917SReza.Sabdar@Sun.COM scan_bus(scsi_adapter_t *sa, int(*hndlr)(), void *args) 4337917SReza.Sabdar@Sun.COM { 4347917SReza.Sabdar@Sun.COM int nerr; 4357917SReza.Sabdar@Sun.COM scsi_link_t *slink; 4367917SReza.Sabdar@Sun.COM struct scsi_inquiry scsi_data; 4377917SReza.Sabdar@Sun.COM 4387917SReza.Sabdar@Sun.COM nerr = 0; 4397917SReza.Sabdar@Sun.COM slink = sa->sa_link_head.sl_next; 4407917SReza.Sabdar@Sun.COM for (; slink != &sa->sa_link_head; slink = slink->sl_next) { 4417917SReza.Sabdar@Sun.COM (void) memset(&scsi_data, 0, sizeof (struct scsi_inquiry)); 4427917SReza.Sabdar@Sun.COM if (read_inquiry_page(slink, &scsi_data) == -1) 4437917SReza.Sabdar@Sun.COM nerr++; 4447917SReza.Sabdar@Sun.COM else 4457917SReza.Sabdar@Sun.COM if ((*hndlr)(slink, &scsi_data, args) != TLM_NO_ERRORS) 4467917SReza.Sabdar@Sun.COM nerr++; 4477917SReza.Sabdar@Sun.COM } 4487917SReza.Sabdar@Sun.COM 4497917SReza.Sabdar@Sun.COM return (nerr); 4507917SReza.Sabdar@Sun.COM } 4517917SReza.Sabdar@Sun.COM 4527917SReza.Sabdar@Sun.COM /* 4537917SReza.Sabdar@Sun.COM * Marks the library/slots inaccessible if there are not enough drives 4547917SReza.Sabdar@Sun.COM * available on the library 4557917SReza.Sabdar@Sun.COM */ 4567917SReza.Sabdar@Sun.COM static void 4577917SReza.Sabdar@Sun.COM inaccbl_drv_warn(int start, int max) 4587917SReza.Sabdar@Sun.COM { 4597917SReza.Sabdar@Sun.COM char *dname; 4607917SReza.Sabdar@Sun.COM int l, d; 4617917SReza.Sabdar@Sun.COM tlm_library_t *lp; 4627917SReza.Sabdar@Sun.COM 4637917SReza.Sabdar@Sun.COM for (l = start; l < max; l++) { 4647917SReza.Sabdar@Sun.COM if (!(lp = tlm_library(l))) 4657917SReza.Sabdar@Sun.COM continue; 4667917SReza.Sabdar@Sun.COM if (lp->tl_drive_count <= 0) 4677917SReza.Sabdar@Sun.COM continue; 4687917SReza.Sabdar@Sun.COM 4697917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 4707917SReza.Sabdar@Sun.COM "Warning: The following drives are not accessible:"); 4717917SReza.Sabdar@Sun.COM for (d = 1; d <= lp->tl_drive_count; d++) 4727917SReza.Sabdar@Sun.COM if (!(dname = tlm_get_tape_name(l, d))) { 4737917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 4747917SReza.Sabdar@Sun.COM "Error getting drive(%d, %d)", l, d); 4757917SReza.Sabdar@Sun.COM } else 4767917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "%s", dname); 4777917SReza.Sabdar@Sun.COM 4787917SReza.Sabdar@Sun.COM /* 4797917SReza.Sabdar@Sun.COM * Note: Make the slots inaccessible to prevent running 4807917SReza.Sabdar@Sun.COM * discovery on these libraries. The better idea is 4817917SReza.Sabdar@Sun.COM * removing these libraries, but we don't have that 4827917SReza.Sabdar@Sun.COM * feature available now. 4837917SReza.Sabdar@Sun.COM */ 4847917SReza.Sabdar@Sun.COM lp->tl_slot_count = 0; 4857917SReza.Sabdar@Sun.COM } 4867917SReza.Sabdar@Sun.COM } 4877917SReza.Sabdar@Sun.COM 4887917SReza.Sabdar@Sun.COM /* 4897917SReza.Sabdar@Sun.COM * Initialize the tape library data structure, asks the libraries what 4907917SReza.Sabdar@Sun.COM * equipments they have. 4917917SReza.Sabdar@Sun.COM */ 4927917SReza.Sabdar@Sun.COM int 4937917SReza.Sabdar@Sun.COM tlm_init(void) 4947917SReza.Sabdar@Sun.COM { 4957917SReza.Sabdar@Sun.COM static int nlibs; /* number of found libraries */ 4967917SReza.Sabdar@Sun.COM int i, nsa; 4977917SReza.Sabdar@Sun.COM int l, vlibs, d; 4987917SReza.Sabdar@Sun.COM int rv; 4997917SReza.Sabdar@Sun.COM scsi_adapter_t *sa; 5007917SReza.Sabdar@Sun.COM tlm_library_t *lp; 5017917SReza.Sabdar@Sun.COM tlm_drive_t *dp; 5027917SReza.Sabdar@Sun.COM 5037917SReza.Sabdar@Sun.COM /* Search through all SCSI adapters, look for tape robots. */ 5047917SReza.Sabdar@Sun.COM nlibs = 0; 5057917SReza.Sabdar@Sun.COM 5067917SReza.Sabdar@Sun.COM /* 5077917SReza.Sabdar@Sun.COM * We probe both changers and tape drives here 5087917SReza.Sabdar@Sun.COM * but later on this needs to be removed as the 5097917SReza.Sabdar@Sun.COM * probe will happen somewhere else. 5107917SReza.Sabdar@Sun.COM */ 5117917SReza.Sabdar@Sun.COM (void) probe_scsi(); 5127917SReza.Sabdar@Sun.COM 5137917SReza.Sabdar@Sun.COM nsa = scsi_get_adapter_count(); 5147917SReza.Sabdar@Sun.COM for (i = 0; i < nsa; i++) 5157917SReza.Sabdar@Sun.COM if ((sa = scsi_get_adapter(i))) 5167917SReza.Sabdar@Sun.COM (void) scan_bus(sa, add_lib, (void *)&nlibs); 5177917SReza.Sabdar@Sun.COM 5187917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "nlibs %d", nlibs); 5197917SReza.Sabdar@Sun.COM 5207917SReza.Sabdar@Sun.COM /* Search through all SCSI adapters, look for tape drives. */ 5217917SReza.Sabdar@Sun.COM vlibs = 0; 5227917SReza.Sabdar@Sun.COM for (i = 0; i < nsa; i++) 5237917SReza.Sabdar@Sun.COM if ((sa = scsi_get_adapter(i))) 5247917SReza.Sabdar@Sun.COM (void) scan_bus(sa, add_drv, (void *)&vlibs); 5257917SReza.Sabdar@Sun.COM 5267917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "vlibs %d", vlibs); 5277917SReza.Sabdar@Sun.COM 5287917SReza.Sabdar@Sun.COM if (nlibs > 0 && vlibs > 0) 5297917SReza.Sabdar@Sun.COM inaccbl_drv_warn(nlibs + 1, vlibs + nlibs + 1); 5307917SReza.Sabdar@Sun.COM 5317917SReza.Sabdar@Sun.COM for (l = 1; l <= tlm_library_count(); l++) { 5327917SReza.Sabdar@Sun.COM if (!(lp = tlm_library(l))) { 5337917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "can't find lib %d", l); 5347917SReza.Sabdar@Sun.COM continue; 5357917SReza.Sabdar@Sun.COM } 5367917SReza.Sabdar@Sun.COM 5377917SReza.Sabdar@Sun.COM /* 5387917SReza.Sabdar@Sun.COM * Make sure all libraries have tape drives. 5397917SReza.Sabdar@Sun.COM */ 5407917SReza.Sabdar@Sun.COM if (lp->tl_drive_count == 0) 5417917SReza.Sabdar@Sun.COM continue; 5427917SReza.Sabdar@Sun.COM 5437917SReza.Sabdar@Sun.COM /* 5447917SReza.Sabdar@Sun.COM * Make sure all tape drives exist. A drive that is not 5457917SReza.Sabdar@Sun.COM * linked into the SCSI chain will be seen by the library 5467917SReza.Sabdar@Sun.COM * but we cannot talk to it. 5477917SReza.Sabdar@Sun.COM */ 5487917SReza.Sabdar@Sun.COM for (d = 1; d <= lp->tl_drive_count; d++) { 5497917SReza.Sabdar@Sun.COM dp = tlm_drive(l, d); 5507917SReza.Sabdar@Sun.COM if (dp && !dp->td_exists) { 5517917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Ghost drive found %d.%d", 5527917SReza.Sabdar@Sun.COM l, d); 5537917SReza.Sabdar@Sun.COM lp->tl_ghost_drives = TRUE; 5547917SReza.Sabdar@Sun.COM continue; 5557917SReza.Sabdar@Sun.COM } 5567917SReza.Sabdar@Sun.COM } 5577917SReza.Sabdar@Sun.COM } 5587917SReza.Sabdar@Sun.COM 5597917SReza.Sabdar@Sun.COM if (nlibs > 0) 5607917SReza.Sabdar@Sun.COM rv = (vlibs > 0) ? 0 : nlibs; 5617917SReza.Sabdar@Sun.COM else 5627917SReza.Sabdar@Sun.COM rv = vlibs; 5637917SReza.Sabdar@Sun.COM 5647917SReza.Sabdar@Sun.COM return (rv); 5657917SReza.Sabdar@Sun.COM } 566