xref: /onnv-gate/usr/src/cmd/ndmpd/tlm/tlm_init.c (revision 8193:9b3c96bc17e3)
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