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