17917SReza.Sabdar@Sun.COM /*
213024SRandall.Ralphs@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
37917SReza.Sabdar@Sun.COM */
47917SReza.Sabdar@Sun.COM
57917SReza.Sabdar@Sun.COM /*
67917SReza.Sabdar@Sun.COM * BSD 3 Clause License
77917SReza.Sabdar@Sun.COM *
87917SReza.Sabdar@Sun.COM * Copyright (c) 2007, The Storage Networking Industry Association.
97917SReza.Sabdar@Sun.COM *
107917SReza.Sabdar@Sun.COM * Redistribution and use in source and binary forms, with or without
117917SReza.Sabdar@Sun.COM * modification, are permitted provided that the following conditions
127917SReza.Sabdar@Sun.COM * are met:
137917SReza.Sabdar@Sun.COM * - Redistributions of source code must retain the above copyright
147917SReza.Sabdar@Sun.COM * notice, this list of conditions and the following disclaimer.
157917SReza.Sabdar@Sun.COM *
167917SReza.Sabdar@Sun.COM * - Redistributions in binary form must reproduce the above copyright
177917SReza.Sabdar@Sun.COM * notice, this list of conditions and the following disclaimer in
187917SReza.Sabdar@Sun.COM * the documentation and/or other materials provided with the
197917SReza.Sabdar@Sun.COM * distribution.
207917SReza.Sabdar@Sun.COM *
217917SReza.Sabdar@Sun.COM * - Neither the name of The Storage Networking Industry Association (SNIA)
227917SReza.Sabdar@Sun.COM * nor the names of its contributors may be used to endorse or promote
237917SReza.Sabdar@Sun.COM * products derived from this software without specific prior written
247917SReza.Sabdar@Sun.COM * permission.
257917SReza.Sabdar@Sun.COM *
267917SReza.Sabdar@Sun.COM * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
277917SReza.Sabdar@Sun.COM * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
287917SReza.Sabdar@Sun.COM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
297917SReza.Sabdar@Sun.COM * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
307917SReza.Sabdar@Sun.COM * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
317917SReza.Sabdar@Sun.COM * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
327917SReza.Sabdar@Sun.COM * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
337917SReza.Sabdar@Sun.COM * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
347917SReza.Sabdar@Sun.COM * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
357917SReza.Sabdar@Sun.COM * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
367917SReza.Sabdar@Sun.COM * POSSIBILITY OF SUCH DAMAGE.
377917SReza.Sabdar@Sun.COM */
387917SReza.Sabdar@Sun.COM #include <sys/errno.h>
397917SReza.Sabdar@Sun.COM #include <sys/types.h>
407917SReza.Sabdar@Sun.COM #include <stdlib.h>
417917SReza.Sabdar@Sun.COM #include <unistd.h>
4213024SRandall.Ralphs@Sun.COM #include <ctype.h>
4313024SRandall.Ralphs@Sun.COM #include <sys/byteorder.h>
447917SReza.Sabdar@Sun.COM #include <sys/scsi/impl/uscsi.h>
457917SReza.Sabdar@Sun.COM #include <sys/scsi/scsi.h>
467917SReza.Sabdar@Sun.COM #include <tlm.h>
477917SReza.Sabdar@Sun.COM #include <pthread.h>
487917SReza.Sabdar@Sun.COM #include "tlm_proto.h"
497917SReza.Sabdar@Sun.COM
507917SReza.Sabdar@Sun.COM /*
517917SReza.Sabdar@Sun.COM * generic routine to read a SCSI page
527917SReza.Sabdar@Sun.COM */
537917SReza.Sabdar@Sun.COM int
read_scsi_page(scsi_link_t * slink,union scsi_cdb * cdb,int command_size,caddr_t data,int size)547917SReza.Sabdar@Sun.COM read_scsi_page(scsi_link_t *slink, union scsi_cdb *cdb,
557917SReza.Sabdar@Sun.COM int command_size, caddr_t data, int size)
567917SReza.Sabdar@Sun.COM {
577917SReza.Sabdar@Sun.COM struct uscsi_cmd uscsi_cmd;
587917SReza.Sabdar@Sun.COM char *dname;
597917SReza.Sabdar@Sun.COM int dev;
607917SReza.Sabdar@Sun.COM
617917SReza.Sabdar@Sun.COM if (slink == 0 || slink->sl_sa == 0)
627917SReza.Sabdar@Sun.COM return (EINVAL);
637917SReza.Sabdar@Sun.COM
647917SReza.Sabdar@Sun.COM (void) memset(&uscsi_cmd, 0, sizeof (uscsi_cmd));
657917SReza.Sabdar@Sun.COM
667917SReza.Sabdar@Sun.COM /* Lun is in the 5th bit */
677917SReza.Sabdar@Sun.COM cdb->scc_lun = slink->sl_lun;
687917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_flags |= USCSI_READ | USCSI_ISOLATE;
697917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_bufaddr = data;
707917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_buflen = size;
717917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_timeout = 1000;
727917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_cdb = (char *)cdb;
737917SReza.Sabdar@Sun.COM
747917SReza.Sabdar@Sun.COM if (cdb->scc_cmd == SCMD_READ_ELEMENT_STATUS) {
757917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_flags |= USCSI_RQENABLE;
767917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_rqbuf = data;
777917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_rqlen = size;
787917SReza.Sabdar@Sun.COM }
797917SReza.Sabdar@Sun.COM uscsi_cmd.uscsi_cdblen = command_size;
807917SReza.Sabdar@Sun.COM
817917SReza.Sabdar@Sun.COM dname = sasd_slink_name(slink);
827917SReza.Sabdar@Sun.COM dev = open(dname, O_RDWR | O_NDELAY);
837917SReza.Sabdar@Sun.COM if (dev == -1) {
847917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Open failed for %s err=%d",
857917SReza.Sabdar@Sun.COM dname, errno);
867917SReza.Sabdar@Sun.COM return (errno);
877917SReza.Sabdar@Sun.COM }
887917SReza.Sabdar@Sun.COM if (tlm_ioctl(dev, USCSICMD, &uscsi_cmd) < 0) {
897917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "SCSI cmd %d failed for %s err=%d",
907917SReza.Sabdar@Sun.COM cdb->scc_cmd, dname, errno);
917917SReza.Sabdar@Sun.COM (void) close(dev);
927917SReza.Sabdar@Sun.COM return (errno);
937917SReza.Sabdar@Sun.COM }
947917SReza.Sabdar@Sun.COM (void) close(dev);
957917SReza.Sabdar@Sun.COM return (uscsi_cmd.uscsi_status);
967917SReza.Sabdar@Sun.COM }
977917SReza.Sabdar@Sun.COM
987917SReza.Sabdar@Sun.COM /*
997917SReza.Sabdar@Sun.COM * Read the Inquiry Page.
1007917SReza.Sabdar@Sun.COM */
1017917SReza.Sabdar@Sun.COM static int
read_inquiry_page(scsi_link_t * slink,struct scsi_inquiry * inq)1027917SReza.Sabdar@Sun.COM read_inquiry_page(scsi_link_t *slink, struct scsi_inquiry *inq)
1037917SReza.Sabdar@Sun.COM {
1047917SReza.Sabdar@Sun.COM union scsi_cdb cdb;
1057917SReza.Sabdar@Sun.COM
1067917SReza.Sabdar@Sun.COM (void) memset(&cdb, 0, sizeof (union scsi_cdb));
1077917SReza.Sabdar@Sun.COM cdb.scc_cmd = SCMD_INQUIRY;
1087917SReza.Sabdar@Sun.COM cdb.g0_count0 = sizeof (struct scsi_inquiry);
1097917SReza.Sabdar@Sun.COM
1107917SReza.Sabdar@Sun.COM return (read_scsi_page(slink, &cdb, CDB_GROUP0,
1117917SReza.Sabdar@Sun.COM (caddr_t)inq, sizeof (*inq)) ? -1 : 0);
1127917SReza.Sabdar@Sun.COM }
1137917SReza.Sabdar@Sun.COM
1147917SReza.Sabdar@Sun.COM /*
1158193SReza.Sabdar@Sun.COM * Read the Product Data Page.
1168193SReza.Sabdar@Sun.COM */
1178193SReza.Sabdar@Sun.COM static int
read_data_page(scsi_link_t * slink,int pcode,char * snum,int size)1188193SReza.Sabdar@Sun.COM read_data_page(scsi_link_t *slink, int pcode, char *snum, int size)
1198193SReza.Sabdar@Sun.COM {
1208193SReza.Sabdar@Sun.COM char cmd[CDB_GROUP0];
1218193SReza.Sabdar@Sun.COM
1228193SReza.Sabdar@Sun.COM (void) memset(cmd, 0, sizeof (cmd));
1238193SReza.Sabdar@Sun.COM
1248193SReza.Sabdar@Sun.COM cmd[0] = SCMD_INQUIRY;
1258193SReza.Sabdar@Sun.COM cmd[1] = pcode ? 0x01 : 0x00;
1268193SReza.Sabdar@Sun.COM cmd[2] = pcode;
1278193SReza.Sabdar@Sun.COM cmd[4] = size;
1288193SReza.Sabdar@Sun.COM
1298193SReza.Sabdar@Sun.COM /* LINTED improper alignment */
1308193SReza.Sabdar@Sun.COM return (read_scsi_page(slink, (union scsi_cdb *)&cmd, CDB_GROUP0,
1318193SReza.Sabdar@Sun.COM (caddr_t)snum, size) == -1 ? -1 : 0);
1328193SReza.Sabdar@Sun.COM }
1338193SReza.Sabdar@Sun.COM
1348193SReza.Sabdar@Sun.COM
1358193SReza.Sabdar@Sun.COM /*
1368193SReza.Sabdar@Sun.COM * Read the Serial Number Page.
1378193SReza.Sabdar@Sun.COM */
1388193SReza.Sabdar@Sun.COM static int
read_serial_num_page(scsi_link_t * slink,char * snum,int size)1398193SReza.Sabdar@Sun.COM read_serial_num_page(scsi_link_t *slink, char *snum, int size)
1408193SReza.Sabdar@Sun.COM {
1418193SReza.Sabdar@Sun.COM scsi_serial_t serial;
1428193SReza.Sabdar@Sun.COM int rv;
1438193SReza.Sabdar@Sun.COM
1448193SReza.Sabdar@Sun.COM (void) memset(&serial, 0, sizeof (scsi_serial_t));
1458193SReza.Sabdar@Sun.COM rv = read_data_page(slink, SCSI_SERIAL_PAGE, (caddr_t)&serial,
1468193SReza.Sabdar@Sun.COM sizeof (scsi_serial_t));
1478193SReza.Sabdar@Sun.COM (void) strlcpy(snum, serial.sr_num, size);
1488193SReza.Sabdar@Sun.COM
1498193SReza.Sabdar@Sun.COM return (rv == -1 ? -1 : 0);
1508193SReza.Sabdar@Sun.COM }
1518193SReza.Sabdar@Sun.COM
1528193SReza.Sabdar@Sun.COM
1538193SReza.Sabdar@Sun.COM /*
1548193SReza.Sabdar@Sun.COM * Read the Device Name Page.
1558193SReza.Sabdar@Sun.COM */
1568193SReza.Sabdar@Sun.COM static int
read_dev_name_page(scsi_link_t * slink,device_ident_header_t * devp,int len)15713024SRandall.Ralphs@Sun.COM read_dev_name_page(scsi_link_t *slink, device_ident_header_t *devp, int len)
1588193SReza.Sabdar@Sun.COM {
15913024SRandall.Ralphs@Sun.COM (void) memset(devp, 0, len);
1608193SReza.Sabdar@Sun.COM
1618193SReza.Sabdar@Sun.COM if (read_data_page(slink, SCSI_DEVICE_IDENT_PAGE, (caddr_t)devp,
16213024SRandall.Ralphs@Sun.COM len) == -1)
1638193SReza.Sabdar@Sun.COM return (-1);
1648193SReza.Sabdar@Sun.COM
16513024SRandall.Ralphs@Sun.COM if (devp->di_page_code != SCSI_DEVICE_IDENT_PAGE)
16613024SRandall.Ralphs@Sun.COM return (-1);
1678193SReza.Sabdar@Sun.COM
16813024SRandall.Ralphs@Sun.COM return (0);
1698193SReza.Sabdar@Sun.COM }
1708193SReza.Sabdar@Sun.COM
1718193SReza.Sabdar@Sun.COM /*
1728193SReza.Sabdar@Sun.COM * Formatted print of WWN
1738193SReza.Sabdar@Sun.COM */
17413024SRandall.Ralphs@Sun.COM static void
snprintf_wwn(char * buf,int size,uint8_t * wwn)1758193SReza.Sabdar@Sun.COM snprintf_wwn(char *buf, int size, uint8_t *wwn)
1768193SReza.Sabdar@Sun.COM {
1778193SReza.Sabdar@Sun.COM if (wwn == NULL || buf == NULL)
17813024SRandall.Ralphs@Sun.COM return;
1798193SReza.Sabdar@Sun.COM
1808193SReza.Sabdar@Sun.COM (void) snprintf(buf, size, "0x%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
1818193SReza.Sabdar@Sun.COM wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
1828193SReza.Sabdar@Sun.COM }
1838193SReza.Sabdar@Sun.COM
1848193SReza.Sabdar@Sun.COM
1858193SReza.Sabdar@Sun.COM /*
1868193SReza.Sabdar@Sun.COM * Extract and print the world wide name (WWN)
1878193SReza.Sabdar@Sun.COM */
1888193SReza.Sabdar@Sun.COM int
read_device_wwn(scsi_link_t * slink,char * wwnp,int wsize)1898193SReza.Sabdar@Sun.COM read_device_wwn(scsi_link_t *slink, char *wwnp, int wsize)
1908193SReza.Sabdar@Sun.COM {
19113024SRandall.Ralphs@Sun.COM device_ident_header_t *header;
19213024SRandall.Ralphs@Sun.COM name_ident_t *ident;
19313024SRandall.Ralphs@Sun.COM uint16_t page_len = sizeof (device_ident_header_t);
19413024SRandall.Ralphs@Sun.COM uint16_t act_len;
19513024SRandall.Ralphs@Sun.COM int accessed;
19613024SRandall.Ralphs@Sun.COM uint8_t *designator_data;
1978193SReza.Sabdar@Sun.COM
1988193SReza.Sabdar@Sun.COM (void) memset(wwnp, 0, wsize);
19913024SRandall.Ralphs@Sun.COM resize:
20013024SRandall.Ralphs@Sun.COM header = malloc(page_len);
20113024SRandall.Ralphs@Sun.COM if (header == NULL)
2028193SReza.Sabdar@Sun.COM return (-1);
2038193SReza.Sabdar@Sun.COM
20413024SRandall.Ralphs@Sun.COM if (read_dev_name_page(slink, header, page_len) == -1) {
20513024SRandall.Ralphs@Sun.COM free(header);
20613024SRandall.Ralphs@Sun.COM return (-1);
2078193SReza.Sabdar@Sun.COM }
20813024SRandall.Ralphs@Sun.COM
20913024SRandall.Ralphs@Sun.COM act_len = BE_16(header->di_page_length);
21013024SRandall.Ralphs@Sun.COM if (act_len > page_len) {
21113024SRandall.Ralphs@Sun.COM free(header);
21213024SRandall.Ralphs@Sun.COM page_len = act_len;
21313024SRandall.Ralphs@Sun.COM goto resize;
2148193SReza.Sabdar@Sun.COM }
21513024SRandall.Ralphs@Sun.COM
21613024SRandall.Ralphs@Sun.COM ident = (name_ident_t *)&header[1];
21713024SRandall.Ralphs@Sun.COM accessed = sizeof (device_ident_header_t);
21813024SRandall.Ralphs@Sun.COM
21913024SRandall.Ralphs@Sun.COM while (accessed < act_len) {
22013024SRandall.Ralphs@Sun.COM
22113024SRandall.Ralphs@Sun.COM accessed += sizeof (name_ident_t);
22213024SRandall.Ralphs@Sun.COM accessed += ident->ni_ident_length;
22313024SRandall.Ralphs@Sun.COM designator_data = (uint8_t *)&ident[1];
22413024SRandall.Ralphs@Sun.COM /*
22513024SRandall.Ralphs@Sun.COM * Looking for code set 1 (Binary) ident type NAA 64 bit
22613024SRandall.Ralphs@Sun.COM * address that is associated with the node (0).
22713024SRandall.Ralphs@Sun.COM */
22813024SRandall.Ralphs@Sun.COM if ((ident->ni_code_set == 1) &&
22913024SRandall.Ralphs@Sun.COM (ident->ni_ident_type == 3)) {
23013024SRandall.Ralphs@Sun.COM snprintf_wwn(wwnp, wsize, designator_data);
23113024SRandall.Ralphs@Sun.COM /*
23213024SRandall.Ralphs@Sun.COM * If assc is zero (Node) this is the one we want.
23313024SRandall.Ralphs@Sun.COM * If we find that we're done.
23413024SRandall.Ralphs@Sun.COM */
23513024SRandall.Ralphs@Sun.COM if (ident->ni_asso == 0)
23613024SRandall.Ralphs@Sun.COM break;
23713024SRandall.Ralphs@Sun.COM }
23813024SRandall.Ralphs@Sun.COM /*
23913024SRandall.Ralphs@Sun.COM * If we find a EUI-64 we can use that also.
24013024SRandall.Ralphs@Sun.COM */
24113024SRandall.Ralphs@Sun.COM if ((ident->ni_code_set == 2) &&
24213024SRandall.Ralphs@Sun.COM (ident->ni_ident_type == 1) &&
24313024SRandall.Ralphs@Sun.COM (ident->ni_asso == 0) &&
24413024SRandall.Ralphs@Sun.COM (isprint(wwnp[0] == 0))) { /* Don't overwrite */
24513024SRandall.Ralphs@Sun.COM /*
24613024SRandall.Ralphs@Sun.COM * This isn't our first choice but we'll print it
24713024SRandall.Ralphs@Sun.COM * in case there is nothing else to use.
24813024SRandall.Ralphs@Sun.COM */
24913024SRandall.Ralphs@Sun.COM (void) snprintf(wwnp, wsize, "%.*s",
25013024SRandall.Ralphs@Sun.COM ident->ni_ident_length, designator_data);
25113024SRandall.Ralphs@Sun.COM }
25213024SRandall.Ralphs@Sun.COM ident =
25313024SRandall.Ralphs@Sun.COM (name_ident_t *)&designator_data[ident->ni_ident_length];
2548193SReza.Sabdar@Sun.COM }
25513024SRandall.Ralphs@Sun.COM free(header);
25613024SRandall.Ralphs@Sun.COM /*
25713024SRandall.Ralphs@Sun.COM * See if we found something.
25813024SRandall.Ralphs@Sun.COM * Memset above would leave wwnp not printable.
25913024SRandall.Ralphs@Sun.COM */
26013024SRandall.Ralphs@Sun.COM if (isprint(wwnp[0]))
2618193SReza.Sabdar@Sun.COM return (0);
2628193SReza.Sabdar@Sun.COM return (-1);
2638193SReza.Sabdar@Sun.COM }
2648193SReza.Sabdar@Sun.COM
2658193SReza.Sabdar@Sun.COM /*
2667917SReza.Sabdar@Sun.COM * Add the tape library call back function (used while scanning the bus)
2677917SReza.Sabdar@Sun.COM */
2687917SReza.Sabdar@Sun.COM static int
add_lib(scsi_link_t * slink,struct scsi_inquiry * sd,void * arg)2697917SReza.Sabdar@Sun.COM add_lib(scsi_link_t *slink, struct scsi_inquiry *sd, void *arg)
2707917SReza.Sabdar@Sun.COM {
2717917SReza.Sabdar@Sun.COM int l;
2727917SReza.Sabdar@Sun.COM int *nlp; /* pointer to library counter */
2737917SReza.Sabdar@Sun.COM sasd_drive_t *ssd;
2747917SReza.Sabdar@Sun.COM
2757917SReza.Sabdar@Sun.COM if (!slink || !sd) {
2767917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Invalid argument %x %x %x",
2777917SReza.Sabdar@Sun.COM slink, sd, arg);
2787917SReza.Sabdar@Sun.COM return (-TLM_INVALID);
2797917SReza.Sabdar@Sun.COM }
2807917SReza.Sabdar@Sun.COM
2817917SReza.Sabdar@Sun.COM if (sd->inq_dtype == DTYPE_CHANGER) {
2827917SReza.Sabdar@Sun.COM /* This is a robot, which means this is also a library */
2837917SReza.Sabdar@Sun.COM nlp = (int *)arg;
2847917SReza.Sabdar@Sun.COM (*nlp)++;
2857917SReza.Sabdar@Sun.COM l = tlm_insert_new_library(slink);
2867917SReza.Sabdar@Sun.COM tlm_enable_barcode(l);
2877917SReza.Sabdar@Sun.COM
2887917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "lib %d sid %d lun %d",
2897917SReza.Sabdar@Sun.COM l, slink->sl_sid, slink->sl_lun);
2907917SReza.Sabdar@Sun.COM
2917917SReza.Sabdar@Sun.COM if ((ssd = sasd_slink_drive(slink)) != NULL) {
2927917SReza.Sabdar@Sun.COM (void) strlcpy(ssd->sd_vendor, sd->inq_vid,
2937917SReza.Sabdar@Sun.COM sizeof (ssd->sd_vendor));
2947917SReza.Sabdar@Sun.COM (void) strlcpy(ssd->sd_id, sd->inq_pid,
2957917SReza.Sabdar@Sun.COM sizeof (ssd->sd_id));
2967917SReza.Sabdar@Sun.COM (void) strlcpy(ssd->sd_rev, sd->inq_revision,
2977917SReza.Sabdar@Sun.COM sizeof (ssd->sd_rev));
2988193SReza.Sabdar@Sun.COM (void) read_serial_num_page(slink, ssd->sd_serial,
2998193SReza.Sabdar@Sun.COM sizeof (ssd->sd_serial));
3008193SReza.Sabdar@Sun.COM (void) read_device_wwn(slink, ssd->sd_wwn,
3018193SReza.Sabdar@Sun.COM sizeof (ssd->sd_wwn));
3027917SReza.Sabdar@Sun.COM }
3037917SReza.Sabdar@Sun.COM }
3047917SReza.Sabdar@Sun.COM
3057917SReza.Sabdar@Sun.COM return (TLM_NO_ERRORS);
3067917SReza.Sabdar@Sun.COM }
3077917SReza.Sabdar@Sun.COM
3087917SReza.Sabdar@Sun.COM /*
3097917SReza.Sabdar@Sun.COM * Create some virutal slots
3107917SReza.Sabdar@Sun.COM */
3117917SReza.Sabdar@Sun.COM static int
make_virtual_slot(int l,tlm_drive_t * dp)3127917SReza.Sabdar@Sun.COM make_virtual_slot(int l, tlm_drive_t *dp)
3137917SReza.Sabdar@Sun.COM {
3147917SReza.Sabdar@Sun.COM int s;
3157917SReza.Sabdar@Sun.COM tlm_slot_t *sp;
3167917SReza.Sabdar@Sun.COM
3177917SReza.Sabdar@Sun.COM if (l <= 0 || !dp) {
3187917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Invalid argument %d, %x", l, dp);
3197917SReza.Sabdar@Sun.COM return (-TLM_INVALID);
3207917SReza.Sabdar@Sun.COM }
3217917SReza.Sabdar@Sun.COM
3227917SReza.Sabdar@Sun.COM if ((s = tlm_insert_new_slot(l)) <= 0)
3237917SReza.Sabdar@Sun.COM return (-TLM_NO_MEMORY);
3247917SReza.Sabdar@Sun.COM
3257917SReza.Sabdar@Sun.COM if (!(sp = tlm_slot(l, s))) {
3267917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Internal error: slot not found %d", s);
3277917SReza.Sabdar@Sun.COM return (-TLM_ERROR_INTERNAL);
3287917SReza.Sabdar@Sun.COM }
3297917SReza.Sabdar@Sun.COM /*
3307917SReza.Sabdar@Sun.COM * For virtual slots element number is 0 and they are always full.
3317917SReza.Sabdar@Sun.COM */
3327917SReza.Sabdar@Sun.COM sp->ts_element = 0;
3337917SReza.Sabdar@Sun.COM sp->ts_status_full = TRUE;
3347917SReza.Sabdar@Sun.COM return (TLM_NO_ERRORS);
3357917SReza.Sabdar@Sun.COM }
3367917SReza.Sabdar@Sun.COM
3377917SReza.Sabdar@Sun.COM /*
3387917SReza.Sabdar@Sun.COM * Make the tape drive not part of a tape library (stand alone)
3397917SReza.Sabdar@Sun.COM */
3407917SReza.Sabdar@Sun.COM static int
make_stand_alone_drive(scsi_link_t * slink,int l)3417917SReza.Sabdar@Sun.COM make_stand_alone_drive(scsi_link_t *slink, int l)
3427917SReza.Sabdar@Sun.COM {
3437917SReza.Sabdar@Sun.COM int d;
3447917SReza.Sabdar@Sun.COM tlm_drive_t *dp;
3457917SReza.Sabdar@Sun.COM
3467917SReza.Sabdar@Sun.COM if (!slink || l <= 0) {
3477917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Invalid argument %x %d", slink, l);
3487917SReza.Sabdar@Sun.COM return (-TLM_INVALID);
3497917SReza.Sabdar@Sun.COM }
3507917SReza.Sabdar@Sun.COM
3517917SReza.Sabdar@Sun.COM d = tlm_insert_new_drive(l);
3527917SReza.Sabdar@Sun.COM if (!(dp = tlm_drive(l, d))) {
3537917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Internal error: drive not found %d", d);
3547917SReza.Sabdar@Sun.COM return (-TLM_ERROR_INTERNAL);
3557917SReza.Sabdar@Sun.COM }
3567917SReza.Sabdar@Sun.COM
3577917SReza.Sabdar@Sun.COM /* For stand-alone drives, the element number is the drive number. */
3587917SReza.Sabdar@Sun.COM dp->td_element = d;
3597917SReza.Sabdar@Sun.COM dp->td_slink = slink;
3607917SReza.Sabdar@Sun.COM dp->td_scsi_id = slink->sl_sid;
3617917SReza.Sabdar@Sun.COM dp->td_lun = slink->sl_lun;
3627917SReza.Sabdar@Sun.COM dp->td_exists = TRUE;
3637917SReza.Sabdar@Sun.COM
3647917SReza.Sabdar@Sun.COM /*
3657917SReza.Sabdar@Sun.COM * Note: There is no way to remove library elements. We cannot clean
3667917SReza.Sabdar@Sun.COM * up if make_virtual_slot() fails.
3677917SReza.Sabdar@Sun.COM */
3687917SReza.Sabdar@Sun.COM (void) make_virtual_slot(l, dp);
3697917SReza.Sabdar@Sun.COM return (d);
3707917SReza.Sabdar@Sun.COM }
3717917SReza.Sabdar@Sun.COM
3727917SReza.Sabdar@Sun.COM /*
3737917SReza.Sabdar@Sun.COM * Find the LIBRARY structure that has control of this DRIVE.
3747917SReza.Sabdar@Sun.COM */
3757917SReza.Sabdar@Sun.COM static int
new_drive(scsi_link_t * slink,int * lib)3767917SReza.Sabdar@Sun.COM new_drive(scsi_link_t *slink, int *lib)
3777917SReza.Sabdar@Sun.COM {
3787917SReza.Sabdar@Sun.COM int d;
3797917SReza.Sabdar@Sun.COM tlm_drive_t *dp;
3807917SReza.Sabdar@Sun.COM tlm_library_t *lp;
3817917SReza.Sabdar@Sun.COM
3827917SReza.Sabdar@Sun.COM /* Walk through all libraries. */
3837917SReza.Sabdar@Sun.COM for (*lib = 1; *lib <= tlm_library_count(); (*lib)++) {
3847917SReza.Sabdar@Sun.COM if (!(lp = tlm_library(*lib)))
3857917SReza.Sabdar@Sun.COM continue;
3867917SReza.Sabdar@Sun.COM /* Walk through drives that are already found. */
3877917SReza.Sabdar@Sun.COM for (d = 1; d <= lp->tl_drive_count; d++) {
3887917SReza.Sabdar@Sun.COM if (!(dp = tlm_drive(*lib, d)))
3897917SReza.Sabdar@Sun.COM continue;
3907917SReza.Sabdar@Sun.COM if (dp->td_scsi_id == slink->sl_sid &&
3917917SReza.Sabdar@Sun.COM dp->td_lun == slink->sl_lun)
3927917SReza.Sabdar@Sun.COM return (d);
3937917SReza.Sabdar@Sun.COM }
3947917SReza.Sabdar@Sun.COM }
3957917SReza.Sabdar@Sun.COM
3967917SReza.Sabdar@Sun.COM /* Not part of any library, this is a newly found tape drive. */
3977917SReza.Sabdar@Sun.COM return (0);
3987917SReza.Sabdar@Sun.COM }
3997917SReza.Sabdar@Sun.COM
4008193SReza.Sabdar@Sun.COM
4017917SReza.Sabdar@Sun.COM /*
4027917SReza.Sabdar@Sun.COM * Add the tape library call back function (used while scanning the bus)
4037917SReza.Sabdar@Sun.COM */
4047917SReza.Sabdar@Sun.COM static int
add_drv(scsi_link_t * slink,struct scsi_inquiry * sd,void * arg)4057917SReza.Sabdar@Sun.COM add_drv(scsi_link_t *slink, struct scsi_inquiry *sd, void *arg)
4067917SReza.Sabdar@Sun.COM {
4077917SReza.Sabdar@Sun.COM int l, d;
4087917SReza.Sabdar@Sun.COM int *vlp; /* pointer to virtual library number */
4097917SReza.Sabdar@Sun.COM sasd_drive_t *ssd;
4107917SReza.Sabdar@Sun.COM tlm_library_t *library;
4117917SReza.Sabdar@Sun.COM tlm_drive_t *drive;
4127917SReza.Sabdar@Sun.COM
4137917SReza.Sabdar@Sun.COM if (!slink || !sd) {
4147917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Invalid argument %x %x %x",
4157917SReza.Sabdar@Sun.COM slink, sd, arg);
4167917SReza.Sabdar@Sun.COM return (-TLM_INVALID);
4177917SReza.Sabdar@Sun.COM }
4187917SReza.Sabdar@Sun.COM
4197917SReza.Sabdar@Sun.COM if (sd->inq_dtype == DTYPE_SEQUENTIAL) {
4207917SReza.Sabdar@Sun.COM vlp = (int *)arg;
4217917SReza.Sabdar@Sun.COM d = new_drive(slink, &l);
4227917SReza.Sabdar@Sun.COM if (d == 0) {
4237917SReza.Sabdar@Sun.COM /* This tape drive was not found inside any robot. */
4247917SReza.Sabdar@Sun.COM if (*vlp == 0) {
4257917SReza.Sabdar@Sun.COM /*
4267917SReza.Sabdar@Sun.COM * First, create a virtual library if it's not
4277917SReza.Sabdar@Sun.COM * done yet.
4287917SReza.Sabdar@Sun.COM */
4297917SReza.Sabdar@Sun.COM *vlp = tlm_insert_new_library(slink);
4307917SReza.Sabdar@Sun.COM if ((library = tlm_library(*vlp)) != NULL)
4317917SReza.Sabdar@Sun.COM library->tl_capability_robot = FALSE;
4327917SReza.Sabdar@Sun.COM }
4337917SReza.Sabdar@Sun.COM if ((d = make_stand_alone_drive(slink, *vlp)) < 0) {
4347917SReza.Sabdar@Sun.COM /* sorry, we can not clean up the vlib now * */
4357917SReza.Sabdar@Sun.COM return (-TLM_INVALID);
4367917SReza.Sabdar@Sun.COM }
4377917SReza.Sabdar@Sun.COM l = *vlp;
4387917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "vlib(%d, %d) sid %d lun %d",
4397917SReza.Sabdar@Sun.COM l, d, slink->sl_sid, slink->sl_lun);
4407917SReza.Sabdar@Sun.COM } else
4417917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "(%d, %d) sid %d lun %d",
4427917SReza.Sabdar@Sun.COM l, d, slink->sl_sid, slink->sl_lun);
4437917SReza.Sabdar@Sun.COM
4447917SReza.Sabdar@Sun.COM if ((drive = tlm_drive(l, d)) != NULL) {
4457917SReza.Sabdar@Sun.COM drive->td_exists = TRUE;
4467917SReza.Sabdar@Sun.COM drive->td_slink = slink;
4477917SReza.Sabdar@Sun.COM }
4487917SReza.Sabdar@Sun.COM if ((ssd = sasd_slink_drive(slink)) != NULL) {
4497917SReza.Sabdar@Sun.COM (void) strlcpy(ssd->sd_vendor,
4507917SReza.Sabdar@Sun.COM sd->inq_vid, sizeof (ssd->sd_vendor));
4517917SReza.Sabdar@Sun.COM (void) strlcpy(ssd->sd_id, sd->inq_pid,
4527917SReza.Sabdar@Sun.COM sizeof (ssd->sd_id));
4537917SReza.Sabdar@Sun.COM (void) strlcpy(ssd->sd_rev, sd->inq_revision,
4547917SReza.Sabdar@Sun.COM sizeof (ssd->sd_rev));
4558193SReza.Sabdar@Sun.COM (void) read_serial_num_page(slink, ssd->sd_serial,
4568193SReza.Sabdar@Sun.COM sizeof (ssd->sd_serial));
4578193SReza.Sabdar@Sun.COM (void) read_device_wwn(slink, ssd->sd_wwn,
4588193SReza.Sabdar@Sun.COM sizeof (ssd->sd_wwn));
4597917SReza.Sabdar@Sun.COM }
4607917SReza.Sabdar@Sun.COM }
4617917SReza.Sabdar@Sun.COM
4627917SReza.Sabdar@Sun.COM return (TLM_NO_ERRORS);
4637917SReza.Sabdar@Sun.COM }
4647917SReza.Sabdar@Sun.COM
4657917SReza.Sabdar@Sun.COM /*
4667917SReza.Sabdar@Sun.COM * Scan the specified bus and call the handler function.
4677917SReza.Sabdar@Sun.COM */
4687917SReza.Sabdar@Sun.COM static int
scan_bus(scsi_adapter_t * sa,int (* hndlr)(),void * args)4697917SReza.Sabdar@Sun.COM scan_bus(scsi_adapter_t *sa, int(*hndlr)(), void *args)
4707917SReza.Sabdar@Sun.COM {
4717917SReza.Sabdar@Sun.COM int nerr;
4727917SReza.Sabdar@Sun.COM scsi_link_t *slink;
4737917SReza.Sabdar@Sun.COM struct scsi_inquiry scsi_data;
4747917SReza.Sabdar@Sun.COM
4757917SReza.Sabdar@Sun.COM nerr = 0;
4767917SReza.Sabdar@Sun.COM slink = sa->sa_link_head.sl_next;
4777917SReza.Sabdar@Sun.COM for (; slink != &sa->sa_link_head; slink = slink->sl_next) {
4787917SReza.Sabdar@Sun.COM (void) memset(&scsi_data, 0, sizeof (struct scsi_inquiry));
4797917SReza.Sabdar@Sun.COM if (read_inquiry_page(slink, &scsi_data) == -1)
4807917SReza.Sabdar@Sun.COM nerr++;
4817917SReza.Sabdar@Sun.COM else
4827917SReza.Sabdar@Sun.COM if ((*hndlr)(slink, &scsi_data, args) != TLM_NO_ERRORS)
4837917SReza.Sabdar@Sun.COM nerr++;
4847917SReza.Sabdar@Sun.COM }
4857917SReza.Sabdar@Sun.COM
4867917SReza.Sabdar@Sun.COM return (nerr);
4877917SReza.Sabdar@Sun.COM }
4887917SReza.Sabdar@Sun.COM
4897917SReza.Sabdar@Sun.COM /*
4907917SReza.Sabdar@Sun.COM * Marks the library/slots inaccessible if there are not enough drives
4917917SReza.Sabdar@Sun.COM * available on the library
4927917SReza.Sabdar@Sun.COM */
4937917SReza.Sabdar@Sun.COM static void
inaccbl_drv_warn(int start,int max)4947917SReza.Sabdar@Sun.COM inaccbl_drv_warn(int start, int max)
4957917SReza.Sabdar@Sun.COM {
4967917SReza.Sabdar@Sun.COM char *dname;
4977917SReza.Sabdar@Sun.COM int l, d;
4987917SReza.Sabdar@Sun.COM tlm_library_t *lp;
4997917SReza.Sabdar@Sun.COM
5007917SReza.Sabdar@Sun.COM for (l = start; l < max; l++) {
5017917SReza.Sabdar@Sun.COM if (!(lp = tlm_library(l)))
5027917SReza.Sabdar@Sun.COM continue;
5037917SReza.Sabdar@Sun.COM if (lp->tl_drive_count <= 0)
5047917SReza.Sabdar@Sun.COM continue;
5057917SReza.Sabdar@Sun.COM
5067917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG,
5077917SReza.Sabdar@Sun.COM "Warning: The following drives are not accessible:");
5087917SReza.Sabdar@Sun.COM for (d = 1; d <= lp->tl_drive_count; d++)
5097917SReza.Sabdar@Sun.COM if (!(dname = tlm_get_tape_name(l, d))) {
5107917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG,
5117917SReza.Sabdar@Sun.COM "Error getting drive(%d, %d)", l, d);
5127917SReza.Sabdar@Sun.COM } else
5137917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "%s", dname);
5147917SReza.Sabdar@Sun.COM
5157917SReza.Sabdar@Sun.COM /*
5167917SReza.Sabdar@Sun.COM * Note: Make the slots inaccessible to prevent running
5177917SReza.Sabdar@Sun.COM * discovery on these libraries. The better idea is
5187917SReza.Sabdar@Sun.COM * removing these libraries, but we don't have that
5197917SReza.Sabdar@Sun.COM * feature available now.
5207917SReza.Sabdar@Sun.COM */
5217917SReza.Sabdar@Sun.COM lp->tl_slot_count = 0;
5227917SReza.Sabdar@Sun.COM }
5237917SReza.Sabdar@Sun.COM }
5247917SReza.Sabdar@Sun.COM
5257917SReza.Sabdar@Sun.COM /*
5267917SReza.Sabdar@Sun.COM * Initialize the tape library data structure, asks the libraries what
5277917SReza.Sabdar@Sun.COM * equipments they have.
5287917SReza.Sabdar@Sun.COM */
5297917SReza.Sabdar@Sun.COM int
tlm_init(void)5307917SReza.Sabdar@Sun.COM tlm_init(void)
5317917SReza.Sabdar@Sun.COM {
5327917SReza.Sabdar@Sun.COM static int nlibs; /* number of found libraries */
5337917SReza.Sabdar@Sun.COM int i, nsa;
5347917SReza.Sabdar@Sun.COM int l, vlibs, d;
5357917SReza.Sabdar@Sun.COM int rv;
5367917SReza.Sabdar@Sun.COM scsi_adapter_t *sa;
5377917SReza.Sabdar@Sun.COM tlm_library_t *lp;
5387917SReza.Sabdar@Sun.COM tlm_drive_t *dp;
5397917SReza.Sabdar@Sun.COM
5407917SReza.Sabdar@Sun.COM /* Search through all SCSI adapters, look for tape robots. */
5417917SReza.Sabdar@Sun.COM nlibs = 0;
5427917SReza.Sabdar@Sun.COM
5437917SReza.Sabdar@Sun.COM /*
5447917SReza.Sabdar@Sun.COM * We probe both changers and tape drives here
5457917SReza.Sabdar@Sun.COM * but later on this needs to be removed as the
5467917SReza.Sabdar@Sun.COM * probe will happen somewhere else.
5477917SReza.Sabdar@Sun.COM */
548*13051SJanice.Chang@Sun.COM if (probe_scsi() < 0)
549*13051SJanice.Chang@Sun.COM return (-1);
5507917SReza.Sabdar@Sun.COM
5517917SReza.Sabdar@Sun.COM nsa = scsi_get_adapter_count();
5527917SReza.Sabdar@Sun.COM for (i = 0; i < nsa; i++)
5537917SReza.Sabdar@Sun.COM if ((sa = scsi_get_adapter(i)))
5547917SReza.Sabdar@Sun.COM (void) scan_bus(sa, add_lib, (void *)&nlibs);
5557917SReza.Sabdar@Sun.COM
5567917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "nlibs %d", nlibs);
5577917SReza.Sabdar@Sun.COM
5587917SReza.Sabdar@Sun.COM /* Search through all SCSI adapters, look for tape drives. */
5597917SReza.Sabdar@Sun.COM vlibs = 0;
5607917SReza.Sabdar@Sun.COM for (i = 0; i < nsa; i++)
5617917SReza.Sabdar@Sun.COM if ((sa = scsi_get_adapter(i)))
5627917SReza.Sabdar@Sun.COM (void) scan_bus(sa, add_drv, (void *)&vlibs);
5637917SReza.Sabdar@Sun.COM
5647917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "vlibs %d", vlibs);
5657917SReza.Sabdar@Sun.COM
5667917SReza.Sabdar@Sun.COM if (nlibs > 0 && vlibs > 0)
5677917SReza.Sabdar@Sun.COM inaccbl_drv_warn(nlibs + 1, vlibs + nlibs + 1);
5687917SReza.Sabdar@Sun.COM
5697917SReza.Sabdar@Sun.COM for (l = 1; l <= tlm_library_count(); l++) {
5707917SReza.Sabdar@Sun.COM if (!(lp = tlm_library(l))) {
5717917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "can't find lib %d", l);
5727917SReza.Sabdar@Sun.COM continue;
5737917SReza.Sabdar@Sun.COM }
5747917SReza.Sabdar@Sun.COM
5757917SReza.Sabdar@Sun.COM /*
5767917SReza.Sabdar@Sun.COM * Make sure all libraries have tape drives.
5777917SReza.Sabdar@Sun.COM */
5787917SReza.Sabdar@Sun.COM if (lp->tl_drive_count == 0)
5797917SReza.Sabdar@Sun.COM continue;
5807917SReza.Sabdar@Sun.COM
5817917SReza.Sabdar@Sun.COM /*
5827917SReza.Sabdar@Sun.COM * Make sure all tape drives exist. A drive that is not
5837917SReza.Sabdar@Sun.COM * linked into the SCSI chain will be seen by the library
5847917SReza.Sabdar@Sun.COM * but we cannot talk to it.
5857917SReza.Sabdar@Sun.COM */
5867917SReza.Sabdar@Sun.COM for (d = 1; d <= lp->tl_drive_count; d++) {
5877917SReza.Sabdar@Sun.COM dp = tlm_drive(l, d);
5887917SReza.Sabdar@Sun.COM if (dp && !dp->td_exists) {
5897917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Ghost drive found %d.%d",
5907917SReza.Sabdar@Sun.COM l, d);
5917917SReza.Sabdar@Sun.COM lp->tl_ghost_drives = TRUE;
5927917SReza.Sabdar@Sun.COM continue;
5937917SReza.Sabdar@Sun.COM }
5947917SReza.Sabdar@Sun.COM }
5957917SReza.Sabdar@Sun.COM }
5967917SReza.Sabdar@Sun.COM
5977917SReza.Sabdar@Sun.COM if (nlibs > 0)
5987917SReza.Sabdar@Sun.COM rv = (vlibs > 0) ? 0 : nlibs;
5997917SReza.Sabdar@Sun.COM else
6007917SReza.Sabdar@Sun.COM rv = vlibs;
6017917SReza.Sabdar@Sun.COM
6027917SReza.Sabdar@Sun.COM return (rv);
6037917SReza.Sabdar@Sun.COM }
604