From:	STAR::GWANG        "GRACE WANG DTN 381-2467 ZK3-4/W23" 29-JAN-1996 14:35:06.97
To:	EVERHART
CC:	GWANG
Subj:	DIAG_TEST.C

#pragma module diag_test "V1.5"

#include <stdio.h>
#include <ctype.h>
#include <ints.h>
#include <iodef.h>
#include <descrip.h>
#include <scsidef.h>
#include <starlet.h>
#include <s2dgbdef.h>

/* Forward Function References */
void format_inq (struct inquiry_data *inq);
void format_mode_6 (unsigned char *data);
void format_mode_10 (unsigned char *data);

/* For this utility, set lower max size values than the SCSI spec does,
   just to keep the program and array sizes more manageable. */

#define MAX_CDB_SIZE 248   	/* Actual max = 248.   */
#define MAX_ASENSE_SIZE 255     /* Actual max = 255.   */
#define MAX_S0_BUF_SIZE 1023      /* Actual max = 65536. */

#define BUILD_YOUR_OWN 99
#define SCSI_GOOD_STATUS 0
#define DISPLAY_BYTES_PER_ROW 6

main()
{
    int i,j; 
    unsigned char scsi_status;
    unsigned short target_chan;
    static unsigned char cdb[MAX_CDB_SIZE] = {0};
    static unsigned char autosense_data[MAX_ASENSE_SIZE] = {0};
    static unsigned char s0_buf[MAX_S0_BUF_SIZE] = {0};
    unsigned char inquiry[6] =  {0X12,0,0,0,0X24,0};
    unsigned char test_unit_ready[6] =  {0,0,0,0,0,0};
    unsigned char mode_select[6] =  {0X15,0X10,0,0,0X14,0};
    unsigned char mode_sense_6_curr[6] =  {0X1A,0,1,0,0X18,0};
    unsigned char mode_sense_6_chg[6] =   {0X1A,0,0X41,0,0X18,0};
    unsigned char mode_sense_10_curr[10] = {0X5A,0,1,0,0,0,0,0,0X1c,0};
    unsigned char mode_sense_10_chg[10] =   {0X5A,0,0X41,0,0,0,0,0,0X1c,0};
    unsigned char request_sense[6] =  {3,0,0,0,MAX_S0_BUF_SIZE,0};
    unsigned char read_lbn100[6] =  {8,0,0,100,1,0};
    short cdb_len = 0, s0_buf_len = 0, choice = 0;
    short read_dir, tagreq, tagmode, disc, asbuff;
    int transfer_length = 0;
    int status;
    int64 iosb = 0;
    typedef struct
    {      
        short int vms_sts;		   
        short int bcnt_lo;		   
        short int bcnt_hi;		   
        char fill;
        unsigned char scsi_sts;
    } IOSB;
    IOSB *iosb_ptr = (IOSB *)(&iosb);
    S2DGB diag_desc; 		
    static $DESCRIPTOR (target_device_desc, "target_dev");

    printf("\n");
    printf("Diag_test V1.5\n");
    printf("\n");

    /*  Assign the device channel */
    status = sys$assign(&target_device_desc,  &target_chan,  0,  0);
    if (!(status & 1))
    {
    	printf ("Unable to assign channel to target_dev.");
	sys$exit (status);
    }

    /* Present a menu */
    do
    {
        printf("\n");
        printf("     Choose one of following SCSI commands to be sent:\n\n");
        printf("     1.  INQUIRY\n\n");  
        printf("     2.  MODE_SENSE_6  (current params, error recovery page)\n\n");  
        printf("     3.  MODE_SENSE_10 (current params, error recovery page)\n\n");  
        printf("     4.  MODE_SENSE_6  (changeable params, error recovery page)\n\n");  
        printf("     5.  MODE_SENSE_10 (changeable params, error recovery page)\n\n");  
        printf("     6.  MODE_SENSE_10 (current params, error recovery page, No Asense Buffer)\n\n");  
        printf("     7.  REQUEST SENSE\n\n");  
        printf("     8.  TEST UNIT READY\n\n");  
        printf("     9.  READ LBN #100. FROM DISK \n\n");  
        printf("     10. Build your own command (must supply all S2DGB inputs)\n\n");  
        printf("     Choice: ");  
        scanf("%hd", &choice);                     
    } while ((choice < 0) || (choice > 10));

    /* Edit this line, and the line above, to add more menu items */
    if (choice == 10)
	choice = BUILD_YOUR_OWN;

    /* Set up the default S2DBG descriptor values */

    diag_desc.s2dgb$l_opcode = 1; 			/* Pass-through - the only code defined */
    diag_desc.s2dgb$l_flags =  (S2DGB$M_READ | 
				S2DGB$M_DISCPRIV | 
				S2DGB$M_SYNCHRONOUS | 
				S2DGB$M_AUTOSENSE);
    diag_desc.s2dgb$l_32cdbaddr = (int)(&cdb[0]);	/* command addr 			*/
    diag_desc.s2dgb$l_32cdblen =  0;			/* command length			*/
    diag_desc.s2dgb$l_32dataddr = 0;			/* data addr 				*/
    diag_desc.s2dgb$l_32datlen =  0;   			/* data length 				*/
    diag_desc.s2dgb$l_32padcnt = 0;			/* pad length 				*/
    diag_desc.s2dgb$l_32phstmo = 20;			/* phase timeout 			*/
    diag_desc.s2dgb$l_32dsctmo = 10;			/* disconnect timeout 			*/
    diag_desc.s2dgb$l_32senseaddr = (int)(&autosense_data[0]);	/* senseaddr 			*/
    diag_desc.s2dgb$l_32senselen = MAX_ASENSE_SIZE;	/* sense length 	*/
    diag_desc.s2dgb$l_reserved1 = 0;			/* Reserved */
    diag_desc.s2dgb$l_reserved2 = 0;			/* Reserved */
    diag_desc.s2dgb$l_reserved3 = 0;			/* Reserved */
    diag_desc.s2dgb$l_reserved4 = 0;			/* Reserved */


    if (choice != BUILD_YOUR_OWN)
    {


        if (choice == 1)
        {
            cdb_len = 6; 
	    s0_buf_len = 0x24;
            for (i=0; i < cdb_len; i++)
	        cdb[i] = inquiry[i];
        }
        else if (choice == 2)
        {
            cdb_len = 6 ; 
	    s0_buf_len = 0x18;
            for (i=0; i < cdb_len; i++)
	        cdb[i] = mode_sense_6_curr[i];
        }
        else if (choice == 3)
        {
	    s0_buf_len = 0x1c;
            cdb_len = 10; 
            for (i=0; i < cdb_len; i++)
	        cdb[i] = mode_sense_10_curr[i];
        }
        else if (choice == 4)
        {
            cdb_len = 6; 
	    s0_buf_len = 0x18;
            for (i=0; i < cdb_len; i++)
	        cdb[i] = mode_sense_6_chg[i];
        }
        else if (choice == 5)
        {
            cdb_len = 10; 
	    s0_buf_len = 0x1c;
            for (i=0; i < cdb_len; i++)
	        cdb[i] = mode_sense_10_chg[i];
        }
        else if (choice == 6)
        {
	    s0_buf_len = 0x1c;
            cdb_len = 10; 
            for (i=0; i < cdb_len; i++)
	        cdb[i] = mode_sense_10_curr[i];
            diag_desc.s2dgb$l_32senseaddr = 0;
            diag_desc.s2dgb$l_32senselen = 0;
	    diag_desc.s2dgb$v_autosense = 0; 
        }
        else if (choice == 7)
        {
            cdb_len = 6; 
	    s0_buf_len = MAX_S0_BUF_SIZE;
            for (i=0; i < cdb_len; i++)
	        cdb[i] = request_sense[i];
            diag_desc.s2dgb$v_autosense =  0;		
        }
        else if (choice == 8)
        {
            cdb_len = 6; 
	    s0_buf_len = 0;
            for (i=0; i < cdb_len; i++)
	        cdb[i] = test_unit_ready[i];
        }
        else if (choice == 9)
        {
            cdb_len = 6; 
	    s0_buf_len = 512;
            for (i=0; i < cdb_len; i++)
	        cdb[i] = read_lbn100[i];
        }



    diag_desc.s2dgb$l_32cdblen =  cdb_len;		/* command length			*/
    diag_desc.s2dgb$l_32datlen =  s0_buf_len;   	/* data length 				*/
    diag_desc.s2dgb$l_32dataddr = (int)(&s0_buf[0]);    /* data addr 				*/
        

    }

    else					/* Build your own */
    {
        do
        {
            printf("\n\n");
            printf("Enter the decimal number of bytes in the CDB [6 or 10]: ");
            scanf("%hd", &cdb_len);                     
            printf("\n");
        } while ((cdb_len != 6) && (cdb_len != 10));

        diag_desc.s2dgb$l_32cdblen =  cdb_len;		/* command length			*/
        do
        {
            printf("\n");
            printf("Enter 1 for read direction, 0 for write : ");
            scanf("%hd", &read_dir);                     
            printf("\n");
        } while ((read_dir != 0) && (read_dir != 1));

        diag_desc.s2dgb$v_read = read_dir;

        do
        {
            printf("\n");
            printf("Enter 1 for tagged request, 0 for untagged : ");
            scanf("%hd", &tagreq);                     
            printf("\n");
        } while ((tagreq != 0) && (tagreq != 1));

        if (tagreq == 1)
        {
            diag_desc.s2dgb$v_tagged_req = 1;
            do
            {
                printf("\n");
                printf("Enter 0 for SIMPLE, 1 for ORDERED, or 2 for EXPRESS : ");
                scanf("%hd", &tagmode);                     
                printf("\n");
            } while ((tagmode < 0) && (tagmode > 2));

            diag_desc.s2dgb$v_tag = tagmode;
	}

        do
        {
            printf("\n");
            printf("Enter 1 for disconnects, 0 for no disconnects : ");
            scanf("%hd", &disc);                     
            printf("\n");
        } while ((disc != 0) && (disc != 1));

        diag_desc.s2dgb$v_discpriv = disc;

        do
        {
            printf("\n");
            printf("Enter 1 for asense buffer, 0 for no asense buffer : ");
            scanf("%hd", &asbuff);                     
            printf("\n");
        } while ((asbuff != 0) && (asbuff != 1));

        diag_desc.s2dgb$v_autosense = asbuff;
	if (asbuff == 0)
        {
	    diag_desc.s2dgb$l_32senseaddr = 0;
            diag_desc.s2dgb$l_32senselen = 0;
        }
        printf("\n\n");
        printf("(Enter all the following requested values in hex.)\n\n");
        printf("Enter the number of bytes in the S0 data buffer: ");
        scanf("%hx", &s0_buf_len);                     
        diag_desc.s2dgb$l_32datlen =  s0_buf_len;   	/* data length 				*/
        printf("\n");

	if (s0_buf_len > 0)
            diag_desc.s2dgb$l_32dataddr = (int)(&s0_buf[0]);    /* data addr 				*/

        printf("\n");
        printf("Enter the CDB bytes, one per line, starting with the SCSI opcode:\n");
        printf("\n");
        for (i=0; i < cdb_len; i++)
        {
            printf("Enter cdb[%d]: ",i);
            scanf("%hx", &cdb[i]);
        }
        if (read_dir == 0)
        {
            printf("\n");
            printf("Enter the S0 data buffer bytes, one per line:\n");
            printf("\n");
            for (i=0; i < s0_buf_len; i++)
            {
                printf("Enter data[%d]: ",i);
                scanf("%hx", &s0_buf[i]);
	    }
        }
    }


    /* Common code for both pre-built and build-your-own commands */

    printf("\n");
    printf("\n");
    printf("The CDB bytes are:  ");
    for (i=0; i < cdb_len ; i++)
    {
        printf("%02X  ", cdb[i]);
    }
    printf("\n");


    printf("The S2DGB structure contains:\n\n");
    printf("	opcode        %8X  IO$_DIAGNOSE\n",diag_desc.s2dgb$l_opcode );  
    printf("	flags         %8X\n",diag_desc.s2dgb$l_flags );


    printf("	   v_read            %1X",diag_desc.s2dgb$v_read );
    if (diag_desc.s2dgb$v_read == 1)
        printf("  Read from target\n"); 
    else
        printf("  Write to target\n"); 


    printf("	   v_discpriv        %1X",diag_desc.s2dgb$v_discpriv );
    if (diag_desc.s2dgb$v_tagged_req == 1)
        printf("  Being ignored since tagged_req = 1\n"); 
    else if (diag_desc.s2dgb$v_discpriv == 1) 
        printf("  Disconnects allowed\n"); 
    else
        printf("  Disconnects disallowed\n"); 


    printf("	   v_synchronous     %1X",diag_desc.s2dgb$v_synchronous );
    if (diag_desc.s2dgb$v_tagged_req == 1)
        printf("  Being ignored since tagged_req = 1\n"); 
    else if (diag_desc.s2dgb$v_synchronous == 1)
        printf("  Synchronous mode\n"); 
    else
        printf("  Asynchronous mode\n"); 


    printf("	   v_tagged_req      %1X",diag_desc.s2dgb$v_tagged_req );
    if (diag_desc.s2dgb$v_tagged_req == 1)
        printf("  Tagged request\n"); 
    else
        printf("  Untagged request\n"); 


    printf("	   v_tag             %1X",diag_desc.s2dgb$v_tag );
    if (diag_desc.s2dgb$v_tagged_req == 0) 
        printf("  Being ignored\n"); 
    else if (diag_desc.s2dgb$v_tag == 0) 
        printf("  Simple\n");
    else if (diag_desc.s2dgb$v_tag == 1) 
        printf("  Ordered\n");
    else if (diag_desc.s2dgb$v_tag == 2) 
        printf("  Express\n");
    else 
        printf("  Illegal Tag Value\n");


    printf("	   v_autosense       %1X",diag_desc.s2dgb$v_autosense );
    if (diag_desc.s2dgb$v_autosense == 1)
        printf("  User-supplied autosense buffer\n");
    else
        printf("  No user-supplied autosense buffer\n");
        

    printf("	32cdbaddr     %8X",diag_desc.s2dgb$l_32cdbaddr );
    printf("  SCSI command block address\n");
    printf("	32cdblen      %8X\n",diag_desc.s2dgb$l_32cdblen );
    printf("	32dataddr     %8X",diag_desc.s2dgb$l_32dataddr );
    printf("  DATAIN/DATAOUT buffer address\n");
    printf("	32datlen      %8X\n",diag_desc.s2dgb$l_32datlen );
    printf("	32padcnt      %8X",diag_desc.s2dgb$l_32padcnt );
    printf("  Pad count for DATAIN/DATAOUT buffer\n");
    printf("	32phstmo      %8X",diag_desc.s2dgb$l_32phstmo );
    printf("  Phase timeout in hex seconds\n");
    printf("	32dsctmo      %8X",diag_desc.s2dgb$l_32dsctmo );
    printf("  Disconnect timeout in hex seconds\n");
    printf("	32senseaddr   %8X",diag_desc.s2dgb$l_32senseaddr );
    printf("  Autosense buffer address\n");
    printf("	32senselen    %8X\n",diag_desc.s2dgb$l_32senselen );
    printf("	reserved1     %8X\n",diag_desc.s2dgb$l_reserved1 );
    printf("	reserved2     %8X\n",diag_desc.s2dgb$l_reserved2 );
    printf("	reserved3     %8X\n",diag_desc.s2dgb$l_reserved3 );
    printf("	reserved4     %8X\n",diag_desc.s2dgb$l_reserved4 );


    iosb_ptr->scsi_sts = 0xff;
    /* Issue the QIO to send the SCSI command and receive the S0 buffer data */
    status = sys$qiow(0, target_chan, IO$_DIAGNOSE, &iosb, 0, 0, 
		      &diag_desc,  S2DGB$K_XCDB32_LENGTH,  0,  0,  0,  0);

    /* Print the various returned status values */
    printf("\n");
    printf ("QIOW call status	 : %08x\n", status);
    printf ("Send_command status : %04x\n", iosb_ptr->vms_sts);
    printf ("Bcnt_lo returned    : %04x\n", iosb_ptr->bcnt_lo);
    printf ("Bcnt_hi returned    : %04x\n", iosb_ptr->bcnt_hi);
    printf ("SCSI status returned: %04x\n", iosb_ptr->scsi_sts);
    printf ("Overall IOSB        : %x\n", iosb);

    /* Was VMS Status OK from QIO? */

    if (!(status & 1))
    	sys$exit (status);

    /* Yes, was VMS Status OK from class driver call to SEND_COMMAND? */

    if ( !((iosb_ptr->vms_sts) & 1) )
    	sys$exit ((int) iosb_ptr->vms_sts);

    /* Yes, was SCSI Status OK from QIO? */

    if (iosb_ptr->scsi_sts != SCSI_GOOD_STATUS)
    {
        printf("\n");
    	printf ("Bad SCSI status returned: %02x\n", iosb_ptr->scsi_sts);
        if (diag_desc.s2dgb$v_autosense == 1)
	{
	    transfer_length = autosense_data[7] + 8;
            printf ("Sense data follows, read left to right:");
            printf ("\n");
            for (i = 0;  i < transfer_length;  )
            {
	        printf ("Byte %2d:  ", i);
	        for (j = 0; j < DISPLAY_BYTES_PER_ROW; j++)
	        {
                    if ((i+j) < transfer_length)
	                printf ("   %02X", autosense_data[i+j]);  	

	        }
                printf ("\n");
	        i += DISPLAY_BYTES_PER_ROW;
            }
	}
        printf ("\n");

	sys$exit (1);
    }

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

    if (cdb[0] == 3)		/* If request_sense, bcnt may be 0 */
        transfer_length = s0_buf[7] + 8;  /* So get len from asense data buff*/
    else
        transfer_length = ( (int)(iosb_ptr->bcnt_lo)        & 0x0000ffff) | 
		          (((int)(iosb_ptr->bcnt_hi) << 16) & 0xffff0000);
    printf("\n");
    printf("Command completed with SUCCESS.\n");
    printf("\n");
    if (transfer_length != 0)
    {
        printf ("SCSI command returned %d. bytes of data, read left to right: \n", 
	     transfer_length);
        printf("\n");
        for (i = 0;  i < transfer_length;  )
        {
	    printf ("Byte %2d:  ", i);
	    for (j = 0; j < DISPLAY_BYTES_PER_ROW; j++)
	    {
                if ((i+j) < transfer_length)
	            printf ("   %02X", s0_buf[i+j]);  	

	    }
            printf ("\n");
	    i += DISPLAY_BYTES_PER_ROW;
        }
    }
    else
        printf("No data was returned to the user buffer.\n");
    printf ("\n");
    if (cdb[0] == 0x12)
	format_inq((struct inquiry_data *) s0_buf);


    printf ("\n");
    if ((cdb[0] == 0x1a) && (cdb[2] != 0)) /* Mode_sense_6 command */
	format_mode_6(s0_buf);

    printf ("\n");
    if ((cdb[0] == 0x5a) && (cdb[2] != 0)) /* Mode_sense_10 command */
	format_mode_10(s0_buf);

}

void format_inq(struct inquiry_data *inq)
{
    int i;

    printf("\n");

    /* Byte 0 */
    printf("Peripheral device type %2X  ",inq->scsi$inq$v_device_type);
    switch (inq->scsi$inq$v_device_type)
    {
    case 0:
        printf("Direct access device\n");
        break;
    case 1:
        printf("Sequential access device\n");
        break;
    case 2:
        printf("Printer device\n");
        break;
    case 3:
        printf("Processor device\n");
        break;
    case 4:
        printf("Write-once device\n");
        break;
    case 5:
        printf("CD-ROM device\n");
        break;
    case 6:
        printf("Scanner device\n");
        break;
    case 7:
        printf("Optical memory device\n");
        break;
    case 8:
        printf("Medium changer device\n");
        break;
    case 9:
        printf("Communications device\n");
        break;
    case 10:
        printf("Graphic Arts\n");
        break;
    case 11:
        printf("Graphics Arts\n");
        break;
    default:
        printf("Unknown device\n");
        break;
    }

    printf("Peripheral qualifier   %2X  ",inq->scsi$inq$v_qualifier); 
    switch(inq->scsi$inq$v_qualifier)
    {
    case 0:
        printf("Supported and physically connected\n");
        break;
    case 1:
        printf("Supported, not physically connected\n");
        break;
    case 2:
        printf("Reserved\n");
        break;
    case 3:
        printf("Cannot support physical device\n");
        break;
    default:
        printf("Vendor specific\n");
        break;
    }
    printf("\n");

    /* Byte 1 */
    printf("Modifier (ignored)     %2X\n",inq->scsi$inq$v_modifier);
    printf("Removable medium bit   %2X\n",inq->scsi$inq$v_rmb);
    printf("\n");

    /* Byte 2 */
    printf("ANSI-approved version  %2X  ",inq->scsi$inq$v_ansi_version);
    switch (inq->scsi$inq$v_ansi_version)
    {
    case 0:
        printf("May not be ANSI-compliant\n");
        break;
    case 1:
        printf("SCSI-1\n");
        break;
    case 2:
        printf("SCSI-2\n");
        break;
    default:
        printf("Reserved\n");
        break;
    }
    printf("ECMA version           %2X\n",inq->scsi$inq$v_ecma_version);
    printf("ISO version            %2X\n",inq->scsi$inq$v_iso_version);
    printf("\n");

    /* Byte 3 */
    printf("Response data format   %2X  ",inq->scsi$inq$v_resp_data_format);
    switch (inq->scsi$inq$v_resp_data_format)
    {
    case 0:
        printf("SCSI-1 format\n");
        break;
    case 1:
        printf("Pre-standard (e.g. CCS) format\n");
        break;
    case 2:
        printf("SCSI-2 format\n");
        break;
    default:
        printf("Reserved\n");
        break;    
    }
    printf("TrmIOP                 %2X\n",inq->scsi$inq$v_trmiop);
    printf("AEN support            %2X\n",inq->scsi$inq$v_aenc);
    printf("\n");

    /* Byte 4 */
    printf("Additional length      %2X\n",inq->scsi$inq$b_add_length);     
    printf("\n");

    /* Bytes 5-6 */
    printf("Reserved byte          %2X\n",inq->scsi$inq$b_reserved2[0]);
    printf("\n");
    printf("Reserved byte          %2X\n",inq->scsi$inq$b_reserved2[1]);
    printf("\n");

    /* Byte 7 */
    printf("Soft Reset             %2X\n",inq->scsi$inq$v_sftre);
    printf("Command queuing        %2X\n",inq->scsi$inq$v_cmdque);
    printf("Linked commands        %2X\n",inq->scsi$inq$v_linked);
    printf("Synchronous            %2X\n",inq->scsi$inq$v_sync);
    printf("16-bit wide            %2X\n",inq->scsi$inq$v_wbus16);
    printf("32-bit wide            %2X\n",inq->scsi$inq$v_wbus32);
    printf("Relative addressing    %2X\n",inq->scsi$inq$v_reladr);
    printf("\n");

    /* Bytes 8-15 */
    printf("Vendor ID (8 bytes)    ");
    for (i=0; i < 8; ++i)
    {
        if (isprint(inq->scsi$inq$b_vendor_id[i]))   
            printf("%c",inq->scsi$inq$b_vendor_id[i]);
        else
            printf(".");
    }
    printf("\n");

    /* Bytes 16-31 */
    printf("Product ID (16 bytes)  ");
    for (i=0; i < 16; ++i)
    {
        if (isprint(inq->scsi$inq$b_product_id[i]))   
            printf("%c",inq->scsi$inq$b_product_id[i]);
        else
            printf(".");
    }
    printf("\n");

    /* Bytes 32-35 */
    printf("Rev level (4 bytes)    ");
    for (i=0; i < 4; ++i)
    {
        if (isprint(inq->scsi$inq$b_product_revision[i]))   
            printf("%c",inq->scsi$inq$b_product_revision[i]);
        else
            printf(".");
    }
    printf("\n");
      
}   
void format_mode_6 (unsigned char *data)
{
    int temp = 0;

    struct error_recovery *err_rec_ptr;
    temp =  4 + data[3];		/* Header size + blk desc size */ 
    err_rec_ptr = (struct error_recovery *) &data[temp];    

    if (err_rec_ptr->scsi$erp$v_page_code == 1)	/* If page code = err rec page */
    {
        printf("Error recovery page was read.  Recovery bits:\n\n");
        printf("   AWRE  ARRE    TB    RC   EER   PER   DTE   DCR\n");   
        printf("%6x",err_rec_ptr->scsi$erp$v_awre); 
        printf("%6x",err_rec_ptr->scsi$erp$v_arre); 
        printf("%6x",err_rec_ptr->scsi$erp$v_tb); 
        printf("%6x",err_rec_ptr->scsi$erp$v_rc); 
        printf("%6x",err_rec_ptr->scsi$erp$v_eer); 
        printf("%6x",err_rec_ptr->scsi$erp$v_per); 
        printf("%6x",err_rec_ptr->scsi$erp$v_dte); 
        printf("%6x",err_rec_ptr->scsi$erp$v_dcr); 
        printf("\n\n");
    }
    
}

void format_mode_10 (unsigned char *data)
{
    int temp = 0;

    struct error_recovery *err_rec_ptr;
    temp =  8 + data[7];		/* Header size + blk desc size */ 
    err_rec_ptr = (struct error_recovery *) &data[temp];    

    if (err_rec_ptr->scsi$erp$v_page_code == 1)	/* If page code = err rec page */
    {
        printf("Error recovery page was read.  Recovery bits:\n\n");
        printf("   AWRE  ARRE    TB    RC   EER   PER   DTE   DCR\n");   
        printf("%6x",err_rec_ptr->scsi$erp$v_awre); 
        printf("%6x",err_rec_ptr->scsi$erp$v_arre); 
        printf("%6x",err_rec_ptr->scsi$erp$v_tb); 
        printf("%6x",err_rec_ptr->scsi$erp$v_rc); 
        printf("%6x",err_rec_ptr->scsi$erp$v_eer); 
        printf("%6x",err_rec_ptr->scsi$erp$v_per); 
        printf("%6x",err_rec_ptr->scsi$erp$v_dte); 
        printf("%6x",err_rec_ptr->scsi$erp$v_dcr); 
        printf("\n\n");
    }
}
