245bf1d26e59964bfa7ba9b20b8c428397dfdc95
[SCSI2SD-V6.git] / software / SCSI2SD / SCSI2SD.cydsn / scsi.c
1 //      Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\r
2 //\r
3 //      This file is part of SCSI2SD.\r
4 //\r
5 //      SCSI2SD is free software: you can redistribute it and/or modify\r
6 //      it under the terms of the GNU General Public License as published by\r
7 //      the Free Software Foundation, either version 3 of the License, or\r
8 //      (at your option) any later version.\r
9 //\r
10 //      SCSI2SD is distributed in the hope that it will be useful,\r
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 //      GNU General Public License for more details.\r
14 //\r
15 //      You should have received a copy of the GNU General Public License\r
16 //      along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 #include "device.h"\r
19 #include "scsi.h"\r
20 #include "scsiPhy.h"\r
21 #include "config.h"\r
22 #include "bits.h"\r
23 #include "diagnostic.h"\r
24 #include "disk.h"\r
25 #include "inquiry.h"\r
26 #include "led.h"\r
27 #include "mode.h"\r
28 #include "disk.h"\r
29 \r
30 #include <string.h>\r
31 \r
32 // Global SCSI device state.\r
33 ScsiDevice scsiDev;\r
34 \r
35 static void enter_SelectionPhase(void);\r
36 static void process_SelectionPhase(void);\r
37 static void enter_BusFree(void);\r
38 static void enter_MessageIn(uint8 message);\r
39 static void process_MessageIn(void);\r
40 static void enter_Status(uint8 status);\r
41 static void process_Status(void);\r
42 static void enter_DataIn(int len);\r
43 static void process_DataIn(void);\r
44 static void process_DataOut(void);\r
45 static void process_Command(void);\r
46 \r
47 static void doReserveRelease(void);\r
48 \r
49 static void enter_BusFree()\r
50 {\r
51         scsiEnterPhase(BUS_FREE);\r
52 \r
53         ledOff();\r
54 \r
55         scsiDev.phase = BUS_FREE;\r
56         SCSI_ClearPin(SCSI_Out_BSY);\r
57 }\r
58 \r
59 static void enter_MessageIn(uint8 message)\r
60 {\r
61         scsiDev.msgIn = message;\r
62         scsiDev.phase = MESSAGE_IN;\r
63 }\r
64 \r
65 static void process_MessageIn()\r
66 {\r
67         scsiEnterPhase(MESSAGE_IN);\r
68         scsiWriteByte(scsiDev.msgIn);\r
69 \r
70         if (scsiDev.atnFlag)\r
71         {\r
72                 // If there was a parity error, we go\r
73                 // back to MESSAGE_OUT first, get out parity error message, then come\r
74                 // back here.\r
75         }\r
76         else /*if (scsiDev.msgIn == MSG_COMMAND_COMPLETE)*/\r
77         {\r
78                 enter_BusFree();\r
79         }\r
80 }\r
81 \r
82 static void messageReject()\r
83 {\r
84         scsiEnterPhase(MESSAGE_IN);\r
85         scsiWriteByte(MSG_REJECT);\r
86 }\r
87 \r
88 static void enter_Status(uint8 status)\r
89 {\r
90         scsiDev.status = status;\r
91         scsiDev.phase = STATUS;\r
92 }\r
93 \r
94 static void process_Status()\r
95 {\r
96         scsiEnterPhase(STATUS);\r
97         scsiWriteByte(scsiDev.status);\r
98 \r
99         // Command Complete occurs AFTER a valid status has been\r
100         // sent. then we go bus-free.\r
101         enter_MessageIn(MSG_COMMAND_COMPLETE);\r
102 }\r
103 \r
104 static void enter_DataIn(int len)\r
105 {\r
106         scsiDev.dataLen = len;\r
107         scsiDev.phase = DATA_IN;\r
108 }\r
109 \r
110 static void process_DataIn()\r
111 {\r
112         uint32 len;\r
113         \r
114         if (scsiDev.dataLen > sizeof(scsiDev.data))\r
115         {\r
116                 scsiDev.dataLen = sizeof(scsiDev.data);\r
117         }\r
118 \r
119         len = scsiDev.dataLen - scsiDev.dataPtr;\r
120         if (len > 0)\r
121         {\r
122                 scsiEnterPhase(DATA_IN);\r
123                 scsiWrite(scsiDev.data + scsiDev.dataPtr, len);\r
124                 scsiDev.dataPtr += len;\r
125         }\r
126 \r
127         if ((scsiDev.dataPtr >= scsiDev.dataLen) &&\r
128                 (transfer.currentBlock == transfer.blocks))\r
129         {\r
130                 enter_Status(GOOD);\r
131         }\r
132 }\r
133 \r
134 static void process_DataOut()\r
135 {\r
136         uint32 len;\r
137         \r
138         if (scsiDev.dataLen > sizeof(scsiDev.data))\r
139         {\r
140                 scsiDev.dataLen = sizeof(scsiDev.data);\r
141         }\r
142 \r
143         scsiDev.parityError = 0;\r
144         len = scsiDev.dataLen - scsiDev.dataPtr;\r
145         if (len > 0)\r
146         {\r
147                 scsiEnterPhase(DATA_OUT);\r
148 \r
149                 scsiRead(scsiDev.data + scsiDev.dataPtr, len);\r
150                 scsiDev.dataPtr += len;\r
151 \r
152                 // TODO re-implement parity checking\r
153                 if (0 && scsiDev.parityError && config->enableParity)\r
154                 {\r
155                         scsiDev.sense.code = ABORTED_COMMAND;\r
156                         scsiDev.sense.asc = SCSI_PARITY_ERROR;\r
157                         enter_Status(CHECK_CONDITION);\r
158                 }\r
159         }\r
160 \r
161         if ((scsiDev.dataPtr >= scsiDev.dataLen) &&\r
162                 (transfer.currentBlock == transfer.blocks))\r
163         {\r
164                 enter_Status(GOOD);\r
165         }\r
166 }\r
167 \r
168 static const uint8 CmdGroupBytes[8] = {6, 10, 10, 6, 6, 12, 6, 6};\r
169 static void process_Command()\r
170 {\r
171         int group;\r
172         int cmdSize;\r
173         uint8 command;\r
174         uint8 lun;\r
175         \r
176         scsiEnterPhase(COMMAND);\r
177         scsiDev.parityError = 0;\r
178 \r
179         memset(scsiDev.cdb, 0, sizeof(scsiDev.cdb));\r
180         scsiDev.cdb[0] = scsiReadByte();\r
181 \r
182         group = scsiDev.cdb[0] >> 5;\r
183         cmdSize = CmdGroupBytes[group];\r
184         scsiRead(scsiDev.cdb + 1, cmdSize - 1);\r
185 \r
186         command = scsiDev.cdb[0];\r
187         lun = scsiDev.cdb[1] >> 5;\r
188 \r
189         if (scsiDev.parityError)\r
190         {\r
191                 scsiDev.sense.code = ABORTED_COMMAND;\r
192                 scsiDev.sense.asc = SCSI_PARITY_ERROR;\r
193                 enter_Status(CHECK_CONDITION);\r
194         }\r
195         else if (command == 0x12)\r
196         {\r
197                 scsiInquiry();\r
198         }\r
199         else if (command == 0x03)\r
200         {\r
201                 // REQUEST SENSE\r
202                 uint32 allocLength = scsiDev.cdb[4];\r
203                 if (allocLength == 0) allocLength = 256;\r
204                 memset(scsiDev.data, 0, 18);\r
205                 scsiDev.data[0] = 0xF0;\r
206                 scsiDev.data[2] = scsiDev.sense.code & 0x0F;\r
207 \r
208                 // TODO populate "information" field with requested LBA.\r
209                 // TODO support more detailed sense data ?\r
210 \r
211                 scsiDev.data[12] = scsiDev.sense.asc >> 8;\r
212                 scsiDev.data[13] = scsiDev.sense.asc;\r
213 \r
214                 // Silently truncate results. SCSI-2 spec 8.2.14.\r
215                 enter_DataIn(allocLength < 18 ? allocLength : 18);\r
216 \r
217                 // This is a good time to clear out old sense information.\r
218                 scsiDev.sense.code = NO_SENSE;\r
219                 scsiDev.sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;\r
220         }\r
221         // Some old SCSI drivers do NOT properly support\r
222         // unitAttention. OTOH, Linux seems to require it\r
223         // confirmed LCIII with unknown scsi driver fials here.\r
224         else if (scsiDev.unitAttention && config->enableUnitAttention)\r
225         {\r
226                 scsiDev.sense.code = UNIT_ATTENTION;\r
227                 scsiDev.sense.asc = scsiDev.unitAttention;\r
228                 enter_Status(CHECK_CONDITION);\r
229         }\r
230         else if (lun)\r
231         {\r
232                 scsiDev.sense.code = ILLEGAL_REQUEST;\r
233                 scsiDev.sense.asc = LOGICAL_UNIT_NOT_SUPPORTED;\r
234                 enter_Status(CHECK_CONDITION);\r
235         }\r
236         else if (command == 0x17 || command == 0x16)\r
237         {\r
238                 doReserveRelease();\r
239         }\r
240         else if ((scsiDev.reservedId >= 0) &&\r
241                 (scsiDev.reservedId != scsiDev.initiatorId))\r
242         {\r
243                 enter_Status(CONFLICT);\r
244         }\r
245         else if (command == 0x1C)\r
246         {\r
247                 scsiReceiveDiagnostic();\r
248         }\r
249         else if (command == 0x1D)\r
250         {\r
251                 scsiSendDiagnostic();\r
252         }\r
253         else if (\r
254                 !scsiModeCommand() &&\r
255                 !scsiDiskCommand())\r
256         {\r
257                 scsiDev.sense.code = ILLEGAL_REQUEST;\r
258                 scsiDev.sense.asc = INVALID_COMMAND_OPERATION_CODE;\r
259                 enter_Status(CHECK_CONDITION);\r
260         }\r
261 \r
262         // Successful\r
263         if (scsiDev.phase == COMMAND) // No status set, and not in DATA_IN\r
264         {\r
265                 enter_Status(GOOD);\r
266         }\r
267 }\r
268 \r
269 static void doReserveRelease()\r
270 {\r
271         int extentReservation = scsiDev.cdb[1] & 1;\r
272         int thirdPty = scsiDev.cdb[1] & 0x10;\r
273         int thirdPtyId = (scsiDev.cdb[1] >> 1) & 0x7;\r
274         uint8 command = scsiDev.cdb[0];\r
275 \r
276         int canRelease =\r
277                 (!thirdPty && (scsiDev.initiatorId == scsiDev.reservedId)) ||\r
278                         (thirdPty &&\r
279                                 (scsiDev.reserverId == scsiDev.initiatorId) &&\r
280                                 (scsiDev.reservedId == thirdPtyId)\r
281                         );\r
282 \r
283         if (extentReservation)\r
284         {\r
285                 // Not supported.\r
286                 scsiDev.sense.code = ILLEGAL_REQUEST;\r
287                 scsiDev.sense.asc = INVALID_FIELD_IN_CDB;\r
288                 enter_Status(CHECK_CONDITION);\r
289         }\r
290         else if (command == 0x17) // release\r
291         {\r
292                 if ((scsiDev.reservedId < 0) || canRelease)\r
293                 {\r
294                         scsiDev.reservedId = -1;\r
295                         scsiDev.reserverId = -1;\r
296                 }\r
297                 else\r
298                 {\r
299                         enter_Status(CONFLICT);\r
300                 }\r
301         }\r
302         else // assume reserve.\r
303         {\r
304                 if ((scsiDev.reservedId < 0) || canRelease)\r
305                 {\r
306                         scsiDev.reserverId = scsiDev.initiatorId;\r
307                         if (thirdPty)\r
308                         {\r
309                                 scsiDev.reservedId = thirdPtyId;\r
310                         }\r
311                         else\r
312                         {\r
313                                 scsiDev.reservedId = scsiDev.initiatorId;\r
314                         }\r
315                 }\r
316                 else\r
317                 {\r
318                         // Already reserved by someone else!\r
319                         enter_Status(CONFLICT);\r
320                 }\r
321         }\r
322 }\r
323 \r
324 static void scsiReset()\r
325 {\r
326         ledOff();\r
327         // done in verilog SCSI_Out_DBx_Write(0);\r
328         SCSI_CTL_IO_Write(0);\r
329         SCSI_ClearPin(SCSI_Out_ATN);\r
330         SCSI_ClearPin(SCSI_Out_BSY);\r
331         SCSI_ClearPin(SCSI_Out_ACK);\r
332         SCSI_ClearPin(SCSI_Out_RST);\r
333         SCSI_ClearPin(SCSI_Out_SEL);\r
334         SCSI_ClearPin(SCSI_Out_REQ);\r
335         SCSI_ClearPin(SCSI_Out_MSG);\r
336         SCSI_ClearPin(SCSI_Out_CD);\r
337 \r
338         scsiDev.parityError = 0;\r
339         scsiDev.phase = BUS_FREE;\r
340 \r
341         if (scsiDev.unitAttention != POWER_ON_RESET)\r
342         {\r
343                 scsiDev.unitAttention = SCSI_BUS_RESET;\r
344         }\r
345         scsiDev.reservedId = -1;\r
346         scsiDev.reserverId = -1;\r
347         scsiDev.sense.code = NO_SENSE;\r
348         scsiDev.sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;\r
349         scsiDiskReset();\r
350 \r
351         // Sleep to allow the bus to settle down a bit.\r
352         // We must be ready again within the "Reset to selection time" of\r
353         // 250ms.\r
354         // There is no guarantee that the RST line will be negated by then.\r
355         // NOTE: We could be connected and powered by USB for configuration,\r
356         // in which case TERMPWR cannot be supplied, and reset will ALWAYS\r
357         // be true.\r
358         CyDelay(10); // 10ms.\r
359         scsiDev.resetFlag = SCSI_ReadPin(SCSI_RST_INT);\r
360         scsiDev.atnFlag = 0;\r
361 }\r
362 \r
363 static void enter_SelectionPhase()\r
364 {\r
365         // Ignore stale versions of this flag, but ensure we know the\r
366         // current value if the flag is still set.\r
367         scsiDev.atnFlag = SCSI_ReadPin(SCSI_ATN_INT);\r
368         scsiDev.parityError = 0;\r
369         scsiDev.dataPtr = 0;\r
370         scsiDev.savedDataPtr = 0;\r
371         scsiDev.dataLen = 0;\r
372         scsiDev.status = GOOD;\r
373         scsiDev.phase = SELECTION;\r
374 \r
375         transfer.blocks = 0;\r
376         transfer.currentBlock = 0;\r
377 }\r
378 \r
379 static void process_SelectionPhase()\r
380 {\r
381         uint8 mask = scsiReadDBxPins();\r
382         int goodParity = (Lookup_OddParity[mask] == SCSI_ReadPin(SCSI_In_DBP));\r
383 \r
384         int sel = SCSI_ReadPin(SCSI_In_SEL);\r
385         int bsy = SCSI_ReadPin(SCSI_In_BSY);\r
386         if (!bsy && sel &&\r
387                 (mask & scsiDev.scsiIdMask) &&\r
388                 (goodParity || !config->enableParity) && (countBits(mask) == 2))\r
389         {\r
390                 // We've been selected!\r
391                 // Assert BSY - Selection success!\r
392                 // must happen within 200us (Selection abort time) of seeing our\r
393                 // ID + SEL.\r
394                 // (Note: the initiator will be waiting the "Selection time-out delay"\r
395                 // for our BSY response, which is actually a very generous 250ms)\r
396                 SCSI_SetPin(SCSI_Out_BSY);\r
397                 ledOn();\r
398 \r
399                 // Wait until the end of the selection phase.\r
400                 while (!scsiDev.resetFlag)\r
401                 {\r
402                         scsiDev.atnFlag |= SCSI_ReadPin(SCSI_ATN_INT);\r
403                         if (!SCSI_ReadPin(SCSI_In_SEL))\r
404                         {\r
405                                 break;\r
406                         }\r
407                 }\r
408 \r
409                 // Save our initiator now that we're no longer in a time-critical\r
410                 // section.\r
411                 {\r
412                         int i;\r
413                         uint8 initiatorMask = mask ^ scsiDev.scsiIdMask;\r
414                         scsiDev.initiatorId = 0;\r
415                         for (i = 0; i < 8; ++i)\r
416                         {\r
417                                 if (initiatorMask & (1 << i))\r
418                                 {\r
419                                         scsiDev.initiatorId = i;\r
420                                         break;\r
421                                 }\r
422                         }\r
423                 }\r
424 \r
425                 scsiDev.phase = COMMAND;\r
426                 \r
427                 CyDelayUs(2); // DODGY HACK\r
428                 scsiDev.atnFlag |= SCSI_ReadPin(SCSI_ATN_INT);\r
429         }\r
430         else if (!sel)\r
431         {\r
432                 scsiDev.phase = BUS_BUSY;\r
433         }\r
434 }\r
435 \r
436 static void process_MessageOut()\r
437 {\r
438         scsiEnterPhase(MESSAGE_OUT);\r
439 \r
440         scsiDev.atnFlag = 0;\r
441         scsiDev.parityError = 0;\r
442         scsiDev.msgOut = scsiReadByte();\r
443 \r
444         if (scsiDev.parityError)\r
445         {\r
446                 // Skip the remaining message bytes, and then start the MESSAGE_OUT\r
447                 // phase again from the start. The initiator will re-send the\r
448                 // same set of messages.\r
449                 while (SCSI_ReadPin(SCSI_ATN_INT) && !scsiDev.resetFlag)\r
450                 {\r
451                         scsiReadByte();\r
452                 }\r
453 \r
454                 // Go-back and try the message again.\r
455                 scsiDev.atnFlag = 1;\r
456                 scsiDev.parityError = 0;\r
457         }\r
458         else if (scsiDev.msgOut == 0x00)\r
459         {\r
460                 // COMMAND COMPLETE. but why would the target be receiving this ? nfi.\r
461                 enter_BusFree();\r
462         }\r
463         else if (scsiDev.msgOut == 0x06)\r
464         {\r
465                 // ABORT\r
466                 scsiDiskReset();\r
467                 enter_BusFree();\r
468         }\r
469         else if (scsiDev.msgOut == 0x0C)\r
470         {\r
471                 // BUS DEVICE RESET\r
472 \r
473                 scsiDiskReset();\r
474 \r
475                 scsiDev.unitAttention = SCSI_BUS_RESET;\r
476 \r
477                 // ANY initiator can reset the reservation state via this message.\r
478                 scsiDev.reservedId = -1;\r
479                 scsiDev.reserverId = -1;\r
480                 enter_BusFree();\r
481         }\r
482         else if (scsiDev.msgOut == 0x05)\r
483         {\r
484                 // Initiate Detected Error\r
485                 // Ignore for now\r
486         }\r
487         else if (scsiDev.msgOut == 0x0F)\r
488         {\r
489                 // INITIATE RECOVERY\r
490                 // Ignore for now\r
491         }\r
492         else if (scsiDev.msgOut == 0x10)\r
493         {\r
494                 // RELEASE RECOVERY\r
495                 // Ignore for now\r
496                 enter_BusFree();\r
497         }\r
498         else if (scsiDev.msgOut == MSG_REJECT)\r
499         {\r
500                 // Message Reject\r
501                 // Oh well.\r
502                 scsiDev.resetFlag = 1;\r
503         }\r
504         else if (scsiDev.msgOut == 0x08)\r
505         {\r
506                 // NOP\r
507         }\r
508         else if (scsiDev.msgOut == 0x09)\r
509         {\r
510                 // Message Parity Error\r
511                 // Go back and re-send the last message.\r
512                 scsiDev.phase = MESSAGE_IN;\r
513         }\r
514         else if (scsiDev.msgOut & 0x80) // 0x80 -> 0xFF\r
515         {\r
516                 // IDENTIFY\r
517                 // We don't disconnect, so ignore disconnect privilege.\r
518                 if ((scsiDev.msgOut & 0x18) || // Reserved bits set.\r
519                         (scsiDev.msgOut & 0x20)  || // We don't have any target routines!\r
520                         (scsiDev.msgOut & 0x7) // We only support LUN 0!\r
521                         )\r
522                 {\r
523                         messageReject();\r
524                 }\r
525         }\r
526         else if (scsiDev.msgOut >= 0x20 && scsiDev.msgOut <= 0x2F)\r
527         {\r
528                 // Two byte message. We don't support these. read and discard.\r
529                 scsiReadByte();\r
530         }\r
531         else if (scsiDev.msgOut == 0x01)\r
532         {\r
533                 int i;\r
534                 \r
535                 // Extended message.\r
536                 int msgLen = scsiReadByte();\r
537                 if (msgLen == 0) msgLen = 256;\r
538                 for (i = 0; i < msgLen && !scsiDev.resetFlag; ++i)\r
539                 {\r
540                         // Discard bytes.\r
541                         scsiReadByte();\r
542                 }\r
543 \r
544                 // We don't support ANY extended messages.\r
545                 // Modify Data Pointer:  We don't support reselection.\r
546                 // Wide Data Transfer Request: No. 8bit only.\r
547                 // Synchronous data transfer request. No, we can't do that.\r
548                 // We don't support any 2-byte messages either.\r
549                 // And we don't support any optional 1-byte messages.\r
550                 // In each case, the correct response is MESSAGE REJECT.\r
551                 messageReject();\r
552         }\r
553         else\r
554         {\r
555                 messageReject();\r
556         }\r
557         \r
558         // Re-check the ATN flag. We won't get another interrupt if\r
559         // it stays asserted.\r
560         CyDelayUs(2); // DODGY HACK\r
561         scsiDev.atnFlag |= SCSI_ReadPin(SCSI_ATN_INT);\r
562 }\r
563 \r
564 \r
565 // TODO remove.\r
566 // This is a hack until I work out why the ATN ISR isn't\r
567 // running when it should.\r
568 static int atnErrCount = 0;\r
569 static int atnHitCount = 0;\r
570 static void checkATN()\r
571 {\r
572         int atn = SCSI_ReadPin(SCSI_ATN_INT);\r
573         if (atn && !scsiDev.atnFlag)\r
574         {\r
575                 atnErrCount++;\r
576                 scsiDev.atnFlag = 1;\r
577         }\r
578         else if (atn && scsiDev.atnFlag)\r
579         {\r
580                 atnHitCount++;\r
581         }\r
582 }\r
583 \r
584 void scsiPoll(void)\r
585 {\r
586         if (scsiDev.resetFlag)\r
587         {\r
588                 scsiReset();\r
589         }\r
590 \r
591         switch (scsiDev.phase)\r
592         {\r
593         case BUS_FREE:\r
594                 if (SCSI_ReadPin(SCSI_In_BSY))\r
595                 {\r
596                         scsiDev.phase = BUS_BUSY;\r
597                 }\r
598         break;\r
599 \r
600         case BUS_BUSY:\r
601                 // Someone is using the bus. Perhaps they are trying to\r
602                 // select us.\r
603                 if (SCSI_ReadPin(SCSI_In_SEL))\r
604                 {\r
605                         enter_SelectionPhase();\r
606                 }\r
607                 else if (!SCSI_ReadPin(SCSI_In_BSY))\r
608                 {\r
609                         scsiDev.phase = BUS_FREE;\r
610                 }\r
611         break;\r
612 \r
613         case ARBITRATION:\r
614                 // TODO Support reselection.\r
615                 break;\r
616 \r
617         case SELECTION:\r
618                 process_SelectionPhase();\r
619         break;\r
620 \r
621         case RESELECTION:\r
622                 // Not currently supported!\r
623         break;\r
624 \r
625         case COMMAND:\r
626                 checkATN();\r
627                 if (scsiDev.atnFlag)\r
628                 {\r
629                         process_MessageOut();\r
630                 }\r
631                 else\r
632                 {\r
633                         process_Command();\r
634                 }\r
635         break;\r
636 \r
637         case DATA_IN:\r
638                 checkATN();\r
639                 if (scsiDev.atnFlag)\r
640                 {\r
641                         process_MessageOut();\r
642                 }\r
643                 else\r
644                 {\r
645                         process_DataIn();\r
646                 }\r
647         break;\r
648 \r
649         case DATA_OUT:\r
650                 checkATN();\r
651                 if (scsiDev.atnFlag)\r
652                 {\r
653                         process_MessageOut();\r
654                 }\r
655                 else\r
656                 {\r
657                         process_DataOut();\r
658                 }\r
659         break;\r
660 \r
661         case STATUS:\r
662                 checkATN();\r
663                 if (scsiDev.atnFlag)\r
664                 {\r
665                         process_MessageOut();\r
666                 }\r
667                 else\r
668                 {\r
669                         process_Status();\r
670                 }\r
671         break;\r
672 \r
673         case MESSAGE_IN:\r
674                 checkATN();\r
675                 if (scsiDev.atnFlag)\r
676                 {\r
677                         process_MessageOut();\r
678                 }\r
679                 else\r
680                 {\r
681                         process_MessageIn();\r
682                 }\r
683 \r
684         break;\r
685 \r
686         case MESSAGE_OUT:\r
687                 process_MessageOut();\r
688         break;\r
689         }\r
690 }\r
691 \r
692 void scsiInit()\r
693 {\r
694         scsiDev.scsiIdMask = 1 << (config->scsiId);\r
695 \r
696         scsiDev.atnFlag = 0;\r
697         scsiDev.resetFlag = 1;\r
698         scsiDev.phase = BUS_FREE;\r
699         scsiDev.reservedId = -1;\r
700         scsiDev.reserverId = -1;\r
701         scsiDev.unitAttention = POWER_ON_RESET;\r
702 }\r
703 \r