home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 28 / amigaformatcd28.iso / -in_the_mag- / under_the_bonnet / scsi / scsidevs / scsidevs.c < prev    next >
C/C++ Source or Header  |  1998-05-02  |  19KB  |  1,022 lines

  1.  
  2. #define VERSION "1.2"
  3.  
  4. /*
  5.  *****       SCSIdevs  
  6.  *
  7.  *      Scans the SCSI bus looking for devices and reports on those found.
  8.  *      If the device has a RDB, bits of it are printed out.
  9.  *
  10.  *      Usage:
  11.  *
  12.  *      SCSIdevs   [-d<scsi-device-name>]
  13.  *
  14.  *      
  15.  *      options;
  16.  *
  17.  *       -d<scsi_device_name> ; (default = *scsi*.device)
  18.  *
  19.  *
  20.  *****  Written by Gary Duncan
  21.  *
  22.  *      Bug reports etc via e-mail to gduncan@werple.net.au)
  23.  *
  24.  *****  Mod record
  25.  *
  26.  *      Version Date            Changes
  27.  *      ~~~~~~~ ~~~~            ~~~~~~~
  28.  *
  29.  *      1.0     01Nov95         Original        
  30.  *      1.1     01Dec95         Better parsing for *scsi*.device        
  31.  *    1.2    09Dec95        Match Open/CloseDevice calls
  32.  *
  33.  *
  34.  *****  Freely distributable for non-commercial purposes
  35.  *
  36.  *      Compiles under SAS/C 6.x 
  37.  *
  38.  * 
  39.  *
  40.  *****  Function List :-
  41.  */
  42.  
  43. /***
  44.  
  45.     main ()
  46.     init ()
  47.     read_sec_scsi ()
  48.     GetDevName ()
  49.     err_str ()
  50.     sense_errs ()
  51.     check_scsi_devices ()
  52.     print_rdsk_info ()
  53.     print_Part_info ()
  54.     print_env_buf ()
  55.     b2Cstr ()
  56.     mkCstr ()
  57.     checksum ()
  58.     hexit ()
  59.     usage ()
  60.  
  61. ***/
  62. #include <stdlib.h>
  63. #include <stdio.h>
  64. #include <dos.h>
  65. #include <dos/filehandler.h>
  66. #include <string.h>
  67. #include <ctype.h>
  68. #include <exec/types.h>
  69. #include <exec/io.h>
  70. #include <exec/execbase.h>
  71. #include <exec/nodes.h>
  72. #include <exec/memory.h>
  73. #include <devices/trackdisk.h>
  74. #include <libraries/dosextens.h>
  75. #include <devices/scsidisk.h>
  76. #include <devices/hardblocks.h>
  77. #include <libraries/dos.h>
  78. #include <proto/dos.h>
  79. #include <proto/exec.h>
  80.  
  81. #include "typedefs.h"
  82. #include "scsi_priv.h"
  83.  
  84. typedef struct SCSICmd SCSICMD;
  85.  
  86. typedef enum
  87.   {
  88.     GOOD, NO_DEV, NO_RDB, SCSI_ERR
  89.   }
  90. RET_VAL;
  91.  
  92. char inq_buf[8 * MAX_DATA_LEN];
  93.  
  94.  
  95. #define SEC_LEN_512     512
  96.  
  97. #include "Proto/SCSIDevs_protos.h"
  98.  
  99. static IDTOSTRING devicetype[] =
  100. {
  101.   0x00, "Disk     ",
  102.   0x01, "Tape     ",
  103.   0x02, "Printer  ",
  104.   0x03, "Processor",
  105.   0x04, "Worm     ",
  106.   0x05, "CDROM    ",
  107.   0x06, "Scanner  ",
  108.   0x07, "Opt-dev  ",
  109.   0x08, "Jukebox  ",
  110.   0x09, "Comm-dev ",
  111.   -1, "????"
  112. };
  113.  
  114. /*
  115.  * we open ( if no -d option) the first *scsi*.device in the device list.
  116.  */
  117. #define SCSI_STRING "*scsi"
  118.  
  119.  
  120. static char A_vers[] = "\0$VER: SCSIdevs\t" VERSION __AMIGADATE__;
  121.  
  122.  
  123. UBYTE *ip_buf = NULL;
  124. UBYTE *scsi_data = NULL;
  125. UBYTE *scsi_sense = NULL;
  126. UBYTE *dev_name = NULL;
  127. MSGPORT *mp_ptr = NULL;
  128. IOSTDREQ *io_ptr = NULL;
  129. SCSICMD scsi_cmd;
  130. int scsi_id = -1;
  131. int on_off = -1;
  132. UBYTE buffer[LINE_BUF];
  133. int secno = -1;
  134. int open_cnt = 0;
  135.  
  136. #define NNN 4            /* KLUGE TO ALLOW CDROM READS (2048 bytes) */
  137.  
  138. BOOL scsi_devs[8];
  139.  
  140. int scsi_devs_type[8];
  141.  
  142.  
  143. char x_buf[RDB_LOCATION_LIMIT * SEC_LEN_512];
  144.  
  145. char buf_rdsk[SEC_LEN_512 * NNN];
  146.  
  147. char buf_part[SEC_LEN_512 * NNN];
  148.  
  149. ULONG next_part_block = -1;
  150.  
  151. RIGIDDISKBLOCK *p_rdb;
  152.  
  153. char p_buf[256];
  154.  
  155. int part_no;
  156. BOOL raw_flag = FALSE;
  157.  
  158. char hdr_rdb[200] = "\
  159. ID  UNIT         SIZE    FS      PARTITION     PRI   BUFFS\n\
  160. ~~  ~~~~         ~~~~    ~~      ~~~~~~~~~     ~~~   ~~~~~\n";
  161.  
  162. /*
  163.  * partition format string
  164.  */
  165.  
  166. char fmt_rdb[100] = "%d   %-10s  %4dM   %3s   %-12s    %4d     %3d\n";
  167.  
  168.  
  169. char hdr_dev[200] = "\
  170. ID  DEVICE      REM   VENDOR      PRODUCT-STRING      REV\n\
  171. ~~  ~~~~~~      ~~~   ~~~~~~      ~~~~~~~~~~~~~~      ~~~\n\
  172. ";
  173.  
  174. char fmt_dev[100] = "%d  %10s     %s   %.8s    %.16s    %.4s\n";
  175.  
  176.  
  177.  
  178.  
  179. /*********************************************************************
  180.  *
  181.  *    main
  182.  *
  183.  *
  184.  ***/
  185.  
  186. void
  187. main (int argc, char **argv)
  188.  
  189. {
  190.  
  191.   if (argc > 1)
  192.     {
  193.       if (strncmp (argv[1], "-d", 2) == 0)
  194.     {
  195.       dev_name = argv[1] + 2;
  196.       if (GetDevName (dev_name) == NULL)
  197.         {
  198.           printf ("Error : Cannot find \"%s\" in device list\n", dev_name);
  199.           exit (1);
  200.         }
  201.     }
  202.       else if (strncmp (argv[1], "-h", 2) == 0)
  203.     {
  204.       usage ("");
  205.       exit (0);
  206.     }
  207.       else
  208.     {
  209.       usage ("Error: Invalid option\n");
  210.       exit (0);
  211.     }
  212.     }
  213.  
  214.   /*
  215.    * find a SCSI device, if no -d option
  216.    */
  217.   if (dev_name == NULL)
  218.     {
  219.       if ((dev_name = GetDevName (SCSI_STRING)) == NULL)
  220.     {
  221.       usage ("Error : no *scsi*.device in device list\n");
  222.       hexit (1);
  223.     }
  224.     }
  225.  
  226.   /*
  227.    *  now set up structures etc for SCSI xfer
  228.    */
  229.   if (init () == FALSE)
  230.     hexit (1);
  231.  
  232.   /*
  233.    * scan SCSI bus, marking existence of devices in scsi_devs[] 
  234.    */
  235.  
  236.   if (check_scsi_devices () == 0)
  237.     {
  238.       printf ("No SCSI devices found\n");
  239.       hexit (1);
  240.     }
  241.  
  242.   printf ("\n%s", hdr_dev);
  243.  
  244.   for (scsi_id = 0; scsi_id < 7; ++scsi_id)
  245.     {
  246.       if (scsi_devs[scsi_id] == TRUE)
  247.     {
  248.       char *qni = &inq_buf[scsi_id * MAX_DATA_LEN];
  249.       int dev_type = qni[0] & 0x1F;
  250.  
  251.       char *dev = id2string (dev_type, devicetype);
  252.       char *m_rem = (qni[1] & 0x80) ? "Y" : "N";
  253.       char *vendor = &qni[8];
  254.       char *product = &qni[16];
  255.       char *rev = &qni[32];
  256.  
  257.       printf (fmt_dev,
  258.           scsi_id, dev, m_rem, vendor, product, rev);
  259.  
  260.       scsi_devs_type[scsi_id] = dev_type;
  261.     }
  262.       else
  263.     {
  264.       scsi_devs_type[scsi_id] = -1;
  265.     }
  266.     }
  267.  
  268.   /*
  269.    * print header, then examine SCSI DISK devices for an RDB
  270.    */
  271.   printf ("\n\n%s", hdr_rdb);
  272.  
  273.   for (scsi_id = 0; scsi_id < 7; ++scsi_id)
  274.     {
  275.  
  276. //      printf ("++++looking for SCSI ID %d\n", scsi_id);
  277.  
  278.       if ((scsi_devs[scsi_id] == TRUE) && (scsi_devs_type[scsi_id] == 0x00))
  279.     {
  280. //        printf ("++++Found SCSI ID %d, and a Disk\n", scsi_id);
  281.  
  282.       if (get_scsi_info (scsi_id) == SCSI_ERR)
  283.         {
  284.           printf ("\n%d   ***SCSI READ ERROR***\n\n", scsi_id);
  285.         }
  286.       else
  287.         {
  288.  
  289. //            printf ("++++Found SCSI ID %d, and a Disk - with no SCSI_ERR\n", scsi_id);
  290.         }
  291.     }
  292.     }
  293. //  printf ("++++Finished SCSI Id loop\n");
  294.  
  295.   hexit (0);
  296.  
  297. }
  298. /*********************************************************************
  299.  *
  300.  *    check for a SCSI device
  301.  *
  302.  */
  303. int
  304. check_scsi_devices ()
  305. {
  306.   int j;
  307.   int count;
  308.  
  309.   for (j = 0, count = 0; j < 7; ++j)
  310.     {
  311.       if (OpenDevice (dev_name, j, (IOREQUEST *) io_ptr, 0) == 0)
  312.     {
  313.       ++open_cnt;
  314.       /*
  315.        * collect inquiry info
  316.        */
  317.  
  318.       inquiry (&inq_buf[j * MAX_DATA_LEN]);
  319.  
  320.       scsi_devs[j] = TRUE;
  321.       ++count;
  322.       CloseDevice ((IOREQUEST *) io_ptr);
  323.       --open_cnt;
  324.  
  325. //        printf ("Found device at ID = %d\n", j);
  326.     }
  327.       else
  328.     {
  329.       scsi_devs[j] = FALSE;
  330.     }
  331.     }
  332.   return count;
  333.  
  334. }
  335.  
  336. /*********************************************************************
  337.  *
  338.  *    Get data from RDB on disk
  339.  *
  340.  *
  341.  */
  342.  
  343. RET_VAL
  344. get_scsi_info (int id)
  345. {
  346.   int j;
  347.   BOOL retval = GOOD;
  348.  
  349.  
  350.   if (OpenDevice (dev_name, id, (IOREQUEST *) io_ptr, 0) != 0)
  351.     {
  352.       return NO_DEV;
  353.     }
  354.  
  355.   ++open_cnt;
  356.  
  357.  
  358.   /*
  359.    *********** find RDSK block 
  360.    */
  361.   for (j = 0;;)
  362.     {
  363.       if (read_sec_scsi (buf_rdsk, j, 1) == FALSE)
  364.     {
  365.       retval = SCSI_ERR;
  366.       goto error;
  367.     }
  368.  
  369.       if (strncmp (buf_rdsk, "RDSK", 4) == 0)
  370.     {
  371.       RIGIDDISKBLOCK *p = (RIGIDDISKBLOCK *) buf_rdsk;
  372.  
  373.       /*
  374.        * check checksum
  375.        */
  376.  
  377.       if (checksum ((LONG *) p, p->rdb_SummedLongs) == FALSE)
  378.         {
  379.           printf ("\n********** RDSK block checksum error!\n");
  380.           retval = SCSI_ERR;
  381.           goto error;
  382.         }
  383.       next_part_block = p->rdb_PartitionList;
  384.       break;
  385.     }
  386.  
  387.       if (++j == RDB_LOCATION_LIMIT)
  388.     {
  389.       retval = NO_RDB;
  390.       goto error;
  391.     }
  392.     }
  393.  
  394.   /*
  395.    *********** loop through Partition Blocks 
  396.    */
  397.  
  398.   for (part_no = 0;;)
  399.     {
  400.  
  401.       PARTITIONBLOCK *p = (PARTITIONBLOCK *) buf_part;
  402.  
  403.       if (read_sec_scsi (buf_part, next_part_block, 1) == FALSE)
  404.     {
  405.       retval = SCSI_ERR;
  406.       goto error;
  407.     }
  408.  
  409.       if (strncmp (buf_part, "PART", 4) != 0)
  410.     {
  411.       printf ("No PART string in header\n");
  412.       retval = SCSI_ERR;
  413.       goto error;
  414.  
  415.     }
  416.       /*
  417.        * check checksum
  418.        */
  419.  
  420.       if (checksum ((LONG *) p, p->pb_SummedLongs) == FALSE)
  421.     {
  422.       printf ("\n********** PART block checksum error!\n");
  423.       retval = SCSI_ERR;
  424.       goto error;
  425.     }
  426.       /*
  427.        * now print out interesting info
  428.        */
  429.  
  430.       print_Part_info (p);
  431.  
  432.       next_part_block = p->pb_Next;
  433.       if (next_part_block == 0xFFFFFFFF)
  434.     {
  435.       break;
  436.     }
  437.     }
  438. error:
  439.   CloseDevice ((IOREQUEST *) io_ptr);
  440.   --open_cnt;
  441.  
  442.   return retval;
  443. }
  444. /*********************************************************************
  445.  *
  446.  *
  447.  *
  448.  */
  449.  
  450. void
  451. print_Part_info (PARTITIONBLOCK * ptr)
  452. {
  453.   DOSENVEC *pe = (DOSENVEC *) & ptr->pb_Environment;
  454.  
  455.  
  456.   ULONG f = ptr->pb_Flags;
  457.   ULONG size;
  458.   ULONG bpcyl;
  459.   char *dostype;
  460.   char *boot;
  461.  
  462.  
  463.   bpcyl = pe->de_Surfaces * pe->de_BlocksPerTrack;
  464.  
  465.   /*
  466.    * append partition name in BSTR form
  467.    */
  468.  
  469.   if (f & PBFF_BOOTABLE)
  470.     boot = "        Boot";
  471.   else if (f & PBFF_NOMOUNT)
  472.     boot = "NonAutoMount";
  473.   else
  474.     boot = "   AutoMount";
  475.  
  476.   /*
  477.    * get bits of env structure
  478.    */
  479.  
  480.   size = ((pe->de_HighCyl - pe->de_LowCyl) * bpcyl) / (2 * 1024);
  481.  
  482.   if (pe->de_DosType == 0X444F5300)
  483.     dostype = "OFS";
  484.   else if (pe->de_DosType == 0X444F5301)
  485.     dostype = "FFS";
  486.   else
  487.     dostype = "???";
  488.  
  489.  
  490.   printf (fmt_rdb,
  491.       scsi_id,
  492.       b2Cstr (&ptr->pb_DriveName[0]),
  493.       size,
  494.       dostype,
  495.       boot,
  496.       pe->de_BootPri,
  497.       pe->de_NumBuffers
  498.     );
  499.  
  500.  
  501. }
  502.  
  503. /*********************************************************************
  504.  *
  505.  *    Initialisation function
  506.  *
  507.  *
  508.  */
  509. BOOLEAN
  510. init ()
  511. {
  512.   if ((scsi_data = (UBYTE *) AllocMem (MAX_DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
  513.     {
  514.       fprintf (stderr, "AllocMem(0) Fail\n");
  515.       return FALSE;
  516.     }
  517.  
  518.   if ((scsi_sense = (UBYTE *) AllocMem (SENSE_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
  519.     {
  520.       fprintf (stderr, "AllocMem(1) Fail\n");
  521.       return FALSE;
  522.     }
  523.  
  524.   if ((ip_buf = (UBYTE *) AllocMem (TD_SECTOR, MEMF_CHIP)) == NULL)
  525.     {
  526.       fprintf (stderr, "AllocMem(2) Fail\n");
  527.       return FALSE;
  528.     }
  529.  
  530.   if ((mp_ptr = (MSGPORT *) CreatePort (NULL, 0)) == NULL)
  531.     {
  532.       fprintf (stderr, "CreatePort Fail\n");
  533.       return FALSE;
  534.     }
  535.  
  536.   if ((io_ptr = (IOSTDREQ *) CreateStdIO (mp_ptr)) == NULL)
  537.     {
  538.       fprintf (stderr, "CreateStdIO Fail\n");
  539.       return FALSE;
  540.     }
  541.  
  542.  
  543.   return TRUE;
  544. }
  545.  
  546. /*********************************************************************
  547.  *
  548.  *    function to read sectors from a starting sector #
  549.  *
  550.  *    - uses scsi device directly
  551.  */
  552.  
  553. BOOL
  554. read_sec_scsi (char *ip_buf, int sec_start, int n_secs)
  555.  
  556. {
  557.   static struct CMD_XREAD
  558.   {
  559.     UBYTE cmd;
  560.     UBYTE lba[3];
  561.     UBYTE numb_secs;
  562.     UBYTE pad;
  563.   }
  564.   command =
  565.   {
  566.     SCSI_CMD_RD,
  567.       0, 0, 0,
  568.       0,
  569.       PAD
  570.   };
  571.  
  572.   int err;
  573.  
  574.  
  575.   io_ptr->io_Command = HD_SCSICMD;
  576.   io_ptr->io_Length = sizeof (SCSICMD);
  577.   io_ptr->io_Data = (APTR) & scsi_cmd;
  578.  
  579.   scsi_cmd.scsi_Command = (UBYTE *) & command;
  580.   scsi_cmd.scsi_CmdLength = sizeof (command);
  581.   scsi_cmd.scsi_Flags = SCSIF_READ | SCSIF_AUTOSENSE;
  582.   scsi_cmd.scsi_Data = (APTR) ip_buf;
  583.   scsi_cmd.scsi_Length = n_secs * SEC_LEN_512 * NNN;
  584.   scsi_cmd.scsi_SenseData = scsi_sense;
  585.   scsi_cmd.scsi_SenseLength = SENSE_LEN;
  586.  
  587.   command.lba[2] = sec_start;
  588.   command.lba[1] = sec_start >> 8;
  589.   command.lba[0] = (sec_start >> 8) & 0x1F;
  590.  
  591.   command.numb_secs = n_secs;
  592.  
  593.   io_ptr->io_Offset = secno * TD_SECTOR;    /* sector offset */
  594.  
  595.   DoIO ((IOREQUEST *) io_ptr);
  596.   if ((err = io_ptr->io_Error) != 0)
  597.     {
  598.       /* DoIO error */
  599. #if 0
  600.       fprintf (stderr, "Error :  sec = %ld dec , %lXH , [%s]\n",
  601.            secno, secno, sense_errs (err));
  602. #endif
  603.  
  604.       return (FALSE);
  605.     }
  606.   return (TRUE);
  607.  
  608. }
  609.  
  610. /*********************************************************************
  611.  *
  612.  * searches DeviceList for a device name with a given string in it.
  613.  * - if found returns with a pointer to it, else NULL
  614.  */
  615.  
  616. extern struct ExecBase *SysBase;
  617.  
  618. UBYTE *
  619. GetDevName (char *grep)
  620.  
  621. {
  622.   LIST *lh = (LIST *) SysBase->DeviceList.lh_Head;
  623.   NODE *ln;
  624.  
  625.   BOOL flag;
  626.   char *p1;
  627.  
  628.   if (*(p1 = grep) == '\0')
  629.     {
  630.       return NULL;
  631.     }
  632.   else if (*p1 == '*')        /* look for "*scsi" */
  633.     {
  634.       ++p1;
  635.       flag = TRUE;
  636.     }
  637.   else
  638.     {
  639.       flag = FALSE;
  640.     }
  641.  
  642.   for (ln = lh->lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
  643.     {
  644.       UBYTE *p = ln->ln_Name;
  645.  
  646.       /* 
  647.        * if first chara is a * (flag = TRUE) , search for pattern,
  648.        * else exact match
  649.        */
  650.  
  651.       if (flag == FALSE)
  652.     {
  653.       if (strcmp (p, p1) == 0)
  654.         {
  655.           return (ln->ln_Name);
  656.         }
  657.     }
  658.       else
  659.     /* look for "*scsi" */
  660.     {
  661.       while (*p && (*p != '.'))
  662.         {
  663.  
  664.           if (strncmp (p, p1, strlen (p1)) == 0)
  665.         {
  666.           return (ln->ln_Name);
  667.         }
  668.           ++p;
  669.         }
  670.     }
  671.     }
  672.  
  673.   return (NULL);        /* not found */
  674. }
  675.  
  676. /*********************************************************************
  677.  *
  678.  *    function to return an error string
  679.  *
  680.  *
  681.  */
  682.  
  683. UBYTE *
  684. err_str (int err)
  685.  
  686. {
  687.  
  688.   static UBYTE *errors[] =
  689.   {
  690.     " cannot issue SCSI command to self ",
  691.     " DMA error ",
  692.     " illegal or unexpected SCSI phase ",
  693.     " SCSI parity error ",
  694.     " Select timed out ",
  695.     " status and/or sense error "
  696.   };
  697.  
  698.   err -= 40;
  699.  
  700.   if ((err < 0) || (err > 5))
  701.     return ("Error out-of-range");
  702.   else
  703.     return (errors[err]);
  704. }
  705.  
  706. /*********************************************************************
  707.  *
  708.  *    sense_errs function ; prints sense errors
  709.  *
  710.  *
  711.  */
  712.  
  713. UBYTE *
  714. sense_errs (int err)
  715.  
  716. {
  717.   static char buf[80];
  718.  
  719.   typedef struct
  720.     {
  721.       BYTE code;
  722.       BYTE sense;
  723.       UBYTE *ptr;
  724.     }
  725.   S_ERRS;
  726.  
  727. /*
  728.  *    only the likely, interesting ones filled in, e.g media errors
  729.  */
  730.   static S_ERRS x[] =
  731.   {
  732.     0x00, 0x00, "No error",
  733.     0x01, 0x04, "?",
  734.     0x02, 0x04, "?",
  735.     0x03, 0x04, "?",
  736.     0x04, 0x02, "?",
  737.     0x06, 0x04, "?",
  738.     0x09, 0x04, "?",
  739.     0x10, 0x03, "?",
  740.     0x10, 0x04, "?",
  741.     0x11, 0x03, "?",
  742.     0x12, 0x03, "?",
  743.     0x13, 0x03, "?",
  744.     0x14, 0x03, "?",
  745.     0x15, 0x04, "Seek error ",
  746.     0x17, 0x01, "?",
  747.     0x18, 0x01, "?",
  748.     0x19, 0x03, "?",
  749.     0x1A, 0x05, "?",
  750.     0x20, 0x05, "Invalid command op code",
  751.     0x21, 0x05, "Illegal sector address",
  752.     0x24, 0x05, "?",
  753.     0x25, 0x05, "Invalid LUN",
  754.     0x26, 0x05, "Invalid field in parameter list",
  755.     0x29, 0x06, "?",
  756.     0x2A, 0x06, "?",
  757.     0x31, 0x03, "?",
  758.     0x32, 0x01, "?",
  759.     0x32, 0x03, "?",
  760.     0x40, 0x04, "?",
  761.     0x41, 0x04, "?",
  762.     0x42, 0x04, "Power-on diagnostic failure",
  763.     0x43, 0x04, "?",
  764.     0x45, 0x04, "Select / reselect failure ",
  765.     0x47, 0x04, "SCSI Interface Parity Error",
  766.     0x48, 0x0B, "?",
  767.     0x49, 0x0B, "Illegal message drive can't support",
  768.     -1, -1, "ILLEGAL sense!!"
  769.   };
  770.  
  771.   int j = 0;
  772.   UBYTE *p;
  773.   char sense;
  774.   char code;
  775.  
  776.   /*
  777.    *  verify that sense data looks valid
  778.    */
  779.   if (((scsi_cmd.scsi_Status & 2) == 0) ||
  780.       (scsi_cmd.scsi_SenseActual < OFFS_KEY))
  781.     {
  782.       return ("");
  783.     }
  784.   sense = scsi_cmd.scsi_SenseData[OFFS_KEY] & 0xF;
  785.   code = scsi_cmd.scsi_SenseData[OFFS_CODE];
  786.  
  787.   do
  788.     {
  789.       p = x[j].ptr;
  790.       if ((x[j].code == code) && (x[j].sense == sense))
  791.     {
  792.       return (p);
  793.     }
  794.     }
  795.   while (x[j++].code != -1);
  796.  
  797.   sprintf (buf, "Sense error ; code = %XH, sense = %XH\n", code, sense);
  798.  
  799.   return (buf);
  800. }
  801.  
  802. /*********************************************************************
  803.  *
  804.  *
  805.  *
  806.  */
  807. BOOL
  808. checksum (LONG * p, int n_longs)
  809. {
  810.   int j;
  811.   LONG csum;
  812.   BOOL retval;
  813.  
  814.   for (j = 0, csum = 0; j < n_longs; ++j)
  815.     {
  816.       csum += p[j];
  817.     }
  818.  
  819.   retval = (csum == 0) ? TRUE : FALSE;
  820.  
  821.   return retval;
  822. }
  823.  
  824. /*********************************************************************
  825.  *
  826.  *
  827.  *
  828.  */
  829. void
  830. hexit (int j)
  831. {
  832. //  printf ("hexit: \n");
  833.  
  834.  
  835. //      printf ("hexit: DeleteStdIO\n");
  836.   DeleteStdIO (io_ptr);
  837.  
  838.   if (mp_ptr)
  839.     {
  840. //      printf ("hexit: Deleteport, mp_ptr = %lx  \n", mp_ptr);
  841.       DeletePort (mp_ptr);
  842.     }
  843.  
  844.   if (ip_buf)
  845.     {
  846. //      printf ("hexit: ip_buf = %lx \n", ip_buf);
  847.       FreeMem (ip_buf, TD_SECTOR);
  848.     }
  849.  
  850.   if (scsi_data)
  851.     {
  852. //      printf ("hexit: scsi_data = %lx \n", scsi_data);
  853.       FreeMem (scsi_data, MAX_DATA_LEN);
  854.     }
  855.  
  856.   if (scsi_sense)
  857.     {
  858. //      printf ("hexit: scsi_sense = %lx\n", scsi_sense);
  859.       FreeMem (scsi_sense, SENSE_LEN);
  860.     }
  861. //printf("open_cnt = %ld\n", open_cnt);
  862.  
  863.   exit (j);
  864. }
  865.  
  866. /*********************************************************************
  867.  *
  868.  *    usage function
  869.  *
  870.  *
  871.  */
  872.  
  873. void
  874. usage (char *p)
  875. {
  876.   static char *zz[] =
  877.   {
  878.     "Options:\n",
  879.     "-d ; specify SCSI device driver, e.g.  -dgvpscsi.device\n",
  880.     "                 (default \"*scsi*.device\")\n",
  881.     "-h ; help (this message)\n",
  882.     "\n",
  883.     "Scans SCSI bus and reports on SCSI devices found. If the device is\n",
  884.     "a disk, a search is made for a Rigid Disk Block, and if found,\n",
  885.     "some elements of the RDB are printed.\n",
  886.  
  887.     ""                /* TERM */
  888.   };
  889.  
  890.   int j = 0;
  891.  
  892.   printf ("%s\n", p);
  893.  
  894.   printf ("SCSIdevs  Vers: %s %s - written by gduncan@werple.net.au\n",
  895.       VERSION, __AMIGADATE__);
  896.  
  897.   printf ("\nUsage : SCSIdevs [-d<scsi-device-name>]  [-h]\n");
  898.  
  899.   while (*zz[j++])
  900.     printf ("%s", zz[j - 1]);
  901.  
  902.   printf ("\n");
  903.  
  904. }
  905. /*********************************************************************
  906.  *
  907.  * 
  908.  *
  909.  */
  910. char *
  911. b2Cstr (char *ptr)
  912. {
  913.   int len = *ptr++;
  914.  
  915.   return (mkCstr (ptr, len));
  916. }
  917.  
  918. /*********************************************************************
  919.  *
  920.  * 
  921.  *
  922.  */
  923. char *
  924. mkCstr (char *ptr, int len)
  925. {
  926.   static char buf[128];
  927.  
  928.   strncpy (buf, ptr, len);
  929.  
  930.   if (buf[len - 1] != '\0')
  931.     buf[len] = '\0';
  932.  
  933.   return buf;
  934. }
  935.  
  936. /*********************************************************************
  937.  *
  938.  *      function to make an inquiry
  939.  *
  940.  */
  941.  
  942. void
  943. inquiry (char *ptr)
  944. {
  945.   static SCSICMD6 command =
  946.   {
  947.     SCSI_CMD_INQ,        /* 0x12 INQUIRY */
  948.     PAD,
  949.     PAD,            /* Page Code */
  950.     PAD,            /* Reserved */
  951.     0,                /* Allocation length */
  952.     PAD                /* Control */
  953.   };
  954.  
  955.   static int err;
  956.  
  957.   command.b4 = MAX_DATA_LEN;    /* Allocation length = max. data length */
  958.  
  959.   if ((err = DoScsiCmd ((UBYTE *) ptr, MAX_DATA_LEN,
  960.             (UBYTE *) & command, sizeof (command),
  961.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  962.     {
  963.       fprintf (stderr, "inquiry() Error : err=%ld , %s\n", err, sense_errs (err));
  964.     }
  965. }
  966. /*********************************************************************
  967.  *
  968.  *
  969.  */
  970.  
  971. char *
  972. id2string (int val, IDTOSTRING * m_ptr)
  973. {
  974.   int j;
  975.  
  976.   for (j = 0;; ++j)
  977.     {
  978.       if (m_ptr->code == val || m_ptr->code == -1)
  979.     return (char *) m_ptr->ptr;
  980.  
  981.       ++m_ptr;
  982.     }
  983. }
  984.  
  985.  
  986. /*********************************************************************
  987.  *
  988.  *      function to use a scsi command
  989.  *
  990.  */
  991. int
  992. DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
  993. {
  994.   int i;
  995.  
  996.   io_ptr->io_Length = sizeof (SCSICMD);
  997.   io_ptr->io_Data = (APTR) & scsi_cmd;
  998.   io_ptr->io_Command = HD_SCSICMD;
  999.  
  1000.   scsi_cmd.scsi_Data = (APTR) data;
  1001.   scsi_cmd.scsi_Length = datasize;
  1002.   scsi_cmd.scsi_SenseActual = 0;
  1003.   scsi_cmd.scsi_SenseData = scsi_sense;
  1004.   scsi_cmd.scsi_SenseLength = SENSE_LEN;
  1005.   scsi_cmd.scsi_Command = cmd;
  1006.   scsi_cmd.scsi_CmdLength = cmdsize;
  1007.   scsi_cmd.scsi_Flags = flags;
  1008.  
  1009.   (void) DoIO ((struct IORequest *) io_ptr);
  1010.  
  1011.   if (scsi_cmd.scsi_SenseActual)
  1012.     {
  1013.       fprintf (stderr, "SENSE_DATA:");
  1014.       for (i = 0; i < scsi_cmd.scsi_SenseActual; i++)
  1015.     {
  1016.       fprintf (stderr, " %02x", scsi_cmd.scsi_SenseData[i]);
  1017.     }
  1018.       fprintf (stderr, "\n");
  1019.     }
  1020.   return (io_ptr->io_Error);
  1021. }
  1022.