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