home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / cdrom / scsidevs / scsidevs.c < prev    next >
C/C++ Source or Header  |  1981-07-07  |  17KB  |  979 lines

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