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
read_scsi_page(scsi_link_t * slink,union scsi_cdb * cdb,int command_size,caddr_t data,int size)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
read_inquiry_page(scsi_link_t * slink,struct scsi_inquiry * inq)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
read_data_page(scsi_link_t * slink,int pcode,char * snum,int size)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
read_serial_num_page(scsi_link_t * slink,char * snum,int size)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
read_dev_name_page(scsi_link_t * slink,device_ident_header_t * devp,int len)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
snprintf_wwn(char * buf,int size,uint8_t * wwn)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
read_device_wwn(scsi_link_t * slink,char * wwnp,int wsize)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
add_lib(scsi_link_t * slink,struct scsi_inquiry * sd,void * arg)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
make_virtual_slot(int l,tlm_drive_t * dp)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
make_stand_alone_drive(scsi_link_t * slink,int l)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
new_drive(scsi_link_t * slink,int * lib)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
add_drv(scsi_link_t * slink,struct scsi_inquiry * sd,void * arg)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
scan_bus(scsi_adapter_t * sa,int (* hndlr)(),void * args)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
inaccbl_drv_warn(int start,int max)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
tlm_init(void)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