]> git.sesse.net Git - pistorm/blob - platforms/amiga/piscsi/device_driver_amiga/piscsi-amiga-2.c
8a76d3fd1de8d6eee6801bca6a0feada71b2324a
[pistorm] / platforms / amiga / piscsi / device_driver_amiga / piscsi-amiga-2.c
1 #include <exec/resident.h>
2 #include <exec/errors.h>
3 #include <exec/memory.h>
4 #include <exec/lists.h>
5 #include <exec/alerts.h>
6 #include <exec/tasks.h>
7 #include <exec/io.h>
8 #include <exec/execbase.h>
9
10 #include <libraries/expansion.h>
11
12 #include <devices/trackdisk.h>
13 #include <devices/timer.h>
14 #include <devices/scsidisk.h>
15
16 #include <dos/filehandler.h>
17
18 #include <proto/exec.h>
19 #include <proto/disk.h>
20 #include <proto/expansion.h>
21
22 #include "newstyle.h"
23
24 #include "../piscsi-enums.h"
25 #include <stdint.h>
26
27 #define STR(s) #s
28 #define XSTR(s) STR(s)
29
30 #define DEVICE_NAME "pi-scsi.device"
31 #define DEVICE_DATE "(3 Feb 2021)"
32 #define DEVICE_ID_STRING "PiSCSI " XSTR(DEVICE_VERSION) "." XSTR(DEVICE_REVISION) " " DEVICE_DATE
33 #define DEVICE_VERSION 43
34 #define DEVICE_REVISION 20
35 #define DEVICE_PRIORITY 0
36
37 #pragma pack(4)
38 struct piscsi_base {
39     struct Device* pi_dev;
40     struct piscsi_unit {
41         struct Unit unit;
42         uint32_t regs_ptr;
43
44         uint8_t enabled;
45         uint8_t present;
46         uint8_t valid;
47         uint8_t read_only;
48         uint8_t motor;
49         uint8_t unit_num;
50         uint16_t h, s;
51         uint32_t c;
52
53         uint32_t change_num;
54     } units[NUM_UNITS];
55 };
56
57 struct ExecBase *SysBase;
58 uint8_t *saved_seg_list;
59 uint8_t is_open;
60
61 #define WRITESHORT(cmd, val) *(unsigned short *)((unsigned long)(PISCSI_OFFSET+cmd)) = val;
62 #define WRITELONG(cmd, val) *(unsigned long *)((unsigned long)(PISCSI_OFFSET+cmd)) = val;
63 #define WRITEBYTE(cmd, val) *(unsigned char *)((unsigned long)(PISCSI_OFFSET+cmd)) = val;
64
65 #define READSHORT(cmd, var) var = *(volatile unsigned short *)(PISCSI_OFFSET + cmd);
66 #define READLONG(cmd, var) var = *(volatile unsigned long *)(PISCSI_OFFSET + cmd);
67
68 int __attribute__((no_reorder)) _start()
69 {
70     return -1;
71 }
72
73 asm("romtag:                                \n"
74     "       dc.w    "XSTR(RTC_MATCHWORD)"   \n"
75     "       dc.l    romtag                  \n"
76     "       dc.l    endcode                 \n"
77     "       dc.b    "XSTR(RTF_AUTOINIT)"    \n"
78     "       dc.b    "XSTR(DEVICE_VERSION)"  \n"
79     "       dc.b    "XSTR(NT_DEVICE)"       \n"
80     "       dc.b    "XSTR(DEVICE_PRIORITY)" \n"
81     "       dc.l    _device_name            \n"
82     "       dc.l    _device_id_string       \n"
83     "       dc.l    _auto_init_tables       \n"
84     "endcode:                               \n");
85
86 char device_name[] = DEVICE_NAME;
87 char device_id_string[] = DEVICE_ID_STRING;
88
89 uint8_t piscsi_perform_io(struct piscsi_unit *u, struct IORequest *io);
90 uint8_t piscsi_rw(struct piscsi_unit *u, struct IORequest *io);
91 uint8_t piscsi_scsi(struct piscsi_unit *u, struct IORequest *io);
92
93 //#define debug(...)
94 //#define debugval(...)
95 #define debug(c, v) WRITESHORT(c, v)
96 #define debugval(c, v) WRITELONG(c, v)
97
98 struct piscsi_base *dev_base = NULL;
99
100 static struct Library __attribute__((used)) *init_device(uint8_t *seg_list asm("a0"), struct Library *dev asm("d0"))
101 {
102     SysBase = *(struct ExecBase **)4L;
103
104     debug(PISCSI_DBG_MSG, DBG_INIT);
105
106     dev_base = AllocMem(sizeof(struct piscsi_base), MEMF_PUBLIC | MEMF_CLEAR);
107     dev_base->pi_dev = (struct Device *)dev;
108
109     for (int i = 0; i < NUM_UNITS; i++) {
110         uint16_t r = 0;
111         WRITESHORT(PISCSI_CMD_DRVNUM, (i * 10));
112         dev_base->units[i].regs_ptr = PISCSI_OFFSET;
113         READSHORT(PISCSI_CMD_DRVTYPE, r);
114         dev_base->units[i].enabled = r;
115         dev_base->units[i].present = r;
116         dev_base->units[i].valid = r;
117         dev_base->units[i].unit_num = i;
118         if (dev_base->units[i].present) {
119             READLONG(PISCSI_CMD_CYLS, dev_base->units[i].c);
120             READSHORT(PISCSI_CMD_HEADS, dev_base->units[i].h);
121             READSHORT(PISCSI_CMD_SECS, dev_base->units[i].s);
122
123             debugval(PISCSI_DBG_VAL1, dev_base->units[i].c);
124             debugval(PISCSI_DBG_VAL2, dev_base->units[i].h);
125             debugval(PISCSI_DBG_VAL3, dev_base->units[i].s);
126             debug(PISCSI_DBG_MSG, DBG_CHS);
127         }
128         dev_base->units[i].change_num++;
129     }
130
131     return dev;
132 }
133
134 static uint8_t* __attribute__((used)) expunge(struct Library *dev asm("a6"))
135 {
136     debug(PISCSI_DBG_MSG, DBG_CLEANUP);
137     /*if (dev_base->open_count)
138         return 0;
139     FreeMem(dev_base, sizeof(struct piscsi_base));*/
140     return 0;
141 }
142
143 static void __attribute__((used)) open(struct Library *dev asm("a6"), struct IOExtTD *iotd asm("a1"), uint32_t num asm("d0"), uint32_t flags asm("d1"))
144 {
145     //struct Node* node = (struct Node*)iotd;
146     int io_err = IOERR_OPENFAIL;
147
148     //WRITESHORT(PISCSI_CMD_DEBUGME, 1);
149
150     int unit_num = 0;
151     WRITELONG(PISCSI_CMD_DRVNUM, num);
152     READLONG(PISCSI_CMD_DRVNUM, unit_num);
153
154     debugval(PISCSI_DBG_VAL1, unit_num);
155     debugval(PISCSI_DBG_VAL2, flags);
156     debugval(PISCSI_DBG_VAL3, num);
157     debug(PISCSI_DBG_MSG, DBG_OPENDEV);
158
159     if (iotd && unit_num < NUM_UNITS) {
160         if (dev_base->units[unit_num].enabled && dev_base->units[unit_num].present) {
161             io_err = 0;
162             iotd->iotd_Req.io_Unit = (struct Unit*)&dev_base->units[unit_num].unit;
163             iotd->iotd_Req.io_Unit->unit_flags = UNITF_ACTIVE;
164             iotd->iotd_Req.io_Unit->unit_OpenCnt = 1;
165         }
166     }
167
168     iotd->iotd_Req.io_Error = io_err;
169     ((struct Library *)dev_base->pi_dev)->lib_OpenCnt++;
170 }
171
172 static uint8_t* __attribute__((used)) close(struct Library *dev asm("a6"), struct IOExtTD *iotd asm("a1"))
173 {
174     ((struct Library *)dev_base->pi_dev)->lib_OpenCnt--;
175     return 0;
176 }
177
178 static void __attribute__((used)) begin_io(struct Library *dev asm("a6"), struct IORequest *io asm("a1"))
179 {
180     if (dev_base == NULL || io == NULL)
181         return;
182     
183     struct piscsi_unit *u;
184     struct Node* node = (struct Node*)io;
185     u = (struct piscsi_unit *)io->io_Unit;
186
187     if (node == NULL || u == NULL)
188         return;
189
190     debugval(PISCSI_DBG_VAL1, io->io_Command);
191     debugval(PISCSI_DBG_VAL2, io->io_Flags);
192     debugval(PISCSI_DBG_VAL3, (io->io_Flags & IOF_QUICK));
193     debug(PISCSI_DBG_MSG, DBG_BEGINIO);
194     io->io_Error = piscsi_perform_io(u, io);
195
196     if (!(io->io_Flags & IOF_QUICK)) {
197         ReplyMsg(&io->io_Message);
198     }
199 }
200
201 static uint32_t __attribute__((used)) abort_io(struct Library *dev asm("a6"), struct IORequest *io asm("a1"))
202 {
203     debug(PISCSI_DBG_MSG, DBG_ABORTIO);
204     if (!io) return IOERR_NOCMD;
205     io->io_Error = IOERR_ABORTED;
206
207     return IOERR_ABORTED;
208 }
209
210 uint8_t piscsi_rw(struct piscsi_unit *u, struct IORequest *io) {
211     struct IOStdReq *iostd = (struct IOStdReq *)io;
212     struct IOExtTD *iotd = (struct IOExtTD *)io;
213
214     uint8_t* data;
215     uint32_t len;
216     //uint32_t block, num_blocks;
217     uint8_t sderr = 0;
218
219     data = iotd->iotd_Req.io_Data;
220     len = iotd->iotd_Req.io_Length;
221
222     if (data == 0) {
223         return IOERR_BADADDRESS;
224     }
225     if (len < PISCSI_BLOCK_SIZE) {
226         iostd->io_Actual = 0;
227         return IOERR_BADLENGTH;
228     }
229
230     switch (io->io_Command) {
231         case TD_WRITE64:
232         case NSCMD_TD_WRITE64:
233         case TD_FORMAT64:
234         case NSCMD_TD_FORMAT64:
235             WRITELONG(PISCSI_CMD_ADDR1, iostd->io_Offset);
236             WRITELONG(PISCSI_CMD_ADDR2, len);
237             WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
238             WRITELONG(PISCSI_CMD_ADDR4, iostd->io_Actual);
239             WRITESHORT(PISCSI_CMD_WRITE64, u->unit_num);
240             break;
241         case TD_READ64:
242         case NSCMD_TD_READ64:
243             WRITELONG(PISCSI_CMD_ADDR1, iostd->io_Offset);
244             WRITELONG(PISCSI_CMD_ADDR2, len);
245             WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
246             WRITELONG(PISCSI_CMD_ADDR4, iostd->io_Actual);
247             WRITESHORT(PISCSI_CMD_READ64, u->unit_num);
248             break;
249         case TD_FORMAT:
250         case CMD_WRITE:
251             WRITELONG(PISCSI_CMD_ADDR1, (iostd->io_Offset >> 9));
252             WRITELONG(PISCSI_CMD_ADDR2, len);
253             WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
254             WRITESHORT(PISCSI_CMD_WRITE, u->unit_num);
255             break;
256         case CMD_READ:
257             WRITELONG(PISCSI_CMD_ADDR1, (iostd->io_Offset >> 9));
258             WRITELONG(PISCSI_CMD_ADDR2, len);
259             WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
260             WRITESHORT(PISCSI_CMD_READ, u->unit_num);
261             break;
262     }
263
264     if (sderr) {
265         iostd->io_Actual = 0;
266
267         if (sderr & SCSIERR_TIMEOUT)
268             return TDERR_DiskChanged;
269         if (sderr & SCSIERR_PARAM)
270             return TDERR_SeekError;
271         if (sderr & SCSIERR_ADDRESS)
272             return TDERR_SeekError;
273         if (sderr & (SCSIERR_ERASESEQ | SCSIERR_ERASERES))
274             return TDERR_BadSecPreamble;
275         if (sderr & SCSIERR_CRC)
276             return TDERR_BadSecSum;
277         if (sderr & SCSIERR_ILLEGAL)
278             return TDERR_TooFewSecs;
279         if (sderr & SCSIERR_IDLE)
280             return TDERR_PostReset;
281
282         return TDERR_SeekError;
283     } else {
284         iostd->io_Actual = iotd->iotd_Req.io_Length;
285     }
286
287     return 0;
288 }
289
290 #define PISCSI_ID_STRING "PISTORM Fake SCSI Disk  0.1 1111111111111111"
291
292 uint8_t piscsi_scsi(struct piscsi_unit *u, struct IORequest *io)
293 {
294     struct IOStdReq *iostd = (struct IOStdReq *)io;
295     struct SCSICmd *scsi = iostd->io_Data;
296     //uint8_t* registers = sdu->sdu_Registers;
297     uint8_t *data = (uint8_t *)scsi->scsi_Data;
298     uint32_t i, block = 0, blocks = 0, maxblocks = 0;
299     uint8_t err = 0;
300     uint8_t write = 0;
301
302     debugval(PISCSI_DBG_VAL1, iostd->io_Length);
303     debugval(PISCSI_DBG_VAL2, scsi->scsi_Command[0]);
304     debugval(PISCSI_DBG_VAL3, scsi->scsi_Command[1]);
305     debugval(PISCSI_DBG_VAL4, scsi->scsi_Command[2]);
306     debugval(PISCSI_DBG_VAL5, scsi->scsi_CmdLength);
307     debug(PISCSI_DBG_MSG, DBG_SCSICMD);
308
309     //maxblocks = u->s * u->c * u->h;
310
311     if (scsi->scsi_CmdLength < 6) {
312         return IOERR_BADLENGTH;
313     }
314
315     if (scsi->scsi_Command == NULL) {
316         return IOERR_BADADDRESS;
317     }
318
319     scsi->scsi_Actual = 0;
320     //iostd->io_Actual = sizeof(*scsi);
321
322     switch (scsi->scsi_Command[0]) {
323         case 0x00:      // TEST_UNIT_READY
324             err = 0;
325             break;
326         
327         case 0x12:      // INQUIRY
328             for (i = 0; i < scsi->scsi_Length; i++) {
329                 uint8_t val = 0;
330
331                 switch (i) {
332                     case 0: // SCSI device type: direct-access device
333                         val = (0 << 5) | 0;
334                         break;
335                     case 1: // RMB = 1
336                         val = (1 << 7);
337                         break;
338                     case 2: // VERSION = 0
339                         val = 0;
340                         break;
341                     case 3: // NORMACA=0, HISUP = 0, RESPONSE_DATA_FORMAT = 2
342                         val = (0 << 5) | (0 << 4) | 2;
343                         break;
344                     case 4: // ADDITIONAL_LENGTH = 44 - 4
345                         val = 44 - 4;
346                         break;
347                     default:
348                         if (i >= 8 && i < 44)
349                             val = PISCSI_ID_STRING[i - 8];
350                         else
351                             val = 0;
352                         break;
353                 }
354                 data[i] = val;
355             }
356             scsi->scsi_Actual = i;
357             err = 0;
358             break;
359         
360         case 0x08: // READ (6)
361         case 0x0a: // WRITE (6)
362         case 0x28: // READ (10)
363         case 0x2A: // WRITE (10)
364             switch (scsi->scsi_Command[0]) {
365                 case 0x0A:
366                     write = 1;
367                 case 0x08:
368                     block = scsi->scsi_Command[1] & 0x1f;
369                     block = (block << 8) | scsi->scsi_Command[2];
370                     block = (block << 8) | scsi->scsi_Command[3];
371                     blocks = scsi->scsi_Command[4];
372                     break;
373                 case 0x2A:
374                     write = 1;
375                 case 0x28:
376                     block = scsi->scsi_Command[2];
377                     block = (block << 8) | scsi->scsi_Command[3];
378                     block = (block << 8) | scsi->scsi_Command[4];
379                     block = (block << 8) | scsi->scsi_Command[5];
380
381                     blocks = scsi->scsi_Command[7];
382                     blocks = (blocks << 8) | scsi->scsi_Command[8];
383                     break;
384             }
385
386             WRITESHORT(PISCSI_CMD_DRVNUM, u->unit_num);
387             READLONG(PISCSI_CMD_BLOCKS, maxblocks);
388             if (block + blocks > maxblocks || blocks == 0) {
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 (write == 0) {
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                 WRITELONG(PISCSI_CMD_ADDR2, block);
409                 WRITELONG(PISCSI_CMD_ADDR2, (blocks << 9));
410                 WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
411                 WRITESHORT(PISCSI_CMD_WRITE, u->unit_num);
412             }
413
414             scsi->scsi_Actual = scsi->scsi_Length;
415             err = 0;
416             break;
417         
418         case 0x25: // READ CAPACITY (10)
419             if (scsi->scsi_CmdLength < 10) {
420                 err = HFERR_BadStatus;
421                 break;
422             }
423
424             block = *((uint32_t*)&scsi->scsi_Command[2]);
425
426             if (scsi->scsi_Length < 8) {
427                 err = IOERR_BADLENGTH;
428                 break;
429             }
430             
431             WRITESHORT(PISCSI_CMD_DRVNUM, u->unit_num);
432             READLONG(PISCSI_CMD_BLOCKS, blocks);
433             ((uint32_t*)data)[0] = blocks - 1;
434             ((uint32_t*)data)[1] = PISCSI_BLOCK_SIZE;
435
436             scsi->scsi_Actual = 8;
437             err = 0;
438
439             break;
440         case 0x1a: // MODE SENSE (6)    
441             data[0] = 3 + 8 + 0x16;
442             data[1] = 0; // MEDIUM TYPE
443             data[2] = 0;
444             data[3] = 8;
445
446             WRITESHORT(PISCSI_CMD_DRVNUM, u->unit_num);
447             READLONG(PISCSI_CMD_BLOCKS, maxblocks);
448             (blocks = (maxblocks - 1) & 0xFFFFFF);
449
450             *((uint32_t *)&data[4]) = blocks;
451             *((uint32_t *)&data[8]) = PISCSI_BLOCK_SIZE;
452
453             switch (((UWORD)scsi->scsi_Command[2] << 8) | scsi->scsi_Command[3]) {
454                 case 0x0300: { // Format Device Mode
455                     debug(PISCSI_DBG_MSG, DBG_SCSI_FORMATDEVICE);
456                     uint8_t *datext = data + 12;
457                     datext[0] = 0x03;
458                     datext[1] = 0x16;
459                     datext[2] = 0x00;
460                     datext[3] = 0x01;
461                     *((uint32_t *)&datext[4]) = 0;
462                     *((uint32_t *)&datext[8]) = 0;
463                     *((uint16_t *)&datext[10]) = u->s;
464                     *((uint16_t *)&datext[12]) = PISCSI_BLOCK_SIZE;
465                     datext[14] = 0x00;
466                     datext[15] = 0x01;
467                     *((uint32_t *)&datext[16]) = 0;
468                     datext[20] = 0x80;
469
470                     scsi->scsi_Actual = data[0] + 1;
471                     err = 0;
472                     break;
473                 }
474                 case 0x0400: // Rigid Drive Geometry
475                     debug(PISCSI_DBG_MSG, DBG_SCSI_RDG);
476                     uint8_t *datext = data + 12;
477                     datext[0] = 0x04;
478                     *((uint32_t *)&datext[1]) = u->c;
479                     datext[1] = 0x16;
480                     datext[5] = u->h;
481                     datext[6] = 0x00;
482                     *((uint32_t *)&datext[6]) = 0;
483                     *((uint32_t *)&datext[10]) = 0;
484                     *((uint32_t *)&datext[13]) = u->c;
485                     datext[17] = 0;
486                     *((uint32_t *)&datext[18]) = 0;
487                     *((uint16_t *)&datext[20]) = 5400;
488
489                     scsi->scsi_Actual = data[0] + 1;
490                     err = 0;
491                     break;
492                 
493                 default:
494                     debugval(PISCSI_DBG_VAL1, (((UWORD)scsi->scsi_Command[2] << 8) | scsi->scsi_Command[3]));
495                     debug(PISCSI_DBG_MSG, DBG_SCSI_UNKNOWN_MODESENSE);
496                     err = HFERR_BadStatus;
497                     break;
498             }
499             break;
500         
501         case 0x37: // READ DEFECT DATA (10)
502             break;
503         case 0x40: // CHANGE DEFINITION
504             break;
505
506         default:
507             debugval(PISCSI_DBG_VAL1, scsi->scsi_Command[0]);
508             debug(PISCSI_DBG_MSG, DBG_SCSI_UNKNOWN_COMMAND);
509             err = HFERR_BadStatus;
510             break;
511     }
512
513     if (err != 0) {
514         debugval(PISCSI_DBG_VAL1, err);
515         debug(PISCSI_DBG_MSG, DBG_SCSIERR);
516         scsi->scsi_Actual = 0;
517     }
518
519     return err;
520 }
521
522 uint16_t ns_support[] = {
523     NSCMD_DEVICEQUERY,
524         CMD_RESET,
525         CMD_READ,
526         CMD_WRITE,
527         CMD_UPDATE,
528         CMD_CLEAR,
529         CMD_START,
530         CMD_STOP,
531         CMD_FLUSH,
532         TD_MOTOR,
533         TD_SEEK,
534         TD_FORMAT,
535         TD_REMOVE,
536         TD_CHANGENUM,
537         TD_CHANGESTATE,
538         TD_PROTSTATUS,
539         TD_GETDRIVETYPE,
540         TD_GETGEOMETRY,
541         TD_ADDCHANGEINT,
542         TD_REMCHANGEINT,
543         HD_SCSICMD,
544         NSCMD_TD_READ64,
545         NSCMD_TD_WRITE64,
546         NSCMD_TD_SEEK64,
547         NSCMD_TD_FORMAT64,
548         0,
549 };
550
551 #define DUMMYCMD iostd->io_Actual = 0; break;
552 uint8_t piscsi_perform_io(struct piscsi_unit *u, struct IORequest *io) {
553     struct IOStdReq *iostd = (struct IOStdReq *)io;
554     struct IOExtTD *iotd = (struct IOExtTD *)io;
555
556     //uint8_t *data;
557     //uint32_t len;
558     //uint32_t offset;
559     //struct DriveGeometry *geom;
560     uint8_t err = 0;
561
562     if (!u->enabled) {
563         return IOERR_OPENFAIL;
564     }
565
566     //data = iotd->iotd_Req.io_Data;
567     //len = iotd->iotd_Req.io_Length;
568
569     if (io->io_Error == IOERR_ABORTED) {
570         return io->io_Error;
571     }
572
573     debugval(PISCSI_DBG_VAL1, io->io_Command);
574     debugval(PISCSI_DBG_VAL2, io->io_Flags);
575     debugval(PISCSI_DBG_VAL3, iostd->io_Length);
576     debug(PISCSI_DBG_MSG, DBG_IOCMD);
577
578     switch (io->io_Command) {
579         case NSCMD_DEVICEQUERY: {
580             struct NSDeviceQueryResult *res = (struct NSDeviceQueryResult *)iotd->iotd_Req.io_Data;
581             res->DevQueryFormat = 0;
582             res->SizeAvailable = 16;;
583             res->DeviceType = NSDEVTYPE_TRACKDISK;
584             res->DeviceSubType = 0;
585             res->SupportedCommands = ns_support;
586
587             iostd->io_Actual = 16;
588             return 0;
589             break;
590         }
591         case CMD_CLEAR:
592             /* Invalidate read buffer */
593             DUMMYCMD;
594         case CMD_UPDATE:
595             /* Flush write buffer */
596             DUMMYCMD;
597         case TD_PROTSTATUS:
598             DUMMYCMD;
599         case TD_CHANGENUM:
600             iostd->io_Actual = u->change_num;
601             break;
602         case TD_REMOVE:
603             DUMMYCMD;
604         case TD_CHANGESTATE:
605             DUMMYCMD;
606         case TD_GETDRIVETYPE:
607             iostd->io_Actual = DG_DIRECT_ACCESS;
608             break;
609         case TD_MOTOR:
610             iostd->io_Actual = u->motor;
611             u->motor = iostd->io_Length ? 1 : 0;
612             break;
613
614         case TD_FORMAT:
615         case TD_FORMAT64:
616         case NSCMD_TD_FORMAT64:
617         case TD_READ64:
618         case NSCMD_TD_READ64:
619         case TD_WRITE64:
620         case NSCMD_TD_WRITE64:
621         case CMD_WRITE:
622         case CMD_READ:
623             err = piscsi_rw(u, io);
624             break;
625         case HD_SCSICMD:
626             //err = 0;
627             err = piscsi_scsi(u, io);
628             break;
629         default: {
630             //int cmd = io->io_Command;
631             debug(PISCSI_DBG_MSG, DBG_IOCMD_UNHANDLED);
632             err = IOERR_NOCMD;
633             break;
634         }
635     }
636
637     return err;
638 }
639 #undef DUMMYCMD
640
641 static uint32_t device_vectors[] = {
642     (uint32_t)open,
643     (uint32_t)close,
644     (uint32_t)expunge,
645     0, //extFunc not used here
646     (uint32_t)begin_io,
647     (uint32_t)abort_io,
648     -1
649 };
650
651 const uint32_t auto_init_tables[4] = {
652     sizeof(struct Library),
653     (uint32_t)device_vectors,
654     0,
655     (uint32_t)init_device
656 };