home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / AmigaOS / scsi_amiga.cpp < prev    next >
C/C++ Source or Header  |  1999-10-03  |  6KB  |  256 lines

  1. /*
  2.  *  scsi_amiga.cpp - SCSI Manager, Amiga specific stuff
  3.  *
  4.  *  Basilisk II (C) 1997-1999 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include <exec/types.h>
  22. #include <exec/memory.h>
  23. #include <devices/trackdisk.h>
  24. #include <devices/scsidisk.h>
  25. #include <proto/exec.h>
  26.  
  27. #include "sysdeps.h"
  28. #include "main.h"
  29. #include "prefs.h"
  30. #include "user_strings.h"
  31. #include "scsi.h"
  32.  
  33. #define DEBUG 0
  34. #include "debug.h"
  35.  
  36.  
  37. // Global variables
  38. static struct SCSICmd scsi;
  39.  
  40. static IOStdReq *ios[8*8];                // IORequests for 8 units and 8 LUNs each
  41. static IOStdReq *io;                    // Active IORequest (selected target)
  42.  
  43. static struct MsgPort *the_port = NULL;    // Message port for device communication
  44.  
  45. static ULONG buffer_size;                // Size of data buffer
  46. static UBYTE *buffer = NULL;            // Pointer to data buffer
  47.  
  48. static UBYTE cmd_buffer[12];            // Buffer for SCSI command
  49.  
  50. const int SENSE_LENGTH = 256;
  51. static UBYTE *sense_buffer = NULL;        // Buffer for autosense data
  52.  
  53.  
  54. /*
  55.  *  Initialization
  56.  */
  57.  
  58. void SCSIInit(void)
  59. {
  60.     int id, lun;
  61.  
  62.     // Create port and buffers
  63.     the_port = CreateMsgPort();
  64.     buffer = (UBYTE *)AllocMem(buffer_size = 0x10000, MEMF_CHIP | MEMF_PUBLIC);
  65.     sense_buffer = (UBYTE *)AllocMem(SENSE_LENGTH, MEMF_CHIP | MEMF_PUBLIC);
  66.     if (the_port == NULL || buffer == NULL || sense_buffer == NULL) {
  67.         ErrorAlert(GetString(STR_NO_MEM_ERR));
  68.         QuitEmulator();
  69.     }
  70.  
  71.     // Create and open IORequests for all 8 units (and all 8 LUNs)
  72.     for (id=0; id<8; id++) {
  73.         for (lun=0; lun<8; lun++)
  74.             ios[id*8+lun] = NULL;
  75.         char prefs_name[16];
  76.         sprintf(prefs_name, "scsi%d", id);
  77.         const char *str = PrefsFindString(prefs_name);
  78.         if (str) {
  79.             char dev_name[256];
  80.             ULONG dev_unit = 0;
  81.             if (sscanf(str, "%[^/]/%ld", dev_name, &dev_unit) == 2) {
  82.                 for (lun=0; lun<8; lun++) {
  83.                     struct IOStdReq *io = (struct IOStdReq *)CreateIORequest(the_port, sizeof(struct IOStdReq));
  84.                     if (io == NULL)
  85.                         continue;
  86.                     if (OpenDevice((UBYTE *)dev_name, dev_unit + lun * 10, (struct IORequest *)io, 0)) {
  87.                         DeleteIORequest(io);
  88.                         continue;
  89.                     }
  90.                     io->io_Data = &scsi;
  91.                     io->io_Length = sizeof(scsi);
  92.                     io->io_Command = HD_SCSICMD;
  93.                     ios[id*8+lun] = io;
  94.                 }
  95.             }
  96.         }
  97.     }
  98.  
  99.     // Reset SCSI bus
  100.     SCSIReset();
  101.  
  102.     // Init SCSICmd
  103.     memset(&scsi, 0, sizeof(scsi));
  104.     scsi.scsi_Command = cmd_buffer;
  105.     scsi.scsi_SenseData = sense_buffer;
  106.     scsi.scsi_SenseLength = SENSE_LENGTH;
  107. }
  108.  
  109.  
  110. /*
  111.  *  Deinitialization
  112.  */
  113.  
  114. void SCSIExit(void)
  115. {
  116.     // Close all devices
  117.     for (int i=0; i<8; i++)
  118.         for (int j=0; j<8; j++) {
  119.             struct IOStdReq *io = ios[i*8+j];
  120.             if (io) {
  121.                 CloseDevice((struct IORequest *)io);
  122.                 DeleteIORequest(io);
  123.             }
  124.         }
  125.  
  126.     // Delete port and buffers
  127.     if (the_port)
  128.         DeleteMsgPort(the_port);
  129.     if (buffer)
  130.         FreeMem(buffer, buffer_size);
  131.     if (sense_buffer)
  132.         FreeMem(sense_buffer, SENSE_LENGTH);
  133. }
  134.  
  135.  
  136. /*
  137.  *  Check if requested data size fits into buffer, allocate new buffer if needed
  138.  */
  139.  
  140. static bool try_buffer(int size)
  141. {
  142.     if (size <= buffer_size)
  143.         return true;
  144.  
  145.     UBYTE *new_buffer = (UBYTE *)AllocMem(size, MEMF_CHIP | MEMF_PUBLIC);
  146.     if (new_buffer == NULL)
  147.         return false;
  148.     FreeMem(buffer, buffer_size);
  149.     buffer = new_buffer;
  150.     buffer_size = size;
  151.     return true;
  152. }
  153.  
  154.  
  155. /*
  156.  *  Set SCSI command to be sent by scsi_send_cmd()
  157.  */
  158.  
  159. void scsi_set_cmd(int cmd_length, uint8 *cmd)
  160. {
  161.     scsi.scsi_CmdLength = cmd_length;
  162.     memcpy(cmd_buffer, cmd, cmd_length);
  163. }
  164.  
  165.  
  166. /*
  167.  *  Check for presence of SCSI target
  168.  */
  169.  
  170. bool scsi_is_target_present(int id)
  171. {
  172.     return ios[id * 8] != NULL;
  173. }
  174.  
  175.  
  176. /*
  177.  *  Set SCSI target (returns false on error)
  178.  */
  179.  
  180. bool scsi_set_target(int id, int lun)
  181. {
  182.     struct IOStdReq *new_io = ios[id * 8 + lun];
  183.     if (new_io == NULL)
  184.         return false;
  185.     if (new_io != io)
  186.         scsi.scsi_SenseActual = 0;    // Clear sense data when selecting new target
  187.     io = new_io;
  188.     return true;
  189. }
  190.  
  191.  
  192. /*
  193.  *  Send SCSI command to active target (scsi_set_command() must have been called),
  194.  *  read/write data according to S/G table (returns false on error); timeout is in 1/60 sec
  195.  */
  196.  
  197. bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout)
  198. {
  199.     // Check if buffer is large enough, allocate new buffer if needed
  200.     if (!try_buffer(data_length)) {
  201.         char str[256];
  202.         sprintf(str, GetString(STR_SCSI_BUFFER_ERR), data_length);
  203.         ErrorAlert(str);
  204.         return false;
  205.     }
  206.  
  207.     // Process S/G table when writing
  208.     if (!reading) {
  209.         D(bug(" writing to buffer\n"));
  210.         uint8 *buffer_ptr = buffer;
  211.         for (int i=0; i<sg_size; i++) {
  212.             uint32 len = sg_len[i];
  213.             D(bug("  %d bytes from %08lx\n", len, sg_ptr[i]));
  214.             memcpy(buffer_ptr, sg_ptr[i], len);
  215.             buffer_ptr += len;
  216.         }
  217.     }
  218.  
  219.     // Request Sense and autosense data valid?
  220.     BYTE res = 0;
  221.     if (cmd_buffer[0] == 0x03 && scsi.scsi_SenseActual) {
  222.  
  223.         // Yes, fake command
  224.         D(bug(" autosense\n"));
  225.         memcpy(buffer, sense_buffer, scsi.scsi_SenseActual);
  226.         scsi.scsi_Status = 0;
  227.  
  228.     } else {
  229.  
  230.         // No, send regular command
  231.         D(bug(" sending command, length %ld\n", data_length));
  232.         scsi.scsi_Data = (UWORD *)buffer;
  233.         scsi.scsi_Length = data_length;
  234.         scsi.scsi_Actual = 0;
  235.         scsi.scsi_Flags = (reading ? SCSIF_READ : SCSIF_WRITE) | SCSIF_AUTOSENSE;
  236.         scsi.scsi_SenseActual = 0;
  237.         scsi.scsi_Status = 0;
  238.         res = DoIO((struct IORequest *)io);
  239.         D(bug(" command sent, res %d, status %d\n", res, scsi.scsi_Status));
  240.         *stat = scsi.scsi_Status;
  241.     }
  242.  
  243.     // Process S/G table when reading
  244.     if (res == 0) {
  245.         D(bug(" reading from buffer\n"));
  246.         uint8 *buffer_ptr = buffer;
  247.         for (int i=0; i<sg_size; i++) {
  248.             uint32 len = sg_len[i];
  249.             D(bug("  %d bytes to %08lx\n", len, sg_ptr[i]));
  250.             memcpy(sg_ptr[i], buffer_ptr, len);
  251.             buffer_ptr += len;
  252.         }
  253.     }
  254.     return res == 0;
  255. }
  256.