|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22:
23: /* Sym8xxExecute.m created by russb2 on Sat 30-May-1998 */
24:
25: #include "Sym8xxController.h"
26:
27: extern "C"
28: {
29: unsigned int ml_phys_read( vm_offset_t paddr );
30: };
31:
32: #if 0
33: static UInt32 dropInt = 0;
34: #endif
35:
36: void Sym8xxSCSIController::Sym8xxStartSRB( SRB *srb )
37: {
38:
39: srb->nexus.targetParms.scntl3Reg = adapter->targetClocks[srb->target].scntl3Reg;
40: srb->nexus.targetParms.sxferReg = adapter->targetClocks[srb->target].sxferReg;
41:
42: adapter->nexusPtrsVirt[srb->nexus.tag] = &srb->nexus;
43: adapter->nexusPtrsPhys[srb->nexus.tag] = (Nexus *)OSSwapHostToLittleInt32( (UInt32)&srb->srbPhys->nexus );
44: adapter->schedMailBox[mailBoxIndex++] = (Nexus *)OSSwapHostToLittleInt32 ( (UInt32)&srb->srbPhys->nexus );
45:
46: Sym8xxSignalScript( srb );
47: }
48:
49:
50: /*-----------------------------------------------------------------------------*
51: * Interrupts from the Symbios chipset are dispatched here at task time under the
52: * IOThread's context.
53: *-----------------------------------------------------------------------------*/
54: void Sym8xxSCSIController::interruptOccurred( IOInterruptEventSource *ies, int intCount )
55: {
56: do
57: {
58: /*
59: * The chipset's ISTAT reg gives us the general interrupting condiditions,
60: * with DSTAT and SIST providing more detailed information.
61: */
62: istatReg = Sym8xxReadRegs( chipBaseAddr, ISTAT, ISTAT_SIZE );
63:
64: /* The INTF bit in ISTAT indicates that the script is signalling the driver
65: * that its IODone mailbox is full and that we should process a completed
66: * request. The script continues to run after posting this interrupt unlike
67: * other chipset interrupts which require the driver to restart the script
68: * engine.
69: */
70: if ( istatReg & INTF )
71: {
72: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, istatReg );
73: #if 0
74: if ( dropInt++ > 100 )
75: {
76: dropInt = 0;
77: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
78: continue;
79: }
80: #endif
81: Sym8xxProcessIODone();
82: }
83:
84: /*
85: * Handle remaining interrupting conditions
86: */
87: if ( istatReg & (SIP | DIP) )
88: {
89: Sym8xxProcessInterrupt();
90: }
91: }
92: while ( istatReg & (SIP | DIP | INTF) );
93:
94: getWorkLoop()->enableAllInterrupts();
95:
96: }
97:
98: /*-----------------------------------------------------------------------------*
99: * Process a request posted in the script's IODone mailbox.
100: *
101: *-----------------------------------------------------------------------------*/
102: void Sym8xxSCSIController::Sym8xxProcessIODone()
103: {
104: SRB *srb;
105: Nexus *nexus;
106: IODoneMailBox *pMailBox;
107:
108:
109: /*
110: * The IODone mailbox contains an index into our Nexus pointer tables.
111: *
112: * The Nexus struct is part of the SRB so we can get our SRB address
113: * by subtracting the offset of the Nexus struct in the SRB.
114: */
115: pMailBox = (IODoneMailBox *)&SCRIPT_VAR(R_ld_IOdone_mailbox);
116: nexus = adapter->nexusPtrsVirt[pMailBox->nexus];
117: srb = (SRB *)((UInt32)nexus - offsetof(SRB, nexus));
118:
119: srb->srbSCSIStatus = pMailBox->status;
120:
121: if ( srb->srbSCSIStatus == kSCSIStatusCheckCondition )
122: {
123: Sym8xxCheckRequestSense( srb );
124: }
125:
126: if ( srb->srbSCSIResult == kIOReturnSuccess )
127: {
128: if ( srb->srbSCSIStatus != kSCSIStatusGood )
129: {
130: srb->srbSCSIResult = kIOReturnIOError;
131: }
132: }
133:
134: Sym8xxUpdateXferOffset( srb );
135:
136: /*
137: * Clear the completed Nexus pointer from our tables and clear the
138: * IODone mailbox.
139: */
140: adapter->nexusPtrsVirt[pMailBox->nexus] = (Nexus *) -1;
141: adapter->nexusPtrsPhys[pMailBox->nexus] = (Nexus *) -1;
142: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
143:
144: /*
145: * Wake up the client's thread to do post-processing
146: */
147: Sym8xxCompleteSRB( srb );
148:
149: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase];
150: }
151: /*-----------------------------------------------------------------------------*
152: *
153: *
154: *-----------------------------------------------------------------------------*/
155: void Sym8xxSCSIController::Sym8xxCompleteSRB( SRB *srb )
156: {
157: IOSCSICommand *scsiCommand;
158: SCSIResults scsiResults;
159:
160: scsiCommand = srb->scsiCommand;
161:
162: bzero( &scsiResults, sizeof(scsiResults) );
163:
164: scsiResults.returnCode = srb->srbSCSIResult;
165:
166: if ( srb == abortSRB )
167: {
168: abortSRB = 0;
169: if ( abortReqPending == true )
170: {
171: abortReqPending = false;
172: enableCommands();
173: }
174: }
175: else
176: {
177: scsiResults.bytesTransferred = srb->xferDone;
178: scsiResults.scsiStatus = srb->srbSCSIStatus;
179: }
180:
181: scsiCommand->setResults( &scsiResults );
182: scsiCommand->complete();
183: }
184:
185: /*-----------------------------------------------------------------------------*
186: * General script interrupt processing
187: *
188: *-----------------------------------------------------------------------------*/
189: void Sym8xxSCSIController::Sym8xxProcessInterrupt()
190: {
191: SRB *srb = NULL;
192: Nexus *nexus = NULL;
193: UInt32 nexusIndex;
194: UInt32 scriptPhase;
195: UInt32 fifoCnt = 0;
196: UInt32 dspsReg = 0;
197: UInt32 dspReg = 0;
198:
199:
200: /*
201: * Read DSTAT/SIST regs to determine why the script stopped.
202: */
203: dstatReg = Sym8xxReadRegs( chipBaseAddr, DSTAT, DSTAT_SIZE );
204: IODelay(5);
205: sistReg = Sym8xxReadRegs( chipBaseAddr, SIST, SIST_SIZE );
206:
207: // printf( "SCSI(Symbios8xx): SIST = %04x DSTAT = %02x\n\r", sistReg, dstatReg );
208:
209: /*
210: * This Script var tells us what the script thinks it was doing when the interrupt occurred.
211: */
212: scriptPhase = OSSwapHostToLittleInt32( SCRIPT_VAR(R_ld_phase_flag) );
213:
214: /*
215: * SCSI Bus reset detected
216: *
217: * Clean up the carnage.
218: * Note: This may be either an adapter or target initiated reset.
219: */
220: if ( sistReg & RSTI )
221: {
222: Sym8xxProcessSCSIBusReset();
223: return;
224: }
225:
226: /*
227: * Calculate our current SRB/Nexus.
228: *
229: * Read a script var to determine the index of the nexus it was processing
230: * when the interrupt occurred. The script will invalidate the index if there
231: * is no target currently connected or the script cannot determine which target
232: * has reconnected.
233: */
234: nexusIndex = OSSwapHostToLittleInt32(SCRIPT_VAR(R_ld_nexus_index));
235: if ( nexusIndex >= MAX_SCSI_TAG )
236: {
237: Sym8xxProcessNoNexus();
238: return;
239: }
240: nexus = adapter->nexusPtrsVirt[nexusIndex];
241: if ( nexus == (Nexus *) -1 )
242: {
243: Sym8xxProcessNoNexus();
244: return;
245: }
246: srb = (SRB *)((UInt32)nexus - offsetof(SRB, nexus));
247:
248: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_phase_handler];
249:
250: /*
251: * Parity and SCSI Gross Errors.
252: *
253: * Abort the current connection. The abort completion will trigger
254: * clean-up of the current SRB/Nexus.
255: */
256: if ( sistReg & PAR )
257: {
258: srb->srbSCSIResult = kIOReturnIOError;
259: Sym8xxAbortCurrent( srb );
260: }
261:
262: else if ( sistReg & SGE )
263: {
264: Sym8xxAbortCurrent( srb );
265: }
266:
267: /*
268: * Unexpected disconnect.
269: *
270: * If we were currently trying to abort this connection then mark the abort
271: * as completed. For all cases clean-up and wake-up the client thread.
272: */
273: else if ( sistReg & UDC )
274: {
275: if ( srb->srbSCSIResult == kIOReturnSuccess )
276: {
277: srb->srbSCSIResult = kIOReturnAborted;
278: }
279: adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1;
280: adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1;
281:
282: if ( scriptPhase == A_kphase_ABORT_CURRENT )
283: {
284: abortCurrentSRB = NULL;
285: }
286:
287: Sym8xxCompleteSRB( srb );
288:
289: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase];
290: }
291:
292: /*
293: * Phase Mis-match
294: *
295: * If we are in MsgOut phase then calculate how much of the message we sent. For
296: * now, however, we dont handle the target rejecting messages, so the request is aborted.
297: *
298: * If we are in DataIn/DataOut phase. We update the SRB/Nexus with our current data
299: * pointers.
300: */
301: else if ( sistReg & MA )
302: {
303: if ( scriptPhase == A_kphase_MSG_OUT )
304: {
305: srb->srbMsgResid = Sym8xxCheckFifo( srb, &fifoCnt );
306: nexus->msg.ppData = OSSwapHostToLittleInt32( OSSwapHostToLittleInt32(nexus->msg.ppData)
307: + OSSwapHostToLittleInt32(nexus->msg.length)
308: - srb->srbMsgResid );
309: nexus->msg.length = OSSwapHostToLittleInt32( srb->srbMsgResid );
310:
311: Sym8xxAbortCurrent( srb );
312: }
313: else if ( (scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_DATA_IN) )
314: {
315: Sym8xxAdjustDataPtrs( srb, nexus );
316: }
317: else
318: {
319: IOLog("SCSI(Symbios8xx): Unexpected phase mismatch - scriptPhase = %08x\n\r", (int)scriptPhase);
320: Sym8xxAbortCurrent( srb );
321: }
322:
323: Sym8xxClearFifo();
324: }
325:
326: /*
327: * Selection Timeout.
328: *
329: * Clean-up the current request.
330: */
331: else if ( sistReg & STO )
332: {
333: srb->srbSCSIResult = kIOReturnOffline;
334:
335: adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1;
336: adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1;
337: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
338:
339: Sym8xxCompleteSRB( srb );
340:
341: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase];
342: }
343:
344: /*
345: * Handle script initiated interrupts
346: */
347: else if ( dstatReg & SIR )
348: {
349: dspsReg = Sym8xxReadRegs( chipBaseAddr, DSPS, DSPS_SIZE );
350:
351: // printf( "SCSI(Symbios8xx): DSPS = %08x\n\r", dspsReg );
352:
353: switch ( dspsReg )
354: {
355: /*
356: * Non-zero SCSI status
357: *
358: * Send request sense CDB or complete request depending on SCSI status value
359: */
360: case A_status_error:
361: Sym8xxProcessIODone();
362: break;
363:
364: /*
365: * Received SDTR/WDTR message from target.
366: *
367: * Prepare reply message if we requested negotiation. Otherwise reject
368: * target initiated negotiation.
369: */
370: case A_negotiateSDTR:
371: Sym8xxNegotiateSDTR( srb, nexus );
372: break;
373:
374: case A_negotiateWDTR:
375: Sym8xxNegotiateWDTR( srb, nexus );
376: break;
377:
378: /*
379: * Partial SG List completed.
380: *
381: * Refresh the list from the remaining addresses to be transfered and set the
382: * script engine to branch into the list.
383: */
384: case A_sglist_complete:
385: Sym8xxUpdateSGList( srb );
386: scriptRestartAddr = (UInt32)&srb->srbPhys->nexus.sgListData[2];
387: break;
388:
389: /*
390: * Completed abort request
391: *
392: * Clean-up the aborted request.
393: */
394: case A_abort_current:
395: adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1;
396: adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1;
397:
398: abortCurrentSRB = NULL;
399:
400: Sym8xxCompleteSRB( srb );
401:
402: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase];
403: break;
404:
405: /*
406: * Script detected protocol errors
407: *
408: * Abort the current request.
409: */
410: case A_unknown_msg_reject:
411: case A_unknown_phase:
412: case A_unexpected_msg:
413: case A_unexpected_ext_msg:
414: srb->srbSCSIResult = kIOReturnAborted;
415: Sym8xxAbortCurrent( srb );
416: break;
417:
418: default:
419: IOLog( "SCSI(Symbios8xx): Unknown Script Int = %08x\n\r", (int)dspsReg );
420: Sym8xxAbortCurrent( srb );
421: }
422: }
423:
424: /*
425: * Illegal script instruction.
426: *
427: * We're toast! Abort the current request and hope for the best!
428: */
429: else if ( dstatReg & IID )
430: {
431: dspReg = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE );
432:
433: IOLog("SCSI(Symbios8xx): Illegal script instruction - dsp = %08x srb=%08x\n\r", (int)dspReg, (int)srb );
434:
435: Sym8xxAbortCurrent( srb );
436: }
437:
438: if ( scriptRestartAddr )
439: {
440: Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
441: }
442: }
443:
444:
445: /*-----------------------------------------------------------------------------*
446: * Current Data Pointer calculations
447: *
448: * To do data transfers the driver generates a list of script instructions
449: * in system storage to deliver data to the requested physical addresses. The
450: * script branches to the list when the target enters data transfer phase.
451: *
452: * When the target changes phase during a data transfer, data is left trapped
453: * inside the various script engine registers. This routine determines how much
454: * data was not actually transfered to/from the target and generates a new
455: * S/G List entry for the partial transfer and a branch back into the original
456: * S/G list. These script instructions are stored in two reserved slots at the
457: * top of the original S/G List.
458: *
459: *-----------------------------------------------------------------------------*/
460: void Sym8xxSCSIController::Sym8xxAdjustDataPtrs( SRB *srb, Nexus *nexus )
461: {
462: UInt32 i;
463: UInt32 sgResid;
464: UInt32 fifoCnt;
465: UInt32 dspReg;
466: UInt32 sgDone;
467: UInt8 scntl2Reg;
468: Nexus *nexusPhys;
469:
470: /*
471: * Determine SG element residual
472: *
473: * This routine returns how much of the current S/G List element the
474: * script was processing remains to be sent/received. All the information
475: * required to do this is stored in the script engine's registers.
476: */
477: sgResid = Sym8xxCheckFifo( srb, &fifoCnt );
478:
479: /*
480: * Determine which script instruction in our SGList we were executing when
481: * the target changed phase.
482: *
483: * The script engine's dspReg tells us where the script thinks it was. Based
484: * on the physical address of our current SRB/Nexus we can calculate
485: * an index into our S/G List.
486: */
487: dspReg = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE );
488:
489: i = ((dspReg - (UInt32)srb->srbPhys->nexus.sgListData) / sizeof(SGEntry)) - 1;
490:
491: if ( i > MAX_SGLIST_ENTRIES-1 )
492: {
493: IOLog("SCSI(Symbios8xx): Bad sgListIndex\n\r");
494: Sym8xxAbortCurrent( srb );
495: return;
496: }
497:
498: /*
499: * Wide/odd-byte transfers.
500: *
501: * When dealing with Wide data transfers, if a S/G List ends with an odd-transfer count, then a
502: * valid received data byte is left in the script engine's SWIDE register. The least painful way
503: * to recover this byte is to construct a small script thunk to transfer one additional byte. The
504: * script will automatically draw this byte from the SWIDE register rather than the SCSI bus.
505: * The script thunk then branches back to script's PhaseHandler entrypoint.
506: *
507: */
508: nexusPhys = &srb->srbPhys->nexus;
509:
510: scntl2Reg = Sym8xxReadRegs( chipBaseAddr, SCNTL2, SCNTL2_SIZE );
511: if ( scntl2Reg & WSR )
512: {
513: adapter->xferSWideInst[0] = OSSwapHostToLittleInt32( srb->directionMask | 1 );
514: adapter->xferSWideInst[1] = nexus->sgListData[i].physAddr;
515: adapter->xferSWideInst[2] = OSSwapHostToLittleInt32( 0x80080000 );
516: adapter->xferSWideInst[3] = OSSwapHostToLittleInt32( (UInt32)&chipRamAddrPhys[Ent_phase_handler] );
517:
518: scriptRestartAddr = (UInt32) adapterPhys->xferSWideInst;
519:
520: /*
521: * Note: There is an assumption here that the sgResid count will be > 1. It appears
522: * that the script engine does not generate a phase-mismatch interrupt until
523: * we attempt to move > 1 byte from the SCSI bus and the only byte available is
524: * in SWIDE.
525: */
526: sgResid--;
527: }
528:
529: /*
530: * Calculate partial S/G List instruction and branch
531: *
532: * Fill in slots 0/1 of the SGList based on the SGList index (i) and SGList residual count
533: * (sgResid) calculated above.
534: *
535: */
536: sgDone = (OSSwapHostToLittleInt32( nexus->sgListData[i].length ) & 0x00ffffff) - sgResid;
537:
538: nexus->sgListData[0].length = OSSwapHostToLittleInt32( sgResid | srb->directionMask );
539: nexus->sgListData[0].physAddr = OSSwapHostToLittleInt32( OSSwapHostToLittleInt32(nexus->sgListData[i].physAddr) + sgDone );
540: /*
541: * If a previously calculated SGList 0 entry was interrupted again, we dont need to calculate
542: * a new branch address since the previous one is still valid.
543: */
544: if ( i != 0 )
545: {
546: nexus->sgListData[1].length = OSSwapHostToLittleInt32( 0x80080000 );
547: nexus->sgListData[1].physAddr = OSSwapHostToLittleInt32( (UInt32)&nexusPhys->sgListData[i+1] );
548: nexus->sgNextIndex = i + 1;
549: }
550: nexus->ppSGList = (SGEntry *)OSSwapHostToLittleInt32( (UInt32) &nexusPhys->sgListData[0] );
551:
552: /*
553: * The script sets this Nexus variable to non-zero each time it calls the driver generated
554: * S/G list. This allows the driver's completion routines to differentiate between a successful
555: * transfer vs no data transfer at all.
556: */
557: nexus->dataXferCalled = 0;
558:
559: return;
560: }
561:
562: /*-----------------------------------------------------------------------------*
563: * Determine SG element residual
564: *
565: * This routine returns how much of the current S/G List element the
566: * script was processing remains to be sent/received. All the information
567: * required to do this is stored in the script engine's registers.
568: *
569: *-----------------------------------------------------------------------------*/
570: UInt32 Sym8xxSCSIController::Sym8xxCheckFifo( SRB *srb, UInt32 *pfifoCnt )
571: {
572: bool fSCSISend;
573: bool fXferSync;
574: UInt32 scriptPhase = 0;
575: UInt32 dbcReg = 0;
576: UInt32 dfifoReg = 0;
577: UInt32 ctest5Reg = 0;
578: UInt8 sstat0Reg = 0;
579: UInt8 sstat1Reg = 0;
580: UInt8 sstat2Reg = 0;
581: UInt32 fifoCnt = 0;
582: UInt32 sgResid = 0;
583:
584: scriptPhase = OSSwapHostToLittleInt32( SCRIPT_VAR(R_ld_phase_flag) );
585:
586: fSCSISend = (scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_MSG_OUT);
587:
588: fXferSync = ((scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_DATA_IN))
589: && (srb->nexus.targetParms.sxferReg & 0x1F);
590:
591: dbcReg = Sym8xxReadRegs( chipBaseAddr, DBC, DBC_SIZE ) & 0x00ffffff;
592:
593: if ( !(dstatReg & DFE) )
594: {
595: ctest5Reg = Sym8xxReadRegs( chipBaseAddr, CTEST5, CTEST5_SIZE );
596: dfifoReg = Sym8xxReadRegs( chipBaseAddr, DFIFO, DFIFO_SIZE );
597:
598: if ( ctest5Reg & DFS )
599: {
600: fifoCnt = ((((ctest5Reg & 0x03) << 8) | dfifoReg) - dbcReg) & 0x3ff;
601: }
602: else
603: {
604: fifoCnt = (dfifoReg - dbcReg) & 0x7f;
605: }
606: }
607:
608: sstat0Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT0, SSTAT0_SIZE );
609: sstat2Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT2, SSTAT2_SIZE );
610:
611: if ( fSCSISend )
612: {
613: fifoCnt += (sstat0Reg & OLF ) ? 1 : 0;
614: fifoCnt += (sstat2Reg & OLF1) ? 1 : 0;
615:
616: if ( fXferSync )
617: {
618: fifoCnt += (sstat0Reg & ORF ) ? 1 : 0;
619: fifoCnt += (sstat2Reg & ORF1) ? 1 : 0;
620: }
621: }
622: else
623: {
624: if ( fXferSync )
625: {
626: sstat1Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT0, SSTAT0_SIZE );
627: fifoCnt += (sstat1Reg >> 4) | (sstat2Reg & FF4);
628: }
629: else
630: {
631: fifoCnt += (sstat0Reg & ILF ) ? 1 : 0;
632: fifoCnt += (sstat2Reg & ILF1) ? 1 : 0;
633: }
634: }
635:
636: sgResid = dbcReg + fifoCnt;
637: *pfifoCnt = fifoCnt;
638:
639: return sgResid;
640: }
641:
642: /*-----------------------------------------------------------------------------*
643: * Calculate transfer counts.
644: *
645: * This routine updates srb->xferDone with the amount of data transferred
646: * by the last S/G List executed.
647: *
648: *-----------------------------------------------------------------------------*/
649: void Sym8xxSCSIController::Sym8xxUpdateXferOffset( SRB *srb )
650: {
651: UInt32 i;
652: UInt32 xferOffset;
653:
654: /*
655: * srb->xferOffset contains the client buffer offset INCLUDING the range
656: * covered by the current SGList.
657: */
658: xferOffset = srb->xferOffset;
659:
660: /*
661: * If script did not complete the current transfer list then we need to determine
662: * how much of the list was completed.
663: */
664: if ( srb->nexus.dataXferCalled == 0 )
665: {
666: /*
667: * srb->xferOffsetPrev contains the client buffer offset EXCLUDING the
668: * range covered by the current SGList.
669: */
670: xferOffset = srb->xferOffsetPrev;
671:
672: /*
673: * Calculate bytes transferred for partially completed list.
674: *
675: * To calculate the amount of this list completed, we sum the residual amount
676: * in SGList Slot 0 and the completed list elements 2 to sgNextIndex-1.
677: */
678: if ( srb->nexus.sgNextIndex != 0 )
679: {
680: xferOffset += OSSwapHostToLittleInt32( srb->nexus.sgListData[srb->nexus.sgNextIndex-1].length )
681: - OSSwapHostToLittleInt32( srb->nexus.sgListData[0].length );
682:
683: for ( i=2; i < srb->nexus.sgNextIndex-1; i++ )
684: {
685: xferOffset += OSSwapHostToLittleInt32( srb->nexus.sgListData[i].length ) & 0x00ffffff;
686: }
687: }
688: }
689:
690: /*
691: * The script leaves the result of any Ignore Wide Residual message received from the target
692: * during the transfer.
693: */
694: xferOffset -= srb->nexus.wideResidCount;
695:
696:
697: #if 0
698: {
699: UInt32 resid = srb->xferOffset - xferOffset;
700: if ( resid )
701: {
702: IOLog( "SCSI(Symbios8xx): Incomplete transfer - Req Count = %08x Act Count = %08x - srb = %08x\n\r",
703: srb->xferCount, xferOffset, (UInt32)srb );
704: }
705: }
706: #endif
707:
708: srb->xferDone = xferOffset;
709: }
710:
711: /*-----------------------------------------------------------------------------*
712: * No SRB/Nexus Processing.
713: *
714: * In some cases (mainly Aborts) not having a SRB/Nexus is normal. In other
715: * cases it indicates a problem such a reconnection from a target that we
716: * have no record of.
717: *
718: *-----------------------------------------------------------------------------*/
719: void Sym8xxSCSIController::Sym8xxProcessNoNexus()
720: {
721: UInt32 dspsReg;
722: UInt32 dspReg = 0;
723: UInt32 scriptPhase = (UInt32)-1 ;
724:
725: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase];
726:
727: dspsReg = Sym8xxReadRegs( chipBaseAddr, DSPS, DSPS_SIZE );
728:
729: scriptPhase = OSSwapHostToLittleInt32( SCRIPT_VAR(R_ld_phase_flag) );
730:
731: /*
732: * If we were trying to abort or disconnect a target and the bus
733: * is now free we consider the abort to have completed.
734: */
735: if ( sistReg & UDC )
736: {
737: if ( (scriptPhase == A_kphase_ABORT_MAILBOX) && abortSRB )
738: {
739: Sym8xxCompleteSRB( abortSRB );
740: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
741: }
742: else if ( scriptPhase == A_kphase_ABORT_CURRENT )
743: {
744: abortCurrentSRB = NULL;
745: }
746: }
747: /*
748: * If we were trying to connect to a target to send it an abort message, and
749: * we timed out, we consider the abort as completed.
750: *
751: * Note: In this case the target may be hung, but at least its not on the bus.
752: */
753: else if ( sistReg & STO )
754: {
755: if ( (scriptPhase == A_kphase_ABORT_MAILBOX) && abortSRB )
756: {
757: Sym8xxCompleteSRB( abortSRB );
758: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
759: }
760: }
761:
762: /*
763: * If the script died, without a vaild nexusIndex, we abort anything that is currently
764: * connected and hope for the best!
765: */
766: else if ( dstatReg & IID )
767: {
768: dspReg = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE );
769: IOLog("SCSI(Symbios8xx): Illegal script instruction - dsp = %08x srb=0\n\r", (int)dspReg );
770: Sym8xxAbortCurrent( (SRB *)-1 );
771: }
772:
773: /*
774: * Script signaled conditions
775: */
776: else if ( dstatReg & SIR )
777: {
778: switch ( dspsReg )
779: {
780: case A_abort_current:
781: abortCurrentSRB = NULL;
782: break;
783:
784: case A_abort_mailbox:
785: Sym8xxCompleteSRB( abortSRB );
786: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
787: break;
788:
789: default:
790: Sym8xxAbortCurrent( (SRB *)-1 );
791: }
792: }
793: else
794: {
795: Sym8xxAbortCurrent( (SRB *)-1 );
796: }
797:
798: if ( scriptRestartAddr )
799: {
800: Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
801: }
802: }
803:
804:
805: /*-----------------------------------------------------------------------------*
806: * Abort currently connected target.
807: *
808: *-----------------------------------------------------------------------------*/
809: void Sym8xxSCSIController::Sym8xxAbortCurrent( SRB *srb )
810: {
811: if ( abortCurrentSRB )
812: {
813: if ( abortCurrentSRB != srb )
814: {
815: IOLog("SCSI(Symbios8xx): Multiple abort immediate SRBs - resetting\n\r");
816: Sym8xxSCSIBusReset( (SRB *)0 );
817: }
818: return;
819: }
820:
821: abortCurrentSRB = srb;
822:
823: if ( srb != (SRB *)-1 )
824: {
825: if ( srb->srbSCSIResult == kIOReturnSuccess )
826: {
827: srb->srbSCSIResult = kIOReturnAborted;
828: }
829: }
830:
831: /*
832: * Issue abort or abort tag depending on whether the is a tagged request
833: */
834: SCRIPT_VAR(R_ld_AbortCode) = OSSwapHostToLittleInt32( ((srb != (SRB *)-1) && (srb->nexus.tag >= MIN_SCSI_TAG)) ? 0x0d : 0x06 );
835: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_issueAbort_BDR];
836:
837: Sym8xxClearFifo();
838: }
839:
840: /*-----------------------------------------------------------------------------*
841: * This routine clears the script engine's SCSI and DMA fifos.
842: *
843: *-----------------------------------------------------------------------------*/
844: void Sym8xxSCSIController::Sym8xxClearFifo()
845: {
846: UInt8 ctest3Reg;
847: UInt8 stest2Reg;
848: UInt8 stest3Reg;
849:
850: stest2Reg = Sym8xxReadRegs( chipBaseAddr, STEST2, STEST2_SIZE );
851: if ( stest2Reg & ROF )
852: {
853: Sym8xxWriteRegs( chipBaseAddr, STEST2, STEST2_SIZE, stest2Reg );
854: }
855:
856: ctest3Reg = Sym8xxReadRegs( chipBaseAddr, CTEST3, CTEST3_SIZE );
857: ctest3Reg |= CLF;
858: Sym8xxWriteRegs( chipBaseAddr, CTEST3, CTEST3_SIZE, ctest3Reg );
859:
860: stest3Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE );
861: stest3Reg |= CSF;
862: Sym8xxWriteRegs( chipBaseAddr,STEST3, STEST3_SIZE, stest3Reg );
863:
864: do
865: {
866: ctest3Reg = Sym8xxReadRegs( chipBaseAddr, CTEST3, CTEST3_SIZE );
867: stest2Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE );
868: stest3Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE );
869: }
870: while( (ctest3Reg & CLF) || (stest3Reg & CSF) || (stest2Reg & ROF) );
871: }
872:
873: /*-----------------------------------------------------------------------------*
874: * This routine processes the target's response to our SDTR message.
875: *
876: * We calculate the values for the script engine's timing registers
877: * for synchronous registers, and update our tables indicating that
878: * requested data transfer mode is in-effect.
879: *
880: *-----------------------------------------------------------------------------*/
881: void Sym8xxSCSIController::Sym8xxNegotiateSDTR( SRB *srb, Nexus *nexus )
882: {
883: UInt32 x;
884: UInt8 *pMsg;
885: UInt32 syncPeriod;
886:
887: /*
888: * If we were not negotiating, the send MsgReject to targets negotiation
889: * attempt.
890: */
891: if ( !(srb->srbCDBFlags & kCDBFlagsNegotiateSDTR) )
892: {
893: Sym8xxSendMsgReject( srb );
894: return;
895: }
896:
897: /*
898: * Get pointer to negotiation message received from target.
899: */
900: pMsg = (UInt8 *) &SCRIPT_VAR(R_ld_message);
901:
902: /*
903: * The target's SDTR response contains the (transfer period / 4).
904: *
905: * We set our sync clock divisor to 1, 2, or 4 giving us a clock rates
906: * of:
907: * 80Mhz (Period = 12.5ns),
908: * 40Mhz (Period = 25.0ns)
909: * 20Mhz (Period = 50.0ns)
910: *
911: * This is further divided by the value in the sxfer reg to give us the final sync clock rate.
912: *
913: * The requested sync period is scaled up by 1000 and the clock periods are scaled up by 10
914: * giving a result scaled up by 100. This is rounded-up and converted to sxfer reg values.
915: */
916: if ( pMsg[4] == 0 )
917: {
918: nexus->targetParms.scntl3Reg &= 0x0f;
919: nexus->targetParms.sxferReg = 0x00;
920: }
921: else
922: {
923: syncPeriod = (UInt32)pMsg[3] << 2;
924: if ( syncPeriod < 100 )
925: {
926: nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_ULTRA;
927: x = (syncPeriod * 1000) / 125;
928: }
929: else if ( syncPeriod < 200 )
930: {
931: nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_FAST;
932: x = (syncPeriod * 1000) / 250;
933: }
934: else
935: {
936: nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_SLOW;
937: x = (syncPeriod * 1000) / 500;
938: }
939:
940: if ( x % 100 ) x += 100;
941:
942: /*
943: * sxferReg Bits: 5-0 - Transfer offset
944: * 7-6 - Sync Clock Divisor (0 = sync clock / 4)
945: */
946: nexus->targetParms.sxferReg = ((x/100 - 4) << 5) | pMsg[4];
947: }
948:
949: /*
950: * Update our per-target tables and set-up the hardware regs for this request.
951: *
952: * On reconnection attempts, the script will use our per-target tables to set-up
953: * the scntl3 and sxfer registers in the script engine.
954: */
955: adapter->targetClocks[srb->target].sxferReg = nexus->targetParms.sxferReg;
956: adapter->targetClocks[srb->target].scntl3Reg = nexus->targetParms.scntl3Reg;
957:
958: Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, nexus->targetParms.scntl3Reg );
959: Sym8xxWriteRegs( chipBaseAddr, SXFER, SXFER_SIZE, nexus->targetParms.sxferReg );
960:
961: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_clearACK];
962: }
963:
964: /*-----------------------------------------------------------------------------*
965: * This routine processes the target's response to our WDTR message.
966: *
967: * In addition, if there is a pending SDTR message, this routine sends it
968: * to the target.
969: *
970: *-----------------------------------------------------------------------------*/
971: void Sym8xxSCSIController::Sym8xxNegotiateWDTR( SRB *srb, Nexus *nexus )
972: {
973: UInt8 *pMsg;
974: UInt32 msgBytesSent;
975: UInt32 msgBytesLeft;
976:
977: /*
978: * If we were not negotiating, the send MsgReject to targets negotiation
979: * attempt.
980: */
981: if ( !(srb->srbCDBFlags & kCDBFlagsNegotiateWDTR) )
982: {
983: Sym8xxSendMsgReject( srb );
984: return;
985: }
986:
987: /*
988: * Set Wide (16-bit) vs Narrow (8-bit) data transfer mode based on target's response.
989: */
990: pMsg = (UInt8 *) &SCRIPT_VAR(R_ld_message);
991:
992: if ( pMsg[3] == 1 )
993: {
994: nexus->targetParms.scntl3Reg |= EWS;
995: }
996: else
997: {
998: nexus->targetParms.scntl3Reg &= ~EWS;
999: }
1000:
1001: /*
1002: * Update our per-target tables and set-up the hardware regs for this request.
1003: *
1004: * On reconnection attempts, the script will use our per-target tables to set-up
1005: * the scntl3 and sxfer registers in the script engine.
1006: */
1007:
1008: adapter->targetClocks[srb->target].scntl3Reg = nexus->targetParms.scntl3Reg;
1009: Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, nexus->targetParms.scntl3Reg );
1010:
1011:
1012: /*
1013: * If there any pending messages left for the target, send them now,
1014: */
1015: msgBytesSent = OSSwapHostToLittleInt32( nexus->msg.length );
1016: msgBytesLeft = srb->srbMsgLength - msgBytesSent;
1017: if ( msgBytesLeft )
1018: {
1019: nexus->msg.length = OSSwapHostToLittleInt32( msgBytesLeft );
1020: nexus->msg.ppData = OSSwapHostToLittleInt32( OSSwapHostToLittleInt32( nexus->msg.ppData ) + msgBytesSent );
1021: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_issueMessageOut];
1022: }
1023:
1024: /*
1025: * Otherwise, tell the script we're done with MsgOut phase.
1026: */
1027: else
1028: {
1029: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_clearACK];
1030: }
1031: }
1032:
1033: /*-----------------------------------------------------------------------------*
1034: * Reject message received from target.
1035: *
1036: *-----------------------------------------------------------------------------*/
1037: void Sym8xxSCSIController::Sym8xxSendMsgReject( SRB *srb )
1038: {
1039: srb->nexus.msg.ppData = OSSwapHostToLittleInt32((UInt32)&srb->srbPhys->nexus.msgData);
1040: srb->nexus.msg.length = OSSwapHostToLittleInt32(0x01);
1041: srb->nexus.msgData[0] = 0x07;
1042:
1043: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_issueMessageOut];
1044: }
1045:
1046:
1047: /*-----------------------------------------------------------------------------*
1048: * This routine initiates a SCSI Bus Reset.
1049: *
1050: * This may be an internally generated request as part of error recovery or
1051: * a client's bus reset request.
1052: *
1053: *-----------------------------------------------------------------------------*/
1054: void Sym8xxSCSIController::Sym8xxSCSIBusReset( SRB *srb )
1055: {
1056: if ( srb )
1057: {
1058: if ( resetSRB )
1059: {
1060: srb->srbSCSIResult = kIOReturnBusy;
1061: Sym8xxCompleteSRB( srb );
1062: return;
1063: }
1064: resetSRB = srb;
1065: }
1066:
1067: Sym8xxAbortScript();
1068:
1069: Sym8xxWriteRegs( chipBaseAddr, SCNTL1, SCNTL1_SIZE, SCNTL1_SCSI_RST );
1070: IODelay( 100 );
1071: Sym8xxWriteRegs( chipBaseAddr, SCNTL1, SCNTL1_SIZE, SCNTL1_INIT );
1072: }
1073:
1074: /*-----------------------------------------------------------------------------*
1075: * This routine handles a SCSI Bus Reset interrupt.
1076: *
1077: * The SCSI Bus reset may be generated by a target on the bus, internally from
1078: * the driver's error recovery or from a client request.
1079: *
1080: * Once the reset is detected we establish a settle period where new client requests
1081: * are blocked in the client thread. In addition we flush all currently executing
1082: * scsi requests back to the client.
1083: *
1084: *-----------------------------------------------------------------------------*/
1085: void Sym8xxSCSIController::Sym8xxProcessSCSIBusReset()
1086: {
1087: UInt32 i;
1088:
1089: Sym8xxClearFifo();
1090:
1091: /*
1092: * We clear the script's request mailboxes. Any work in the script mailboxes is
1093: * already in the NexusPtr tables so we have already have handled the SRB/Nexus
1094: * cleanup.
1095: */
1096: for ( i=0; i < MAX_SCHED_MAILBOXES; i++ )
1097: {
1098: adapter->schedMailBox[i] = 0;
1099: }
1100:
1101: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
1102: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
1103: SCRIPT_VAR(R_ld_counter) = 0;
1104: mailBoxIndex = 0;
1105:
1106:
1107: /*
1108: * Reset the data transfer mode/clocks in our per-target tables back to Async/Narrow 8-bit
1109: */
1110: for ( i=0; i < MAX_SCSI_TARGETS; i++ )
1111: {
1112: adapter->targetClocks[i].scntl3Reg = SCNTL3_INIT_875;
1113: adapter->targetClocks[i].sxferReg = 0;
1114: }
1115:
1116: scriptRestartAddr = (UInt32) &chipRamAddrPhys[Ent_select_phase];
1117: Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
1118:
1119: if ( resetSRB )
1120: {
1121: resetSRB->srbSCSIResult = kIOReturnSuccess;
1122: Sym8xxCompleteSRB( resetSRB );
1123: resetSRB = 0;
1124: }
1125: else if ( initialReset == true )
1126: {
1127: initialReset = false;
1128: }
1129: else
1130: {
1131: resetOccurred();
1132: }
1133: }
1134:
1135: /*-----------------------------------------------------------------------------*
1136: * This routine sets the SIGP bit in the script engine's ISTAT
1137: * register. This signals the script to wake-up for a WAIT for
1138: * reselection instruction. The script will then check the mailboxes
1139: * for work to do.
1140: *
1141: *-----------------------------------------------------------------------------*/
1142: void Sym8xxSCSIController::Sym8xxSignalScript( SRB *srb )
1143: {
1144: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, SIGP );
1145: }
1146:
1147: /*-----------------------------------------------------------------------------*
1148: *
1149: *
1150: *
1151: *
1152: *
1153: *-----------------------------------------------------------------------------*/
1154: void Sym8xxSCSIController::Sym8xxCheckRequestSense( SRB *srb )
1155: {
1156: IOSCSICommand *scsiCommand;
1157: IOMemoryDescriptor *reqSenseDesc;
1158:
1159: scsiCommand = srb->scsiCommand;
1160:
1161: scsiCommand->getPointers( &reqSenseDesc, 0, 0, true );
1162:
1163: if ( reqSenseDesc != 0 )
1164: {
1165: Sym8xxCancelMailBox( srb->target, srb->lun, true );
1166: }
1167: }
1168:
1169: /*-----------------------------------------------------------------------------*
1170: * This routine does a mailbox abort.
1171: *
1172: * This type of abort is used for targets not currently connected to the SCSI Bus.
1173: *
1174: * The script will select the target and send a tag (if required) followed by the
1175: * appropriate abort message (abort/abort-tag)
1176: *
1177: *-----------------------------------------------------------------------------*/
1178: void Sym8xxSCSIController::Sym8xxAbortBdr( SRB *srb )
1179: {
1180: IOAbortBdrMailBox abortMailBox;
1181:
1182: abortSRB = srb;
1183:
1184: /*
1185: * Setup a script variable containing the abort information.
1186: */
1187: abortMailBox.identify = srb->nexus.msgData[0];
1188: abortMailBox.tag = srb->nexus.msgData[1];
1189: abortMailBox.message = srb->nexus.msgData[2];
1190: abortMailBox.scsi_id = srb->target;
1191:
1192: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = *(UInt32 *) &abortMailBox;
1193:
1194: Sym8xxSignalScript( srb );
1195: }
1196:
1197: /*-----------------------------------------------------------------------------*
1198: *
1199: *
1200: *
1201: *
1202: *-----------------------------------------------------------------------------*/
1203: bool Sym8xxSCSIController::Sym8xxCancelMailBox( Nexus *nexusCancel )
1204: {
1205: Nexus *nexusPhys;
1206: UInt32 i;
1207:
1208: nexusPhys = (Nexus *)OSSwapHostToLittleInt32( (UInt32)nexusCancel );
1209: for ( i=0; i < MAX_SCHED_MAILBOXES; i++ )
1210: {
1211: if ( nexusPhys == adapter->schedMailBox[i] )
1212: {
1213: adapter->schedMailBox[i] = (Nexus *)OSSwapHostToLittleInt32( kMailBoxCancel );
1214: return true;
1215: }
1216: }
1217: return false;
1218: }
1219:
1220:
1221: /*-----------------------------------------------------------------------------*
1222: *
1223: *
1224: *
1225: *
1226: *-----------------------------------------------------------------------------*/
1227: void Sym8xxSCSIController::Sym8xxCancelMailBox( UInt32 target, UInt32 lun, bool fReschedule )
1228: {
1229: UInt32 tag;
1230: UInt32 tagPos;
1231: UInt32 tagShift;
1232:
1233: UInt32 i;
1234:
1235: SRB *srb;
1236: Nexus *nexus;
1237: Nexus *nexusPhys;
1238:
1239: tagPos = offsetof(Nexus, tag) & 0x03;
1240: tagShift = 24 - (tagPos << 3);
1241:
1242: for ( i=0; i < MAX_SCHED_MAILBOXES; i++ )
1243: {
1244: nexusPhys = (Nexus *)OSSwapHostToLittleInt32( (UInt32)adapter->schedMailBox[i] );
1245: if ( (nexusPhys != (Nexus *)kMailBoxEmpty) && (nexusPhys != (Nexus *)kMailBoxCancel) )
1246: {
1247: /*
1248: * Read the 'tag' byte given Nexus physical address from the mailBox.
1249: * Look-up the virtual address of the corresponding Nexus struct.
1250: */
1251: tag = ml_phys_read((UInt32)&nexusPhys->tag - tagPos);
1252: tag = (tag >> tagShift) & 0xff;
1253:
1254: nexus = adapter->nexusPtrsVirt[tag];
1255: if ( nexus == (Nexus *)-1 )
1256: {
1257: continue;
1258: }
1259:
1260: /*
1261: * If the SCSI target of the mailbox entry matches the abort SRB target,
1262: * then we may have a winner.
1263: */
1264: srb = (SRB *)((UInt32)nexus - offsetof(SRB, nexus));
1265:
1266: if ( srb->target == target )
1267: {
1268: /*
1269: * For a device reset, we cancel all requests for that target regardless of lun.
1270: * For an abort all, we must match on both target and lun
1271: */
1272: if ( (lun == (UInt32)-1) || (srb->lun == lun) )
1273: {
1274: adapter->schedMailBox[i] = (Nexus *)OSSwapHostToLittleInt32( kMailBoxCancel );
1275:
1276: if ( fReschedule == true )
1277: {
1278: rescheduleCommand( srb->scsiCommand );
1279: }
1280: }
1281: }
1282: }
1283: }
1284: }
1285:
1286: /*-----------------------------------------------------------------------------*
1287: * This routine is used to shutdown the script engine in an orderly fashion.
1288: *
1289: * Normally the script engine automatically stops when an interrupt is generated. However,
1290: * in the case of timeouts we need to change the script engine's dsp reg (instruction pointer).
1291: * to issue an abort.
1292: *
1293: *-----------------------------------------------------------------------------*/
1294: void Sym8xxSCSIController::Sym8xxAbortScript()
1295: {
1296: mach_timespec_t currentTime;
1297: mach_timespec_t startTime;
1298:
1299: getWorkLoop()->disableAllInterrupts();
1300:
1301: /*
1302: * We set the ABRT bit in ISTAT and spin until the script engine acknowledges the
1303: * abort or we timeout.
1304: */
1305: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, ABRT );
1306:
1307: IOGetTime( &startTime );
1308:
1309: do
1310: {
1311: IOGetTime( ¤tTime );
1312: SUB_MACH_TIMESPEC( ¤tTime, &startTime );
1313:
1314: istatReg = Sym8xxReadRegs( chipBaseAddr, ISTAT, ISTAT_SIZE );
1315:
1316: if ( istatReg & SIP )
1317: {
1318: Sym8xxReadRegs( chipBaseAddr, SIST, SIST_SIZE );
1319: continue;
1320: }
1321:
1322: if ( istatReg & DIP )
1323: {
1324: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, 0x00 );
1325: Sym8xxReadRegs( chipBaseAddr, DSTAT, DSTAT_SIZE );
1326: break;
1327: }
1328: }
1329: while ( currentTime.tv_nsec < (kAbortScriptTimeoutMS * 1000 * 1000) );
1330:
1331: istatReg = SIGP;
1332: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, istatReg );
1333:
1334: getWorkLoop()->enableAllInterrupts();
1335:
1336: if ( currentTime.tv_nsec >= (kAbortScriptTimeoutMS * 1000 * 1000) )
1337: {
1338: IOLog( "SCSI(Symbios8xx): Abort script failed - resetting bus\n\r" );
1339: }
1340:
1341: }
1342:
1343:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.