]> git.sesse.net Git - pistorm/blob - platforms/amiga/piscsi/device_driver_amiga/piscsi-amiga.c
be3738e5ee16a3058ab79d3203766c4bbc842745
[pistorm] / platforms / amiga / piscsi / device_driver_amiga / piscsi-amiga.c
1 /*
2  * Based on:
3  * Amiga ZZ9000 USB Storage Driver (ZZ9000USBStorage.device)
4  * Copyright (C) 2016-2020, Lukas F. Hartmann <lukas@mntre.com>
5  * Based on code Copyright (C) 2016, Jason S. McMullan <jason.mcmullan@gmail.com>
6  * All rights reserved.
7  *
8  * Licensed under the MIT License:
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining
11  * a copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  */
28
29 #include <exec/resident.h>
30 #include <exec/errors.h>
31 #include <exec/memory.h>
32 #include <exec/lists.h>
33 #include <exec/alerts.h>
34 #include <exec/tasks.h>
35 #include <exec/io.h>
36 #include <exec/execbase.h>
37
38 #include <libraries/expansion.h>
39
40 #include <devices/trackdisk.h>
41 #include <devices/timer.h>
42 #include <devices/scsidisk.h>
43
44 #include <dos/filehandler.h>
45
46 #include <proto/exec.h>
47 #include <proto/disk.h>
48 #include <proto/expansion.h>
49
50 #include <clib/debug_protos.h>
51 #include <stdint.h>
52 #include <stdlib.h>
53 #include "../piscsi-enums.h"
54
55 #define WRITESHORT(cmd, val) *(unsigned short *)((unsigned long)(PISCSI_OFFSET+cmd)) = val;
56 #define WRITELONG(cmd, val) *(unsigned long *)((unsigned long)(PISCSI_OFFSET+cmd)) = val;
57 #define WRITEBYTE(cmd, val) *(unsigned char *)((unsigned long)(PISCSI_OFFSET+cmd)) = val;
58
59 #define READSHORT(cmd, var) var = *(volatile unsigned short *)(PISCSI_OFFSET + cmd);
60 #define READLONG(cmd, var) var = *(volatile unsigned long *)(PISCSI_OFFSET + cmd);
61
62 #pragma pack(4)
63 struct piscsi_base {
64     struct Device* pi_dev;
65     struct piscsi_unit {
66         struct Unit unit;
67         uint32_t regs_ptr;
68
69         uint8_t enabled;
70         uint8_t present;
71         uint8_t valid;
72         uint8_t read_only;
73         uint8_t motor;
74         uint8_t unit_num;
75         uint16_t h, s;
76         uint32_t c;
77
78         uint32_t change_num;
79     } units[NUM_UNITS];
80 };
81
82 struct ExecBase* SysBase = NULL;
83
84 #ifdef _FSCSIDEV
85 const char DevName[] = "scsi.device";
86 #elif _FSCSI2ND
87 const char DevName[] = "2nd.scsi.device";
88 #else
89 const char DevName[] = "pi-scsi.device";
90 #endif
91 const char DevIdString[] = "Pi-SCSI 0.1";
92
93 const UWORD DevVersion = 43;
94 const UWORD DevRevision = 10;
95
96 #include "stabs.h"
97
98 struct piscsi_base *dev_base = NULL;
99
100 struct WBStartup *_WBenchMsg = NULL;
101
102 //#define exit(...)
103 //#define debug(...)
104 #define KPrintF(...)
105 #define debug(...)
106 #define debugval(...)
107 //#define debug(c, v) WRITESHORT(c, v)
108 //#define debugval(c, v) WRITELONG(c, v)
109
110 //#define bug(x,args...) KPrintF(x ,##args);
111 //#define debug(x,args...) bug("%s:%ld " x "\n", __func__, (unsigned long)__LINE__ ,##args)
112
113 uint8_t piscsi_perform_io(struct piscsi_unit *u, struct IORequest *io);
114 uint8_t piscsi_rw(struct piscsi_unit *u, struct IORequest *io, uint32_t offset, uint8_t write);
115 uint8_t piscsi_scsi(struct piscsi_unit *u, struct IORequest *io);
116
117 extern void* DOSBase[2];
118
119 uint32_t __UserDevInit(struct Device* dev) {
120     //uint8_t* registers = NULL;
121     SysBase = *(struct ExecBase **)4L;
122
123     KPrintF("Initializing devices.\n");
124     debug(PISCSI_DBG_MSG, DBG_INIT);
125
126     dev_base = AllocMem(sizeof(struct piscsi_base), MEMF_PUBLIC | MEMF_CLEAR);
127     dev_base->pi_dev = dev;
128
129     for (int i = 0; i < NUM_UNITS; i++) {
130         uint16_t r = 0;
131         WRITESHORT(PISCSI_CMD_DRVNUM, i);
132         dev_base->units[i].regs_ptr = PISCSI_OFFSET;
133         READSHORT(PISCSI_CMD_DRVTYPE, r);
134         dev_base->units[i].enabled = r;
135         dev_base->units[i].present = r;
136         dev_base->units[i].valid = r;
137         dev_base->units[i].unit_num = i;
138         if (dev_base->units[i].present) {
139             READLONG(PISCSI_CMD_CYLS, dev_base->units[i].c);
140             READSHORT(PISCSI_CMD_HEADS, dev_base->units[i].h);
141             READSHORT(PISCSI_CMD_SECS, dev_base->units[i].s);
142             KPrintF("C/H/S: %ld / %ld / %ld\n", dev_base->units[i].c, dev_base->units[i].h, dev_base->units[i].s);
143
144             debugval(PISCSI_DBG_VAL1, dev_base->units[i].c);
145             debugval(PISCSI_DBG_VAL2, dev_base->units[i].h);
146             debugval(PISCSI_DBG_VAL3, dev_base->units[i].s);
147             debug(PISCSI_DBG_MSG, DBG_CHS);
148         }
149         dev_base->units[i].change_num++;
150         // Send any reset signal to the "SCSI" device here.
151     }
152
153     return 1;
154 }
155
156 uint32_t __UserDevCleanup(void) {
157     KPrintF("Cleaning up.\n");
158     debug(PISCSI_DBG_MSG, DBG_CLEANUP);
159     FreeMem(dev_base, sizeof(struct piscsi_base));
160     return 0;
161 }
162
163 uint32_t __UserDevOpen(struct IOExtTD *iotd, uint32_t num, uint32_t flags) {
164     struct Node* node = (struct Node*)iotd;
165     int io_err = IOERR_OPENFAIL;
166
167     //WRITESHORT(PISCSI_CMD_DEBUGME, 1);
168
169     int unit_num = 0;
170     WRITELONG(PISCSI_CMD_DRVNUM, num);
171     READLONG(PISCSI_CMD_DRVNUM, unit_num);
172
173     debugval(PISCSI_DBG_VAL1, unit_num);
174     debugval(PISCSI_DBG_VAL2, flags);
175     debugval(PISCSI_DBG_VAL3, num);
176     debug(PISCSI_DBG_MSG, DBG_OPENDEV);
177     KPrintF("Opening device %ld Flags: %ld (%lx)\n", unit_num, flags, flags);
178
179     if (iotd && unit_num < NUM_UNITS) {
180         if (dev_base->units[unit_num].enabled && dev_base->units[unit_num].present) {
181             io_err = 0;
182             iotd->iotd_Req.io_Unit = (struct Unit*)&dev_base->units[unit_num].unit;
183             iotd->iotd_Req.io_Unit->unit_flags = UNITF_ACTIVE;
184             iotd->iotd_Req.io_Unit->unit_OpenCnt = 1;
185         }
186     }
187
188 skip:;
189     iotd->iotd_Req.io_Error = io_err;
190
191     return io_err;
192 }
193
194 uint32_t __UserDevClose(struct IOExtTD *iotd) {
195   return 0;
196 }
197
198 void exit(int status) { }
199
200 ADDTABL_1(__BeginIO,a1);
201 void __BeginIO(struct IORequest *io) {
202     if (dev_base == NULL || io == NULL)
203         return;
204     
205     struct piscsi_unit *u;
206     struct Node* node = (struct Node*)io;
207     u = (struct piscsi_unit *)io->io_Unit;
208
209     if (node == NULL || u == NULL)
210         return;
211
212     debugval(PISCSI_DBG_VAL1, io->io_Command);
213     debugval(PISCSI_DBG_VAL2, io->io_Flags);
214     debugval(PISCSI_DBG_VAL3, (io->io_Flags & IOF_QUICK));
215     debug(PISCSI_DBG_MSG, DBG_BEGINIO);
216     KPrintF("io_Command = %ld, io_Flags = 0x%lx quick = %lx\n", io->io_Command, io->io_Flags, (io->io_Flags & IOF_QUICK));
217     io->io_Error = piscsi_perform_io(u, io);
218
219     if (!(io->io_Flags & IOF_QUICK)) {
220         ReplyMsg(&io->io_Message);
221     }
222 }
223
224 ADDTABL_1(__AbortIO,a1);
225 void __AbortIO(struct IORequest* io) {
226     debug(PISCSI_DBG_MSG, DBG_ABORTIO);
227     KPrintF("AbortIO!\n");
228     if (!io) return;
229     io->io_Error = IOERR_ABORTED;
230 }
231
232 uint8_t piscsi_rw(struct piscsi_unit *u, struct IORequest *io, uint32_t offset, uint8_t write) {
233     struct IOStdReq *iostd = (struct IOStdReq *)io;
234     struct IOExtTD *iotd = (struct IOExtTD *)io;
235
236     uint8_t* data;
237     uint32_t len, num_blocks;
238     uint32_t block, max_addr;
239     uint8_t sderr;
240
241     data = iotd->iotd_Req.io_Data;
242     len = iotd->iotd_Req.io_Length;
243     //uint32_t offset2 = iostd->io_Offset;
244
245     max_addr = 0xffffffff;
246
247     // well... if we had 64 bits this would make sense
248     if ((offset > max_addr) || (offset+len > max_addr))
249         return IOERR_BADADDRESS;
250     if (data == 0)
251         return IOERR_BADADDRESS;
252     if (len < PISCSI_BLOCK_SIZE) {
253         iostd->io_Actual = 0;
254         return IOERR_BADLENGTH;
255     }
256
257     //block = offset;// >> SD_SECTOR_SHIFT;
258     //num_blocks = len;// >> SD_SECTOR_SHIFT;
259     sderr = 0;
260
261     if (write) {
262         //uint32_t retries = 10;
263         //KPrintF("Write %lx -> %lx %lx\n", (uint32_t)data, offset, len);
264         WRITELONG(PISCSI_CMD_ADDR1, (offset >> 9));
265         WRITELONG(PISCSI_CMD_ADDR2, len);
266         WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
267         WRITESHORT(PISCSI_CMD_WRITE, u->unit_num);
268     } else {
269         //KPrintF("read %lx %lx -> %lx\n", offset, len, (uint32_t)data);
270         WRITELONG(PISCSI_CMD_ADDR1, (offset >> 9));
271         WRITELONG(PISCSI_CMD_ADDR2, len);
272         WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
273         WRITESHORT(PISCSI_CMD_READ, u->unit_num);
274     }
275
276     if (sderr) {
277         iostd->io_Actual = 0;
278
279         if (sderr & SCSIERR_TIMEOUT)
280             return TDERR_DiskChanged;
281         if (sderr & SCSIERR_PARAM)
282             return TDERR_SeekError;
283         if (sderr & SCSIERR_ADDRESS)
284             return TDERR_SeekError;
285         if (sderr & (SCSIERR_ERASESEQ | SCSIERR_ERASERES))
286             return TDERR_BadSecPreamble;
287         if (sderr & SCSIERR_CRC)
288             return TDERR_BadSecSum;
289         if (sderr & SCSIERR_ILLEGAL)
290             return TDERR_TooFewSecs;
291         if (sderr & SCSIERR_IDLE)
292             return TDERR_PostReset;
293
294         return TDERR_SeekError;
295     } else {
296         iostd->io_Actual = len;
297     }
298
299     return 0;
300 }
301
302 #define PISCSI_ID_STRING "PISTORM Fake SCSI Disk  0.1 1111111111111111"
303
304 uint8_t piscsi_scsi(struct piscsi_unit *u, struct IORequest *io)
305 {
306     struct IOStdReq *iostd = (struct IOStdReq *)io;
307     struct SCSICmd *scsi = iostd->io_Data;
308     //uint8_t* registers = sdu->sdu_Registers;
309     uint8_t *data = (uint8_t *)scsi->scsi_Data;
310     uint32_t i, block, blocks, maxblocks;
311     uint8_t err = 0;
312
313     KPrintF("SCSI len=%ld, cmd = %02lx %02lx %02lx ... (%ld)\n",
314         iostd->io_Length, scsi->scsi_Command[0],
315         scsi->scsi_Command[1], scsi->scsi_Command[2],
316         scsi->scsi_CmdLength);
317
318     debugval(PISCSI_DBG_VAL1, iostd->io_Length);
319     debugval(PISCSI_DBG_VAL2, scsi->scsi_Command[0]);
320     debugval(PISCSI_DBG_VAL3, scsi->scsi_Command[1]);
321     debugval(PISCSI_DBG_VAL4, scsi->scsi_Command[2]);
322     debugval(PISCSI_DBG_VAL5, scsi->scsi_CmdLength);
323     debug(PISCSI_DBG_MSG, DBG_SCSICMD);
324
325     //maxblocks = u->s * u->c * u->h;
326
327     if (scsi->scsi_CmdLength < 6) {
328         //KPrintF("SCSICMD BADLENGTH2");
329         return IOERR_BADLENGTH;
330     }
331
332     if (scsi->scsi_Command == NULL) {
333         //KPrintF("SCSICMD IOERR_BADADDRESS1");
334         return IOERR_BADADDRESS;
335     }
336
337     scsi->scsi_Actual = 0;
338     //iostd->io_Actual = sizeof(*scsi);
339
340     switch (scsi->scsi_Command[0]) {
341         case 0x00:      // TEST_UNIT_READY
342             err = 0;
343             break;
344         
345         case 0x12:      // INQUIRY
346             for (i = 0; i < scsi->scsi_Length; i++) {
347                 uint8_t val = 0;
348
349                 switch (i) {
350                     case 0: // SCSI device type: direct-access device
351                         val = (0 << 5) | 0;
352                         break;
353                     case 1: // RMB = 1
354                         val = (1 << 7);
355                         break;
356                     case 2: // VERSION = 0
357                         val = 0;
358                         break;
359                     case 3: // NORMACA=0, HISUP = 0, RESPONSE_DATA_FORMAT = 2
360                         val = (0 << 5) | (0 << 4) | 2;
361                         break;
362                     case 4: // ADDITIONAL_LENGTH = 44 - 4
363                         val = 44 - 4;
364                         break;
365                     default:
366                         if (i >= 8 && i < 44)
367                             val = PISCSI_ID_STRING[i - 8];
368                         else
369                             val = 0;
370                         break;
371                 }
372                 data[i] = val;
373             }
374             scsi->scsi_Actual = i;
375             err = 0;
376             break;
377         
378         case 0x08: // READ (6)
379         case 0x0a: // WRITE (6)
380             block = scsi->scsi_Command[1] & 0x1f;
381             block = (block << 8) | scsi->scsi_Command[2];
382             block = (block << 8) | scsi->scsi_Command[3];
383             blocks = scsi->scsi_Command[4];
384
385             READLONG(PISCSI_CMD_BLOCKS, maxblocks);
386             if (block + blocks > maxblocks) {
387                 err = IOERR_BADADDRESS;
388                 break;
389             }
390             /*if (scsi->scsi_Length < (blocks << SD_SECTOR_SHIFT)) {
391                 err = IOERR_BADLENGTH;
392                 break;
393             }*/
394             if (data == NULL) {
395                 err = IOERR_BADADDRESS;
396                 break;
397             }
398
399             if (scsi->scsi_Command[0] == 0x08) {
400                 //KPrintF("scsi_read %lx %lx\n",block,blocks);
401                 //KPrintF("SCSI read %lx %lx -> %lx\n", block, blocks, (uint32_t)data);
402                 WRITELONG(PISCSI_CMD_ADDR2, block);
403                 WRITELONG(PISCSI_CMD_ADDR2, (blocks << 9));
404                 WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
405                 WRITESHORT(PISCSI_CMD_READ, u->unit_num);
406             }
407             else {
408                 //KPrintF("scsi_write %lx %lx\n",block,blocks);
409                 //KPrintF("SCSI write %lx -> %lx %lx\n", (uint32_t)data, block, blocks);
410                 WRITELONG(PISCSI_CMD_ADDR2, block);
411                 WRITELONG(PISCSI_CMD_ADDR2, (blocks << 9));
412                 WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
413                 WRITESHORT(PISCSI_CMD_WRITE, u->unit_num);
414             }
415
416             scsi->scsi_Actual = scsi->scsi_Length;
417             err = 0;
418             break;
419         
420         case 0x25: // READ CAPACITY (10)
421             //KPrintF("SCSI command: Read Capacity.\n");
422             if (scsi->scsi_CmdLength < 10) {
423                 err = HFERR_BadStatus;
424                 break;
425             }
426
427             block = *((uint32_t*)&scsi->scsi_Command[2]);
428
429             /*if ((scsi->scsi_Command[8] & 1) || block != 0) {
430                 // PMI Not supported
431                 KPrintF("PMI not supported.\n");
432                 err = HFERR_BadStatus;
433                 break;
434             }*/
435
436             if (scsi->scsi_Length < 8) {
437                 err = IOERR_BADLENGTH;
438                 break;
439             }
440
441             READLONG(PISCSI_CMD_BLOCKS, blocks);
442             ((uint32_t*)data)[0] = blocks - 1;
443             ((uint32_t*)data)[1] = PISCSI_BLOCK_SIZE;
444
445             scsi->scsi_Actual = 8;
446             err = 0;
447
448             break;
449         case 0x1a: // MODE SENSE (6)    
450             //KPrintF("SCSI command: Mode Sense.\n");
451             data[0] = 3 + 8 + 0x16;
452             data[1] = 0; // MEDIUM TYPE
453             data[2] = 0;
454             data[3] = 8;
455
456             READLONG(PISCSI_CMD_BLOCKS, maxblocks);
457             (blocks = (maxblocks - 1) & 0xFFFFFF);
458
459             *((uint32_t *)&data[4]) = blocks;
460             *((uint32_t *)&data[8]) = PISCSI_BLOCK_SIZE;
461
462             switch (((UWORD)scsi->scsi_Command[2] << 8) | scsi->scsi_Command[3]) {
463                 case 0x0300: { // Format Device Mode
464                     KPrintF("Grabbing SCSI format device mode data.\n");
465                     debug(PISCSI_DBG_MSG, DBG_SCSI_FORMATDEVICE);
466                     uint8_t *datext = data + 12;
467                     datext[0] = 0x03;
468                     datext[1] = 0x16;
469                     datext[2] = 0x00;
470                     datext[3] = 0x01;
471                     *((uint32_t *)&datext[4]) = 0;
472                     *((uint32_t *)&datext[8]) = 0;
473                     *((uint16_t *)&datext[10]) = u->s;
474                     *((uint16_t *)&datext[12]) = PISCSI_BLOCK_SIZE;
475                     datext[14] = 0x00;
476                     datext[15] = 0x01;
477                     *((uint32_t *)&datext[16]) = 0;
478                     datext[20] = 0x80;
479
480                     scsi->scsi_Actual = data[0] + 1;
481                     err = 0;
482                     break;
483                 }
484                 case 0x0400: // Rigid Drive Geometry
485                     KPrintF("Grabbing SCSI rigid drive geometry.\n");
486                     debug(PISCSI_DBG_MSG, DBG_SCSI_RDG);
487                     uint8_t *datext = data + 12;
488                     datext[0] = 0x04;
489                     *((uint32_t *)&datext[1]) = u->c;
490                     datext[1] = 0x16;
491                     datext[5] = u->h;
492                     datext[6] = 0x00;
493                     *((uint32_t *)&datext[6]) = 0;
494                     *((uint32_t *)&datext[10]) = 0;
495                     *((uint32_t *)&datext[13]) = u->c;
496                     datext[17] = 0;
497                     *((uint32_t *)&datext[18]) = 0;
498                     *((uint16_t *)&datext[20]) = 5400;
499
500                     scsi->scsi_Actual = data[0] + 1;
501                     err = 0;
502                     break;
503                 
504                 default:
505                     KPrintF("[WARN] Unhandled mode sense thing: %lx\n", ((UWORD)scsi->scsi_Command[2] << 8) | scsi->scsi_Command[3]);
506                     debugval(PISCSI_DBG_VAL1, (((UWORD)scsi->scsi_Command[2] << 8) | scsi->scsi_Command[3]));
507                     debug(PISCSI_DBG_MSG, DBG_SCSI_UNKNOWN_MODESENSE);
508                     err = HFERR_BadStatus;
509                     break;
510             }
511             break;
512         
513         case 0x37: // READ DEFECT DATA (10)
514             
515             break;
516
517         default:
518             debugval(PISCSI_DBG_VAL1, scsi->scsi_Command[0]);
519             debug(PISCSI_DBG_MSG, DBG_SCSI_UNKNOWN_COMMAND);
520             KPrintF("Unknown/unhandled SCSI command %lx.\n", scsi->scsi_Command[0]);
521             err = HFERR_BadStatus;
522             break;
523     }
524
525     if (err != 0) {
526         debugval(PISCSI_DBG_VAL1, err);
527         debug(PISCSI_DBG_MSG, DBG_SCSIERR);
528         KPrintF("Some SCSI error occured: %ld\n", err);
529         scsi->scsi_Actual = 0;
530     }
531
532     return err;
533 }
534
535 #define DUMMYCMD iostd->io_Actual = 0; break;
536 uint8_t piscsi_perform_io(struct piscsi_unit *u, struct IORequest *io) {
537     struct IOStdReq *iostd = (struct IOStdReq *)io;
538     struct IOExtTD *iotd = (struct IOExtTD *)io;
539
540     uint8_t *data;
541     uint32_t len;
542     uint32_t offset;
543     //struct DriveGeometry *geom;
544     uint8_t err = 0;
545
546     if (!u->enabled) {
547         return IOERR_OPENFAIL;
548     }
549
550     data = iotd->iotd_Req.io_Data;
551     len = iotd->iotd_Req.io_Length;
552
553     if (io->io_Error == IOERR_ABORTED) {
554         return io->io_Error;
555     }
556
557     debugval(PISCSI_DBG_VAL1, io->io_Command);
558     debugval(PISCSI_DBG_VAL2, io->io_Flags);
559     debugval(PISCSI_DBG_VAL3, iostd->io_Length);
560     debug(PISCSI_DBG_MSG, DBG_IOCMD);
561     //KPrintF("cmd: %s\n",cmd_name(io->io_Command));
562     //KPrintF("IO %lx Start, io_Flags = %ld, io_Command = %ld\n", io, io->io_Flags, io->io_Command);
563
564     switch (io->io_Command) {
565         case CMD_CLEAR:
566             /* Invalidate read buffer */
567             DUMMYCMD;
568         case CMD_UPDATE:
569             /* Flush write buffer */
570             DUMMYCMD;
571         case TD_PROTSTATUS:
572             DUMMYCMD;
573         case TD_CHANGENUM:
574             iostd->io_Actual = u->change_num;
575             break;
576         case TD_REMOVE:
577             DUMMYCMD;
578         case TD_CHANGESTATE:
579             DUMMYCMD;
580         case TD_GETDRIVETYPE:
581             iostd->io_Actual = DG_DIRECT_ACCESS;
582             break;
583         case TD_MOTOR:
584             iostd->io_Actual = u->motor;
585             u->motor = iostd->io_Length ? 1 : 0;
586             break;
587
588         case TD_FORMAT:
589             offset = iotd->iotd_Req.io_Offset;
590             //err = 0;
591             err = piscsi_rw(u, io, offset, 1);
592             break;
593         case CMD_WRITE:
594             offset = iotd->iotd_Req.io_Offset;
595             //err = 0;
596             err = piscsi_rw(u, io, offset, 1);
597             break;
598         case CMD_READ:
599             offset = iotd->iotd_Req.io_Offset;
600             //err = 0;
601             err = piscsi_rw(u, io, offset, 0);
602             break;
603         case HD_SCSICMD:
604             //err = 0;
605             err = piscsi_scsi(u, io);
606             break;
607         default: {
608             int cmd = io->io_Command;
609             debug(PISCSI_DBG_MSG, DBG_IOCMD_UNHANDLED);
610             err = IOERR_NOCMD;
611             break;
612         }
613     }
614
615     return err;
616 }
617 #undef DUMMYCMD
618
619 ADDTABL_END();