xref: /illumos-gate/usr/src/cmd/ndmpd/tlm/tlm_init.c (revision e461e790)
12654012fSReza Sabdar /*
2*e461e790SRandall 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>
42*e461e790SRandall Ralphs #include <ctype.h>
43*e461e790SRandall 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 
1147bc22e45SReza 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
157*e461e790SRandall Ralphs read_dev_name_page(scsi_link_t *slink, device_ident_header_t *devp, int len)
1587bc22e45SReza Sabdar {
159*e461e790SRandall Ralphs 	(void) memset(devp, 0, len);
1607bc22e45SReza Sabdar 
1617bc22e45SReza Sabdar 	if (read_data_page(slink, SCSI_DEVICE_IDENT_PAGE, (caddr_t)devp,
162*e461e790SRandall Ralphs 	    len) == -1)
1637bc22e45SReza Sabdar 		return (-1);
1647bc22e45SReza Sabdar 
165*e461e790SRandall Ralphs 	if (devp->di_page_code != SCSI_DEVICE_IDENT_PAGE)
166*e461e790SRandall Ralphs 		return (-1);
1677bc22e45SReza Sabdar 
168*e461e790SRandall Ralphs 	return (0);
1697bc22e45SReza Sabdar }
1707bc22e45SReza Sabdar 
1717bc22e45SReza Sabdar /*
1727bc22e45SReza Sabdar  * Formatted print of WWN
1737bc22e45SReza Sabdar  */
174*e461e790SRandall Ralphs static void
1757bc22e45SReza Sabdar snprintf_wwn(char *buf, int size, uint8_t *wwn)
1767bc22e45SReza Sabdar {
1777bc22e45SReza Sabdar 	if (wwn == NULL || buf == NULL)
178*e461e790SRandall 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 {
191*e461e790SRandall Ralphs 	device_ident_header_t *header;
192*e461e790SRandall Ralphs 	name_ident_t *ident;
193*e461e790SRandall Ralphs 	uint16_t page_len = sizeof (device_ident_header_t);
194*e461e790SRandall Ralphs 	uint16_t act_len;
195*e461e790SRandall Ralphs 	int accessed;
196*e461e790SRandall Ralphs 	uint8_t *designator_data;
1977bc22e45SReza Sabdar 
1987bc22e45SReza Sabdar 	(void) memset(wwnp, 0, wsize);
199*e461e790SRandall Ralphs resize:
200*e461e790SRandall Ralphs 	header = malloc(page_len);
201*e461e790SRandall Ralphs 	if (header == NULL)
2027bc22e45SReza Sabdar 		return (-1);
2037bc22e45SReza Sabdar 
204*e461e790SRandall Ralphs 	if (read_dev_name_page(slink, header, page_len) == -1) {
205*e461e790SRandall Ralphs 		free(header);
206*e461e790SRandall Ralphs 		return (-1);
2077bc22e45SReza Sabdar 	}
208*e461e790SRandall Ralphs 
209*e461e790SRandall Ralphs 	act_len = BE_16(header->di_page_length);
210*e461e790SRandall Ralphs 	if (act_len > page_len) {
211*e461e790SRandall Ralphs 		free(header);
212*e461e790SRandall Ralphs 		page_len = act_len;
213*e461e790SRandall Ralphs 		goto resize;
2147bc22e45SReza Sabdar 	}
215*e461e790SRandall Ralphs 
216*e461e790SRandall Ralphs 	ident = (name_ident_t *)&header[1];
217*e461e790SRandall Ralphs 	accessed = sizeof (device_ident_header_t);
218*e461e790SRandall Ralphs 
219*e461e790SRandall Ralphs 	while (accessed < act_len) {
220*e461e790SRandall Ralphs 
221*e461e790SRandall Ralphs 		accessed += sizeof (name_ident_t);
222*e461e790SRandall Ralphs 		accessed += ident->ni_ident_length;
223*e461e790SRandall Ralphs 		designator_data = (uint8_t *)&ident[1];
224*e461e790SRandall Ralphs 		/*
225*e461e790SRandall Ralphs 		 * Looking for code set 1 (Binary) ident type NAA 64 bit
226*e461e790SRandall Ralphs 		 * address that is associated with the node (0).
227*e461e790SRandall Ralphs 		 */
228*e461e790SRandall Ralphs 		if ((ident->ni_code_set == 1) &&
229*e461e790SRandall Ralphs 		    (ident->ni_ident_type == 3)) {
230*e461e790SRandall Ralphs 			snprintf_wwn(wwnp, wsize, designator_data);
231*e461e790SRandall Ralphs 			/*
232*e461e790SRandall Ralphs 			 * If assc is zero (Node) this is the one we want.
233*e461e790SRandall Ralphs 			 * If we find that we're done.
234*e461e790SRandall Ralphs 			 */
235*e461e790SRandall Ralphs 			if (ident->ni_asso == 0)
236*e461e790SRandall Ralphs 				break;
237*e461e790SRandall Ralphs 		}
238*e461e790SRandall Ralphs 		/*
239*e461e790SRandall Ralphs 		 * If we find a EUI-64 we can use that also.
240*e461e790SRandall Ralphs 		 */
241*e461e790SRandall Ralphs 		if ((ident->ni_code_set == 2) &&
242*e461e790SRandall Ralphs 		    (ident->ni_ident_type == 1) &&
243*e461e790SRandall Ralphs 		    (ident->ni_asso == 0) &&
244*e461e790SRandall Ralphs 		    (isprint(wwnp[0] == 0))) { /* Don't overwrite */
245*e461e790SRandall Ralphs 			/*
246*e461e790SRandall Ralphs 			 * This isn't our first choice but we'll print it
247*e461e790SRandall Ralphs 			 * in case there is nothing else to use.
248*e461e790SRandall Ralphs 			 */
249*e461e790SRandall Ralphs 			(void) snprintf(wwnp, wsize, "%.*s",
250*e461e790SRandall Ralphs 			    ident->ni_ident_length, designator_data);
251*e461e790SRandall Ralphs 		}
252*e461e790SRandall Ralphs 		ident =
253*e461e790SRandall Ralphs 		    (name_ident_t *)&designator_data[ident->ni_ident_length];
2547bc22e45SReza Sabdar 	}
255*e461e790SRandall Ralphs 	free(header);
256*e461e790SRandall Ralphs 	/*
257*e461e790SRandall Ralphs 	 * See if we found something.
258*e461e790SRandall Ralphs 	 * Memset above would leave wwnp not printable.
259*e461e790SRandall Ralphs 	 */
260*e461e790SRandall Ralphs 	if (isprint(wwnp[0]))
2617bc22e45SReza Sabdar 		return (0);
2627bc22e45SReza Sabdar 	return (-1);
2637bc22e45SReza Sabdar }
2647bc22e45SReza Sabdar 
2652654012fSReza 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 	 */
5482654012fSReza Sabdar 	(void) probe_scsi();
5492654012fSReza Sabdar 
5502654012fSReza Sabdar 	nsa = scsi_get_adapter_count();
5512654012fSReza Sabdar 	for (i = 0; i < nsa; i++)
5522654012fSReza Sabdar 		if ((sa = scsi_get_adapter(i)))
5532654012fSReza Sabdar 			(void) scan_bus(sa, add_lib, (void *)&nlibs);
5542654012fSReza Sabdar 
5552654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "nlibs %d", nlibs);
5562654012fSReza Sabdar 
5572654012fSReza Sabdar 	/* Search through all SCSI adapters, look for tape drives. */
5582654012fSReza Sabdar 	vlibs = 0;
5592654012fSReza Sabdar 	for (i = 0; i < nsa; i++)
5602654012fSReza Sabdar 		if ((sa = scsi_get_adapter(i)))
5612654012fSReza Sabdar 			(void) scan_bus(sa, add_drv, (void *)&vlibs);
5622654012fSReza Sabdar 
5632654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "vlibs %d", vlibs);
5642654012fSReza Sabdar 
5652654012fSReza Sabdar 	if (nlibs > 0 && vlibs > 0)
5662654012fSReza Sabdar 		inaccbl_drv_warn(nlibs + 1, vlibs + nlibs + 1);
5672654012fSReza Sabdar 
5682654012fSReza Sabdar 	for (l = 1; l <= tlm_library_count(); l++) {
5692654012fSReza Sabdar 		if (!(lp = tlm_library(l))) {
5702654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "can't find lib %d", l);
5712654012fSReza Sabdar 			continue;
5722654012fSReza Sabdar 		}
5732654012fSReza Sabdar 
5742654012fSReza Sabdar 		/*
5752654012fSReza Sabdar 		 * Make sure all libraries have tape drives.
5762654012fSReza Sabdar 		 */
5772654012fSReza Sabdar 		if (lp->tl_drive_count == 0)
5782654012fSReza Sabdar 			continue;
5792654012fSReza Sabdar 
5802654012fSReza Sabdar 		/*
5812654012fSReza Sabdar 		 * Make sure all tape drives exist. A drive that is not
5822654012fSReza Sabdar 		 * linked into the SCSI chain will be seen by the library
5832654012fSReza Sabdar 		 * but we cannot talk to it.
5842654012fSReza Sabdar 		 */
5852654012fSReza Sabdar 		for (d = 1; d <= lp->tl_drive_count; d++) {
5862654012fSReza Sabdar 			dp = tlm_drive(l, d);
5872654012fSReza Sabdar 			if (dp && !dp->td_exists) {
5882654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "Ghost drive found %d.%d",
5892654012fSReza Sabdar 				    l, d);
5902654012fSReza Sabdar 				lp->tl_ghost_drives = TRUE;
5912654012fSReza Sabdar 				continue;
5922654012fSReza Sabdar 			}
5932654012fSReza Sabdar 		}
5942654012fSReza Sabdar 	}
5952654012fSReza Sabdar 
5962654012fSReza Sabdar 	if (nlibs > 0)
5972654012fSReza Sabdar 		rv = (vlibs > 0) ? 0 : nlibs;
5982654012fSReza Sabdar 	else
5992654012fSReza Sabdar 		rv = vlibs;
6002654012fSReza Sabdar 
6012654012fSReza Sabdar 	return (rv);
6022654012fSReza Sabdar }
603