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