Index: Makefile.in =================================================================== RCS file: /home/cvsroot/scsidev/Makefile.in,v retrieving revision 1.9 retrieving revision 1.9.2.2 diff -u -r1.9 -r1.9.2.2 --- Makefile.in 2000/09/05 09:22:35 1.9 +++ Makefile.in 2002/07/27 00:17:23 1.9.2.2 @@ -1,5 +1,5 @@ # -# $Id: Makefile.in,v 1.9 2000/09/05 09:22:35 garloff Exp $ +# $Id: Makefile.in,v 1.9.2.2 2002/07/27 00:17:23 garloff Exp $ # ## Makefile for scsidev. @@ -57,12 +57,11 @@ dist: clean rm Makefile - (cd .. && mv scsidev scsidev-$(VERSION) && tar cvvf - \ - --exclude scsidev-$(VERSION)/CVS scsidev-$(VERSION) \ - | gzip -9 > scsidev-$(VERSION).tar.gz; mv scsidev-$(VERSION) scsidev) + (DIR=`/bin/pwd`; DIR=`basename $$DIR`; cd .. && mv $$DIR scsidev-$(VERSION) \ + && tar cvvf - --exclude scsidev-$(VERSION)/CVS scsidev-$(VERSION) \ + | gzip -9 > scsidev-$(VERSION).tar.gz; mv scsidev-$(VERSION) $$DIR) clean: rm -f *~ .*~ *.o scsidev /bin/rm -f config.status config.log config.cache config.h - Index: README =================================================================== RCS file: /home/cvsroot/scsidev/README,v retrieving revision 1.2 retrieving revision 1.2.2.1 diff -u -r1.2 -r1.2.2.1 --- README 2000/02/14 22:54:03 1.2 +++ README 2002/07/27 00:16:10 1.2.2.1 @@ -1,9 +1,9 @@ -# $Id: README,v 1.2 2000/02/14 22:54:03 garloff Exp $ +# $Id: README,v 1.2.2.1 2002/07/27 00:16:10 garloff Exp $ NOTE: This docu is out of date. Please refer to the man page and the ===== web page mentioned there. KG. - The linux SCSI code assigns minor numbers to devices dynamicly. Thus -if you add or remove a device, the device numbering will change, and this + The linux SCSI code assigns minor numbers to devices dynamically. +Thus if you add or remove a device, the device numbering will change, and this obviously screws up things like /etc/fstab, /etc/rc*, and a few other things. What we desire is a uniform naming scheme whereby the name used for a device remains the same as you add or remove other bits of hardware. Index: VERSION =================================================================== RCS file: /home/cvsroot/scsidev/VERSION,v retrieving revision 1.8 diff -u -r1.8 VERSION --- VERSION 2000/09/04 18:43:11 1.8 +++ VERSION 2002/07/27 00:25:55 @@ -1 +1 @@ -2.22 +2.23 Index: scsidev.8 =================================================================== RCS file: /home/cvsroot/scsidev/scsidev.8,v retrieving revision 1.11 retrieving revision 1.11.2.1 diff -u -r1.11 -r1.11.2.1 --- scsidev.8 2000/07/14 23:59:35 1.11 +++ scsidev.8 2002/07/26 23:28:54 1.11.2.1 @@ -1,8 +1,8 @@ # -# $Id: scsidev.8,v 1.11 2000/07/14 23:59:35 garloff Exp $ +# $Id: scsidev.8,v 1.11.2.1 2002/07/26 23:28:54 garloff Exp $ # .\" -*- nroff -*- -.TH SCSIDEV 8 "July 2000" "Version 2.20" +.TH SCSIDEV 8 "July 2002" "Version 2.23" .SH NAME scsidev \- populate /dev/scsi with device names that are independent of reconfiguration. .SH SYNOPSIS @@ -32,6 +32,9 @@ .B \-r ] [ +.B \-e +] +[ .B \-s ] [ @@ -151,9 +154,17 @@ will do the right guesses. So using \-r in bootup scripts is safe. After you removed devices from your SCSI config, it isn't safe any longer. .TP +.I \-e +Instructs +.B scsidev +to use devfs like names, i.e. using the cbtu (controller, bus, target +unit) chraracters instead of hcil (host, channel, scsi Id, scsi Lun) to +build the device name. +.TP .I \-s Tells scsidev to print out the device serial numbers of all detected -devices on the system. This string can be useful for forming aliases. +devices on the system. This string can be useful for forming aliases. +If supported, also the WWID is printed. .TP .I \-v Verbosity. Mainly used for debugging purposes. Use multiple times for @@ -208,7 +219,16 @@ Specifies the serial number of the device. Not all devices implement this, but for those that do it provides a convenient mechanism to uniquely identify a device no matter where it is found on the -scsi chain. +scsi chain. The serial number is the one reported in INQUIRY page +0x80 with EVPD=1. It is displayed by +.B scsidev -s . +.TP +.I wwid= +Specifies the WWID number of a device. This is a 64bit world wide +unique number, which is supported by SCSI-3 devices and reported +via INQUIRY page 0x83 with EVPD=1. If supported, it's displayed +by +.B scsidev -s . .TP .I id= Specifies the scsi id number for the device. Index: scsidev.c =================================================================== RCS file: /home/cvsroot/scsidev/scsidev.c,v retrieving revision 1.28 retrieving revision 1.28.2.7 diff -u -r1.28 -r1.28.2.7 --- scsidev.c 2000/09/04 18:43:01 1.28 +++ scsidev.c 2002/07/27 00:16:10 1.28.2.7 @@ -61,6 +61,20 @@ * - Bugfix for long hostnames from Doug Gilbert (=> 2.21) * - Fix parsing of scsi.alias file: Broke on missing LF at the end * -> 2.22 + * + * * 2002/07/26: Kurt Garloff + * - optional (-e) cbtu naming scheme + * - bugfix WRT alias handling of subdevices (parititons, non-rew. tap) + * - Support for large SCSI IDs and LUNs. (from MGE) + * - Support WWID (INQ EVPD 0x83) report + aliases + * - Fix hex number parser + * -> 2.23 + * + * * 2002/07/30: Kurt Garloff + * - Support for /proc/scsi/scsi extensions + * - More sane way of storing permissions + * -> 2.25 + * */ #include @@ -75,13 +89,15 @@ #include #include #include +#include +#include -static char rcsid[] ="$Id: scsidev.c,v 1.28 2000/09/04 18:43:01 garloff Exp $"; +static char rcsid[] ="$Id: scsidev.c,v 1.28.2.7 2002/07/27 00:16:10 garloff Exp $"; static char *versid = "scsidev " VERSION " 2000/01/17"; static char *copyright = "Copyright: GNU GPL (see file COPYING)\n" \ " (w) 1994--1997 Eric Youngdale \n"\ -" 2000 Kurt Garloff "; +" 2000--2002 Kurt Garloff "; #include "config.h" @@ -107,17 +123,19 @@ int filemode = 0600; int verbose = 0; int quiet = 0; -int maxmiss = 0; +int maxmiss = 8; int force = 0; int san_del = 0; int no_san = 0; +int nm_cbtu = 0; int supp_rmvbl = 0; char * no_serial = "No serial number"; +unsigned long long no_wwid = 0; #define DEVSCSI "/dev/scsi" #define TESTDEV DEVSCSI "/testdev" +#define PROCSCSI "/proc/scsi/scsi" - /* * This program builds entries in /dev/scsi that have names that are tied * to the actual device number and lun. This is pretty solid as long as @@ -141,17 +159,18 @@ char * model; char * rev; char * serial; + unsigned long long wwid; char inq_devtp; char rmvbl; - char hostnum; char unsafe; int hostid; int major; int minor; char * hostname; - char chan; - char id; - char lun; + int hostnum; + int chan; + int id; + int lun; char partition; struct regnames * alias; // TBR struct regnames * related; @@ -174,6 +193,7 @@ ( memcmp (spnt->model, "SC-", 3) && \ memcmp (spnt->model, "DI-", 3) && \ memcmp (spnt->model, "DP-", 3) && \ + memcmp (spnt->model, "FW-", 3) && \ memcmp (spnt->model, "USB", 3) ) ) ) @@ -187,8 +207,9 @@ sname * pnt; for (pnt = reglist; pnt; pnt = pnt->next) { - printf ("%s: %s %s %s (%s)\n", pnt->name, - pnt->manufacturer, pnt->model, pnt->rev, pnt->serial); + printf ("%s: %s %s %s (%s) %Lx\n", pnt->name, + pnt->manufacturer, pnt->model, pnt->rev, pnt->serial, + pnt->wwid); printf (" on %s (%d-%x): c%di%dl%d", pnt->hostname, pnt->hostnum, pnt->hostid, pnt->chan, pnt->id, pnt->lun); if (pnt->partition != -1) printf ("p%d", pnt->partition); @@ -225,6 +246,7 @@ if (strcmp (sp1->model, sp2->model)) return 7; if (strcmp (sp1->rev, sp2->rev)) return 8; if (strcmp (sp1->serial, sp2->serial)) return 9; + if (sp1->wwid != sp2->wwid) return 10; return 0; } @@ -256,6 +278,7 @@ * Initialize this - they may be needed later. */ spnt->model = spnt->manufacturer = spnt->serial = spnt->rev = NULL; + spnt->wwid = no_wwid; spnt->next = reglist; reglist = spnt; return spnt; } @@ -384,9 +407,14 @@ sprintf (app, "p%d", spnt->minor % 0x10); } genpart = nm + strlen (nm); - sprintf (genpart, "s%ch%d-%xc%di%dl%d", devchar, - spnt->hostnum, spnt->hostid, - spnt->chan, spnt->id, spnt->lun); + if (nm_cbtu) + sprintf (genpart, "s%cc%db%dt%du%d", devchar, + spnt->hostnum, + spnt->chan, spnt->id, spnt->lun); + else + sprintf (genpart, "s%ch%d-%xc%di%dl%d", devchar, + spnt->hostnum, spnt->hostid, + spnt->chan, spnt->id, spnt->lun); if (*app) strcat (genpart, app); spnt->name = strdup (nm); return spnt->name; @@ -603,12 +631,12 @@ if (verbose == 2) fprintf (stderr, "Found %x with idlun %x\n", makedev (spnt->major, spnt->minor), id[0]); - spnt->hostnum = id[0] >> 24; - spnt->chan = id[0] >> 16; //()&0xff - spnt->lun = id[0] >> 8; - spnt->id = id[0]; + spnt->hostnum = id[0] >> 24 & 0xff; + spnt->chan = id[0] >> 16 & 0xff; + spnt->lun = id[0] >> 8 & 0xff; + spnt->id = id[0] & 0xff; spnt->hostid = id[1]; - + status = inquiry (fd, spnt); scsiname (spnt); return status; @@ -878,6 +906,135 @@ status = getscsiinfo (fd, spnt); close (fd); + if (status) { + free (spnt); miss++; + if (miss > maxmiss) break; + else { minor++; continue; } + } + scsiname (spnt); + + spnt->next = reglist; reglist = spnt; + create_dev (spnt); + + if (!quiet) printf ("Found %s (Type %02x) %c on %s \n", spnt->name, + spnt->inq_devtp, (spnt->rmvbl? 'R' : ' '), + spnt->hostname); + + /* Now register cdroms, tapes, and disks as well */ + switch (spnt->inq_devtp) { + case TYPE_DISK: + case TYPE_MOD: + if (!build_disk (spnt, disks)) disks++; + else if (!build_disk (spnt, disks+1)) disks += 2; + break; + case TYPE_TAPE: + if (OSST_SUPPORTS(spnt)) + { + if (!build_os_tape (spnt, tapes)) tapes++; + else if (!build_os_tape (spnt, tapes+1)) tapes += 2; + } + else + { + if (!build_tape (spnt, tapes)) tapes++; + else if (!build_tape (spnt, tapes+1)) tapes += 2; + } + break; + case TYPE_ROM: + case TYPE_WORM: + if (!build_cdrom (spnt, cdroms)) cdroms++; + else if (!build_cdrom (spnt, cdroms+1)) cdroms += 2; + break; + default: + ;/* nothing to be done */ + } + minor += 1; + } + //unlink (TESTDEV); +} + +#if 0 + +/* Test for availability of /proc/scsi/scsi extensions */ +int scsi_ext_status () +{ +} + +/* Try to switch on extensions */ +void scsi_ext_on () +{ +} + +/* Try to switch on extensions */ +void scsi_ext_off () +{ +} + +void build_sgdevlist_procscsi () +{ + int fd; + struct stat statbuf; + int status; + sname * spnt; + int miss = 0; + int minor = 0; int major = SCSI_GENERIC_MAJOR; + char devchar = 'g'; int mode = O_RDWR; + int devtype = (SCSI_BLK_MAJOR(major)? S_IFBLK: S_IFCHR); + char* buf; int buflen; + FILE* mapfile; + + status = stat (DEVSCSI, &statbuf); + if (status == -1) + return; + + status = stat (TESTDEV, &statbuf); + if (status == 0) + unlink (TESTDEV); + + if (verbose >= 1) + fprintf (stderr, "Building list for s%c (%s dev major %i)\n", + devchar, (SCSI_BLK_MAJOR(major)? "block": "char"), major); + + mapfile = fopen (PROCSCSI, "r"); + if (!mapfile) { + fprintf (stderr, "scsidev: could not open " PROCSCSI ": %s\n", + strerror (errno)); + return; + } + + buf = malloc(128); buflen = 128; + + + + while (getline (&buf, &buflen, mapfile) != -1) + { + int h,c,i,l; + int inqtp, onl; + char *nm, *dev, *rest; + if (buf[0] == '#') + continue; + + errno = 0; + status = mknod ( TESTDEV, 0600 | devtype , + makedev (major, minor) ); + if (status) { perror ("scsidev: mknod"); exit (3); } + fd = open (TESTDEV, mode); + unlink (TESTDEV); + if (fd == -1) { + if (verbose == 2) + { + fprintf (stderr, "open(%x/%x) returned %d (%d)\n", + major, minor, fd, errno); + } + miss++; + if (miss > maxmiss) break; + else { minor++; continue; } + } + spnt = (sname*) malloc (sizeof (sname)); + spnt->major = major; spnt->minor = minor; + spnt->name = TESTDEV; spnt->partition = -1; + status = getscsiinfo (fd, spnt); + close (fd); + if (status) { free (spnt); return; }; scsiname (spnt); @@ -918,9 +1075,25 @@ minor += 1; } //unlink (TESTDEV); + free(buf); } +int try_procscsi () +{ + int se_status = scsi_ext_status(); + if (!se_status) + scsi_ext_on(); + if (!scsi_ext_status()) + return -1; + + build_sgdevlist_procscsi(); + + if (!se_status) + scsi_ext_off(); +} +#endif + void usage() { fprintf (stderr, "%s\n", versid); @@ -930,9 +1103,10 @@ fprintf (stderr, " -d : sanitize by Deleting undetected entries (def: minor->255)\n"); fprintf (stderr, " -l/-L : create symLinks for device names / alias names\n"); fprintf (stderr, " -m mode: permissions to create dev nodes with\n"); - fprintf (stderr, " -s : list Serial numbers of devices (if available)\n"); + fprintf (stderr, " -s : list Serial numbers /WWIDs of devices (if available)\n"); fprintf (stderr, " -c mxms: Continue scanning until mxms missing devs found\n"); fprintf (stderr, " -r : trust Removeable media (only safe after boot)\n"); + fprintf (stderr, " -e : use dEvfs like naming (cbtu chars)\n"); fprintf (stderr, " -v/-q : Verbose/Quiet operation\n"); fprintf (stderr, " -h : print Help and exit.\n"); } @@ -955,7 +1129,7 @@ fprintf(stderr, DEVSCSI " either does not exist, or is not a directory\n"); exit(0); } - while ((c = getopt(argc, argv, "flLvqshndrm:c:")) != EOF) + while ((c = getopt(argc, argv, "flLvqshnderm:c:")) != EOF) { switch (c) { @@ -977,6 +1151,8 @@ san_del = 1; break; case 'r': supp_rmvbl = 1; break; + case 'e': + nm_cbtu = 1; break; case 'v': verbose++; break; case 'h': @@ -993,22 +1169,24 @@ if( force ) flush_sdev (); #ifdef DEBUG - register_dev("/dev/scsi/sdh4-334c0i0l0", 8, 0, 6, 0x334, 0, 0, 0, -1, "debug", NULL); - register_dev("/dev/scsi/sdh4-334c0i0l0p1", 8, 1, 6, 0x334, 0, 0, 0, 1, "debug", NULL); - register_dev("/dev/scsi/sdh4-334c0i0l0p2",8, 2,6, 0x334, 0, 0, 0, 2, "debug", NULL); - register_dev("/dev/scsi/sdh4-334c0i0l0p3",8, 3,6, 0x334, 0, 0, 0, 3, "debug", NULL); - register_dev("/dev/scsi/sgh4-334c0i0l0", 21, 0,6, 0x334, 0, 0, 0, -1, "debug", NULL); - register_dev("/dev/scsi/sgh4-334c0i2l0", 21, 1,6, 0x334, 0, 2, 0, -1, "debug", NULL); - register_dev("/dev/scsi/sgh4-334c0i5l0", 21, 2,6, 0x334, 0, 5, 0, -1, "debug", NULL); - register_dev("/dev/scsi/srh4-334c0i2l0", 11, 0,6, 0x334, 0, 2, 0, -1, "debug", NULL); - register_dev("/dev/scsi/sth4-334c0i5l0", 9, 0,6, 0x334, 0, 5, 0, -1, "debug", NULL); - register_dev("/dev/scsi/rsth4-334c0i5l0", 9,128,6, 0x334, 0, 5, 0, -1, "debug", NULL); + register_dev("/dev/scsi/sdh4-334c0i0l0", 8, 0, 6, 0x334, 0, 0, 0, -1, "debug", NULL); + register_dev("/dev/scsi/sdh4-334c0i0l0p1",8, 1, 6, 0x334, 0, 0, 0, 1, "debug", NULL); + register_dev("/dev/scsi/sdh4-334c0i0l0p2",8, 2, 6, 0x334, 0, 0, 0, 2, "debug", NULL); + register_dev("/dev/scsi/sdh4-334c0i0l0p3",8, 3, 6, 0x334, 0, 0, 0, 3, "debug", NULL); + register_dev("/dev/scsi/sgh4-334c0i0l0", 21, 0, 6, 0x334, 0, 0, 0, -1, "debug", NULL); + register_dev("/dev/scsi/sgh4-334c0i2l0", 21, 1, 6, 0x334, 0, 2, 0, -1, "debug", NULL); + register_dev("/dev/scsi/sgh4-334c0i5l0", 21, 2, 6, 0x334, 0, 5, 0, -1, "debug", NULL); + register_dev("/dev/scsi/srh4-334c0i2l0", 11, 0, 6, 0x334, 0, 2, 0, -1, "debug", NULL); + register_dev("/dev/scsi/sth4-334c0i5l0", 9, 0, 6, 0x334, 0, 5, 0, -1, "debug", NULL); + register_dev("/dev/scsi/rsth4-334c0i5l0", 9,128, 6, 0x334, 0, 5, 0, -1, "debug", NULL); #else build_sgdevlist (); #endif if( show_serial ) { + if (verbose) + dumplist(); for (spnt = reglist; spnt; spnt = spnt->next) { if( spnt->partition != -1 ) continue; @@ -1020,6 +1198,8 @@ printf("Device %s has no serial number\n", spnt->name); else printf("Serial number of %s: \"%s\"\n", spnt->name, spnt->serial); + if ( spnt->wwid != no_wwid ) + printf (" WWID: %Lx\n", spnt->wwid); } } @@ -1065,6 +1245,58 @@ return pnt; } +char * get_llnumber (char * pnt, unsigned long long * result) +{ + int base = 10; + unsigned long long num; + + while (*pnt == ' ' || *pnt == '\t') pnt++; + if (pnt[0] == '0' && pnt[1] == 'x') { base = 16; pnt += 2; } + + num = 0; + while (1) + { + if (base == 10 && *pnt >= '0' && *pnt <= '9' ) + { + num = num * 10ULL + *pnt - '0'; + pnt++; + continue; + } + if ( base == 16 ) + { + if (*pnt >= '0' && *pnt <= '9') + { + num = (num << 4) + *pnt - '0'; + pnt++; + continue; + } + if (*pnt >= 'a' && *pnt <= 'f') + { + num = (num << 4) + *pnt - 'a' + 10; + pnt++; + continue; + } + if (*pnt >= 'A' && *pnt <= 'F') + { + num = (num << 4) + *pnt - 'A' + 10; + pnt++; + continue; + } + break; + } + /* + * Isn't a digit. Must be the end of the number. + */ + break; + } + while (*pnt == ' ' || *pnt == '\t') pnt++; + if (*pnt == ',') pnt++; + while (*pnt == ' ' || *pnt == '\t') pnt++; + *result = num; + return pnt; + +} + char * get_number (char * pnt, int * result) { int base = 10; @@ -1086,19 +1318,19 @@ { if (*pnt >= '0' && *pnt <= '9') { - num = num * 10 + *pnt - '0'; + num = (num << 4) + *pnt - '0'; pnt++; continue; } if (*pnt >= 'a' && *pnt <= 'f') { - num = num * 10 + *pnt - 'a' + 10; + num = (num << 4) + *pnt - 'a' + 10; pnt++; continue; } if (*pnt >= 'A' && *pnt <= 'F') { - num = num * 10 + *pnt - 'A' + 10; + num = (num << 4) + *pnt - 'A' + 10; pnt++; continue; } @@ -1133,6 +1365,7 @@ * MANUFACTURER="string" * MODEL="string" * SERIAL_NUMBER="string" (for those devices that support this). + * WWID=number ( " " " " " " ) * REV="string" * NAME="string" (alias) * DEVTYPE="disk", "tape", "osst", "generic", or "cdrom". @@ -1150,6 +1383,7 @@ int lun, chan, id, part, hostid, hostnum; int line; + unsigned long long wwid; /* host byte order ... */ int devtype_i; char *manufacturer, *model, *serial_number, *name, *devtype, *rev, *host; char *scsialias; @@ -1186,11 +1420,11 @@ lun = -1; id = -1; chan = -1; hostid = -1; hostnum = -1; - part = -1; + part = -1; wwid = no_wwid; host = NULL; manufacturer = NULL; model = NULL; serial_number = NULL; rev = NULL; - name = NULL; + name = NULL; devtype = NULL; pnt = buffer; while (*pnt == ' ' || *pnt == '\t') pnt++; @@ -1218,6 +1452,10 @@ { pnt = get_string(pnt1 + 1, &serial_number); } + else if ( strcmp(pnt, "wwid") == 0 ) + { + pnt = get_llnumber(pnt1 + 1, &wwid); + } else if ( strncmp(pnt, "rev", 3) == 0 ) { pnt = get_string(pnt1 + 1, &rev); @@ -1320,6 +1558,7 @@ if( part != spnt->partition ) continue; if( (spnt->major == SCSI_TAPE_MAJOR || spnt->major == OSST_MAJOR) && (spnt->minor & 0x80) != 0) continue; + if( wwid != no_wwid && wwid != spnt->wwid ) continue; /* * OK, that matches, now obtain some of the strings @@ -1386,7 +1625,7 @@ else fprintf (stderr, "\n"); } - if( devtype_i == SCSI_DISK0_MAJOR + if( SCSI_DISK_MAJOR(devtype_i) || devtype_i == SCSI_CDROM_MAJOR ) type = S_IFBLK; else @@ -1397,7 +1636,7 @@ * Just create it. */ sprintf (scsidev, DEVSCSI "/%s", name); - register_dev (scsidev, match->major, match->minor | 0x80, + register_dev (scsidev, match->major, match->minor, 0, 0, 0, 0, 0, 0, 0, match); if (symlink_alias) { unlink (scsidev); @@ -1445,7 +1684,7 @@ sprintf(scsidev, DEVSCSI "/%s-p%d", name, spnt->partition); - register_dev (scsidev, match->major, match->minor | 0x80, + register_dev (scsidev, match->major, spnt->minor, 0, 0, 0, 0, 0, 0, 0, spnt); if (symlink_alias) { unlink (scsidev); @@ -1490,6 +1729,48 @@ return str; } +unsigned long long extract_wwid (unsigned char* page) +{ + unsigned int hi, lo; + if (page[1] != 0x83) + return no_wwid; + /* We only support binary data */ + if ((page[4] & 0x0f) != 1) + return no_wwid; + /* We support identifier types 2, 3 */ + if ((page[5] & 0x0f) != 3 && (page[5] & 0x0f) != 2) + return no_wwid; + /* Id length should be 8 (64 bits) */ + if (page[7] != 8) + return no_wwid; + /* Now translate network byte order to host byte order */ + hi = ntohl (*(unsigned int*)(page+ 8)); + lo = ntohl (*(unsigned int*)(page+12)); + return ((unsigned long long) hi << 32) + (unsigned long long) lo; +} + +#define INQBUFSZ 512 +int get_inq_page (int file, int lun, unsigned char* buf, unsigned char page, char evpd) +{ + unsigned char *cmd; + + memset (buf, 0, INQBUFSZ); + + *( (int *) buf) = 0; /* length of input data */ + *( ((int *) buf) + 1 ) = INQBUFSZ-32; /* length of output buffer */ + + cmd = (char *) ( ((int *) buf) + 2 ); + + cmd[0] = 0x12; /* INQUIRY */ + cmd[1] = (lun << 5) | (evpd? 1: 0); /* lun, evpd=... */ + cmd[2] = page; /* page code 0: std inquiry */ + cmd[3] = 0x00; /* (reserved) */ + cmd[4] = 0xfc; /* allocation length */ + cmd[5] = 0x00; /* control */ + + return ioctl (file, SCSI_IOCTL_SEND_COMMAND, buf); +} + int inquiry (int infile, sname * spnt) { #ifdef DEBUG @@ -1508,73 +1789,68 @@ } #else int status; - unsigned char *cmd; - unsigned char * pagestart; - unsigned char buffer[1024]; + unsigned char buffer[INQBUFSZ]; + unsigned char * const pagestart = buffer + 8; //int infile; - - memset (buffer, 0, sizeof(buffer)); - - *( (int *) buffer ) = 0; /* length of input data */ - *( ((int *) buffer) + 1 ) = sizeof(buffer)-16; /* length of output buffer */ - - cmd = (char *) ( ((int *) buffer) + 2 ); - - cmd[0] = 0x12; /* INQUIRY */ - cmd[1] = (spnt->lun << 5) | 0x01; /* lun, evpd=1 */ - cmd[2] = 0x80; /* page code = 0x80, serial number */ - cmd[3] = 0x00; /* (reserved) */ - cmd[4] = 0xff; /* allocation length */ - cmd[5] = 0x00; /* control */ - + char have_ser_page = 0; + char have_wwid_page = 0; + int ln; int off; + int lun; int ansi; + //infile = open(spnt->name, O_RDWR); if( infile == -1 ) return -1; - - status = ioctl( infile, 1, buffer ); - //close(infile); - pagestart = buffer + 8; - - if (status) - spnt->serial = no_serial; - else - spnt->serial = getstr (pagestart, 4, 3+pagestart[3]); - - if (verbose == 2) printf ("Serial for %s: %s\n", spnt->name, spnt->serial); - memset (buffer, 0, sizeof(buffer)); - - *( (int *) buffer ) = 0; /* length of input data */ - *( ((int *) buffer) + 1 ) = sizeof(buffer)-16; /* length of output buffer */ - - cmd = (char *) ( ((int *) buffer) + 2 ); - - cmd[0] = 0x12; /* INQUIRY */ - cmd[1] = (spnt->lun << 5); /* lun, evpd=0 */ - cmd[2] = 0x00; /* page code 0: std inquiry */ - cmd[3] = 0x00; /* (reserved) */ - cmd[4] = 0xff; /* allocation length */ - cmd[5] = 0x00; /* control */ - - //infile = open (spnt->name, O_RDWR); - //if( infile == -1 ) return -1; - - status = ioctl( infile, 1, buffer ); - //close(infile); - pagestart = buffer + 8; + // Std. inquiry + status = get_inq_page (infile, 0, buffer, 0, 0); if (status) { - fprintf (stderr, "INQUIRY failed for %s (%i-%i)!\n", - spnt->name, spnt->id, spnt->lun); - return -1; + fprintf (stderr, "INQUIRY failed for %s (%i-%i/%02x:%02x)!\n", + spnt->name, spnt->id, spnt->lun, spnt->major, spnt->minor); + return -1; } - if (verbose == 2) dumppage (pagestart); + if (verbose == 2) + dumppage (pagestart); spnt->manufacturer = getstr (pagestart, 8, 15); spnt->model = getstr (pagestart, 16, 31); spnt->rev = getstr (pagestart, 32, 35); spnt->inq_devtp = pagestart[0] & 0x1f; spnt->rmvbl = (pagestart[1] & 0x80) >> 7; + spnt->wwid = no_wwid; spnt->serial = no_serial; + ansi = pagestart[2] & 7; + + if (ansi >= 3) + lun = 0; + else + lun = spnt->lun; + + /* TODO: Extract serial number from bytes 36--43 ? */ + + // List of supported EVPD pages ... + if (get_inq_page (infile, lun, buffer, 0, 1)) + return 0; + ln = pagestart[3]; + for (off = 0; off < ln; ++off) { + if (pagestart[4+off] == 0x80) + have_ser_page = 1; + if (pagestart[4+off] == 0x83) + have_wwid_page = 1; + } + + if (have_ser_page && !get_inq_page (infile, lun, buffer, 0x80, 1)) { + spnt->serial = getstr (pagestart, 4, 3+pagestart[3]); + if (verbose == 2) + printf ("Serial for %s: %s\n", spnt->name, spnt->serial); + } + + if (have_wwid_page && !get_inq_page (infile, lun, buffer, 0x83, 1)) { + spnt->wwid = extract_wwid (pagestart); + + if (verbose == 2) + printf ("WWID for %s: %Lx\n", spnt->name, spnt->wwid); + } + //close(infile); return 0; #endif }