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