xref: /illumos-gate/usr/src/cmd/ndmpd/tlm/tlm_init.c (revision 7bc22e45)
12654012fSReza Sabdar /*
22654012fSReza Sabdar  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
32654012fSReza Sabdar  * Use is subject to license terms.
42654012fSReza Sabdar  */
52654012fSReza Sabdar 
62654012fSReza Sabdar /*
72654012fSReza Sabdar  * BSD 3 Clause License
82654012fSReza Sabdar  *
92654012fSReza Sabdar  * Copyright (c) 2007, The Storage Networking Industry Association.
102654012fSReza Sabdar  *
112654012fSReza Sabdar  * Redistribution and use in source and binary forms, with or without
122654012fSReza Sabdar  * modification, are permitted provided that the following conditions
132654012fSReza Sabdar  * are met:
142654012fSReza Sabdar  * 	- Redistributions of source code must retain the above copyright
152654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer.
162654012fSReza Sabdar  *
172654012fSReza Sabdar  * 	- Redistributions in binary form must reproduce the above copyright
182654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer in
192654012fSReza Sabdar  *	  the documentation and/or other materials provided with the
202654012fSReza Sabdar  *	  distribution.
212654012fSReza Sabdar  *
222654012fSReza Sabdar  *	- Neither the name of The Storage Networking Industry Association (SNIA)
232654012fSReza Sabdar  *	  nor the names of its contributors may be used to endorse or promote
242654012fSReza Sabdar  *	  products derived from this software without specific prior written
252654012fSReza Sabdar  *	  permission.
262654012fSReza Sabdar  *
272654012fSReza Sabdar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
282654012fSReza Sabdar  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
292654012fSReza Sabdar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
302654012fSReza Sabdar  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
312654012fSReza Sabdar  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
322654012fSReza Sabdar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
332654012fSReza Sabdar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
342654012fSReza Sabdar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
352654012fSReza Sabdar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
362654012fSReza Sabdar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
372654012fSReza Sabdar  * POSSIBILITY OF SUCH DAMAGE.
382654012fSReza Sabdar  */
392654012fSReza Sabdar #include <sys/errno.h>
402654012fSReza Sabdar #include <sys/types.h>
412654012fSReza Sabdar #include <stdlib.h>
422654012fSReza Sabdar #include <unistd.h>
432654012fSReza Sabdar #include <sys/scsi/impl/uscsi.h>
442654012fSReza Sabdar #include <sys/scsi/scsi.h>
452654012fSReza Sabdar #include <tlm.h>
462654012fSReza Sabdar #include <pthread.h>
472654012fSReza Sabdar #include "tlm_proto.h"
482654012fSReza Sabdar 
492654012fSReza Sabdar /*
502654012fSReza Sabdar  * generic routine to read a SCSI page
512654012fSReza Sabdar  */
522654012fSReza Sabdar int
532654012fSReza Sabdar read_scsi_page(scsi_link_t *slink, union scsi_cdb *cdb,
542654012fSReza Sabdar     int command_size, caddr_t data, int size)
552654012fSReza Sabdar {
562654012fSReza Sabdar 	struct uscsi_cmd uscsi_cmd;
572654012fSReza Sabdar 	char *dname;
582654012fSReza Sabdar 	int dev;
592654012fSReza Sabdar 
602654012fSReza Sabdar 	if (slink == 0 || slink->sl_sa == 0)
612654012fSReza Sabdar 		return (EINVAL);
622654012fSReza Sabdar 
632654012fSReza Sabdar 	(void) memset(&uscsi_cmd, 0, sizeof (uscsi_cmd));
642654012fSReza Sabdar 
652654012fSReza Sabdar 	/* Lun is in the 5th bit */
662654012fSReza Sabdar 	cdb->scc_lun = slink->sl_lun;
672654012fSReza Sabdar 	uscsi_cmd.uscsi_flags |= USCSI_READ | USCSI_ISOLATE;
682654012fSReza Sabdar 	uscsi_cmd.uscsi_bufaddr = data;
692654012fSReza Sabdar 	uscsi_cmd.uscsi_buflen = size;
702654012fSReza Sabdar 	uscsi_cmd.uscsi_timeout = 1000;
712654012fSReza Sabdar 	uscsi_cmd.uscsi_cdb = (char *)cdb;
722654012fSReza Sabdar 
732654012fSReza Sabdar 	if (cdb->scc_cmd == SCMD_READ_ELEMENT_STATUS) {
742654012fSReza Sabdar 		uscsi_cmd.uscsi_flags |= USCSI_RQENABLE;
752654012fSReza Sabdar 		uscsi_cmd.uscsi_rqbuf = data;
762654012fSReza Sabdar 		uscsi_cmd.uscsi_rqlen = size;
772654012fSReza Sabdar 	}
782654012fSReza Sabdar 	uscsi_cmd.uscsi_cdblen = command_size;
792654012fSReza Sabdar 
802654012fSReza Sabdar 	dname = sasd_slink_name(slink);
812654012fSReza Sabdar 	dev = open(dname, O_RDWR | O_NDELAY);
822654012fSReza Sabdar 	if (dev == -1) {
832654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Open failed for %s err=%d",
842654012fSReza Sabdar 		    dname, errno);
852654012fSReza Sabdar 		return (errno);
862654012fSReza Sabdar 	}
872654012fSReza Sabdar 	if (tlm_ioctl(dev, USCSICMD, &uscsi_cmd) < 0) {
882654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "SCSI cmd %d failed for %s err=%d",
892654012fSReza Sabdar 		    cdb->scc_cmd, dname, errno);
902654012fSReza Sabdar 		(void) close(dev);
912654012fSReza Sabdar 		return (errno);
922654012fSReza Sabdar 	}
932654012fSReza Sabdar 	(void) close(dev);
942654012fSReza Sabdar 	return (uscsi_cmd.uscsi_status);
952654012fSReza Sabdar }
962654012fSReza Sabdar 
972654012fSReza Sabdar /*
982654012fSReza Sabdar  * Read the Inquiry Page.
992654012fSReza Sabdar  */
1002654012fSReza Sabdar static int
1012654012fSReza Sabdar read_inquiry_page(scsi_link_t *slink, struct scsi_inquiry *inq)
1022654012fSReza Sabdar {
1032654012fSReza Sabdar 	union scsi_cdb cdb;
1042654012fSReza Sabdar 
1052654012fSReza Sabdar 	(void) memset(&cdb, 0, sizeof (union scsi_cdb));
1062654012fSReza Sabdar 	cdb.scc_cmd = SCMD_INQUIRY;
1072654012fSReza Sabdar 	cdb.g0_count0 = sizeof (struct scsi_inquiry);
1082654012fSReza Sabdar 
1092654012fSReza Sabdar 	return (read_scsi_page(slink, &cdb, CDB_GROUP0,
1102654012fSReza Sabdar 	    (caddr_t)inq, sizeof (*inq)) ? -1 : 0);
1112654012fSReza Sabdar }
1122654012fSReza Sabdar 
113*7bc22e45SReza Sabdar /*
114*7bc22e45SReza Sabdar  * Read the Product Data Page.
115*7bc22e45SReza Sabdar  */
116*7bc22e45SReza Sabdar static int
117*7bc22e45SReza Sabdar read_data_page(scsi_link_t *slink, int pcode, char *snum, int size)
118*7bc22e45SReza Sabdar {
119*7bc22e45SReza Sabdar 	char cmd[CDB_GROUP0];
120*7bc22e45SReza Sabdar 
121*7bc22e45SReza Sabdar 	(void) memset(cmd, 0, sizeof (cmd));
122*7bc22e45SReza Sabdar 
123*7bc22e45SReza Sabdar 	cmd[0] = SCMD_INQUIRY;
124*7bc22e45SReza Sabdar 	cmd[1] = pcode ? 0x01 : 0x00;
125*7bc22e45SReza Sabdar 	cmd[2] = pcode;
126*7bc22e45SReza Sabdar 	cmd[4] = size;
127*7bc22e45SReza Sabdar 
128*7bc22e45SReza Sabdar 	/* LINTED improper alignment */
129*7bc22e45SReza Sabdar 	return (read_scsi_page(slink, (union scsi_cdb *)&cmd, CDB_GROUP0,
130*7bc22e45SReza Sabdar 	    (caddr_t)snum, size) == -1 ? -1 : 0);
131*7bc22e45SReza Sabdar }
132*7bc22e45SReza Sabdar 
133*7bc22e45SReza Sabdar 
134*7bc22e45SReza Sabdar /*
135*7bc22e45SReza Sabdar  * Read the Serial Number Page.
136*7bc22e45SReza Sabdar  */
137*7bc22e45SReza Sabdar static int
138*7bc22e45SReza Sabdar read_serial_num_page(scsi_link_t *slink, char *snum, int size)
139*7bc22e45SReza Sabdar {
140*7bc22e45SReza Sabdar 	scsi_serial_t serial;
141*7bc22e45SReza Sabdar 	int rv;
142*7bc22e45SReza Sabdar 
143*7bc22e45SReza Sabdar 	(void) memset(&serial, 0, sizeof (scsi_serial_t));
144*7bc22e45SReza Sabdar 	rv = read_data_page(slink, SCSI_SERIAL_PAGE, (caddr_t)&serial,
145*7bc22e45SReza Sabdar 	    sizeof (scsi_serial_t));
146*7bc22e45SReza Sabdar 	(void) strlcpy(snum, serial.sr_num, size);
147*7bc22e45SReza Sabdar 
148*7bc22e45SReza Sabdar 	return (rv == -1 ? -1 : 0);
149*7bc22e45SReza Sabdar }
150*7bc22e45SReza Sabdar 
151*7bc22e45SReza Sabdar 
152*7bc22e45SReza Sabdar /*
153*7bc22e45SReza Sabdar  * Read the Device Name Page.
154*7bc22e45SReza Sabdar  */
155*7bc22e45SReza Sabdar static int
156*7bc22e45SReza Sabdar read_dev_name_page(scsi_link_t *slink, device_name_page_t *devp)
157*7bc22e45SReza Sabdar {
158*7bc22e45SReza Sabdar 	(void) memset(devp, 0, sizeof (device_name_page_t));
159*7bc22e45SReza Sabdar 
160*7bc22e45SReza Sabdar 	if (read_data_page(slink, SCSI_DEVICE_IDENT_PAGE, (caddr_t)devp,
161*7bc22e45SReza Sabdar 	    sizeof (device_name_page_t)) == -1)
162*7bc22e45SReza Sabdar 		return (-1);
163*7bc22e45SReza Sabdar 
164*7bc22e45SReza Sabdar 	if (devp->np_header.di_page_code == SCSI_DEVICE_IDENT_PAGE &&
165*7bc22e45SReza Sabdar 	    devp->np_node.ni_code_set == 1 &&
166*7bc22e45SReza Sabdar 	    devp->np_node.ni_ident_type == 3 &&
167*7bc22e45SReza Sabdar 	    devp->np_node.ni_ident_length == 8)
168*7bc22e45SReza Sabdar 		return (0);
169*7bc22e45SReza Sabdar 
170*7bc22e45SReza Sabdar 	if (devp->np_header.di_page_code == SCSI_DEVICE_IDENT_PAGE)
171*7bc22e45SReza Sabdar 		return (0);
172*7bc22e45SReza Sabdar 
173*7bc22e45SReza Sabdar 	return (-1);
174*7bc22e45SReza Sabdar }
175*7bc22e45SReza Sabdar 
176*7bc22e45SReza Sabdar /*
177*7bc22e45SReza Sabdar  * Formatted print of WWN
178*7bc22e45SReza Sabdar  */
179*7bc22e45SReza Sabdar char *
180*7bc22e45SReza Sabdar snprintf_wwn(char *buf, int size, uint8_t *wwn)
181*7bc22e45SReza Sabdar {
182*7bc22e45SReza Sabdar 	if (wwn == NULL || buf == NULL)
183*7bc22e45SReza Sabdar 		return (0);
184*7bc22e45SReza Sabdar 
185*7bc22e45SReza Sabdar 	(void) snprintf(buf, size, "0x%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
186*7bc22e45SReza Sabdar 	    wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
187*7bc22e45SReza Sabdar 	return (buf);
188*7bc22e45SReza Sabdar }
189*7bc22e45SReza Sabdar 
190*7bc22e45SReza Sabdar 
191*7bc22e45SReza Sabdar /*
192*7bc22e45SReza Sabdar  * Extract and print the world wide name (WWN)
193*7bc22e45SReza Sabdar  */
194*7bc22e45SReza Sabdar int
195*7bc22e45SReza Sabdar read_device_wwn(scsi_link_t *slink, char *wwnp, int wsize)
196*7bc22e45SReza Sabdar {
197*7bc22e45SReza Sabdar 	device_name_page_t dinfo;
198*7bc22e45SReza Sabdar 
199*7bc22e45SReza Sabdar 	(void) memset(wwnp, 0, wsize);
200*7bc22e45SReza Sabdar 	if (read_dev_name_page(slink, &dinfo) == -1)
201*7bc22e45SReza Sabdar 		return (-1);
202*7bc22e45SReza Sabdar 
203*7bc22e45SReza Sabdar 	if (dinfo.np_port.ni_code_set == 1 &&
204*7bc22e45SReza Sabdar 	    dinfo.np_port.ni_ident_type == 3) {
205*7bc22e45SReza Sabdar 		(void) snprintf_wwn(wwnp, wsize, dinfo.np_port_info.d_name);
206*7bc22e45SReza Sabdar 		return (0);
207*7bc22e45SReza Sabdar 	}
208*7bc22e45SReza Sabdar 	if (dinfo.np_node.ni_code_set == 1 &&
209*7bc22e45SReza Sabdar 	    dinfo.np_node.ni_ident_type == 3) {
210*7bc22e45SReza Sabdar 		(void) snprintf_wwn(wwnp, wsize, dinfo.np_node_info.d_name);
211*7bc22e45SReza Sabdar 		return (0);
212*7bc22e45SReza Sabdar 	}
213*7bc22e45SReza Sabdar 	if (dinfo.np_port.ni_code_set == 2 &&
214*7bc22e45SReza Sabdar 	    dinfo.np_port.ni_ident_type == 1) {
215*7bc22e45SReza Sabdar 		(void) snprintf(wwnp, wsize, "%.*s",
216*7bc22e45SReza Sabdar 		    dinfo.np_port.ni_ident_length, dinfo.np_port_info.d_name);
217*7bc22e45SReza Sabdar 		return (0);
218*7bc22e45SReza Sabdar 	}
219*7bc22e45SReza Sabdar 	if (dinfo.np_node.ni_code_set == 2 &&
220*7bc22e45SReza Sabdar 	    dinfo.np_node.ni_ident_type == 1) {
221*7bc22e45SReza Sabdar 		(void) snprintf(wwnp, wsize, "%.*s",
222*7bc22e45SReza Sabdar 		    dinfo.np_node.ni_ident_length, dinfo.np_node_info.d_name);
223*7bc22e45SReza Sabdar 		return (0);
224*7bc22e45SReza Sabdar 	}
225*7bc22e45SReza Sabdar 	return (-1);
226*7bc22e45SReza Sabdar }
227*7bc22e45SReza Sabdar 
2282654012fSReza Sabdar /*
2292654012fSReza Sabdar  * Add the tape library call back function (used while scanning the bus)
2302654012fSReza Sabdar  */
2312654012fSReza Sabdar static int
2322654012fSReza Sabdar add_lib(scsi_link_t *slink, struct scsi_inquiry *sd, void *arg)
2332654012fSReza Sabdar {
2342654012fSReza Sabdar 	int l;
2352654012fSReza Sabdar 	int *nlp; /* pointer to library counter */
2362654012fSReza Sabdar 	sasd_drive_t *ssd;
2372654012fSReza Sabdar 
2382654012fSReza Sabdar 	if (!slink || !sd) {
2392654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid argument %x %x %x",
2402654012fSReza Sabdar 		    slink, sd, arg);
2412654012fSReza Sabdar 		return (-TLM_INVALID);
2422654012fSReza Sabdar 	}
2432654012fSReza Sabdar 
2442654012fSReza Sabdar 	if (sd->inq_dtype == DTYPE_CHANGER) {
2452654012fSReza Sabdar 		/* This is a robot, which means this is also a library */
2462654012fSReza Sabdar 		nlp = (int *)arg;
2472654012fSReza Sabdar 		(*nlp)++;
2482654012fSReza Sabdar 		l = tlm_insert_new_library(slink);
2492654012fSReza Sabdar 		tlm_enable_barcode(l);
2502654012fSReza Sabdar 
2512654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "lib %d sid %d lun %d",
2522654012fSReza Sabdar 		    l, slink->sl_sid, slink->sl_lun);
2532654012fSReza Sabdar 
2542654012fSReza Sabdar 		if ((ssd = sasd_slink_drive(slink)) != NULL) {
2552654012fSReza Sabdar 			(void) strlcpy(ssd->sd_vendor, sd->inq_vid,
2562654012fSReza Sabdar 			    sizeof (ssd->sd_vendor));
2572654012fSReza Sabdar 			(void) strlcpy(ssd->sd_id, sd->inq_pid,
2582654012fSReza Sabdar 			    sizeof (ssd->sd_id));
2592654012fSReza Sabdar 			(void) strlcpy(ssd->sd_rev, sd->inq_revision,
2602654012fSReza Sabdar 			    sizeof (ssd->sd_rev));
261*7bc22e45SReza Sabdar 			(void) read_serial_num_page(slink, ssd->sd_serial,
262*7bc22e45SReza Sabdar 			    sizeof (ssd->sd_serial));
263*7bc22e45SReza Sabdar 			(void) read_device_wwn(slink, ssd->sd_wwn,
264*7bc22e45SReza Sabdar 			    sizeof (ssd->sd_wwn));
2652654012fSReza Sabdar 		}
2662654012fSReza Sabdar 	}
2672654012fSReza Sabdar 
2682654012fSReza Sabdar 	return (TLM_NO_ERRORS);
2692654012fSReza Sabdar }
2702654012fSReza Sabdar 
2712654012fSReza Sabdar /*
2722654012fSReza Sabdar  * Create some virutal slots
2732654012fSReza Sabdar  */
2742654012fSReza Sabdar static int
2752654012fSReza Sabdar make_virtual_slot(int l, tlm_drive_t *dp)
2762654012fSReza Sabdar {
2772654012fSReza Sabdar 	int s;
2782654012fSReza Sabdar 	tlm_slot_t *sp;
2792654012fSReza Sabdar 
2802654012fSReza Sabdar 	if (l <= 0 || !dp) {
2812654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid argument %d, %x", l, dp);
2822654012fSReza Sabdar 		return (-TLM_INVALID);
2832654012fSReza Sabdar 	}
2842654012fSReza Sabdar 
2852654012fSReza Sabdar 	if ((s = tlm_insert_new_slot(l)) <= 0)
2862654012fSReza Sabdar 		return (-TLM_NO_MEMORY);
2872654012fSReza Sabdar 
2882654012fSReza Sabdar 	if (!(sp = tlm_slot(l, s))) {
2892654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Internal error: slot not found %d", s);
2902654012fSReza Sabdar 		return (-TLM_ERROR_INTERNAL);
2912654012fSReza Sabdar 	}
2922654012fSReza Sabdar 	/*
2932654012fSReza Sabdar 	 * For virtual slots element number is 0 and they are always full.
2942654012fSReza Sabdar 	 */
2952654012fSReza Sabdar 	sp->ts_element = 0;
2962654012fSReza Sabdar 	sp->ts_status_full = TRUE;
2972654012fSReza Sabdar 	return (TLM_NO_ERRORS);
2982654012fSReza Sabdar }
2992654012fSReza Sabdar 
3002654012fSReza Sabdar /*
3012654012fSReza Sabdar  * Make the tape drive not part of a tape library (stand alone)
3022654012fSReza Sabdar  */
3032654012fSReza Sabdar static int
3042654012fSReza Sabdar make_stand_alone_drive(scsi_link_t *slink, int l)
3052654012fSReza Sabdar {
3062654012fSReza Sabdar 	int d;
3072654012fSReza Sabdar 	tlm_drive_t *dp;
3082654012fSReza Sabdar 
3092654012fSReza Sabdar 	if (!slink || l <= 0) {
3102654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid argument %x %d", slink, l);
3112654012fSReza Sabdar 		return (-TLM_INVALID);
3122654012fSReza Sabdar 	}
3132654012fSReza Sabdar 
3142654012fSReza Sabdar 	d = tlm_insert_new_drive(l);
3152654012fSReza Sabdar 	if (!(dp = tlm_drive(l, d))) {
3162654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Internal error: drive not found %d", d);
3172654012fSReza Sabdar 		return (-TLM_ERROR_INTERNAL);
3182654012fSReza Sabdar 	}
3192654012fSReza Sabdar 
3202654012fSReza Sabdar 	/* For stand-alone drives, the element number is the drive number. */
3212654012fSReza Sabdar 	dp->td_element = d;
3222654012fSReza Sabdar 	dp->td_slink = slink;
3232654012fSReza Sabdar 	dp->td_scsi_id = slink->sl_sid;
3242654012fSReza Sabdar 	dp->td_lun = slink->sl_lun;
3252654012fSReza Sabdar 	dp->td_exists = TRUE;
3262654012fSReza Sabdar 
3272654012fSReza Sabdar 	/*
3282654012fSReza Sabdar 	 * Note: There is no way to remove library elements.  We cannot clean
3292654012fSReza Sabdar 	 * up if make_virtual_slot() fails.
3302654012fSReza Sabdar 	 */
3312654012fSReza Sabdar 	(void) make_virtual_slot(l, dp);
3322654012fSReza Sabdar 	return (d);
3332654012fSReza Sabdar }
3342654012fSReza Sabdar 
3352654012fSReza Sabdar /*
3362654012fSReza Sabdar  * Find the LIBRARY structure that has control of this DRIVE.
3372654012fSReza Sabdar  */
3382654012fSReza Sabdar static int
3392654012fSReza Sabdar new_drive(scsi_link_t *slink, int *lib)
3402654012fSReza Sabdar {
3412654012fSReza Sabdar 	int d;
3422654012fSReza Sabdar 	tlm_drive_t *dp;
3432654012fSReza Sabdar 	tlm_library_t *lp;
3442654012fSReza Sabdar 
3452654012fSReza Sabdar 	/* Walk through all libraries. */
3462654012fSReza Sabdar 	for (*lib = 1; *lib <= tlm_library_count(); (*lib)++) {
3472654012fSReza Sabdar 		if (!(lp = tlm_library(*lib)))
3482654012fSReza Sabdar 			continue;
3492654012fSReza Sabdar 		/* Walk through drives that are already found. */
3502654012fSReza Sabdar 		for (d = 1; d <= lp->tl_drive_count; d++) {
3512654012fSReza Sabdar 			if (!(dp = tlm_drive(*lib, d)))
3522654012fSReza Sabdar 				continue;
3532654012fSReza Sabdar 			if (dp->td_scsi_id == slink->sl_sid &&
3542654012fSReza Sabdar 			    dp->td_lun == slink->sl_lun)
3552654012fSReza Sabdar 				return (d);
3562654012fSReza Sabdar 		}
3572654012fSReza Sabdar 	}
3582654012fSReza Sabdar 
3592654012fSReza Sabdar 	/* Not part of any library, this is a newly found tape drive. */
3602654012fSReza Sabdar 	return (0);
3612654012fSReza Sabdar }
3622654012fSReza Sabdar 
363*7bc22e45SReza Sabdar 
3642654012fSReza Sabdar /*
3652654012fSReza Sabdar  * Add the tape library call back function (used while scanning the bus)
3662654012fSReza Sabdar  */
3672654012fSReza Sabdar static int
3682654012fSReza Sabdar add_drv(scsi_link_t *slink, struct scsi_inquiry *sd, void *arg)
3692654012fSReza Sabdar {
3702654012fSReza Sabdar 	int l, d;
3712654012fSReza Sabdar 	int *vlp; /* pointer to virtual library number */
3722654012fSReza Sabdar 	sasd_drive_t *ssd;
3732654012fSReza Sabdar 	tlm_library_t *library;
3742654012fSReza Sabdar 	tlm_drive_t *drive;
3752654012fSReza Sabdar 
3762654012fSReza Sabdar 	if (!slink || !sd) {
3772654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid argument %x %x %x",
3782654012fSReza Sabdar 		    slink, sd, arg);
3792654012fSReza Sabdar 		return (-TLM_INVALID);
3802654012fSReza Sabdar 	}
3812654012fSReza Sabdar 
3822654012fSReza Sabdar 	if (sd->inq_dtype == DTYPE_SEQUENTIAL) {
3832654012fSReza Sabdar 		vlp = (int *)arg;
3842654012fSReza Sabdar 		d = new_drive(slink, &l);
3852654012fSReza Sabdar 		if (d == 0) {
3862654012fSReza Sabdar 			/* This tape drive was not found inside any robot. */
3872654012fSReza Sabdar 			if (*vlp == 0) {
3882654012fSReza Sabdar 				/*
3892654012fSReza Sabdar 				 * First, create a virtual library if it's not
3902654012fSReza Sabdar 				 * done yet.
3912654012fSReza Sabdar 				 */
3922654012fSReza Sabdar 				*vlp = tlm_insert_new_library(slink);
3932654012fSReza Sabdar 				if ((library = tlm_library(*vlp)) != NULL)
3942654012fSReza Sabdar 					library->tl_capability_robot = FALSE;
3952654012fSReza Sabdar 			}
3962654012fSReza Sabdar 			if ((d = make_stand_alone_drive(slink, *vlp)) < 0) {
3972654012fSReza Sabdar 				/* sorry, we can not clean up the vlib now * */
3982654012fSReza Sabdar 				return (-TLM_INVALID);
3992654012fSReza Sabdar 			}
4002654012fSReza Sabdar 			l = *vlp;
4012654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "vlib(%d, %d) sid %d lun %d",
4022654012fSReza Sabdar 			    l, d, slink->sl_sid, slink->sl_lun);
4032654012fSReza Sabdar 		} else
4042654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "(%d, %d) sid %d lun %d",
4052654012fSReza Sabdar 			    l, d, slink->sl_sid, slink->sl_lun);
4062654012fSReza Sabdar 
4072654012fSReza Sabdar 		if ((drive = tlm_drive(l, d)) != NULL) {
4082654012fSReza Sabdar 			drive->td_exists = TRUE;
4092654012fSReza Sabdar 			drive->td_slink = slink;
4102654012fSReza Sabdar 		}
4112654012fSReza Sabdar 		if ((ssd = sasd_slink_drive(slink)) != NULL) {
4122654012fSReza Sabdar 			(void) strlcpy(ssd->sd_vendor,
4132654012fSReza Sabdar 			    sd->inq_vid, sizeof (ssd->sd_vendor));
4142654012fSReza Sabdar 			(void) strlcpy(ssd->sd_id, sd->inq_pid,
4152654012fSReza Sabdar 			    sizeof (ssd->sd_id));
4162654012fSReza Sabdar 			(void) strlcpy(ssd->sd_rev, sd->inq_revision,
4172654012fSReza Sabdar 			    sizeof (ssd->sd_rev));
418*7bc22e45SReza Sabdar 			(void) read_serial_num_page(slink, ssd->sd_serial,
419*7bc22e45SReza Sabdar 			    sizeof (ssd->sd_serial));
420*7bc22e45SReza Sabdar 			(void) read_device_wwn(slink, ssd->sd_wwn,
421*7bc22e45SReza Sabdar 			    sizeof (ssd->sd_wwn));
4222654012fSReza Sabdar 		}
4232654012fSReza Sabdar 	}
4242654012fSReza Sabdar 
4252654012fSReza Sabdar 	return (TLM_NO_ERRORS);
4262654012fSReza Sabdar }
4272654012fSReza Sabdar 
4282654012fSReza Sabdar /*
4292654012fSReza Sabdar  * Scan the specified bus and call the handler function.
4302654012fSReza Sabdar  */
4312654012fSReza Sabdar static int
4322654012fSReza Sabdar scan_bus(scsi_adapter_t *sa, int(*hndlr)(), void *args)
4332654012fSReza Sabdar {
4342654012fSReza Sabdar 	int nerr;
4352654012fSReza Sabdar 	scsi_link_t *slink;
4362654012fSReza Sabdar 	struct scsi_inquiry scsi_data;
4372654012fSReza Sabdar 
4382654012fSReza Sabdar 	nerr = 0;
4392654012fSReza Sabdar 	slink = sa->sa_link_head.sl_next;
4402654012fSReza Sabdar 	for (; slink != &sa->sa_link_head; slink = slink->sl_next) {
4412654012fSReza Sabdar 		(void) memset(&scsi_data, 0, sizeof (struct scsi_inquiry));
4422654012fSReza Sabdar 		if (read_inquiry_page(slink, &scsi_data) == -1)
4432654012fSReza Sabdar 			nerr++;
4442654012fSReza Sabdar 		else
4452654012fSReza Sabdar 			if ((*hndlr)(slink, &scsi_data, args) != TLM_NO_ERRORS)
4462654012fSReza Sabdar 				nerr++;
4472654012fSReza Sabdar 	}
4482654012fSReza Sabdar 
4492654012fSReza Sabdar 	return (nerr);
4502654012fSReza Sabdar }
4512654012fSReza Sabdar 
4522654012fSReza Sabdar /*
4532654012fSReza Sabdar  * Marks the library/slots inaccessible if there are not enough drives
4542654012fSReza Sabdar  * available on the library
4552654012fSReza Sabdar  */
4562654012fSReza Sabdar static void
4572654012fSReza Sabdar inaccbl_drv_warn(int start, int max)
4582654012fSReza Sabdar {
4592654012fSReza Sabdar 	char *dname;
4602654012fSReza Sabdar 	int l, d;
4612654012fSReza Sabdar 	tlm_library_t *lp;
4622654012fSReza Sabdar 
4632654012fSReza Sabdar 	for (l = start; l < max; l++) {
4642654012fSReza Sabdar 		if (!(lp = tlm_library(l)))
4652654012fSReza Sabdar 			continue;
4662654012fSReza Sabdar 		if (lp->tl_drive_count <= 0)
4672654012fSReza Sabdar 			continue;
4682654012fSReza Sabdar 
4692654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
4702654012fSReza Sabdar 		    "Warning: The following drives are not accessible:");
4712654012fSReza Sabdar 		for (d = 1; d <= lp->tl_drive_count; d++)
4722654012fSReza Sabdar 			if (!(dname = tlm_get_tape_name(l, d))) {
4732654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
4742654012fSReza Sabdar 				    "Error getting drive(%d, %d)", l, d);
4752654012fSReza Sabdar 			} else
4762654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "%s", dname);
4772654012fSReza Sabdar 
4782654012fSReza Sabdar 		/*
4792654012fSReza Sabdar 		 * Note: Make the slots inaccessible to prevent running
4802654012fSReza Sabdar 		 * discovery on these libraries.  The better idea is
4812654012fSReza Sabdar 		 * removing these libraries, but we don't have that
4822654012fSReza Sabdar 		 * feature available now.
4832654012fSReza Sabdar 		 */
4842654012fSReza Sabdar 		lp->tl_slot_count = 0;
4852654012fSReza Sabdar 	}
4862654012fSReza Sabdar }
4872654012fSReza Sabdar 
4882654012fSReza Sabdar /*
4892654012fSReza Sabdar  * Initialize the tape library data structure, asks the libraries what
4902654012fSReza Sabdar  * equipments they have.
4912654012fSReza Sabdar  */
4922654012fSReza Sabdar int
4932654012fSReza Sabdar tlm_init(void)
4942654012fSReza Sabdar {
4952654012fSReza Sabdar 	static int nlibs; /* number of found libraries */
4962654012fSReza Sabdar 	int i, nsa;
4972654012fSReza Sabdar 	int l, vlibs, d;
4982654012fSReza Sabdar 	int rv;
4992654012fSReza Sabdar 	scsi_adapter_t *sa;
5002654012fSReza Sabdar 	tlm_library_t *lp;
5012654012fSReza Sabdar 	tlm_drive_t *dp;
5022654012fSReza Sabdar 
5032654012fSReza Sabdar 	/* Search through all SCSI adapters, look for tape robots. */
5042654012fSReza Sabdar 	nlibs = 0;
5052654012fSReza Sabdar 
5062654012fSReza Sabdar 	/*
5072654012fSReza Sabdar 	 * We probe both changers and tape drives here
5082654012fSReza Sabdar 	 * but later on this needs to be removed as the
5092654012fSReza Sabdar 	 * probe will happen somewhere else.
5102654012fSReza Sabdar 	 */
5112654012fSReza Sabdar 	(void) probe_scsi();
5122654012fSReza Sabdar 
5132654012fSReza Sabdar 	nsa = scsi_get_adapter_count();
5142654012fSReza Sabdar 	for (i = 0; i < nsa; i++)
5152654012fSReza Sabdar 		if ((sa = scsi_get_adapter(i)))
5162654012fSReza Sabdar 			(void) scan_bus(sa, add_lib, (void *)&nlibs);
5172654012fSReza Sabdar 
5182654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "nlibs %d", nlibs);
5192654012fSReza Sabdar 
5202654012fSReza Sabdar 	/* Search through all SCSI adapters, look for tape drives. */
5212654012fSReza Sabdar 	vlibs = 0;
5222654012fSReza Sabdar 	for (i = 0; i < nsa; i++)
5232654012fSReza Sabdar 		if ((sa = scsi_get_adapter(i)))
5242654012fSReza Sabdar 			(void) scan_bus(sa, add_drv, (void *)&vlibs);
5252654012fSReza Sabdar 
5262654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "vlibs %d", vlibs);
5272654012fSReza Sabdar 
5282654012fSReza Sabdar 	if (nlibs > 0 && vlibs > 0)
5292654012fSReza Sabdar 		inaccbl_drv_warn(nlibs + 1, vlibs + nlibs + 1);
5302654012fSReza Sabdar 
5312654012fSReza Sabdar 	for (l = 1; l <= tlm_library_count(); l++) {
5322654012fSReza Sabdar 		if (!(lp = tlm_library(l))) {
5332654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "can't find lib %d", l);
5342654012fSReza Sabdar 			continue;
5352654012fSReza Sabdar 		}
5362654012fSReza Sabdar 
5372654012fSReza Sabdar 		/*
5382654012fSReza Sabdar 		 * Make sure all libraries have tape drives.
5392654012fSReza Sabdar 		 */
5402654012fSReza Sabdar 		if (lp->tl_drive_count == 0)
5412654012fSReza Sabdar 			continue;
5422654012fSReza Sabdar 
5432654012fSReza Sabdar 		/*
5442654012fSReza Sabdar 		 * Make sure all tape drives exist. A drive that is not
5452654012fSReza Sabdar 		 * linked into the SCSI chain will be seen by the library
5462654012fSReza Sabdar 		 * but we cannot talk to it.
5472654012fSReza Sabdar 		 */
5482654012fSReza Sabdar 		for (d = 1; d <= lp->tl_drive_count; d++) {
5492654012fSReza Sabdar 			dp = tlm_drive(l, d);
5502654012fSReza Sabdar 			if (dp && !dp->td_exists) {
5512654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "Ghost drive found %d.%d",
5522654012fSReza Sabdar 				    l, d);
5532654012fSReza Sabdar 				lp->tl_ghost_drives = TRUE;
5542654012fSReza Sabdar 				continue;
5552654012fSReza Sabdar 			}
5562654012fSReza Sabdar 		}
5572654012fSReza Sabdar 	}
5582654012fSReza Sabdar 
5592654012fSReza Sabdar 	if (nlibs > 0)
5602654012fSReza Sabdar 		rv = (vlibs > 0) ? 0 : nlibs;
5612654012fSReza Sabdar 	else
5622654012fSReza Sabdar 		rv = vlibs;
5632654012fSReza Sabdar 
5642654012fSReza Sabdar 	return (rv);
5652654012fSReza Sabdar }
566