From:	SMTP%"lauri@elwing.fnal.gov"  6-JUN-1994 10:51:38.24
To:	EVERHART
CC:	
Subj:	Re: SCSI INQUIRY command to a SYSTEM disk -- can it be done?

From: lauri@fndcd.fnal.gov (Laurelin of Middle Earth)
X-Newsgroups: comp.os.vms
Subject: Re: SCSI INQUIRY command to a SYSTEM disk -- can it be done?
Date: 3 Jun 1994 14:18:25 GMT
Organization: Fermi National Accelerator Lab
Lines: 317
Message-Id: <2sne3h$6gg@fnnews.fnal.gov>
Reply-To: lauri@elwing.fnal.gov
Nntp-Posting-Host: dcd00.fnal.gov
To: Info-VAX@CRVAX.SRI.COM
X-Gateway-Source-Info: USENET

Some time back I wrote:
>I am writing a program in C to send a SCSI INQUIRY command to various
>devices so that I can read the vendor-specific information contained in
>the inquiry data page.
>
>The program works fine for all disks, 8mm tape drives, and CD players (in
>short, all of the SCSI devices) on my system *except* the system disk. 
>When I try the bootnode, the node crashes with FATALEXCPT (Fatal executive
>or kernel mode exception).  [It crashes on the call to $QIOW].
>
> [deletia]

I am not sure that the previous message was successfully posted, in part
because I haven't heard anything -- not flames, not questions, nothing.  So
please forgive me if it eats up bandwidth, I will provide more information and
the *whole* of my current code.

The system disk in question is a DSP3105, perhaps it is this particular
hardware that causes the problem.  Unfortunately, I don't have access to any
non-system-disk DSP3105's to test that hypothesis.  Perhaps some kind
gentleperson would be willing to try my code on a non-system-disk DSP3105?

Or perhaps some wise individual will have insight into why IO$_DIAGNOSE (as
used below) fails on a system disk, or what magic incantations I need to muble
to make it work.  VMS V5.5-2 (plus many patches), VAXC032-047, VAXstation
4000-90 as a bootnode in an LAVC.

The code follows.  To build:
	$ CC DISK_INQ
	$ DEFINE/USER LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB
	$ LINK DISK_INQ

To run,
	$ DEFINE SCSI_TARGET scsi-device-name	! logical or physical
	$ RUN DISK_INQ

Example output (which is all expected):  I will run this program on my
satellite's page/swap disk, ELWING$DKA0 (also known as ELWING$PAGE):

	$
	$ define scsi_target elwing$page
	%DCL-I-SUPERSEDE, SCSI_TARGET's old value was stupid anyway
	$ run elwing$local:[lauri.duff]disk_inq

	$QIOW using IO$_DIAGNOSE to SCSI_TARGET...
	SCSI inquiry data returned:
	        Peripheral Device Type  0
	        Peripheral Qualifier    0
	        Device Type Modifier    0
	        Removable media (RMB)   0
	        ANSI Version    1
	        ECMA Version    0
	        ISO Version     0
	        Response Data Format    1
	        Terminate I/O Process message (TrmIOP)  0
	        Async Event Notification Capability (AENC)      0
	        Additional length       31
	        Soft reset response     0
	        Command queueing        0
	        Linked commands 1
	        Sync data transfers     1
	        16-bit wide bus support 0
	        32-bit wide bus support 0
	        Relative addressing     0
	        Vendor:         FUJITSU
	        Product id:     M2612S
	        Revision Level:         0606
	        Vendor-specific:
	        Unit S/N:

Thanks, lauri
/-----------------------------------------------------------------------------\
| Lauri Loebel Carpenter        "All that is gold does not glitter,           |
| lauri@elwing.fnal.gov          Not all those who wander are lost..." - JRRT |
| #include <std.disclaimer>           /* I only speak for myself */           |
\-----------------------------------------------------------------------------/
--------------------------- C U T  H E R E ------------------------------------

/*
 * DISK_INQ.C
 * Send the SCSI INQUIRY command to SCSI devices,
 * learn about them.
 *
 * Author: L. Loebel Carpenter, Computing Division, Fermilab
 *
 * History:
 * 31may94 lll	Initial, heavily based upon FjNagy's MKINQ routines.
 */


#include <ctype.h>
#include <stdio.h>
#include <descrip.h>

#include "SCSI_INQ.H"

globalvalue IO$_DIAGNOSE;

struct SCSI_INQ_CMD inqcmd;				/* command buffer for SCSI INQUIRY command */

struct SCSI_INQ_RES inqres;				/* buffer for information returned from SCSI INQUIRY command */

struct SCSI_DESC tgtdesc;				/* descriptor of device which is queried */

struct SCSI_IOSB tgtiosb;				/* descriptor of i/o status block for target device */

static readonly $DESCRIPTOR(d_target, "SCSI_TARGET");

main ()
{
int sts, i;
short tgtchan;

/*
 Assign a channel to SCSI_TARGET
 */

 sts = sys$assign ( &d_target, &tgtchan, 0, 0);
 if (!(sts & 1)) sys$exit (sts);

/*
 Set up the descriptor with the SCSI information to be sent to the target.
 */
 tgtdesc.opcode = 1;
 tgtdesc.flags = 0;
 tgtdesc.dir = 1;
 tgtdesc.dis = 1;
 tgtdesc.cdbptr = (struct SCSI_INQ_CMD *) &inqcmd;
 tgtdesc.cdblen = sizeof inqcmd;
 tgtdesc.dataptr = (char *) &inqres;
 tgtdesc.datalen = sizeof inqres;
 tgtdesc.padlen = 0;
 tgtdesc.phasetmo = 60;
 tgtdesc.discontmo = 60;

/*
 Set up SCSI command buffer for INQUIRY command
*/
 inqcmd.opcode = SCSI_INQUIRY;
 inqcmd.evpd = 0;
 inqcmd.lun = 0;
 inqcmd.pagecode = 0;
 inqcmd.allolen = sizeof inqres;

/*
 Send the $QIOW to the SCSI_TARGET device.
 */

 printf ("\n$QIOW using IO$_DIAGNOSE to SCSI_TARGET...\n");
 sts = sys$qiow (0, tgtchan, IO$_DIAGNOSE, &tgtiosb, 0, 0, 
		&tgtdesc, sizeof tgtdesc, 0, 0, 0, 0);
 if (!(sts & 1)) sys$exit (sts);
 if (!(tgtiosb.status & 1)) sys$exit (tgtiosb.status);
 if (tgtiosb.scsi_sts) {
    printf ("Bad SCSI status returned: %02.2x\n", tgtiosb.scsi_sts);
    sys$exit (1);
    }

/*
 The command succeeded. Display the SCSI data returned from the target
*/

 printf ("SCSI inquiry data returned: \n");
 printf( "\tPeripheral Device Type\t%d\n", inqres.devicetype);
 printf( "\tPeripheral Qualifier\t%d\n", inqres.pqualifier);
 printf( "\tDevice Type Modifier\t%d\n", inqres.dtmodifier);
 printf( "\tRemovable media (RMB)\t%d\n", inqres.rmb);
 printf( "\tANSI Version\t%d\n", inqres.ansi);
 printf( "\tECMA Version\t%d\n", inqres.ecma);
 printf( "\tISO Version\t%d\n", inqres.iso );
 printf( "\tResponse Data Format\t%d\n", inqres.respfmt);
 printf( "\tTerminate I/O Process message (TrmIOP)\t%d\n", inqres.trmiop);
 printf( "\tAsync Event Notification Capability (AENC)\t%d\n", inqres.aenc);
 printf( "\tAdditional length\t%d\n", inqres.addlen);
 printf( "\tSoft reset response\t%d\n", inqres.sftre);
 printf( "\tCommand queueing\t%d\n", inqres.cmdque);
 printf( "\tLinked commands\t%d\n", inqres.linked);
 printf( "\tSync data transfers\t%d\n", inqres.sync);
 printf( "\t16-bit wide bus support\t%d\n", inqres.wbus16);
 printf( "\t32-bit wide bus support\t%d\n", inqres.wbus32);
 printf( "\tRelative addressing\t%d\n", inqres.reladr);
 printf( "\tVendor: \t%.8s\n", inqres.vendor);
 printf( "\tProduct id: \t%.16s\n", inqres.prodid);
 printf( "\tRevision Level: \t%.4s\n", inqres.revlvl);
 printf( "\tVendor-specific: \t%.20s\n", inqres.vendor_spec);
 printf( "\tUnit S/N: \t%.10s\n", inqres.unitsn);
}
--------------------------- C U T  A G A I N  H E R E ------------------------
/*
 *
 * SCSI_INQ.H:
 * Header information for SCSI INQUIRY Command.
 *
 * Author:
 * L. Loebel Carpenter, Computing Division, Fermilab
 *
 * History:
 * 31may94 lll	Initial, based heavily on FjNagy's EXABYTE.H files from
 *		testing of MKDRIVER inquiry commands.
 *
 */

#define	SCSI_INQUIRY		0X12	/* Return identification information */

/*
 SCSI Status Byte codes (includes the reserved bits)
*/
#define SCSISTS_GOOD		0	/* Operation completed successfully */
#define SCSISTS_CHECK		2	/* Error or other exception */
#define SCSISTS_BUSY		8	/* Device is busy */
#define SCSISTS_CONFLICT	0X18	/* Reservation conflict */


struct SCSI_INQ_CMD {
    unsigned char opcode;		/* opcode for INQUIRY = 12h */
    unsigned evpd : 1;			/* Enable Vital Product Data */
    unsigned : 4;			/* reserved */
    unsigned lun : 3;			/* logical unit number */
    unsigned char pagecode;		/* Page Code */
    unsigned : 8;			/* reserved */
    unsigned char allolen;		/* allocation length */
    unsigned : 8;			/* control byte */
};

struct SCSI_INQ_RES {
    unsigned devicetype : 5;		/* peripheral device type */
    unsigned pqualifier : 3;		/* peripheral qualifier */
    unsigned dtmodifier : 7;		/* device-type qualifier */
    unsigned rmb : 1;			/* removable media bit */
    unsigned ansi : 3;			/* ANSI version */
    unsigned ecma : 3;			/* ECMA version */
    unsigned iso : 2;			/* ISO version */
    unsigned respfmt : 4;		/* response data format */
    unsigned : 2;			/* reserved */
    unsigned trmiop : 1;		/* terminate i/o process bit */
    unsigned aenc : 1;			/* asynchronous event notification capability bit */
    unsigned char addlen;		/* additional length */
    unsigned : 16;			/* reserved */
    unsigned sftre : 1;			/* software reset bit */
    unsigned cmdque : 1;		/* tagged command queueing bit */
    unsigned  : 1;			/* reserved */
    unsigned linked: 1;			/* linked commands bit */
    unsigned sync : 1;			/* synchronous data transfer bit */
    unsigned wbus16 : 1;		/* 16-bit data transfer bit */
    unsigned wbus32 : 1;		/* 21-bit data transfer bit */
    unsigned reladr : 1;		/* relative addressing bit */
    char vendor[8];			/* vendor identification string */
    char prodid[16];			/* product identification string */
    char revlvl[4];			/* product revision level string */
    char vendor_spec[20];		/* vendor-specific information */
    char reserved1[40];			/* reserved */
    char unitsn[10];			/* vendor-specific information */
};

#define SCSI_PDT_SUPPORTED	0	/* peripheral device type field is supported */
#define SCSI_PDT_NOT_CONNECTED	1	/* device is not connected, pdt specifies what could be supported */
#define SCSI_PDT_RESERVED	2	/* reserved */
#define SCSI_PDT_LUN_UNSUPPORTED 3	/* peripheral device type field is not supported */

#define SCSI_DIRECT_ACCESS	0X00	/* direct_access device */
#define SCSI_SEQUENTIAL_ACCESS	0X01	/* sequential_access device */
#define SCSI_PRINTER		0X02	/* printer device */
#define SCSI_PROCESSOR		0X03	/* processor device */
#define SCSI_WORM		0X04	/* worm device */
#define SCSI_CDROM		0X05	/* cdrom device */
#define SCSI_SCANNER		0X06	/* scanner device */
#define SCSI_OPTICAL_MEMORY	0X07	/* optical_memory device */
#define SCSI_MEDIUM_CHANGER	0X08	/* medium_changer device */
#define SCSI_COMMUNICATION	0X09	/* communication device */
#define SCSI_GRAPHICS		0X0A	/* graphics device */
#define SCSI_UNKNOWN		0X1F	/* unknown device */

#define SCSI_ANSI_0		0X00	/* device may or may not comply with any ANSI SCSI standards */
#define SCSI_ANSI_1		0X01	/* device claims to comply with ANSI SCSI-1 standards */
#define SCSI_ANSI_2		0X02	/* device claims to comply with ANSI SCSI-2 standards */


/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
#ifdef VMS
/*
 VMS-specific:
 SCSI descriptor used for SCSI IO$_DIAGNOSE operations
*/
struct SCSI_DESC {
    unsigned long opcode;		/* Opcode */
    variant_union {
	variant_struct {
	    unsigned dir : 1;		/* Transfer direction, 1=READ/0=WRITE */
	    unsigned dis : 1;		/* Enable disconnection */
	    unsigned syn : 1;		/* Enable synchronous mode */
	    unsigned dpr : 1;		/* Disable port retry */
	    } flags_struct;
	unsigned long flags;
	} flags_union;
    unsigned char *cdbptr;		/* Pointer to SCSI command buffer */
    unsigned long cdblen;		/* Length of SCSI command */
    unsigned char *dataptr;		/* Pointer to SCSI data buffer */
    unsigned long datalen;		/* Length of SCSI data buffer */
    unsigned long padlen;		/* SCSI pad length */
    unsigned long phasetmo;		/* Phase change timeout */
    unsigned long discontmo;		/* Disconnection timeout */
    unsigned long unused[6];		/* Reserved */
};

/*
 VMS-specific:
 VMS I/O status block for SCSI IO$_DIAGNOSE operations
*/
struct SCSI_IOSB {
    unsigned short status;		/* VMS status code */
    unsigned long tfrcnt;		/* Transfer count */
    unsigned : 8;
    unsigned char scsi_sts;		/* SCSI status code */
};

#endif
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */

