]> git.sesse.net Git - pistorm/blob - platforms/amiga/piscsi/device_driver_amiga/piscsi-amiga-2.c
Add license information to source
[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
223     data = iotd->iotd_Req.io_Data;
224     len = iotd->iotd_Req.io_Length;
225
226     if (data == 0) {
227         return IOERR_BADADDRESS;
228     }
229     if (len < PISCSI_BLOCK_SIZE) {
230         iostd->io_Actual = 0;
231         return IOERR_BADLENGTH;
232     }
233
234     switch (io->io_Command) {
235         case TD_WRITE64:
236         case NSCMD_TD_WRITE64:
237         case TD_FORMAT64:
238         case NSCMD_TD_FORMAT64:
239             WRITELONG(PISCSI_CMD_ADDR1, iostd->io_Offset);
240             WRITELONG(PISCSI_CMD_ADDR2, len);
241             WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
242             WRITELONG(PISCSI_CMD_ADDR4, iostd->io_Actual);
243             WRITESHORT(PISCSI_CMD_WRITE64, u->unit_num);
244             break;
245         case TD_READ64:
246         case NSCMD_TD_READ64:
247             WRITELONG(PISCSI_CMD_ADDR1, iostd->io_Offset);
248             WRITELONG(PISCSI_CMD_ADDR2, len);
249             WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
250             WRITELONG(PISCSI_CMD_ADDR4, iostd->io_Actual);
251             WRITESHORT(PISCSI_CMD_READ64, u->unit_num);
252             break;
253         case TD_FORMAT:
254         case CMD_WRITE:
255             WRITELONG(PISCSI_CMD_ADDR1, (iostd->io_Offset >> 9));
256             WRITELONG(PISCSI_CMD_ADDR2, len);
257             WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
258             WRITESHORT(PISCSI_CMD_WRITE, u->unit_num);
259             break;
260         case CMD_READ:
261             WRITELONG(PISCSI_CMD_ADDR1, (iostd->io_Offset >> 9));
262             WRITELONG(PISCSI_CMD_ADDR2, len);
263             WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
264             WRITESHORT(PISCSI_CMD_READ, u->unit_num);
265             break;
266     }
267
268     if (sderr) {
269         iostd->io_Actual = 0;
270
271         if (sderr & SCSIERR_TIMEOUT)
272             return TDERR_DiskChanged;
273         if (sderr & SCSIERR_PARAM)
274             return TDERR_SeekError;
275         if (sderr & SCSIERR_ADDRESS)
276             return TDERR_SeekError;
277         if (sderr & (SCSIERR_ERASESEQ | SCSIERR_ERASERES))
278             return TDERR_BadSecPreamble;
279         if (sderr & SCSIERR_CRC)
280             return TDERR_BadSecSum;
281         if (sderr & SCSIERR_ILLEGAL)
282             return TDERR_TooFewSecs;
283         if (sderr & SCSIERR_IDLE)
284             return TDERR_PostReset;
285
286         return TDERR_SeekError;
287     } else {
288         iostd->io_Actual = iotd->iotd_Req.io_Length;
289     }
290
291     return 0;
292 }
293
294 #define PISCSI_ID_STRING "PISTORM Fake SCSI Disk  0.1 1111111111111111"
295
296 uint8_t piscsi_scsi(struct piscsi_unit *u, struct IORequest *io)
297 {
298     struct IOStdReq *iostd = (struct IOStdReq *)io;
299     struct SCSICmd *scsi = iostd->io_Data;
300     //uint8_t* registers = sdu->sdu_Registers;
301     uint8_t *data = (uint8_t *)scsi->scsi_Data;
302     uint32_t i, block = 0, blocks = 0, maxblocks = 0;
303     uint8_t err = 0;
304     uint8_t write = 0;
305
306     debugval(PISCSI_DBG_VAL1, iostd->io_Length);
307     debugval(PISCSI_DBG_VAL2, scsi->scsi_Command[0]);
308     debugval(PISCSI_DBG_VAL3, scsi->scsi_Command[1]);
309     debugval(PISCSI_DBG_VAL4, scsi->scsi_Command[2]);
310     debugval(PISCSI_DBG_VAL5, scsi->scsi_CmdLength);
311     debug(PISCSI_DBG_MSG, DBG_SCSICMD);
312
313     //maxblocks = u->s * u->c * u->h;
314
315     if (scsi->scsi_CmdLength < 6) {
316         return IOERR_BADLENGTH;
317     }
318
319     if (scsi->scsi_Command == NULL) {
320         return IOERR_BADADDRESS;
321     }
322
323     scsi->scsi_Actual = 0;
324     //iostd->io_Actual = sizeof(*scsi);
325
326     switch (scsi->scsi_Command[0]) {
327         case SCSICMD_TEST_UNIT_READY:
328             err = 0;
329             break;
330         
331         case SCSICMD_INQUIRY:
332             for (i = 0; i < scsi->scsi_Length; i++) {
333                 uint8_t val = 0;
334
335                 switch (i) {
336                     case 0: // SCSI device type: direct-access device
337                         val = (0 << 5) | 0;
338                         break;
339                     case 1: // RMB = 1
340                         val = (1 << 7);
341                         break;
342                     case 2: // VERSION = 0
343                         val = 0;
344                         break;
345                     case 3: // NORMACA=0, HISUP = 0, RESPONSE_DATA_FORMAT = 2
346                         val = (0 << 5) | (0 << 4) | 2;
347                         break;
348                     case 4: // ADDITIONAL_LENGTH = 44 - 4
349                         val = 44 - 4;
350                         break;
351                     default:
352                         if (i >= 8 && i < 44)
353                             val = PISCSI_ID_STRING[i - 8];
354                         else
355                             val = 0;
356                         break;
357                 }
358                 data[i] = val;
359             }
360             scsi->scsi_Actual = i;
361             err = 0;
362             break;
363         
364         case SCSICMD_WRITE_6:
365             write = 1;
366         case SCSICMD_READ_6:
367             //block = *(uint32_t *)(&scsi->scsi_Command[0]) & 0x001FFFFF;
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             debugval(PISCSI_DBG_VAL1, (uint32_t)scsi->scsi_Command);
373             debug(PISCSI_DBG_MSG, DBG_SCSICMD_RW6);
374             goto scsireadwrite;
375         case SCSICMD_WRITE_10:
376             write = 1;
377         case SCSICMD_READ_10:
378             debugval(PISCSI_DBG_VAL1, (uint32_t)scsi->scsi_Command);
379             debug(PISCSI_DBG_MSG, DBG_SCSICMD_RW10);
380             //block = *(uint32_t *)(&scsi->scsi_Command[2]);
381             block = scsi->scsi_Command[2];
382             block = (block << 8) | scsi->scsi_Command[3];
383             block = (block << 8) | scsi->scsi_Command[4];
384             block = (block << 8) | scsi->scsi_Command[5];
385
386             //blocks = *(uint16_t *)(&scsi->scsi_Command[7]);
387             blocks = scsi->scsi_Command[7];
388             blocks = (blocks << 8) | scsi->scsi_Command[8];
389
390 scsireadwrite:;
391             WRITESHORT(PISCSI_CMD_DRVNUM, (u->scsi_num));
392             READLONG(PISCSI_CMD_BLOCKS, maxblocks);
393             if (block + blocks > maxblocks || blocks == 0) {
394                 err = IOERR_BADADDRESS;
395                 break;
396             }
397             if (data == NULL) {
398                 err = IOERR_BADADDRESS;
399                 break;
400             }
401
402             if (write == 0) {
403                 WRITELONG(PISCSI_CMD_ADDR1, block);
404                 WRITELONG(PISCSI_CMD_ADDR2, (blocks << 9));
405                 WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
406                 WRITESHORT(PISCSI_CMD_READ, u->unit_num);
407             }
408             else {
409                 WRITELONG(PISCSI_CMD_ADDR1, block);
410                 WRITELONG(PISCSI_CMD_ADDR2, (blocks << 9));
411                 WRITELONG(PISCSI_CMD_ADDR3, (uint32_t)data);
412                 WRITESHORT(PISCSI_CMD_WRITE, u->unit_num);
413             }
414
415             scsi->scsi_Actual = scsi->scsi_Length;
416             err = 0;
417             break;
418         
419         case SCSICMD_READ_CAPACITY_10:
420             if (scsi->scsi_CmdLength < 10) {
421                 err = HFERR_BadStatus;
422                 break;
423             }
424
425             if (scsi->scsi_Length < 8) {
426                 err = IOERR_BADLENGTH;
427                 break;
428             }
429             
430             WRITESHORT(PISCSI_CMD_DRVNUM, (u->scsi_num));
431             READLONG(PISCSI_CMD_BLOCKS, blocks);
432             ((uint32_t*)data)[0] = blocks - 1;
433             ((uint32_t*)data)[1] = PISCSI_BLOCK_SIZE;
434
435             scsi->scsi_Actual = 8;
436             err = 0;
437
438             break;
439         case SCSICMD_MODE_SENSE_6:
440             data[0] = 3 + 8 + 0x16;
441             data[1] = 0; // MEDIUM TYPE
442             data[2] = 0;
443             data[3] = 8;
444
445             debugval(PISCSI_DBG_VAL1, ((uint32_t)scsi->scsi_Command));
446             debug(PISCSI_DBG_MSG, DBG_SCSI_DEBUG_MODESENSE_6);
447
448             WRITESHORT(PISCSI_CMD_DRVNUM, (u->scsi_num));
449             READLONG(PISCSI_CMD_BLOCKS, maxblocks);
450             (blocks = (maxblocks - 1) & 0xFFFFFF);
451
452             *((uint32_t *)&data[4]) = blocks;
453             *((uint32_t *)&data[8]) = PISCSI_BLOCK_SIZE;
454
455             switch (((UWORD)scsi->scsi_Command[2] << 8) | scsi->scsi_Command[3]) {
456                 case 0x0300: { // Format Device Mode
457                     debug(PISCSI_DBG_MSG, DBG_SCSI_FORMATDEVICE);
458                     uint8_t *datext = data + 12;
459                     datext[0] = 0x03;
460                     datext[1] = 0x16;
461                     datext[2] = 0x00;
462                     datext[3] = 0x01;
463                     *((uint32_t *)&datext[4]) = 0;
464                     *((uint32_t *)&datext[8]) = 0;
465                     *((uint16_t *)&datext[10]) = u->s;
466                     *((uint16_t *)&datext[12]) = PISCSI_BLOCK_SIZE;
467                     datext[14] = 0x00;
468                     datext[15] = 0x01;
469                     *((uint32_t *)&datext[16]) = 0;
470                     datext[20] = 0x80;
471
472                     scsi->scsi_Actual = data[0] + 1;
473                     err = 0;
474                     break;
475                 }
476                 case 0x0400: // Rigid Drive Geometry
477                     debug(PISCSI_DBG_MSG, DBG_SCSI_RDG);
478                     uint8_t *datext = data + 12;
479                     datext[0] = 0x04;
480                     *((uint32_t *)&datext[1]) = u->c;
481                     datext[1] = 0x16;
482                     datext[5] = u->h;
483                     datext[6] = 0x00;
484                     *((uint32_t *)&datext[6]) = 0;
485                     *((uint32_t *)&datext[10]) = 0;
486                     *((uint32_t *)&datext[13]) = u->c;
487                     datext[17] = 0;
488                     *((uint32_t *)&datext[18]) = 0;
489                     *((uint16_t *)&datext[20]) = 5400;
490
491                     scsi->scsi_Actual = data[0] + 1;
492                     err = 0;
493                     break;
494                 
495                 default:
496                     debugval(PISCSI_DBG_VAL1, (((UWORD)scsi->scsi_Command[2] << 8) | scsi->scsi_Command[3]));
497                     debug(PISCSI_DBG_MSG, DBG_SCSI_UNKNOWN_MODESENSE);
498                     err = HFERR_BadStatus;
499                     break;
500             }
501             break;
502         
503         case SCSICMD_READ_DEFECT_DATA_10:
504             break;
505         case SCSICMD_CHANGE_DEFINITION:
506             break;
507
508         default:
509             debugval(PISCSI_DBG_VAL1, scsi->scsi_Command[0]);
510             debug(PISCSI_DBG_MSG, DBG_SCSI_UNKNOWN_COMMAND);
511             err = HFERR_BadStatus;
512             break;
513     }
514
515     if (err != 0) {
516         debugval(PISCSI_DBG_VAL1, err);
517         debug(PISCSI_DBG_MSG, DBG_SCSIERR);
518         scsi->scsi_Actual = 0;
519     }
520
521     return err;
522 }
523
524 uint16_t ns_support[] = {
525     NSCMD_DEVICEQUERY,
526         CMD_RESET,
527         CMD_READ,
528         CMD_WRITE,
529         CMD_UPDATE,
530         CMD_CLEAR,
531         CMD_START,
532         CMD_STOP,
533         CMD_FLUSH,
534         TD_MOTOR,
535         TD_SEEK,
536         TD_FORMAT,
537         TD_REMOVE,
538         TD_CHANGENUM,
539         TD_CHANGESTATE,
540         TD_PROTSTATUS,
541         TD_GETDRIVETYPE,
542         TD_GETGEOMETRY,
543         TD_ADDCHANGEINT,
544         TD_REMCHANGEINT,
545         HD_SCSICMD,
546         NSCMD_TD_READ64,
547         NSCMD_TD_WRITE64,
548         NSCMD_TD_SEEK64,
549         NSCMD_TD_FORMAT64,
550         0,
551 };
552
553 #define DUMMYCMD iostd->io_Actual = 0; break;
554 uint8_t piscsi_perform_io(struct piscsi_unit *u, struct IORequest *io) {
555     struct IOStdReq *iostd = (struct IOStdReq *)io;
556     struct IOExtTD *iotd = (struct IOExtTD *)io;
557
558     //uint8_t *data;
559     //uint32_t len;
560     //uint32_t offset;
561     //struct DriveGeometry *geom;
562     uint8_t err = 0;
563
564     if (!u->enabled) {
565         return IOERR_OPENFAIL;
566     }
567
568     //data = iotd->iotd_Req.io_Data;
569     //len = iotd->iotd_Req.io_Length;
570
571     if (io->io_Error == IOERR_ABORTED) {
572         return io->io_Error;
573     }
574
575     debugval(PISCSI_DBG_VAL1, io->io_Command);
576     debugval(PISCSI_DBG_VAL2, io->io_Flags);
577     debugval(PISCSI_DBG_VAL3, iostd->io_Length);
578     debug(PISCSI_DBG_MSG, DBG_IOCMD);
579
580     switch (io->io_Command) {
581         case NSCMD_DEVICEQUERY: {
582             struct NSDeviceQueryResult *res = (struct NSDeviceQueryResult *)iotd->iotd_Req.io_Data;
583             res->DevQueryFormat = 0;
584             res->SizeAvailable = 16;;
585             res->DeviceType = NSDEVTYPE_TRACKDISK;
586             res->DeviceSubType = 0;
587             res->SupportedCommands = ns_support;
588
589             iostd->io_Actual = 16;
590             return 0;
591             break;
592         }
593         case CMD_CLEAR:
594             /* Invalidate read buffer */
595             DUMMYCMD;
596         case CMD_UPDATE:
597             /* Flush write buffer */
598             DUMMYCMD;
599         case TD_PROTSTATUS:
600             DUMMYCMD;
601         case TD_CHANGENUM:
602             iostd->io_Actual = u->change_num;
603             break;
604         case TD_REMOVE:
605             DUMMYCMD;
606         case TD_CHANGESTATE:
607             DUMMYCMD;
608         case TD_GETDRIVETYPE:
609             iostd->io_Actual = DG_DIRECT_ACCESS;
610             break;
611         case TD_MOTOR:
612             iostd->io_Actual = u->motor;
613             u->motor = iostd->io_Length ? 1 : 0;
614             break;
615
616         case TD_FORMAT:
617         case TD_FORMAT64:
618         case NSCMD_TD_FORMAT64:
619         case TD_READ64:
620         case NSCMD_TD_READ64:
621         case TD_WRITE64:
622         case NSCMD_TD_WRITE64:
623         case CMD_WRITE:
624         case CMD_READ:
625             err = piscsi_rw(u, io);
626             break;
627         case HD_SCSICMD:
628             //err = 0;
629             err = piscsi_scsi(u, io);
630             break;
631         default: {
632             //int cmd = io->io_Command;
633             debug(PISCSI_DBG_MSG, DBG_IOCMD_UNHANDLED);
634             err = IOERR_NOCMD;
635             break;
636         }
637     }
638
639     return err;
640 }
641 #undef DUMMYCMD
642
643 static uint32_t device_vectors[] = {
644     (uint32_t)open,
645     (uint32_t)close,
646     (uint32_t)expunge,
647     0, //extFunc not used here
648     (uint32_t)begin_io,
649     (uint32_t)abort_io,
650     -1
651 };
652
653 const uint32_t auto_init_tables[4] = {
654     sizeof(struct Library),
655     (uint32_t)device_vectors,
656     0,
657     (uint32_t)init_device
658 };