AmendHub

Download

jcs

/

detritus

/

scsi.c

 

(View History)

jcs   *: Shuffle things around yet again Latest amendment: 30 on 2024-11-11

1 /*
2 * Copyright (c) 2023 joshua stein <jcs@jcs.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <SCSI.h>
18 #include <string.h>
19 #include <stdio.h>
20
21 #include "detritus.h"
22 #include "request.h"
23
24 struct scsi_inquiry {
25 unsigned char deviceType;
26 unsigned char deviceQualifier;
27 unsigned char version;
28 unsigned char responseFormat;
29 unsigned char additionalLength;
30 unsigned char vendor;
31 short reserved;
32 unsigned char vendorID[8];
33 unsigned char productID[16];
34 unsigned char revision[4];
35 unsigned char vendor2[20];
36 unsigned char reserved2[42];
37 unsigned char vendor3[158];
38 };
39
40 enum {
41 SCSI_READ,
42 SCSI_READ_UNKNOWN_SIZE,
43 SCSI_WRITE
44 };
45
46 #define BLUESCSI_TLS_CMD 0x1d
47 #define BLUESCSI_TLS_CMD_INIT 0x01
48 #define BLUESCSI_TLS_CMD_STATUS 0x02
49 #define BLUESCSI_TLS_CMD_READ_PLAIN 0x03
50 #define BLUESCSI_TLS_CMD_WRITE_PLAIN 0x04
51 #define BLUESCSI_TLS_CMD_READ_CIPHER 0x05
52 #define BLUESCSI_TLS_CMD_WRITE_CIPHER 0x06
53 #define BLUESCSI_TLS_CMD_CLOSE 0x07
54
55 uint8_t tls_req_last_id = 1;
56 static short tls_scsi_id = -1;
57 static struct SCSIInstr tib[2];
58 static unsigned char scsi_buf[2048];
59
60 short scsi_io(unsigned char *cdb, unsigned long cdb_len, short io_type,
61 unsigned char *buf, unsigned long len);
62
63 bool
64 scsi_can_do_tls(void)
65 {
66 return (tls_scsi_id != -1);
67 }
68
69 short
70 scsi_find_tls(void)
71 {
72 struct scsi_inquiry inq;
73 unsigned char cdb[16] = { 0 };
74 short stat, msg, err;
75 short i, scsi_id;
76
77 cdb[0] = 0x12; /* inquiry */
78 cdb[4] = 5; /* length */
79
80 tib[0].scOpcode = scNoInc;
81 tib[0].scParam1 = (unsigned long)&inq;
82 tib[0].scParam2 = 5;
83 tib[1].scOpcode = scStop;
84 tib[1].scParam1 = 0;
85 tib[1].scParam2 = 0;
86
87 SCSIReset();
88
89 for (scsi_id = 0; scsi_id <= 7; scsi_id++) {
90 for (i = 0; i <= 1; i++) {
91 if (SCSIGet() != noErr)
92 goto scan_failed;
93
94 if (SCSISelect(scsi_id) != noErr)
95 break;
96
97 if (SCSICmd((Ptr)&cdb, 6) != noErr) {
98 SCSIComplete(&stat, &msg, 300);
99 goto scan_failed;
100 }
101
102 memset(&inq, 0, sizeof(inq));
103
104 if (SCSIRead((Ptr)&tib) != noErr) {
105 SCSIComplete(&stat, &msg, 300);
106 goto scan_failed;
107 }
108
109 if (i == 0) {
110 cdb[4] += inq.additionalLength;
111 tib[0].scParam2 += inq.additionalLength;
112 }
113
114 if (SCSIComplete(&stat, &msg, 300) != noErr)
115 goto scan_failed;
116
117 if (memcmp(inq.vendorID, "BlueSCSI", 8) == 0 &&
118 memcmp(inq.productID, "TLS", 3) == 0) {
119 tls_scsi_id = scsi_id;
120 return noErr;
121 }
122 }
123 }
124
125 scan_failed:
126 return -1;
127 }
128
129 uint8_t
130 scsi_tls_init(struct tls_init_request *req)
131 {
132 unsigned char cdb[6];
133 unsigned short size;
134 uint8_t tls_id;
135
136 tls_id = ++tls_req_last_id;
137
138 memset(cdb, 0, sizeof(cdb));
139 cdb[0] = BLUESCSI_TLS_CMD;
140 cdb[1] = BLUESCSI_TLS_CMD_INIT;
141 cdb[2] = tls_id;
142
143 size = sizeof(struct tls_init_request);
144 cdb[3] = (size >> 8) & 0xff;
145 cdb[4] = size & 0xff;
146
147 memcpy(scsi_buf, req, size);
148
149 if (scsi_io(cdb, sizeof(cdb), SCSI_WRITE, scsi_buf, size) == -1)
150 return 0;
151
152 return tls_id;
153 }
154
155 bool
156 scsi_tls_close(uint8_t tls_id)
157 {
158 unsigned char cdb[6];
159
160 memset(cdb, 0, sizeof(cdb));
161 cdb[0] = BLUESCSI_TLS_CMD;
162 cdb[1] = BLUESCSI_TLS_CMD_CLOSE;
163 cdb[2] = tls_id;
164
165 return (scsi_io(cdb, sizeof(cdb), SCSI_WRITE, NULL, 0) != -1);
166 }
167
168 short
169 scsi_tls_status(uint8_t tls_id, short *cipherspace, short *plainspace,
170 short *error)
171 {
172 unsigned char cdb[6];
173 size_t size;
174 short ret;
175
176 memset(cdb, 0, sizeof(cdb));
177 cdb[0] = BLUESCSI_TLS_CMD;
178 cdb[1] = BLUESCSI_TLS_CMD_STATUS;
179 cdb[2] = tls_id;
180
181 ret = scsi_io(cdb, sizeof(cdb), SCSI_READ, (unsigned char *)&scsi_buf, 8);
182 if (ret != 8)
183 return 0;
184
185 *cipherspace = ((short)scsi_buf[2] << 8) | scsi_buf[3];
186 *plainspace = ((short)scsi_buf[4] << 8) | scsi_buf[5];
187 *error = ((short)scsi_buf[6] << 8) | scsi_buf[7];
188
189 return (((short)scsi_buf[0] << 8) | scsi_buf[1]);
190 }
191
192 size_t
193 scsi_tls_read(uint8_t tls_id, unsigned char **buf, size_t max_size,
194 bool cipher)
195 {
196 unsigned char cdb[6];
197 short ret;
198
199 if (*buf == NULL) {
200 *buf = (unsigned char *)&scsi_buf;
201 if (max_size == 0 || max_size > sizeof(scsi_buf))
202 max_size = sizeof(scsi_buf);
203 }
204
205 memset(cdb, 0, sizeof(cdb));
206 cdb[0] = BLUESCSI_TLS_CMD;
207 if (cipher)
208 cdb[1] = BLUESCSI_TLS_CMD_READ_CIPHER;
209 else
210 cdb[1] = BLUESCSI_TLS_CMD_READ_PLAIN;
211 cdb[2] = tls_id;
212 cdb[3] = (max_size >> 8) & 0xff;
213 cdb[4] = max_size & 0xff;
214
215 ret = scsi_io(cdb, sizeof(cdb), SCSI_READ_UNKNOWN_SIZE, *buf, max_size);
216 if (ret < 0) {
217 *buf = NULL;
218 return 0;
219 }
220
221 return ret;
222 }
223
224 size_t
225 scsi_tls_write(uint8_t tls_id, unsigned char *buf, size_t buf_size,
226 bool cipher)
227 {
228 unsigned char cdb[6];
229 short ret;
230
231 memset(cdb, 0, sizeof(cdb));
232 cdb[0] = BLUESCSI_TLS_CMD;
233 if (cipher)
234 cdb[1] = BLUESCSI_TLS_CMD_WRITE_CIPHER;
235 else
236 cdb[1] = BLUESCSI_TLS_CMD_WRITE_PLAIN;
237 cdb[2] = tls_id;
238 cdb[3] = (buf_size >> 8) & 0xff;
239 cdb[4] = buf_size & 0xff;
240
241 ret = scsi_io(cdb, sizeof(cdb), SCSI_WRITE, buf, buf_size);
242 if (ret < 0)
243 return 0;
244
245 return ret;
246 }
247
248 short
249 scsi_io(unsigned char *cdb, unsigned long cdb_len, short io_type,
250 unsigned char *buf, unsigned long len)
251 {
252 short ret, ioret, stat, msg, err, tlen;
253
254 if (SCSIGet() != noErr) {
255 warn("SCSIGet failed");
256 return -1;
257 }
258
259 if (SCSISelect(tls_scsi_id) != noErr) {
260 warn("SCSISelect failed");
261 return -1;
262 }
263
264 if (SCSICmd((Ptr)cdb, cdb_len) != noErr) {
265 SCSIComplete(&stat, &msg, 300);
266 warn("SCSICmd failed");
267 return -1;
268 }
269
270 if (len) {
271 switch (io_type) {
272 case SCSI_READ:
273 memset(buf, 0, len);
274
275 tib[0].scOpcode = scNoInc;
276 tib[0].scParam1 = (long)buf;
277 tib[0].scParam2 = len;
278 tib[1].scOpcode = scStop;
279 tib[1].scParam1 = 0;
280 tib[1].scParam2 = 0;
281
282 ioret = SCSIRead((Ptr)&tib);
283 break;
284 case SCSI_READ_UNKNOWN_SIZE:
285 memset(buf, 0, len);
286
287 tib[0].scOpcode = scNoInc;
288 tib[0].scParam1 = (long)buf;
289 tib[0].scParam2 = 2;
290 tib[1].scOpcode = scStop;
291 tib[1].scParam1 = 0;
292 tib[1].scParam2 = 0;
293
294 ioret = SCSIRead((Ptr)&tib);
295 tlen = ((short)buf[0] << 8) + buf[1];
296
297 if (tlen > len) {
298 warn("SCSI trying to read %ld bytes but buf is only %ld",
299 tlen, len);
300 tlen = len;
301 }
302
303 len = tlen;
304
305 if (tlen) {
306 memset(buf, 0, tlen);
307 tib[0].scOpcode = scNoInc;
308 tib[0].scParam1 = (long)buf;
309 tib[0].scParam2 = tlen;
310 tib[1].scOpcode = scStop;
311 tib[1].scParam1 = 0;
312 tib[1].scParam2 = 0;
313
314 ioret = SCSIRead((Ptr)&tib);
315 }
316
317 break;
318 case SCSI_WRITE:
319 tib[0].scOpcode = scNoInc;
320 tib[0].scParam1 = (long)buf;
321 tib[0].scParam2 = len;
322 tib[1].scOpcode = scStop;
323 tib[1].scParam1 = 0;
324 tib[1].scParam2 = 0;
325
326 ioret = SCSIWrite((Ptr)&tib);
327 break;
328 }
329 } else {
330 tib[0].scOpcode = scStop;
331 tib[0].scParam1 = 0;
332 tib[0].scParam2 = 0;
333
334 ioret = SCSIWrite((Ptr)&tib);
335 }
336
337 /* complete and free the bus before responding to the read/write */
338 if ((ret = SCSIComplete(&stat, &msg, 300 /* 1/60 ticks */)) != noErr) {
339 warn("SCSIComplete failed");
340 return -1;
341 }
342
343 if (ioret != noErr && ioret != scPhaseErr)
344 warn("SCSIRead/Write failed");
345
346 if (stat != noErr)
347 return -1;
348
349 return len;
350 }
351
352 void
353 scsi_cleanup(void)
354 {
355 short stat, msg;
356
357 SCSIComplete(&stat, &msg, 60);
358 }