home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 648c.lha / SCSIutil / SCSIutil.c < prev    next >
C/C++ Source or Header  |  1992-05-21  |  22KB  |  1,118 lines

  1. /*
  2.  *****    SCSIutil
  3.  *
  4.  *    A utility to do some low-level operations to a SCSI disk, e.g.
  5.  *
  6.  *        - start/stop motor
  7.  *        - read sectors
  8.  *        - read disk capacity info
  9.  *        - get inquiry info (manufacturers name etc)
  10.  *        - seek to a sector's cylinder (use to park heads)
  11.  *
  12.  *    NOTE:  this program is based on SCSI information taken from
  13.  *           the accompanying documentation of a NEC D3841 SCSI disk.
  14.  *           I don't know the extent to which SCSI standards are
  15.  *           supported by that disk.
  16.  *
  17.  *           These commands work on the above disk. But a seek to
  18.  *           sector -1 (park on the NEC disk) fails on my Quantum 105.D
  19.  *
  20.  *****    Written by Gary Duncan
  21.  *
  22.  *    Bug reports etc via e-mail to gduncan@philips.oz.au) , or mail to
  23.  *
  24.  *    Gary Duncan
  25.  *    Philips PTS
  26.  *      23 Lakeside Dr
  27.  *    Tally-Ho Technology Park
  28.  *    Burwood East Vic 3151
  29.  *    Australia
  30.  *
  31.  *
  32.  *****    Freely distributable for non-commercial purposes
  33.  *
  34.  *    Complies under Lattice 5.10
  35.  *    - needs AmigaDosA 2.0  #includes
  36.  *
  37.  ***** Thanks to Markus Illenseer for some beta-testing.
  38.  *
  39.  *****    Function List :-
  40.  *
  41.  *    motor ()
  42.  *    read_sec ()
  43.  *    init ()
  44.  *    seek ()
  45.  *    inquiry()
  46.  *    read_capacity()
  47.  *    gcomp()
  48.  *    GetDevName()
  49.  *    breakcheck()
  50.  *    chkabort()
  51.  *    err_str()
  52.  *    usage()
  53.  *    sense_errs()
  54.  *
  55.  */
  56.  
  57. #define VERSION "1.1"
  58.  
  59. #include <stdio.h>
  60. #include <string.h>
  61. #include <ctype.h>
  62. #include <exec/types.h>
  63. #include <exec/io.h>
  64. #include <exec/execbase.h>
  65. #include <exec/nodes.h>
  66. #include <exec/memory.h>
  67. #include <devices/trackdisk.h>
  68. #include <devices/scsidisk.h>
  69. #include <libraries/dos.h>
  70. #include "scsi_priv.h"
  71.  
  72. #define BYTES_PER_LINE    16
  73. #define SENSE_LEN 252
  74. #define MAX_DATA_LEN 252
  75. #define PAD 0
  76. #define    LINE_BUF    (128)
  77.  
  78. #define OFFS_KEY 2
  79. #define OFFS_CODE 12
  80.  
  81. /*
  82.  * we open ( if no -d option) the first *scsi*.device in the device list.
  83.  */
  84. #define SCSI_STRING "scsi"
  85.  
  86. typedef struct MsgPort MSGPORT;
  87. typedef struct IOStdReq IOSTDREQ;
  88. typedef struct List LIST;
  89. typedef struct Node NODE;
  90. typedef struct SCSICmd SCSICMD;
  91.  
  92. #undef  FALSE
  93. #undef TRUE
  94. typedef enum
  95. {
  96.   FALSE = 0, TRUE
  97. } BOOLEAN;
  98.  
  99. UBYTE *ip_buf = NULL;
  100. UBYTE *scsi_data = NULL;
  101. UBYTE *scsi_sense = NULL;
  102. UBYTE *dev = "";
  103. MSGPORT *mp_ptr = NULL;
  104. IOSTDREQ *io_ptr = NULL;
  105. SCSICMD scsi_cmd;
  106. int scsi_id = -1;
  107. int on_off = -1;
  108. UBYTE *pname;
  109. UBYTE buffer[LINE_BUF];
  110. int secno = -1;
  111. /*
  112.  *    function decs
  113.  */
  114. void usage ();
  115. void motor ();
  116. void read_capacity ();
  117. void read_sec ();
  118. void read_sec_scsi ();
  119. void inquiry ();
  120. void seek ();
  121. UBYTE *sense_errs ();
  122. UBYTE *GetDevName ();
  123. BOOLEAN init ();
  124. UBYTE *err_str ();
  125.  
  126.  
  127. /*********************************************************************
  128.  *
  129.  *    main
  130.  *
  131.  *
  132.  */
  133.  
  134. main (argc, argv)
  135.  
  136.      int argc;
  137.      char **argv;
  138. {
  139.   UBYTE *p;
  140.   int j = 0;
  141.  
  142.   /*
  143.    *      see if a SCSI.device specified
  144.    */
  145.   if (strncmp (argv[1], "-d", 2) == 0)
  146.     {
  147.       j = 1;
  148.       dev = argv[1] + 2;
  149.     }
  150.   else if ((dev = GetDevName (SCSI_STRING)) == NULL)
  151.     {
  152.       usage ("Error : no *scsi*.device in device list\n");
  153.       exit (1);
  154.     }
  155.   pname = argv[0];
  156.   if (argc < (j + 2))
  157.     {
  158.       usage ("");        /* help inquiry */
  159.       exit (1);
  160.     }
  161.  
  162.   if (argc < (j + 3))
  163.     {
  164.       usage ("Error : Not enough params\n");
  165.       exit (1);
  166.     }
  167.   if (*(p = argv[j + 2]) != '-')
  168.     {
  169.       usage ("Error : bad option\n");    /* help inquiry */
  170.       exit (1);
  171.     }
  172.  
  173.   /*
  174.    *    pick up SCSI id ; do a rough check
  175.    */
  176.   sscanf (argv[j + 1], "%d", &scsi_id);
  177.   if (scsi_id < 0)
  178.     {
  179.       usage ("Error : Bad scsi id\n");
  180.       exit (1);
  181.     }
  182.  
  183.  
  184.   /*
  185.    *    now set up structures etc for SCSI xfer
  186.    */
  187.   if (init () == FALSE)
  188.     goto error;
  189.  
  190.   /*
  191.    **********************    now examine the options
  192.    */
  193.   switch (*++p)
  194.     {
  195.       /*
  196.        ****    read capacity
  197.        */
  198.     case 'c':
  199.       read_capacity ();
  200.       break;
  201.  
  202.       /*
  203.        ****    inquiry
  204.        */
  205.     case 'i':
  206.       inquiry ();
  207.       break;
  208.  
  209.       /*
  210.        ****    read sectors
  211.        */
  212.     case 'R':
  213.       if (argc != (j + 4))
  214.     {
  215.       usage ("Error : bad param count\n");
  216.       exit (1);
  217.     }
  218.       /*
  219.        *    get sector #
  220.        */
  221.       if (sscanf (argv[j + 3], "%d", &secno) != 1)
  222.     {
  223.       usage ("Error : Bad sec no\n");
  224.       exit (1);
  225.     }
  226.  
  227.       read_sec ();
  228.       break;
  229.  
  230.     case 'r':
  231.       if (argc != (j + 4))
  232.     {
  233.       usage ("Error : bad param count\n");
  234.       exit (1);
  235.     }
  236.       /*
  237.        *    get sector #
  238.        */
  239.       if (sscanf (argv[j + 3], "%d", &secno) != 1)
  240.     {
  241.       usage ("Error : Bad sec no\n");
  242.       exit (1);
  243.     }
  244.  
  245.       read_sec_scsi ();
  246.       break;
  247.  
  248.       /*
  249.        ****    seek to cylinder containing secno
  250.        */
  251.     case 's':
  252.       if (argc != (j + 4))
  253.     {
  254.       usage ("Error : bad param count\n");
  255.       exit (1);
  256.     }
  257.       /*
  258.        *    get sector #
  259.        */
  260.       if (sscanf (argv[j + 3], "%d", &secno) != 1)
  261.     {
  262.       usage ("Error : Bad sec no\n");
  263.       exit (1);
  264.     }
  265.  
  266.       seek ();
  267.       break;
  268.  
  269.       /*
  270.        ****    fill sector with a byte
  271.        */
  272.     case 'f':
  273.       if (argc != (j + 5))
  274.     {
  275.       usage ("Error : bad param count\n");
  276.       exit (1);
  277.     }
  278.  
  279.       /*
  280.        *    get sector #
  281.        */
  282.       sscanf (argv[j + 3], "%d", &secno);
  283.       if (secno == -1)
  284.     {
  285.       usage ("Error : Bad sec no\n");
  286.       exit (1);
  287.     }
  288.       break;
  289.  
  290.       /*
  291.        ****    stop/start motor
  292.        */
  293.     case 'm':
  294.       if (argc != (j + 4))
  295.     {
  296.       usage ("Error : bad param count\n");
  297.       exit (1);
  298.     }
  299.       sscanf (argv[j + 3], "%d", &on_off);
  300.       if ((on_off == -1) || ((on_off != 0) && (on_off != 1)))
  301.     {
  302.       usage ("Error : motor control must be 0 or 1\n");
  303.       exit (1);
  304.     }
  305.  
  306.       motor ();
  307.       break;
  308.  
  309.     default:
  310.       usage ("Error : bad option\n");    /* help inquiry */
  311.       exit (1);
  312.     }
  313.  
  314. error:
  315.  
  316.   if (io_ptr)
  317.     {
  318.       CloseDevice ((IOSTDREQ *) io_ptr);
  319.       DeleteStdIO (io_ptr);
  320.     }
  321.  
  322.   if (mp_ptr)
  323.     DeletePort (mp_ptr);
  324.  
  325.   if (ip_buf)
  326.     FreeMem (ip_buf, TD_SECTOR);
  327.  
  328.   if (scsi_data)
  329.     FreeMem (scsi_data, MAX_DATA_LEN);
  330.  
  331.   if (scsi_sense)
  332.     FreeMem (scsi_sense, SENSE_LEN);
  333.  
  334. }
  335.  
  336. /*********************************************************************
  337.  *
  338.  *    Initialisation function
  339.  *
  340.  *
  341.  */
  342. BOOLEAN
  343. init ()
  344. {
  345.   if ((scsi_data = (UBYTE *) AllocMem (MAX_DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
  346.     {
  347.       fprintf (stderr, "AllocMem(0) Fail\n");
  348.       return FALSE;
  349.     }
  350.  
  351.   if ((scsi_sense = (UBYTE *) AllocMem (SENSE_LEN, MEMF_CHIP || MEMF_CLEAR)) == NULL)
  352.     {
  353.       fprintf (stderr, "AllocMem(1) Fail\n");
  354.       return FALSE;
  355.     }
  356.  
  357.   if ((ip_buf = (UBYTE *) AllocMem (TD_SECTOR, MEMF_CHIP)) == NULL)
  358.     {
  359.       fprintf (stderr, "AllocMem(2) Fail\n");
  360.       return FALSE;
  361.     }
  362.  
  363.   if ((mp_ptr = (MSGPORT *) CreatePort (NULL, 0)) == NULL)
  364.     {
  365.       fprintf (stderr, "CreatePort Fail\n");
  366.       return FALSE;
  367.     }
  368.  
  369.   if ((io_ptr = (IOSTDREQ *) CreateStdIO (mp_ptr)) == NULL)
  370.     {
  371.       fprintf (stderr, "CreateStdIO Fail\n");
  372.       return FALSE;
  373.     }
  374.  
  375.   if (OpenDevice (dev, scsi_id, io_ptr, 0) != 0)
  376.     {
  377.       fprintf (stderr,
  378.            "Error %d while opening SCSI dev \"%s\", unit (%d)\n",
  379.            io_ptr->io_Error, dev, scsi_id);
  380.  
  381.       return FALSE;
  382.     }
  383.  
  384.   return TRUE;
  385. }
  386.  
  387. /*********************************************************************
  388.  *
  389.  *    function to read sectors from a starting sector #
  390.  *    - similar adjacent lines are suppressed on printout.
  391.  *
  392.  *    - uses trackdisk.device
  393.  */
  394.  
  395. void
  396. read_sec ()
  397.  
  398. {
  399.   UBYTE *sec_click_ptr;        /* click = 16 bytes    */
  400.   UBYTE *pref;
  401.   UBYTE *p;
  402.   UWORD j;
  403.   UWORD k;
  404.   int err;
  405.  
  406.   /*
  407.    *  keep printing sectors until ^C , or until error
  408.    */
  409.   io_ptr->io_Command = CMD_READ;
  410.   io_ptr->io_Length = TD_SECTOR;
  411.   io_ptr->io_Data = (APTR) ip_buf;
  412.   io_ptr->io_Offset = secno * TD_SECTOR;    /* will be updated... */
  413.  
  414.  
  415.   /*
  416.    *  keep reading sectors : stop on ^C on bad sector #
  417.    */
  418.   for (;; ++secno)
  419.     {
  420.       UBYTE *ss;
  421.       UWORD m_sec_offs;
  422.  
  423.       if (breakcheck ())    /* ^C ? */
  424.     break;
  425.  
  426.       io_ptr->io_Offset = secno * TD_SECTOR;    /* sector offset */
  427.  
  428.       DoIO ((IOSTDREQ *) io_ptr);
  429.       if ((err = io_ptr->io_Error) == 0)
  430.     {
  431.       printf ("\n");
  432.       /*
  433.        * scan this sector ...
  434.         */
  435.       for (sec_click_ptr = pref = ip_buf, m_sec_offs = 0;
  436.            m_sec_offs < TD_SECTOR;
  437.            m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
  438.         {
  439.           int xxxlen = strlen (" xx");    /* byte */
  440.  
  441.           if (breakcheck ())
  442.         break;
  443.           /*
  444.            * don't print line if same contents as previous
  445.            */
  446.           if (gcomp (sec_click_ptr, pref, BYTES_PER_LINE) == TRUE)
  447.         {
  448.           if (m_sec_offs > 1)
  449.             continue;    /* same */
  450.         }
  451.           (void) setmem (buffer, sizeof (buffer), ' ');    /* put spaces in buffer */
  452.  
  453.           sprintf (buffer, "%05X:%03X = ", secno, m_sec_offs);
  454.  
  455.           /* set up for loop */
  456.  
  457.           k = strlen (buffer);
  458.           ss = buffer + k;
  459.           k += (BYTES_PER_LINE * xxxlen) + 1;
  460.           for (p = sec_click_ptr, j = 0;
  461.            j < BYTES_PER_LINE;
  462.            ss += xxxlen, ++j, ++k)
  463.         {
  464.           UBYTE dd = *p++;
  465.           UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
  466.           sprintf (ss, " %02X", dd);    /* 2 hex charas  */
  467.           buffer[k] = que;
  468.         }
  469.  
  470.           buffer[strlen (buffer)] = ' ';
  471.           buffer[k++] = '\n';
  472.           buffer[k++] = '\0';
  473.  
  474.           printf ("%s", buffer);
  475.           pref = sec_click_ptr;
  476.  
  477.         }
  478.     }
  479.       else
  480.     {
  481.       /* else DoIO error */
  482.  
  483.       fprintf (stderr, "Error :  sec = %ld dec , $%lX , [%s]\n",
  484.            secno, secno, sense_errs (err));
  485.  
  486.       return;
  487.     }
  488.     }
  489. }
  490.  
  491. /*********************************************************************
  492.  *
  493.  *    function to read sectors from a starting sector #
  494.  *    - similar adjacent lines are suppressed on printout.
  495.  *
  496.  *    - uses scsi device directly
  497.  */
  498.  
  499. void
  500. read_sec_scsi ()
  501.  
  502. {
  503.   static struct CMD_XREAD
  504.   {
  505.     UBYTE cmd;
  506.     UBYTE lba[3];
  507.     UBYTE numb_secs;
  508.     UBYTE pad;
  509.   } command =
  510.   {
  511.     SCSI_CMD_RD,
  512.     0, 0, 0,
  513.     0,
  514.     PAD
  515.   };
  516.  
  517.   UBYTE *sec_click_ptr;        /* click = 16 bytes    */
  518.   UBYTE *pref;
  519.   UBYTE *p;
  520.   UWORD j;
  521.   UWORD k;
  522.   int err;
  523.  
  524.   /*
  525.    *  keep printing sectors until ^C , or until error
  526.    */
  527.  
  528.  
  529.   io_ptr->io_Command = HD_SCSICMD;
  530.   io_ptr->io_Length = sizeof (SCSICMD);
  531.   io_ptr->io_Data = (APTR) & scsi_cmd;
  532.  
  533.   scsi_cmd.scsi_Command = (UBYTE *) & command;
  534.   scsi_cmd.scsi_CmdLength = sizeof (command);
  535.   scsi_cmd.scsi_Flags = SCSIF_READ | SCSIF_AUTOSENSE;
  536.   scsi_cmd.scsi_Data = (APTR) ip_buf;
  537.   scsi_cmd.scsi_Length = 512;
  538.   scsi_cmd.scsi_SenseData = scsi_sense;
  539.   scsi_cmd.scsi_SenseLength = SENSE_LEN;
  540.  
  541.   /*
  542.    *  keep reading sectors : stop on ^C on bad sector #
  543.    */
  544.   for (;; ++secno)
  545.     {
  546.       UBYTE *ss;
  547.       UWORD m_sec_offs;
  548.  
  549.       command.lba[2] = secno;
  550.       command.lba[1] = secno >> 8;
  551.       command.lba[0] = (secno >> 8) & 0x1F;
  552.  
  553.       command.numb_secs = 1;
  554.  
  555.       if (breakcheck ())    /* ^C ? */
  556.     break;
  557.  
  558.       io_ptr->io_Offset = secno * TD_SECTOR;    /* sector offset */
  559.  
  560.       DoIO ((IOSTDREQ *) io_ptr);
  561.       if ((err = io_ptr->io_Error) == 0)
  562.     {
  563.       printf ("\n");
  564.       /*
  565.        * scan this sector ...
  566.         */
  567.       for (sec_click_ptr = pref = ip_buf, m_sec_offs = 0;
  568.            m_sec_offs < TD_SECTOR;
  569.            m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
  570.         {
  571.           int xxxlen = strlen (" xx");    /* byte */
  572.  
  573.           if (breakcheck ())
  574.         break;
  575.           /*
  576.            * don't print line if same contents as previous
  577.            */
  578.           if (gcomp (sec_click_ptr, pref, BYTES_PER_LINE) == TRUE)
  579.         {
  580.           if (m_sec_offs > 1)
  581.             continue;    /* same */
  582.         }
  583.           (void) setmem (buffer, sizeof (buffer), ' ');    /* put spaces in buffer */
  584.  
  585.           sprintf (buffer, "%05X:%03X = ", secno, m_sec_offs);
  586.  
  587.           /* set up for loop */
  588.  
  589.           k = strlen (buffer);
  590.           ss = buffer + k;
  591.           k += (BYTES_PER_LINE * xxxlen) + 1;
  592.           for (p = sec_click_ptr, j = 0;
  593.            j < BYTES_PER_LINE;
  594.            ss += xxxlen, ++j, ++k)
  595.         {
  596.           UBYTE dd = *p++;
  597.           UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
  598.           sprintf (ss, " %02X", dd);    /* 2 hex charas  */
  599.           buffer[k] = que;
  600.         }
  601.  
  602.           buffer[strlen (buffer)] = ' ';
  603.           buffer[k++] = '\n';
  604.           buffer[k++] = '\0';
  605.  
  606.           printf ("%s", buffer);
  607.           pref = sec_click_ptr;
  608.  
  609.         }
  610.     }
  611.       else
  612.     {
  613.       /* else DoIO error */
  614.  
  615.       fprintf (stderr, "Error :  sec = %ld dec , $%lX , [%s]\n",
  616.            secno, secno, sense_errs (err));
  617.       return;
  618.     }
  619.     }
  620. }
  621.  
  622. /*********************************************************************
  623.  *
  624.  *    function to stop/start motor on SCSI device
  625.  *
  626.  */
  627.  
  628. void
  629. motor ()
  630.  
  631. {
  632.   static struct CMD_SSU
  633.   {
  634.     UBYTE cmd;
  635.     UBYTE imm;
  636.     UBYTE pad_a[2];
  637.     UBYTE start_stop;
  638.     UBYTE pad_b;
  639.   } command =
  640.   {
  641.     SCSI_CMD_SSU,
  642.     0,
  643.     PAD, PAD,
  644.     0,
  645.     PAD
  646.   };
  647.  
  648.   int err;
  649.  
  650.   command.start_stop = on_off;
  651.  
  652.   io_ptr->io_Command = HD_SCSICMD;
  653.   io_ptr->io_Length = sizeof (SCSICMD);
  654.   io_ptr->io_Data = (APTR) & scsi_cmd;
  655.  
  656.   scsi_cmd.scsi_Command = (UBYTE *) & command;
  657.   scsi_cmd.scsi_CmdLength = sizeof (command);
  658.   scsi_cmd.scsi_Flags = SCSIF_READ | SCSIF_AUTOSENSE;
  659.   scsi_cmd.scsi_SenseData = scsi_sense;
  660.   scsi_cmd.scsi_SenseLength = SENSE_LEN;
  661.  
  662.  
  663.   (void) DoIO ((IOSTDREQ *) io_ptr);
  664.   if ((err = io_ptr->io_Error) != 0)
  665.     {
  666.       fprintf (stderr, "Error :   [%s]\n", sense_errs (err));
  667.     }
  668. }
  669.  
  670. /*********************************************************************
  671.  *
  672.  *    function to seek to a cylinder
  673.  *
  674.  */
  675.  
  676. void
  677. seek ()
  678.  
  679. {
  680.   static struct CMD_SEEK
  681.   {
  682.     UBYTE cmd;
  683.     UBYTE pad_a;
  684.     ULONG lba;
  685.     UBYTE pad[4];
  686.   } command =
  687.   {
  688.     SCSI_CMD_SKX,
  689.     PAD,
  690.     0,
  691.     PAD, PAD, PAD, PAD
  692.   };
  693.  
  694.   int err;
  695.   /*
  696.    *    load sector # (log block addr)
  697.    */
  698.  
  699.   command.lba = secno;
  700.  
  701.   io_ptr->io_Command = HD_SCSICMD;
  702.   io_ptr->io_Length = sizeof (SCSICMD);
  703.   io_ptr->io_Data = (APTR) & scsi_cmd;
  704.  
  705.   scsi_cmd.scsi_Command = (UBYTE *) & command;
  706.   scsi_cmd.scsi_CmdLength = sizeof (command);
  707.   scsi_cmd.scsi_Flags = SCSIF_READ | SCSIF_AUTOSENSE;
  708.   scsi_cmd.scsi_SenseData = scsi_sense;
  709.   scsi_cmd.scsi_SenseLength = SENSE_LEN;
  710.  
  711.  
  712.   (void) DoIO ((IOSTDREQ *) io_ptr);
  713.   if ((err = io_ptr->io_Error) != 0)
  714.     {
  715.       fprintf (stderr, "Error :  sec = %ld dec , $%lX , [%s]\n",
  716.            secno, secno, sense_errs (err));
  717.     }
  718. }
  719.  
  720. /*********************************************************************
  721.  *
  722.  *    function to make an inquiry
  723.  *
  724.  */
  725.  
  726. void
  727. inquiry ()
  728. {
  729.   static struct CMD_INQUIRY
  730.   {
  731.     UBYTE cmd;
  732.     UBYTE pad_a[3];
  733.     UBYTE len;
  734.     UBYTE pad_b;
  735.   } command =
  736.   {
  737.     SCSI_CMD_INQ,
  738.     PAD, PAD, PAD,
  739.     0,
  740.     PAD
  741.   };
  742.   UBYTE *sec_click_ptr;        /* click = 16 bytes    */
  743.   UBYTE *p;
  744.   UBYTE *ss;
  745.   UWORD m_sec_offs;
  746.   UWORD k;
  747.   int err;
  748.   int j;
  749.  
  750.   command.len = MAX_DATA_LEN;
  751.  
  752.   io_ptr->io_Command = HD_SCSICMD;
  753.   io_ptr->io_Length = sizeof (struct SCSICmd);
  754.   io_ptr->io_Data = (APTR) & scsi_cmd;
  755.  
  756.   scsi_cmd.scsi_Data = (UWORD *) scsi_data;
  757.   scsi_cmd.scsi_Length = MAX_DATA_LEN;
  758.   scsi_cmd.scsi_Command = (UBYTE *) & command;
  759.   scsi_cmd.scsi_CmdLength = sizeof (command);
  760.   scsi_cmd.scsi_Flags = SCSIF_READ | SCSIF_AUTOSENSE;
  761.   scsi_cmd.scsi_SenseData = scsi_sense;
  762.   scsi_cmd.scsi_SenseLength = SENSE_LEN;
  763.  
  764.  
  765.   (void) DoIO ((IOSTDREQ *) io_ptr);
  766.  
  767.   if ((err = io_ptr->io_Error) == 0)
  768.     {
  769.       int rem = scsi_cmd.scsi_Actual;
  770.  
  771.       printf ("\n");
  772.       /*
  773.        * now print it out
  774.        */
  775.       for (sec_click_ptr = scsi_data, m_sec_offs = 0;
  776.        ;
  777.        m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
  778.     {
  779.       int xxxlen = strlen (" xx");    /* byte */
  780.  
  781.       (void) setmem (buffer, sizeof (buffer), ' ');    /* put spaces in buffer */
  782.  
  783.       sprintf (buffer, "%3X = ", m_sec_offs);
  784.  
  785.       /* set up for loop */
  786.  
  787.       k = strlen (buffer);
  788.       ss = buffer + k;
  789.       k += (BYTES_PER_LINE * xxxlen) + 1;
  790.       for (p = sec_click_ptr, j = 0;
  791.            j < BYTES_PER_LINE;
  792.            ss += xxxlen, ++j)
  793.         {
  794.           UBYTE dd = *p++;
  795.           UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
  796.           sprintf (ss, " %02X", dd);    /* 2 hex charas  */
  797.           buffer[k++] = que;
  798.           if (--rem == 0)
  799.         break;
  800.         }
  801.  
  802.       buffer[strlen (buffer)] = ' ';
  803.       buffer[k++] = '\n';
  804.       buffer[k++] = '\0';
  805.  
  806.       printf ("%s", buffer);
  807.       if (rem <= 0)
  808.         return;
  809.     }
  810.     }
  811.   else
  812.     /* error */
  813.     {
  814.       fprintf (stderr, "Error : %s\n", sense_errs (err));
  815.  
  816.     }
  817. }
  818.  
  819. /*********************************************************************
  820.  *
  821.  *    function to read disk capacity
  822.  *
  823.  */
  824.  
  825. void
  826. read_capacity ()
  827. {
  828.   static struct CMD_READ_CAPACITY
  829.   {
  830.     UBYTE cmd;
  831.     UBYTE pad_a;
  832.     ULONG lba;
  833.     UBYTE pad_b[2];
  834.     UBYTE pmi;
  835.     UBYTE pad_c;
  836.   } command =
  837.   {
  838.     SCSI_CMD_RCP,
  839.     PAD,
  840.     0,                /* start from sec 0 */
  841.     PAD, PAD,
  842.     0,
  843.     PAD
  844.   };
  845.  
  846.   int err;
  847.  
  848.   io_ptr->io_Command = HD_SCSICMD;
  849.   io_ptr->io_Length = sizeof (struct SCSICmd);
  850.   io_ptr->io_Data = (APTR) & scsi_cmd;
  851.  
  852.   scsi_cmd.scsi_Data = (UWORD *) scsi_data;
  853.   scsi_cmd.scsi_Length = MAX_DATA_LEN;
  854.   scsi_cmd.scsi_Command = (UBYTE *) & command;
  855.   scsi_cmd.scsi_CmdLength = sizeof (command);
  856.   scsi_cmd.scsi_Flags = SCSIF_READ | SCSIF_AUTOSENSE;
  857.   scsi_cmd.scsi_SenseData = scsi_sense;
  858.   scsi_cmd.scsi_SenseLength = SENSE_LEN;
  859.  
  860.  
  861.   (void) DoIO ((IOSTDREQ *) io_ptr);
  862.  
  863.   if ((err = io_ptr->io_Error) == 0)
  864.     {
  865.       ULONG sec_no = *((ULONG *) & scsi_data[0]);
  866.       ULONG sec_size = *((ULONG *) & scsi_data[4]);
  867.  
  868.       printf ("Max Sec = %6ld , sec size = %4ld (capacity = %6ld KB)\n",
  869.           sec_no, sec_size, (sec_no * sec_size) / 1024);
  870.     }
  871.   else
  872.     {
  873.       fprintf (stderr, "Error : %s \n", sense_errs (err));
  874.     }
  875. }
  876.  
  877. /*********************************************************************
  878.  *
  879.  *    function to compare two binary strings
  880.  *
  881.  *    returns FALSE if different
  882.  */
  883.  
  884. int
  885. gcomp (p1, p2, len)
  886.  
  887.      char *p1;
  888.      char *p2;
  889.      int len;
  890. {
  891.   while (len--)
  892.     {
  893.       if (*p1++ != *p2++)
  894.     return (FALSE);
  895.     }
  896.   return (TRUE);
  897. }
  898.  
  899. /*********************************************************************
  900.  *
  901.  * searches DeviceList for a device name with a given string in it.
  902.  * - if found returns with a pointer to it, else NULL
  903.  */
  904.  
  905. extern struct ExecBase *SysBase;
  906.  
  907. UBYTE *
  908. GetDevName (grep)
  909.  
  910.      char *grep;
  911. {
  912.   LIST *lh = (LIST *) SysBase->DeviceList.lh_Head;
  913.   NODE *ln;
  914.  
  915.   for (ln = lh->lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
  916.     {
  917.       UBYTE *p = ln->ln_Name;
  918.  
  919.       while (*p != '.')
  920.     {
  921.       if (strncmp (p, grep, 4) == 0)
  922.         {
  923.           return (ln->ln_Name);
  924.         }
  925.       ++p;
  926.     }
  927.     }
  928.  
  929.   return (NULL);        /* not found */
  930. }
  931.  
  932. /*********************************************************************
  933.  *
  934.  *    Break (^C) function
  935.  *
  936.  */
  937.  
  938. int
  939. breakcheck ()
  940. {
  941.   int zz = SetSignal (0L, 0L) & SIGBREAKF_CTRL_C;
  942.  
  943.   if (zz)
  944.     {
  945.       printf ("\n^C");
  946.     }
  947.   return (zz);
  948. }
  949.  
  950. /*********************************************************************
  951.  *
  952.  *  tell Lattice to return
  953.  */
  954. int
  955. chkabort (void)
  956. {
  957.   return (0);
  958. }
  959.  
  960.  
  961. /*********************************************************************
  962.  *
  963.  *    function to return an error string
  964.  *
  965.  *
  966.  */
  967.  
  968. UBYTE *
  969. err_str (err)
  970.  
  971.      int err;
  972. {
  973.  
  974.   static UBYTE *errors[] =
  975.   {
  976.     " cannot issue SCSI command to self ",
  977.     " DMA error ",
  978.     " illegal or unexpected SCSI phase ",
  979.     " SCSI parity error ",
  980.     " Select timed out ",
  981.     " status and/or sense error "
  982.   };
  983.  
  984.   err -= 40;
  985.  
  986.   if ((err < 0) || (err > 5))
  987.     return ("Error out-of-range");
  988.   else
  989.     return (errors[err]);
  990. }
  991.  
  992. /*********************************************************************
  993.  *
  994.  *    usage function
  995.  *
  996.  *
  997.  */
  998.  
  999. void
  1000. usage (p)
  1001.      char *p;
  1002. {
  1003.   static char *zz[] =
  1004.   {
  1005.     "Inquiry            :   SCSIutil [-dscsi_dev] scsi_id -i\n",
  1006.     "Read sectors (2)   :                                 -R sec_no\n",
  1007.     "Read sectors       :                                 -r sec_no\n",
  1008.     "Read capacity      :                                 -c\n",
  1009. /*    "Fill sector        :                                 -f sec_no byte\n", */
  1010.     "Stop/Start motor   :                                 -m {0=stop,1=start}\n",
  1011.     "Seek to sector (3) :                                 -s sec_no\n",
  1012.     "\n",
  1013.   "Note 1: usually scsi_id = (BOARD * 100) + (LUN * 10) + SCSI_TARGET_ID\n",
  1014.     "     2: uses trackdisk.device\n",
  1015.     "     3: to park heads, try sec_no of -1\n",
  1016.     ""                /* TERM */
  1017.   };
  1018.  
  1019.   int j = 0;
  1020.  
  1021.  
  1022.   printf ("%s", p);
  1023.   printf ("Usage : SCSIutil V%s [%s : %s] - written by Gary Duncan\n",
  1024.       VERSION, __DATE__, __TIME__, pname);
  1025.  
  1026.   while (*zz[j++])
  1027.     printf ("%s", zz[j - 1]);
  1028. }
  1029.  
  1030. /*********************************************************************
  1031.  *
  1032.  *    sense_errs function ; prints sense errors
  1033.  *
  1034.  *
  1035.  */
  1036.  
  1037. UBYTE *
  1038. sense_errs (err)
  1039.  
  1040.      int err;
  1041. {
  1042.   typedef struct
  1043.   {
  1044.     BYTE code;
  1045.     BYTE sense;
  1046.     UBYTE *ptr;
  1047.   } S_ERRS;
  1048.  
  1049. /*
  1050.  *    only the likely, interesting ones filled in, e.g media errors
  1051.  */
  1052.   static S_ERRS x[] =
  1053.   {
  1054.     0x00, 0x00, "No error",
  1055.     0x01, 0x04, "?",
  1056.     0x02, 0x04, "?",
  1057.     0x03, 0x04, "?",
  1058.     0x04, 0x02, "?",
  1059.     0x06, 0x04, "?",
  1060.     0x09, 0x04, "?",
  1061.     0x10, 0x03, "?",
  1062.     0x10, 0x04, "?",
  1063.     0x11, 0x03, "?",
  1064.     0x12, 0x03, "?",
  1065.     0x13, 0x03, "?",
  1066.     0x14, 0x03, "?",
  1067.     0x15, 0x04, "Seek error ",
  1068.     0x17, 0x01, "?",
  1069.     0x18, 0x01, "?",
  1070.     0x19, 0x03, "?",
  1071.     0x1A, 0x05, "?",
  1072.     0x20, 0x05, "Invalid command op code",
  1073.     0x21, 0x05, "Illegal sector address",
  1074.     0x24, 0x05, "?",
  1075.     0x25, 0x05, "Invalid LUN",
  1076.     0x26, 0x05, "Invalid field in parameter list",
  1077.     0x29, 0x06, "?",
  1078.     0x2A, 0x06, "?",
  1079.     0x31, 0x03, "?",
  1080.     0x32, 0x01, "?",
  1081.     0x32, 0x03, "?",
  1082.     0x40, 0x04, "?",
  1083.     0x41, 0x04, "?",
  1084.     0x42, 0x04, "Power-on diagnostic failure",
  1085.     0x43, 0x04, "?",
  1086.     0x45, 0x04, "Select / reselect failure ",
  1087.     0x47, 0x04, "SCSI Interface Parity Error",
  1088.     0x48, 0x0B, "?",
  1089.     0x49, 0x0B, "Illegal message drive can't support",
  1090.     -1, -1, "ILLEGAL sense!!"
  1091.   };
  1092.  
  1093.   int j = 0;
  1094.   UBYTE *p;
  1095.   char sense;
  1096.   char code;
  1097.  
  1098.   /*
  1099.    *    verify that sense data looks valid
  1100.    */
  1101.   if (((scsi_cmd.scsi_Status & 2) == 0) ||
  1102.       (scsi_cmd.scsi_SenseActual < OFFS_KEY))
  1103.     {
  1104.       return ("");
  1105.     }
  1106.   sense = scsi_cmd.scsi_SenseData[OFFS_KEY] & 0xF;
  1107.   code = scsi_cmd.scsi_SenseData[OFFS_CODE];
  1108.  
  1109.   do
  1110.     {
  1111.       p = x[j].ptr;
  1112.       if ((x[j].code == code) && (x[j].sense == sense))
  1113.     break;
  1114.   } while (x[j++].code != -1);
  1115.  
  1116.   return (p);
  1117. }
  1118.