]> git.ozlabs.org Git - minimigmac.git/blob - pic/scsi.c
Initial commit
[minimigmac.git] / pic / scsi.c
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "hardware.h"
7 #include "mmc.h"
8 #include "fat16.h"
9 #include "scsi.h"
10
11 /* SCSI Backbus interface */
12 #define BB_REG_LINES    0
13 #define BB_LINES_BSY    7
14 #define BB_LINES_SEL    6       
15 #define BB_LINES_ACK    5
16 #define BB_LINES_ATN    4
17 #define BB_LINES_RST    3
18
19 #define BB_REG_ASSERT   1
20 #define BB_ASSERT_BSY   7
21 #define BB_ASSERT_SEL   6
22 #define BB_ASSERT_CD    5
23 #define BB_ASSERT_IO    4
24 #define BB_ASSERT_MSG   3
25 #define BB_ASSERT_REQ   2
26 #define BB_ASSERT_RST   1
27 #define BB_ASSERT_AUTO  0       /* Automatic mode */
28
29 #define BB_REG_ODATA    2
30 #define BB_REG_IDATA    3
31 #define BB_REG_ACNT_HI  4
32 #define BB_REG_ACNT_LO  5
33
34 #define MASK(bit)       (1u << (bit))
35
36 static unsigned char scsi_cmd[12];
37 static unsigned char scsi_assert;
38 static unsigned long scsi_size;
39
40 #define scsi_dbg(fmt...)
41
42 void scsi_open(void)
43 {
44         long size;
45
46         size = fat_open("MACHD   IMG");
47         if (size < 0) {
48                 printf("File MACHD.IMG not found !\n");
49                 return;
50         }
51         scsi_size = size;
52         fat_file_seek(0);
53 }
54
55 static unsigned char scsi_get_lines(void)
56 {
57         unsigned char lines;
58
59         spi_enable_fpga();
60         do_spi(BB_REG_SCSI_BASE | BB_REG_LINES);
61         do_spi(0xff);
62         lines = do_spi(0xff);
63         spi_disable_fpga();
64
65         return lines;
66 }
67
68 static void scsi_set_assert(void)
69 {
70         spi_enable_fpga();
71         do_spi(BB_WRITE | BB_REG_SCSI_BASE | BB_REG_ASSERT);
72
73
74         do_spi(scsi_assert);
75         spi_disable_fpga();
76 }
77
78 static unsigned char scsi_get_data(void)
79 {
80         unsigned char lines;
81
82         spi_enable_fpga();
83         do_spi(BB_REG_SCSI_BASE | BB_REG_ODATA);
84         do_spi(0xff);
85         lines = do_spi(0xff);
86         spi_disable_fpga();
87
88         return lines;
89 }
90
91 static void scsi_set_data(unsigned char val)
92 {
93         spi_enable_fpga();
94         do_spi(BB_WRITE | BB_REG_SCSI_BASE | BB_REG_IDATA);
95         do_spi(val);
96         spi_disable_fpga();
97 }
98
99 static void scsi_set_autocnt(unsigned short cnt)
100 {
101         spi_enable_fpga();
102         do_spi(BB_WRITE | BB_AUTOINC | BB_REG_SCSI_BASE | BB_REG_ACNT_HI);
103         do_spi(cnt >> 8);
104         do_spi(cnt & 0xff);
105         spi_disable_fpga();
106 }
107
108 static unsigned char scsi_do_data_in(unsigned short len)
109 {
110         unsigned short i = 0;
111
112         scsi_assert |= MASK(BB_ASSERT_AUTO) | MASK(BB_ASSERT_IO);
113         scsi_set_assert();
114         scsi_set_autocnt(len);
115
116         spi_enable_fpga();
117         do_spi(BB_WRITE | BB_REG_SCSI_BASE | BB_REG_IDATA);
118         while(len--) {
119                 do_spi(secbuf[i++]);
120                 /* Handhake goes down approx. 160ns after the above
121                  * and we then need to wait for it to go back up,
122                  * the PIC executes an instruction in about 200ns so
123                  * we shouldn't need any delay here before we test it
124                  */
125                 while(!SCSI_HSHAKE);
126         }
127         scsi_assert &= ~MASK(BB_ASSERT_AUTO);
128         scsi_set_assert();
129         return 0;
130 }
131
132 static unsigned char scsi_do_data_out(unsigned short len)
133 {
134         unsigned short i = 0;
135
136         scsi_assert |= MASK(BB_ASSERT_AUTO);
137         scsi_assert &= ~MASK(BB_ASSERT_IO);
138         scsi_set_assert();
139         scsi_set_autocnt(len);
140
141         spi_enable_fpga();
142         do_spi(BB_REG_SCSI_BASE | BB_REG_ODATA);
143         /* See handshake timing comment in scsi_do_data_in() */
144         while(!SCSI_HSHAKE);
145         do_spi(0xff);
146         while(!SCSI_HSHAKE);
147         do_spi(0xff);
148         while(!SCSI_HSHAKE);
149         do_spi(0xff);
150         while(len--) {
151                 while(!SCSI_HSHAKE);
152                 secbuf[i++] = do_spi(0xff);
153         }
154         scsi_assert &= ~MASK(BB_ASSERT_AUTO);
155         scsi_set_assert();
156         return 0;
157 }
158
159 static unsigned char scsi_do_read(unsigned long lba,
160                                   unsigned short cnt)
161 {
162         unsigned char rc = true;
163
164         if (scsi_size == 0)
165                 return 1;
166         diskled_on();
167         fat_file_seek(lba);
168         while(cnt--) {
169                 if (rc)
170                         rc = fat_file_read();
171                 if (!rc) {
172                         diskled_off();
173                         return 1;
174                 }
175                 scsi_do_data_in(512);
176                 if (cnt)
177                         rc = fat_file_next_sector();
178         }
179         diskled_off();
180         return 0;
181 }
182
183 static unsigned char scsi_do_write(unsigned long lba,
184                                    unsigned short cnt)
185 {
186         unsigned char rc;
187
188         if (scsi_size == 0)
189                 return 1;
190         diskled_on();
191         fat_file_seek(lba);
192         while(cnt--) {
193                 scsi_do_data_out(512);
194                 rc = fat_file_write();
195                 if (rc && cnt)
196                         rc = fat_file_next_sector();
197                 if (!rc) {
198                         diskled_off();
199                         return 1;
200                 }
201         }
202         diskled_off();
203         return 0;
204 }
205
206 static unsigned char scsi_do_cmd(void)
207 {
208         unsigned long lba;
209         unsigned short cnt;
210
211         switch(scsi_cmd[0]) {
212         case 0x00:
213                 printf("scsi: TEST_UNIT_READY !\n");
214                 return 0;
215         case 0x03:
216                 printf("scsi: REQUEST_SENSE !\n");
217                 fat_inval_cache();
218                 memset(secbuf, 0, 13);
219                 secbuf[0] = 0xf0;
220                 return scsi_do_data_in(13);
221         case 0x04:
222                 printf("scsi: FORMAT_UNIT !\n");
223                 return 1;
224         case 0x08:
225                 lba = scsi_cmd[1] & 0x1f;
226                 lba = (lba << 8) | scsi_cmd[2];
227                 lba = (lba << 8) | scsi_cmd[3];
228                 cnt = scsi_cmd[4];
229                 if (!cnt)
230                         cnt = 256;
231                 printf("scsi: READ6 (lba=%lx cnt=%x) !\n", lba, cnt);
232                 return scsi_do_read(lba, cnt);
233         case 0x0a:
234                 lba = scsi_cmd[1] & 0x1f;
235                 lba = (lba << 8) | scsi_cmd[2];
236                 lba = (lba << 8) | scsi_cmd[3];
237                 cnt = scsi_cmd[4];
238                 if (!cnt)
239                         cnt = 256;
240                 printf("scsi: WRITE6 (lba=%lx cnt=%x) !\n", lba, cnt);
241                 return scsi_do_write(lba, cnt);
242         case 0x12:
243                 printf("scsi: INQUIRY !\n");
244                 fat_inval_cache();
245                 memset(secbuf, 0, 36);
246                 memcpy(secbuf + 8, " SEAGATE", 8);
247                 memcpy(secbuf + 16, "          ST225N", 16);
248                 secbuf[4] = 32;
249                 cnt = scsi_cmd[4];
250                 if (cnt > 36)
251                         cnt = 36;
252                 return scsi_do_data_in(cnt);
253         case 0x15:
254                 printf("scsi: MODE_SELECT !\n");
255                 return 1;
256         case 0x1a:
257                 printf("scsi: MODE_SENSE !\n");
258                 return 1;
259         case 0x1b:
260                 printf("scsi: START_STOP !\n");
261                 return 1;
262         case 0x25:
263                 printf("scsi: READ_CAPACITY !\n");
264                 return 1;
265         case 0x28:
266                 printf("scsi: READ10 !\n");
267                 lba = scsi_cmd[2];
268                 lba = (lba << 8) | scsi_cmd[3];
269                 lba = (lba << 8) | scsi_cmd[4];
270                 lba = (lba << 8) | scsi_cmd[5];
271                 cnt = scsi_cmd[7];
272                 cnt = (cnt << 8) | scsi_cmd[8];
273                 return scsi_do_read(lba, cnt);
274         case 0x2a:
275                 printf("scsi: WRITE10 !\n");
276                 lba = scsi_cmd[2];
277                 lba = (lba << 8) | scsi_cmd[3];
278                 lba = (lba << 8) | scsi_cmd[4];
279                 lba = (lba << 8) | scsi_cmd[5];
280                 cnt = scsi_cmd[7];
281                 cnt = (cnt << 8) | scsi_cmd[8];
282                 return scsi_do_write(lba, cnt);
283         case 0x2f:
284                 printf("scsi: VERIFY10 !\n");
285                 return 10;
286         case 0x3c:
287                 printf("scsi: READ_BUFFER !\n");
288                 return 6;
289         }
290         return 1;
291 }
292
293 static void scsi_req_ack(void)
294 {
295         unsigned char l;
296
297         scsi_assert |= MASK(BB_ASSERT_REQ);
298         scsi_set_assert();
299         do
300                 l = scsi_get_lines();
301         while (!(l & MASK(BB_LINES_ACK)));
302 }
303
304 static void scsi_nreq_nack(void)
305 {
306         unsigned char l;
307
308         scsi_assert &= ~MASK(BB_ASSERT_REQ);
309         scsi_set_assert();
310         do
311                 l = scsi_get_lines();
312         while (l & MASK(BB_LINES_ACK));
313 }
314
315 void do_scsi(void)
316 {
317         unsigned char lines, val, i, len, stat;
318
319         lines = scsi_get_lines();
320         if ((lines & MASK(BB_LINES_SEL)) /*&& !(lines & MASK(BB_LINES_BSY)) */) {
321                 val = scsi_get_data();
322                 if (!(val & MASK(6))) {
323                         //printf("scsi: Wrong ID 0x%x\n", val);
324                         return;
325                 }
326                 scsi_assert = MASK(BB_ASSERT_BSY);
327                 scsi_set_assert();
328         } else if (lines & MASK(BB_LINES_RST)) {
329                 printf("scsi: RESET !\n");
330                 return;
331         } else {
332                 printf("scsi: Glitch (reset ?) lines=%x!\n", lines);
333                 return;
334         }
335         while(lines & MASK(BB_LINES_SEL))
336                 lines = scsi_get_lines();
337         /* XXX Check for ATN for MESSAGE_OUT phase, Mac ROM doesn't do it */
338         scsi_dbg("scsi: Selected, command phase...\n");
339         i = 0;
340         stat = 0;
341         len = 1;
342         scsi_assert |= MASK(BB_ASSERT_CD);
343         scsi_set_assert();
344         while(len) {
345                 scsi_req_ack();
346                 val = scsi_get_data();
347                 scsi_cmd[i++] = scsi_get_data();
348                 scsi_dbg("scsi: CMD = 0x%x\n", val);
349                 if (i == 1) {
350                         if (val == 0x00 || /* TEST_UNIT_READY */
351                             val == 0x03 || /* REQUEST_SENSE */
352                             val == 0x04 || /* FORMAT_UNIT */
353                             val == 0x08 || /* READ6 */
354                             val == 0x0a || /* WRITE6 */
355                             val == 0x12 || /* INQUIRY */
356                             val == 0x15 || /* MODE_SELECT */
357                             val == 0x1a || /* MODE_SENSE */
358                             val == 0x1b || /* START_STOP */
359                             val == 0x3c || /* READ_BUFFER */
360                             0)
361                                 len = 6;
362                         else if (val == 0x25 || /* READ_CAPACITY */
363                                  val == 0x28 || /* READ10 */
364                                  val == 0x2a || /* WRITE10 */
365                                  val == 0x2f || /* VERIFY10 */
366                                  0)
367                                 len = 10;
368                         else {
369                                 stat = 1;
370                                 goto fail;
371                         }
372                 }
373                 len--;
374         fail:
375                 scsi_nreq_nack();
376         }
377         scsi_assert &= ~MASK(BB_ASSERT_CD);
378         stat = scsi_do_cmd();
379         scsi_dbg("Status phase (stat=%x)\n", stat);
380         scsi_assert |= MASK(BB_ASSERT_IO) | MASK(BB_ASSERT_CD);
381         scsi_set_data(stat);
382         scsi_req_ack();
383         scsi_nreq_nack();
384         scsi_dbg("Message IN phase (stat=%x)\n", stat);
385         scsi_assert |= MASK(BB_ASSERT_MSG);
386         scsi_set_data(0);
387         scsi_req_ack();
388         scsi_nreq_nack();
389         scsi_assert = 0;
390         scsi_set_assert();
391 }
392