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

  1. /*
  2.  *  scsi.cpp - SCSI Manager
  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. /*
  22.  *  SEE ALSO
  23.  *    Inside Macintosh: Devices, chapter 3 "SCSI Manager"
  24.  *    Technote DV 24: "Fear No SCSI"
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <string.h>
  29.  
  30. #include "sysdeps.h"
  31. #include "cpu_emulation.h"
  32. #include "main.h"
  33. #include "user_strings.h"
  34. #include "scsi.h"
  35.  
  36. #define DEBUG 0
  37. #include "debug.h"
  38.  
  39.  
  40. // Error codes
  41. enum {
  42.     scCommErr = 2,
  43.     scArbNBErr,
  44.     scBadParmsErr,
  45.     scPhaseErr,
  46.     scCompareErr,
  47.     scMgrBusyErr,
  48.     scSequenceErr,
  49.     scBusTOErr,
  50.     scComplPhaseErr
  51. };
  52.  
  53. // TIB opcodes
  54. enum {
  55.     scInc = 1,
  56.     scNoInc,
  57.     scAdd,
  58.     scMove,
  59.     scLoop,
  60.     scNop,
  61.     scStop,
  62.     scComp
  63. };
  64.  
  65. // Logical SCSI phases
  66. enum {
  67.     PH_FREE,        // Bus free
  68.     PH_ARBITRATED,    // Bus arbitrated (after SCSIGet())
  69.     PH_SELECTED,    // Target selected (after SCSISelect())
  70.     PH_TRANSFER        // Command sent (after SCSICmd())
  71. };
  72.  
  73. // Global variables
  74. static int target_id;                    // ID of active target
  75. static int phase;                        // Logical SCSI phase
  76. static uint16 fake_status;                // Faked 5830 status word
  77. static bool reading;                    // Flag: reading from device
  78.  
  79. const int SG_TABLE_SIZE = 1024;
  80. static int sg_index;                    // Index of first unused entry in S/G table
  81. static uint8 *sg_ptr[SG_TABLE_SIZE];    // Scatter/gather table data pointer (host address space)
  82. static uint32 sg_len[SG_TABLE_SIZE];    // Scatter/gather table data length
  83. static uint32 sg_total_length;            // Total data length
  84.  
  85.  
  86. /*
  87.  *  Execute TIB, constructing S/G table
  88.  */
  89.  
  90. static int16 exec_tib(uint32 tib)
  91. {
  92.     for (;;) {
  93.  
  94.         // Read next opcode and parameters
  95.         uint16 cmd = ReadMacInt16(tib); tib += 2;
  96.         uint32 ptr = ReadMacInt32(tib); tib += 4;
  97.         uint32 len = ReadMacInt32(tib); tib += 4;
  98.  
  99.         D(bug(" %d %08x %d\n", cmd, ptr, len));
  100.  
  101.         switch (cmd) {
  102.             case scInc:
  103.                 WriteMacInt32(tib - 8, ptr + len);
  104.             case scNoInc:
  105.                 if ((sg_index > 0) && (Mac2HostAddr(ptr) == sg_ptr[sg_index-1] + sg_len[sg_index-1]))
  106.                     sg_len[sg_index-1] += len;                // Merge to previous entry
  107.                 else {
  108.                     if (sg_index == SG_TABLE_SIZE) {
  109.                         ErrorAlert(GetString(STR_SCSI_SG_FULL_ERR));
  110.                         return -108;
  111.                     }
  112.                     sg_ptr[sg_index] = Mac2HostAddr(ptr);    // Create new entry
  113.                     sg_len[sg_index] = len;
  114.                     sg_index++;
  115.                 }
  116.                 sg_total_length += len;
  117.                 break;
  118.  
  119.             case scAdd:
  120.                 WriteMacInt32(ptr, ReadMacInt32(ptr) + len);
  121.                 break;
  122.  
  123.             case scMove:
  124.                 WriteMacInt32(len, ReadMacInt32(ptr));
  125.                 break;
  126.  
  127.             case scLoop:
  128.                 WriteMacInt32(tib - 4, len - 1);
  129.                 if (len - 1 > 0)
  130.                     tib += (int32)ptr - 10;
  131.                 break;
  132.  
  133.             case scNop:
  134.                 break;
  135.  
  136.             case scStop:
  137.                 return 0;
  138.  
  139.             case scComp:
  140.                 printf("WARNING: Unimplemented scComp opcode\n");
  141.                 return scCompareErr;
  142.  
  143.             default:
  144.                 printf("FATAL: Unrecognized TIB opcode %d\n", cmd);
  145.                 return scBadParmsErr;
  146.         }
  147.     }
  148. }
  149.  
  150.  
  151. /*
  152.  *  Reset SCSI bus
  153.  */
  154.  
  155. int16 SCSIReset(void)
  156. {
  157.     D(bug("SCSIReset\n"));
  158.  
  159.     phase = PH_FREE;
  160.     fake_status = 0x0000;    // Bus free
  161.     sg_index = 0;
  162.     target_id = 8;
  163.     return 0;
  164. }
  165.  
  166.  
  167. /*
  168.  *  Arbitrate bus
  169.  */
  170.  
  171. int16 SCSIGet(void)
  172. {
  173.     D(bug("SCSIGet\n"));
  174.     if (phase != PH_FREE)
  175.         return scMgrBusyErr;
  176.  
  177.     phase = PH_ARBITRATED;
  178.     fake_status = 0x0040;    // Bus busy
  179.     reading = false;
  180.     sg_index = 0;            // Flush S/G table
  181.     sg_total_length = 0;
  182.     return 0;
  183. }
  184.  
  185.  
  186. /*
  187.  *  Select SCSI device
  188.  */
  189.  
  190. int16 SCSISelect(int id)
  191. {
  192.     D(bug("SCSISelect %d\n", id));
  193.     if (phase != PH_ARBITRATED)
  194.         return scSequenceErr;
  195.  
  196.     // ID valid?
  197.     if (id >= 0 && id <= 7) {
  198.         target_id = id;
  199.  
  200.         // Target present?
  201.         if (scsi_is_target_present(target_id)) {
  202.             phase = PH_SELECTED;
  203.             fake_status = 0x006a;            // Target selected, command phase
  204.             return 0;
  205.         }
  206.     }
  207.  
  208.     // Error
  209.     phase = PH_FREE;
  210.     fake_status = 0x0000;        // Bus free
  211.     return scCommErr;
  212. }
  213.  
  214.  
  215. /*
  216.  *  Send SCSI command
  217.  */
  218.  
  219. int16 SCSICmd(int cmd_length, uint8 *cmd)
  220. {
  221.     D(bug("SCSICmd len %d, cmd %08x%08x%08x\n", cmd_length, ntohl(0[(uint32 *)cmd]), ntohl(1[(uint32 *)cmd]), ntohl(2[(uint32 *)cmd])));
  222.     if (phase != PH_SELECTED)
  223.         return scPhaseErr;
  224.  
  225.     // Commdn length valid?
  226.     if (cmd_length != 6 && cmd_length != 10 && cmd_length != 12)
  227.         return scBadParmsErr;
  228.  
  229.     // Set command, extract LUN
  230.     scsi_set_cmd(cmd_length, cmd);
  231.  
  232.     // Extract LUN, set target
  233.     if (!scsi_set_target(target_id, (cmd[1] >> 5) & 7)) {
  234.         phase = PH_FREE;
  235.         fake_status = 0x0000;    // Bus free
  236.         return scCommErr;
  237.     }
  238.  
  239.     phase = PH_TRANSFER;
  240.     fake_status = 0x006e;        // Target selected, data phase
  241.     return 0;
  242. }
  243.  
  244.  
  245. /*
  246.  *  Read data
  247.  */
  248.  
  249. int16 SCSIRead(uint32 tib)
  250. {
  251.     D(bug("SCSIRead TIB %08lx\n", tib));
  252.     if (phase != PH_TRANSFER)
  253.         return scPhaseErr;
  254.  
  255.     // Execute TIB, fill S/G table
  256.     reading = true;
  257.     return exec_tib(tib);
  258. }
  259.  
  260.  
  261. /*
  262.  *  Write data
  263.  */
  264.  
  265. int16 SCSIWrite(uint32 tib)
  266. {
  267.     D(bug("SCSIWrite TIB %08lx\n", tib));
  268.     if (phase != PH_TRANSFER)
  269.         return scPhaseErr;
  270.  
  271.     // Execute TIB, fill S/G table
  272.     return exec_tib(tib);
  273. }
  274.  
  275.  
  276. /*
  277.  *  Wait for command completion (we're actually doing everything in here...)
  278.  */
  279.  
  280. int16 SCSIComplete(uint32 timeout, uint32 message, uint32 stat)
  281. {
  282.     D(bug("SCSIComplete wait %d, msg %08lx, stat %08lx\n", timeout, message, stat));
  283.     WriteMacInt16(message, 0);
  284.     if (phase != PH_TRANSFER)
  285.         return scPhaseErr;
  286.  
  287.     // Send command, process S/G table
  288.     uint16 scsi_stat = 0;
  289.     bool success = scsi_send_cmd(sg_total_length, reading, sg_index, sg_ptr, sg_len, &scsi_stat, timeout);
  290.     WriteMacInt16(stat, scsi_stat);
  291.  
  292.     // Complete command
  293.     phase = PH_FREE;
  294.     fake_status = 0x0000;    // Bus free
  295.     return success ? 0 : scCommErr;
  296. }
  297.  
  298.  
  299. /*
  300.  *  Get bus status
  301.  */
  302.  
  303. uint16 SCSIStat(void)
  304. {
  305.     D(bug("SCSIStat returns %04x\n", fake_status));
  306.     return fake_status;
  307. }
  308.  
  309.  
  310. /*
  311.  *  SCSI Manager busy?
  312.  */
  313.  
  314. int16 SCSIMgrBusy(void)
  315. {
  316. //    D(bug("SCSIMgrBusy\n"));
  317.     return phase != PH_FREE;
  318. }
  319.