home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / os2 / gtak / source / tape / scsitape.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-14  |  14.3 KB  |  634 lines

  1. /*****************************************************************************
  2.  * $Id: scsitape.c,v 1.4 1992/10/14 18:35:14 ak Exp $
  3.  *****************************************************************************
  4.  * $Log: scsitape.c,v $
  5.  * Revision 1.4  1992/10/14  18:35:14  ak
  6.  * IBM SCSI driver.
  7.  *
  8.  * Revision 1.3  1992/09/12  18:10:52  ak
  9.  * Added scsi_name
  10.  * Added device name support to tctl.c
  11.  *
  12.  * Revision 1.2  1992/09/02  19:05:43  ak
  13.  * Version 2.0
  14.  * - EMX version
  15.  * - AIX version
  16.  * - SCSI-2 commands
  17.  * - ADD Driver
  18.  * - blocksize support
  19.  *
  20.  * Revision 1.1.1.1  1992/01/06  20:27:14  ak
  21.  * Interface now based on ST01 and ASPI.
  22.  * AHA_DRVR no longer supported.
  23.  * Files reorganized.
  24.  *
  25.  * Revision 1.1  1992/01/06  20:27:12  ak
  26.  * Initial revision
  27.  *
  28.  *****************************************************************************/
  29.  
  30. static char *rcsid = "$Id: scsitape.c,v 1.4 1992/10/14 18:35:14 ak Exp $";
  31.  
  32. #include <stdio.h>
  33. #include <stdarg.h>
  34. #include <stdlib.h>
  35. #define INCL_DOSFILEMGR
  36. #define INCL_DOSDEVICES
  37. #define INCL_DOSPROCESS
  38. #define INCL_DOSSEMAPHORES
  39. #define INCL_ERRORS
  40. #include <os2.h>
  41.  
  42. #ifdef __EMX__
  43. #ifndef _far
  44. #define _far
  45. #endif
  46. #endif
  47.  
  48. #include "scsi.h"
  49. #include "aspi.h"
  50. #include "tapedrvr.h"
  51.  
  52. #define CDB_LEN        12
  53. #define SENSE_LEN    40
  54.  
  55. #if OS2 >= 2
  56.   typedef ULONG        Word;
  57. #else
  58.   typedef USHORT    Word;
  59. #endif
  60.  
  61. typedef struct SCB {
  62.     void *        cdb;
  63.     void _far *    data;
  64.     long        data_len;
  65.     BYTE        target;
  66.     BYTE        lun;
  67.     BYTE        cdb_len;
  68.     BYTE        sense_len;
  69.     BYTE        readflag;
  70.     BYTE        sense [SENSE_LEN];
  71.     unsigned    error;
  72. } SCB;
  73.  
  74. static HFILE    hdev;
  75. static BYTE    sense_cmd[6] = { CmdRequestSense, 0, 0, 0, 0, 0 };
  76. static TID    thread_id;
  77. #if OS2 >= 2
  78.   static HMTX    mutex;
  79.   static HEV    done;
  80. #else
  81.   static BYTE    thread_stack[4096];
  82.   static ULONG    sema;
  83. #endif
  84. static SCB    *thread_scb;
  85. static BYTE    trace = 0;
  86. static BYTE    drvLevel = ST01driver;
  87. enum SenseMode    senseMode = Sensekey;
  88.  
  89. static void
  90. fatal(char *msg, ...)
  91. {
  92.     va_list ap;
  93.     fprintf(stderr, "Fatal SCSI error: ");
  94.     va_start(ap, msg);
  95.     vfprintf(stderr, msg, ap);
  96.     va_end (ap);
  97.     fprintf(stderr, "\n");
  98.     exit (2);
  99. }
  100.  
  101. command(BYTE *cdb, int len)
  102. {
  103.     int i;
  104.     fprintf(stderr, "SCSI op:");
  105.     for (i = 0; i < len; ++i)
  106.         fprintf(stderr, " %02X", cdb[i]);
  107.     fprintf(stderr, "\n");
  108. }
  109.  
  110. status(BYTE *sense, int len)
  111. {
  112.     int i;
  113.     fprintf(stderr, "SCSI status:");
  114.     for (i = 0; i < len; ++i) {
  115.         if (i && (i % 16) == 0)
  116.             fprintf(stderr, "\n            ");
  117.         fprintf(stderr, " %02X", sense[i]);
  118.     }
  119.     fprintf(stderr, "\n");
  120. }
  121.  
  122. static void
  123. init()
  124. {
  125.     BYTE data[2];
  126.     char *cp;
  127. #if OS2 >= 2
  128.     ULONG datalen = 2;
  129.  
  130.     if (DosDevIOCtl(hdev, IOCtlCategory, IOCtlLevel,
  131.                 0, 0, 0,  data, datalen, &datalen) == 0)
  132. #else
  133.     if (DosDevIOCtl2(data, 2, 0, 0, IOCtlLevel, IOCtlCategory, hdev) == 0)
  134. #endif
  135.     {
  136.         drvLevel = data[0];
  137.         senseMode = data[1];
  138.         if (trace)
  139.             fprintf(stderr, "Device driver level: %d, sense mode: %d\n",
  140.                 drvLevel, senseMode);
  141.     } else {
  142.         if ((cp = getenv("TAPEMODE")) != NULL)
  143.             senseMode = atoi(cp);
  144.         if (trace)
  145.             fprintf(stderr, "Device driver level: 0, sense mode: %d\n",
  146.                 senseMode);
  147.     }
  148. }
  149.  
  150. void
  151. scsi_file(int fd)
  152. {
  153.     hdev = fd;
  154.     init();
  155. }
  156.  
  157. void
  158. scsi_name(char *name)
  159. {
  160.     Word rc, action;
  161.     char *cp;
  162.  
  163.     if (!name) {
  164.         name = getenv("TAPE");
  165.         if (name == NULL)
  166.             fatal("Missing environment name TAPE\n");
  167.     }
  168.     while (*name == '+')
  169.         ++name;
  170.  
  171. #if OS2 >= 2
  172.     rc = DosOpen((PSZ)name, &hdev, &action, 0L, 0,
  173.         FILE_OPEN, OPEN_ACCESS_READWRITE+OPEN_SHARE_DENYNONE+OPEN_FLAGS_FAIL_ON_ERROR, 0);
  174. #else
  175.     rc = DosOpen((PSZ)name, &hdev, &action, 0L, 0,
  176.         FILE_OPEN, OPEN_ACCESS_READWRITE+OPEN_SHARE_DENYNONE+OPEN_FLAGS_FAIL_ON_ERROR, 0L);
  177. #endif
  178.     if (rc)
  179.         fatal("Cannot access device %s, return code %u", name, rc);
  180.     init();
  181. }
  182.  
  183. void
  184. scsi_init(void)
  185. {
  186.     scsi_name(NULL);
  187. }
  188.  
  189. void
  190. scsi_term(void)
  191. {
  192.     DosClose(hdev);
  193. }
  194.  
  195. void
  196. scsi_trace(int level)
  197. {
  198.     trace = level;
  199. }
  200.  
  201. void *
  202. scsi_alloc(void)
  203. {
  204.     void *p = malloc(sizeof(SCB));
  205.     if (p == NULL)
  206.         fatal("No memory for SCSI Control Block\n");
  207. }
  208.  
  209. void
  210. scsi_free(void *p)
  211. {
  212.     free(p);
  213. }
  214.  
  215. static int
  216. mapDriverError(unsigned rc)
  217. {
  218.     if (rc < 0xFF00)
  219.         return SystemError + ErrorCode(rc);
  220.     rc &= 0xFF;
  221.  
  222.     switch (drvLevel) {
  223.     case ST01driver:
  224.         return DriverError + ErrST01Driver + (rc & ErrMask);
  225.     case ADDdriver:
  226.         if (rc < ErrTapeDriver)
  227.             return MappedError + rc;
  228.         break;
  229.     case SCSIdriver:
  230.         if (rc < 0x20)
  231.             return DriverError + 0x100 + rc;
  232.         if (rc < 0x40)
  233.             return UnknownError + (rc - 0x20);
  234.         if (rc < 0x50)
  235.             return StatusError + ((rc - 0x40) << 1);
  236.         if (rc < 0x80)
  237.             return HostError + 0x100 + (rc - 0x50);
  238.         if (rc < 0xA0)
  239.             return DriverError + 0x100 + rc;
  240.     }
  241.  
  242.     switch (rc & ErrSource) {
  243.     case ErrTargetStatus:
  244.         return StatusError + (rc & ErrMask);
  245.     case ErrST01Driver:
  246.     case ErrASPIDriver1:
  247.     case ErrASPIDriver2:
  248.     case ErrTapeDriver:
  249.         return DriverError + rc;
  250.     case ErrHostAdapter:
  251.         return HostError + (rc & ErrMask);
  252.     default:
  253.         return UnknownError + rc;
  254.     }
  255. }
  256.  
  257. int
  258. scsi_cmd(int target, int lun,
  259.     void *cdb, int cdb_len,    void *sense, int sense_len,
  260.     void _far *data, long data_len,
  261.     int readflag)
  262. {
  263.     BYTE    cmd, *sptr;
  264.     Word    fcn, rc, rc2, len;
  265. #if OS2 >= 2
  266.     ULONG    parmlen, datalen;
  267. #endif
  268.  
  269.     if (cdb_len > CDB_LEN || sense_len > SENSE_LEN)
  270.         return SenseKey+IllegalRequest;
  271.  
  272.     cmd = *(BYTE *)cdb;
  273.     fcn = (cmd == SeqRead || cmd == SeqWrite) ? IOCtlFast : IOCtlSlow;
  274.     if (drvLevel)
  275.         fcn += readflag ? IOCtlRead : IOCtlWrite;
  276.     if (trace) {
  277.         fprintf(stderr, "\tIOCtl=%02X, ", fcn);
  278.         command(cdb, cdb_len);
  279.     }
  280. #if OS2 >= 2
  281.     parmlen = cdb_len;
  282.     datalen = data_len;
  283.     rc = DosDevIOCtl(hdev, IOCtlCategory, fcn,
  284.             cdb, parmlen, &parmlen,  data, datalen, &datalen);
  285. #else
  286.     if (data_len)
  287.         rc = DosDevIOCtl2(data, (Word)data_len, cdb, cdb_len,
  288.                 fcn, IOCtlCategory, hdev);
  289.     else
  290.         rc = DosDevIOCtl2(0, 0, cdb, cdb_len,
  291.                 fcn, IOCtlCategory, hdev);
  292. #endif
  293.  
  294.     if (trace >= 2)
  295.         fprintf(stderr, "IOCtl return %X\n", rc);
  296.     if (drvLevel != ST01driver && rc == 0)
  297.         return 0;
  298.     if (cmd == CmdRequestSense)
  299.         return rc ? mapDriverError(rc) : 0;
  300.     if (rc)
  301.         switch (drvLevel) {
  302.         case ST01driver:
  303.             if (rc != 0xFF00+CheckStatus)
  304.                 return mapDriverError(rc);
  305.             break;
  306.         case ASPIdriver:
  307.             if (rc != 0xFF00+ErrTargetStatus+CheckStatus)
  308.                 return mapDriverError(rc);
  309.             break;
  310.         case SCSIdriver:
  311.             if (rc != 0xFF41)
  312.                 return mapDriverError(rc);
  313.             break;
  314.         }
  315.  
  316. #if OS2 >= 2
  317.     parmlen = sizeof sense_cmd;
  318.     datalen = sense_len;
  319.     rc2 = DosDevIOCtl(hdev, IOCtlCategory, drvLevel ? IOCtlSense : IOCtlSlow,
  320.             sense_cmd, parmlen, &parmlen, sense, datalen, &datalen);
  321.     if (trace && sense_len != datalen) {
  322.         fprintf(stderr, "Got %d sense bytes\n", datalen);
  323.         sense_len = datalen;
  324.     }
  325. #else
  326.     rc2 = DosDevIOCtl2(sense, (Word)sense_len, sense_cmd, sizeof sense_cmd,
  327.             drvLevel ? IOCtlSense : IOCtlSlow, IOCtlCategory, hdev);
  328. #endif
  329.     if (rc2)
  330.         return mapDriverError(rc ? rc : rc2);
  331.  
  332.     if (trace)
  333.         status(sense, sense_len);
  334.  
  335.     sptr = (BYTE *)sense;
  336.     if ((sptr[0] & 0x7E) != 0x70)
  337.         return sptr[0] ? ExtendedError + (sptr[0] & 0x7F) : 0;
  338.     if (sense_len <= 2)
  339.         return UnknownError;
  340.     return sptr[2] ? SenseKey + (sptr[2] & 0x0F) : 0;
  341. }
  342.  
  343. #pragma check_stack(off)
  344.  
  345. static void _far
  346. #if OS2 >= 2
  347.   thread_fcn(ULONG dummy)
  348. #else
  349.   thread_fcn(void)
  350. #endif
  351. {
  352.     for (;;) {
  353.         DosSuspendThread(thread_id);
  354.         if (thread_scb) {
  355.             thread_scb->error = scsi_cmd(thread_scb->target,
  356.                 thread_scb->lun,
  357.                 thread_scb->cdb, thread_scb->cdb_len,
  358.                 thread_scb->sense, thread_scb->sense_len,
  359.                 thread_scb->data, thread_scb->data_len,
  360.                 thread_scb->readflag);
  361. #if OS2 >= 2
  362.             DosPostEventSem(done);
  363.             DosReleaseMutexSem(mutex);
  364. #else
  365.             DosSemClear((HSEM)&sema);
  366. #endif
  367.         }
  368.     }
  369. }
  370.  
  371. #pragma check_stack()
  372.  
  373. int
  374. scsi_start(void *dcb, 
  375.     int target, int lun,
  376.     void *cdb, int cdb_len, int sense_len,
  377.     void _far *data, long data_len,
  378.     int readflag)
  379. {
  380.     SCB *scb = (SCB *)dcb;
  381. #if OS2 >= 2
  382.     ULONG npost;
  383. #endif
  384.  
  385.     if (sense_len > SENSE_LEN)
  386.         return SenseKey+IllegalRequest;
  387.  
  388.     if (thread_id == 0) {
  389.         Word rc;
  390. #if OS2 >= 2
  391.         rc = DosCreateThread(&thread_id, thread_fcn, 0, 0, 8192);
  392.         if (rc)
  393.             fatal("Cannot create thread, return code %u", rc);
  394.         rc = DosCreateMutexSem(0, &mutex, 0, 0);
  395.         if (rc)
  396.             fatal("Cannot create mutex sema, return code %u", rc);
  397.         rc = DosCreateEventSem(0, &done, 0, 0);
  398.         if (rc)
  399.             fatal("Cannot create event sema, return code %u", rc);
  400. #else
  401.         rc = DosCreateThread(thread_fcn, &thread_id, thread_stack+4096);
  402.         if (rc)
  403.             fatal("Cannot create thread, return code %u", rc);
  404.         DosSemClear((HSEM)&sema);
  405. #endif
  406.     }
  407.  
  408.     if (thread_scb)
  409.         return SystemError+ErrorCode(ERROR_DEVICE_IN_USE);
  410.  
  411. #if OS2 >= 2
  412.     DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT);
  413. #else
  414.     DosSemWait((HSEM)&sema, -1);
  415. #endif
  416.  
  417.     scb->target    = target;
  418.     scb->lun       = lun;
  419.     scb->cdb       = cdb;
  420.     scb->cdb_len   = cdb_len;
  421.     scb->data      = data;
  422.     scb->data_len  = data_len;
  423.     scb->sense_len = sense_len;
  424.     scb->readflag  = readflag;
  425.     thread_scb = scb;
  426.  
  427. #if OS2 >= 2
  428.     DosResetEventSem(done, &npost);
  429. #else
  430.     DosSemSet((HSEM)&sema);
  431. #endif
  432.     DosResumeThread(thread_id);
  433.  
  434.     return ComeAgain;
  435. }
  436.  
  437. int
  438. scsi_wait(void *dcb, void *sense, int wait)
  439. {
  440.     SCB *scb = (SCB *)dcb;
  441.     int r;
  442.  
  443.     if (scb != thread_scb)
  444.         return SystemError+ErrorCode(ERROR_INVALID_HANDLE);
  445. #if OS2 >= 2
  446.     if (DosWaitEventSem(done, SEM_INDEFINITE_WAIT))
  447. #else
  448.     if (DosSemWait((HSEM)&sema, wait ? -1 : 0))
  449. #endif
  450.         return ComeAgain;
  451.     thread_scb = 0;
  452.     memcpy(sense, scb->sense, scb->sense_len);
  453.     r = scb->error;
  454.     return r;
  455. }
  456.  
  457. int
  458. scsi_reset(int target, int lun, int bus)
  459. {
  460. #if OS2 >= 2
  461.     Word rc = DosDevIOCtl(hdev, IOCtlCategory, bus ? IOCtlBusReset : IOCtlDevReset,
  462.             0, 0, 0,  0, 0, 0);
  463. #else
  464.     Word rc = DosDevIOCtl(0, 0,
  465.         bus ? IOCtlBusReset : IOCtlDevReset, IOCtlCategory, hdev);
  466. #endif
  467.     if (rc)
  468.         return mapDriverError(rc);
  469.     return NoError;
  470. }
  471.  
  472. long
  473. scsi_get_blocksize(int target, int lun)
  474. {
  475.     long sz;
  476. #if OS2 >= 2
  477.     ULONG dlen;
  478.     Word rc = DosDevIOCtl(hdev, IOCtlCategory, IOCtlBlocksize,
  479.             0, 0, 0,  &sz, sizeof sz, &dlen);
  480. #else
  481.     Word rc = DosDevIOCtl2(&sz, sizeof sz,  0, 0,
  482.             IOCtlBlocksize, IOCtlCategory, hdev);
  483. #endif
  484.     return rc ? mapDriverError(rc) : sz;
  485. }
  486.  
  487. long
  488. scsi_set_blocksize(int target, int lun, long size)
  489. {
  490.     long sz = size;
  491. #if OS2 >= 2
  492.     ULONG plen, dlen;
  493.     Word rc = DosDevIOCtl(hdev, IOCtlCategory, IOCtlBlocksize,
  494.             &size, sizeof size, &plen,  &sz, sizeof sz, &dlen);
  495. #else
  496.     Word rc = DosDevIOCtl2(&sz, sizeof sz,  &size, sizeof size,
  497.             IOCtlBlocksize, IOCtlCategory, hdev);
  498. #endif
  499.     return rc ? mapDriverError(rc) : sz;
  500. }
  501.  
  502. int
  503. scsi_set_trace(int level)
  504. {
  505.     unsigned char lvl = level;
  506. #if OS2 >= 2
  507.     ULONG plen, dlen;
  508.     Word rc = DosDevIOCtl(hdev, IOCtlCategory, IOCtlTrace,
  509.             &level, sizeof level, &plen,  &lvl, sizeof lvl, &dlen);
  510. #else
  511.     Word rc = DosDevIOCtl2(&lvl, sizeof lvl,  &level, sizeof level,
  512.             IOCtlTrace, IOCtlCategory, hdev);
  513. #endif
  514.     return rc ? mapDriverError(rc) : lvl;
  515. }
  516.  
  517. char *
  518. scsi_error(int code)
  519. {
  520.     static char text[80];
  521.     static ErrorTable driverTab[] = {
  522.             /* ST01 driver error codes */
  523.         ErrST01Driver+0x02,    "Device not ready",
  524.         ErrST01Driver+0x0C,    "Bus sequence error",
  525.         ErrST01Driver+0x13,    "Parameter error",
  526.  
  527.             /* ASPI status codes */
  528.         ErrASPIDriver1+0x00,    "Busy",
  529.         ErrASPIDriver1+0x01,    "Done",
  530.         ErrASPIDriver1+0x02,    "Aborted",
  531.         ErrASPIDriver1+0x03,    "Bad aborted",
  532.         ErrASPIDriver1+0x04,    "Error",
  533.         ErrASPIDriver1+0x10,    "Busy POST",
  534.         ErrASPIDriver2+0x00,    "Invalid ASPI request",
  535.         ErrASPIDriver2+0x01,    "Invalid host adapter",
  536.         ErrASPIDriver2+0x02,    "Device not installed",
  537.  
  538.             /* ASPITAPE driver error codes */
  539.         TapeInvalidFcn,        "Invalid ioctl cat/fcn code",
  540.         TapeInvalidParm,    "Invalid parm pointer/length",
  541.         TapeInvalidData,    "Invalid data pointer/length",
  542.         TapeNoSenseData,    "No sense data",
  543.  
  544.             /* OS2SCSI.DMD driver error codes */
  545.                 /* general driver error codes */
  546.         0x100,            "Write protected",
  547.         0x101,            "Unknown unit",
  548.         0x102,            "Device not ready",
  549.         0x103,            "Unknown command",
  550.         0x104,            "CRC error",
  551.         0x105,            "Bad request struct length",
  552.         0x10A,            "Write fault",
  553.         0x10B,            "Read fault",
  554.         0x10C,            "Generail failure",
  555.         0x10D,            "Change disk",
  556.         0x110,            "Uncertain media",
  557.         0x114,            "Device in use",
  558.                 /* OS2SCSI.DMD specific codes */
  559.         0x180,            "Device error",
  560.         0x181,            "Timeout error",
  561.         0x182,            "Unusual wakeup",
  562.         0x183,            "DevHlp error",
  563.         0x184,            "Request block not available",
  564.         0x185,            "Maximum device support exceeded",
  565.         0x186,            "Interrupt level not available",
  566.         0x187,            "Device not available",
  567.         0x188,            "More IRQ levelsthan adapters",
  568.         0x189,            "Device busy",
  569.         0x18A,            "Request sense failed",
  570.         0x18B,            "Intelligent buffer not supported",
  571.  
  572.         -1
  573.     };
  574.     static ErrorTable hostTab[] = {
  575.             /* Adaptec 154x host adapter status */
  576.         SRB_NoError,        "No error",
  577.         SRB_Timeout,        "Selection timeout",
  578.         SRB_DataLength,        "Data length error",
  579.         SRB_BusFree,        "Unexpected bus free",
  580.         SRB_BusSequence,    "Target bus sequence failure",
  581.             /* IBM SCSI adapter error */
  582.         0x101,            "Bus reset",
  583.         0x102,            "Interface fault",
  584.         0x110,            "Selection timeout",
  585.         0x111,            "Unexpected bus free",
  586.         0x113,            "Bus sequence error",
  587.         0x120,            "Short data",
  588.         -1
  589.     };
  590.  
  591.     if (code == 0)
  592.         return "No error";
  593.     if (code == ComeAgain)
  594.         return "Busy";
  595.     switch (ErrorClass(code)) {
  596.     case ErrorClass(SenseKey):
  597.         return senseTab[code & 0x0F];
  598.     case ErrorClass(ExtendedError):
  599.         switch (senseMode) {
  600.         case TDC3600:
  601.             sprintf(text, "Error code: %s",
  602.                 find_error(tdc3600ercd, ErrorCode(code)));
  603.             break;
  604.         default:
  605.             sprintf(text, "Additional sense code: %02X",
  606.                 ErrorCode(code));
  607.         }
  608.         break;
  609.     case ErrorClass(StatusError):
  610.         sprintf(text, "Target status: %s",
  611.             find_error(targetStatusTab, ErrorCode(code)));
  612.         break;
  613.     case ErrorClass(DriverError):
  614.         sprintf(text, "Driver error: %s",
  615.             find_error(driverTab, ErrorCode(code)));
  616.         break;
  617.     case ErrorClass(SystemError):
  618.         sprintf(text, "System error: %u", ErrorCode(code));
  619.         break;
  620.     case ErrorClass(HostError):
  621.         sprintf(text, "Host adapter error: %s",
  622.             find_error(hostTab, ErrorCode(code)));
  623.         break;
  624.     case ErrorClass(MappedError):
  625.         sprintf(text, "ADD error code: %s",
  626.             find_error(addErrorTab, ErrorCode(code)));
  627.         break;
  628.     default:
  629.         sprintf(text, "Other error: %04X", code);
  630.         break;
  631.     }
  632.     return text;
  633. }
  634.