1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * SCSI emulation (not uaescsi.device)
5 *
6 * Copyright 2007 Toni Wilen
7 *
8 */
9
10 #include "sysconfig.h"
11 #include "sysdeps.h"
12
13 #include "options.h"
14 #include "scsi.h"
15 #include "filesys.h"
16 #include "blkdev.h"
17
18 static int outcmd[] = { 0x0a, 0x2a, 0x2f, 0xaa, 0x15, 0x55, -1 };
19 static int incmd[] = { 0x03, 0x08, 0x12, 0x1a, 0x5a, 0x25, 0x28, 0x37, 0x42, 0x43, 0xa8, 0x51, 0x52, -1 };
20 static int nonecmd[] = { 0x00, 0x1b, 0x1e, 0x35, -1 };
21 static int scsicmdsizes[] = { 6, 10, 10, 12, 16, 12, 10, 10 };
22
scsi_data_dir(struct scsi_data * sd)23 static int scsi_data_dir(struct scsi_data *sd)
24 {
25 int i;
26 uae_u8 cmd;
27
28 cmd = sd->cmd[0];
29 for (i = 0; outcmd[i] >= 0; i++) {
30 if (cmd == outcmd[i]) {
31 return 1;
32 }
33 }
34 for (i = 0; incmd[i] >= 0; i++) {
35 if (cmd == incmd[i]) {
36 return -1;
37 }
38 }
39 for (i = 0; nonecmd[i] >= 0; i++) {
40 if (cmd == nonecmd[i]) {
41 return 0;
42 }
43 }
44 write_log (_T("SCSI command %02X, no direction specified!\n"), sd->cmd[0]);
45 return 0;
46 }
47
scsi_emulate_analyze(struct scsi_data * sd)48 void scsi_emulate_analyze (struct scsi_data *sd)
49 {
50 int cmd_len, data_len;
51
52 data_len = sd->data_len;
53 cmd_len = scsicmdsizes[sd->cmd[0] >> 5];
54 switch (sd->cmd[0])
55 {
56 case 0x0a:
57 data_len = sd->cmd[4] * sd->blocksize;
58 break;
59 case 0x2a:
60 data_len = ((sd->cmd[7] << 8) | (sd->cmd[8] << 0)) * (uae_s64)sd->blocksize;
61 break;
62 case 0xaa:
63 data_len = ((sd->cmd[6] << 24) | (sd->cmd[7] << 16) | (sd->cmd[8] << 8) | (sd->cmd[9] << 0)) * (uae_s64)sd->blocksize;
64 break;
65 }
66 sd->cmd_len = cmd_len;
67 sd->data_len = data_len;
68 sd->direction = scsi_data_dir (sd);
69 }
70
scsi_illegal_lun(struct scsi_data * sd)71 void scsi_illegal_lun(struct scsi_data *sd)
72 {
73 uae_u8 *s = sd->sense;
74
75 memset (s, 0, sizeof (sd->sense));
76 sd->status = 2; /* CHECK CONDITION */
77 s[0] = 0x70;
78 s[2] = 5; /* ILLEGAL REQUEST */
79 s[12] = 0x25; /* INVALID LUN */
80 sd->sense_len = 0x12;
81 }
82
scsi_emulate_cmd(struct scsi_data * sd)83 void scsi_emulate_cmd(struct scsi_data *sd)
84 {
85 sd->status = 0;
86 if ((sd->message[0] & 0xc0) == 0x80 && (sd->message[0] & 0x1f)) {
87 uae_u8 lun = sd->message[0] & 0x1f;
88 if (lun > 7)
89 lun = 7;
90 sd->cmd[1] &= ~(7 << 5);
91 sd->cmd[1] |= lun << 5;
92 }
93 //write_log (_T("CMD=%02x\n"), sd->cmd[0]);
94 if (sd->cd_emu_unit >= 0) {
95 if (sd->cmd[0] == 0x03) { /* REQUEST SENSE */
96 int len = sd->cmd[4];
97 scsi_cd_emulate(sd->cd_emu_unit, sd->cmd, 0, 0, 0, 0, 0, 0, 0, sd->atapi); /* ack request sense */
98 memset (sd->buffer, 0, len);
99 memcpy (sd->buffer, sd->sense, sd->sense_len > len ? len : sd->sense_len);
100 sd->data_len = len;
101 } else {
102 sd->status = scsi_cd_emulate(sd->cd_emu_unit, sd->cmd, sd->cmd_len, sd->buffer, &sd->data_len, sd->reply, &sd->reply_len, sd->sense, &sd->sense_len, sd->atapi);
103 if (sd->status == 0) {
104 if (sd->reply_len > 0) {
105 memset(sd->buffer, 0, 256);
106 memcpy(sd->buffer, sd->reply, sd->reply_len);
107 }
108 }
109 }
110 } else if (sd->nativescsiunit < 0) {
111 if (sd->cmd[0] == 0x03) { /* REQUEST SENSE */
112 int len = sd->cmd[4];
113 memset (sd->buffer, 0, len);
114 memcpy (sd->buffer, sd->sense, sd->sense_len > len ? len : sd->sense_len);
115 sd->data_len = len;
116 } else {
117 sd->status = scsi_hd_emulate(&sd->hfd->hfd, sd->hfd,
118 sd->cmd, sd->cmd_len, sd->buffer, &sd->data_len, sd->reply, &sd->reply_len, sd->sense, &sd->sense_len);
119 if (sd->status == 0) {
120 if (sd->reply_len > 0) {
121 memset(sd->buffer, 0, 256);
122 memcpy(sd->buffer, sd->reply, sd->reply_len);
123 }
124 }
125 }
126 } else {
127 struct amigascsi as;
128
129 memset(sd->sense, 0, 256);
130 memset(&as, 0, sizeof as);
131 memcpy (&as.cmd, sd->cmd, sd->cmd_len);
132 as.flags = 2 | 1;
133 if (sd->direction > 0)
134 as.flags &= ~1;
135 as.sense_len = 32;
136 as.cmd_len = sd->cmd_len;
137 as.data = sd->buffer;
138 as.len = sd->direction < 0 ? DEVICE_SCSI_BUFSIZE : sd->data_len;
139 sys_command_scsi_direct_native(sd->nativescsiunit, &as);
140 sd->status = as.status;
141 sd->data_len = as.len;
142 if (sd->status) {
143 sd->direction = 0;
144 sd->data_len = 0;
145 memcpy(sd->sense, as.sensedata, as.sense_len);
146 }
147 }
148 sd->offset = 0;
149 }
150
scsi_alloc_hd(int id,struct hd_hardfiledata * hfd)151 struct scsi_data *scsi_alloc_hd(int id, struct hd_hardfiledata *hfd)
152 {
153 struct scsi_data *sd = xcalloc (struct scsi_data, 1);
154 sd->hfd = hfd;
155 sd->id = id;
156 sd->nativescsiunit = -1;
157 sd->cd_emu_unit = -1;
158 sd->blocksize = hfd->hfd.ci.blocksize;
159 return sd;
160 }
161
scsi_alloc_cd(int id,int unitnum,bool atapi)162 struct scsi_data *scsi_alloc_cd(int id, int unitnum, bool atapi)
163 {
164 struct scsi_data *sd;
165 if (!sys_command_open (unitnum)) {
166 write_log (_T("SCSI: CD EMU scsi unit %d failed to open\n"), unitnum);
167 return NULL;
168 }
169 sd = xcalloc (struct scsi_data, 1);
170 sd->id = id;
171 sd->cd_emu_unit = unitnum;
172 sd->nativescsiunit = -1;
173 sd->atapi = atapi;
174 sd->blocksize = 2048;
175 return sd;
176 }
177
scsi_alloc_native(int id,int nativeunit)178 struct scsi_data *scsi_alloc_native(int id, int nativeunit)
179 {
180 struct scsi_data *sd;
181 if (!sys_command_open (nativeunit)) {
182 write_log (_T("SCSI: native scsi unit %d failed to open\n"), nativeunit);
183 return NULL;
184 }
185 sd = xcalloc (struct scsi_data, 1);
186 sd->id = id;
187 sd->nativescsiunit = nativeunit;
188 sd->cd_emu_unit = -1;
189 sd->blocksize = 2048;
190 return sd;
191 }
192
scsi_reset(void)193 void scsi_reset(void)
194 {
195 //device_func_init (DEVICE_TYPE_SCSI);
196 }
197
scsi_free(struct scsi_data * sd)198 void scsi_free(struct scsi_data *sd)
199 {
200 if (!sd)
201 return;
202 if (sd->nativescsiunit >= 0) {
203 sys_command_close (sd->nativescsiunit);
204 sd->nativescsiunit = -1;
205 }
206 if (sd->cd_emu_unit >= 0) {
207 sys_command_close (sd->cd_emu_unit);
208 sd->cd_emu_unit = -1;
209 }
210 xfree(sd);
211 }
212
scsi_start_transfer(struct scsi_data * sd)213 void scsi_start_transfer(struct scsi_data *sd)
214 {
215 sd->offset = 0;
216 }
217
scsi_send_data(struct scsi_data * sd,uae_u8 b)218 int scsi_send_data(struct scsi_data *sd, uae_u8 b)
219 {
220 if (sd->direction == 1) {
221 if (sd->offset >= SCSI_DATA_BUFFER_SIZE) {
222 write_log (_T("SCSI data buffer overflow!\n"));
223 return 0;
224 }
225 sd->buffer[sd->offset++] = b;
226 } else if (sd->direction == 2) {
227 if (sd->offset >= 16) {
228 write_log (_T("SCSI command buffer overflow!\n"));
229 return 0;
230 }
231 sd->cmd[sd->offset++] = b;
232 if (sd->offset == sd->cmd_len)
233 return 1;
234 } else {
235 write_log (_T("scsi_send_data() without direction!\n"));
236 return 0;
237 }
238 if (sd->offset == sd->data_len)
239 return 1;
240 return 0;
241 }
242
scsi_receive_data(struct scsi_data * sd,uae_u8 * b)243 int scsi_receive_data(struct scsi_data *sd, uae_u8 *b)
244 {
245 if (!sd->data_len)
246 return -1;
247 *b = sd->buffer[sd->offset++];
248 if (sd->offset == sd->data_len)
249 return 1; // requested length got
250 return 0;
251 }
252