|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Sym8xxExecute.m created by russb2 on Sat 30-May-1998 */
26:
27: #import "Sym8xxController.h"
28:
29: /*-----------------------------------------------------------------------------*
30: * IOThread Routines
31: *
32: * This module contains routines that run on the driver's IOThread.
33: *
34: *-----------------------------------------------------------------------------*/
35:
36: @implementation Sym8xxController(Execute)
37:
38: /*-----------------------------------------------------------------------------*
39: * This is the main command processing loop for the driver's I/O thread.
40: * It removes SRBs from the driver's command queue and processes them according
41: * to the command code in srb->srbCmd.
42: *
43: *-----------------------------------------------------------------------------*/
44: - (void) commandRequestOccurred
45: {
46: SRB *srb = NULL;
47:
48: while ( 1 )
49: {
50: [srbPendingQLock lock];
51:
52: if ( queue_empty(&srbPendingQ) )
53: {
54: [srbPendingQLock unlock];
55: break;
56: }
57: queue_remove_first( &srbPendingQ, srb, SRB *, srbQ );
58:
59: [srbPendingQLock unlock];
60:
61:
62: /*
63: * If we are in the quiet period after a SCSI Bus reset, then reject new SRBs. In
64: * general the client thread processing will block new SRBs, however, some may have
65: * been on the IOThread's SRB queue when the reset occurred.
66: */
67: if ( resetQuiesceTimer )
68: {
69: srb->srbSCSIResult = SR_IOST_RESET;
70: [srb->srbCmdLock unlockWith: ksrbCmdComplete];
71: continue;
72: }
73:
74: switch ( srb->srbCmd )
75: {
76: /*
77: * For a SCSI CDB request, stuff the physical address of the SRB's Nexus struct into a
78: * mailbox and signal the Symbios script engine.
79: */
80: case ksrbCmdExecuteReq:
81: srb->nexus.targetParms.scntl3Reg = adapter->targetClocks[srb->target].scntl3Reg;
82: srb->nexus.targetParms.sxferReg = adapter->targetClocks[srb->target].sxferReg;
83:
84: adapter->nexusPtrsVirt[srb->nexus.tag] = &srb->nexus;
85: adapter->nexusPtrsPhys[srb->nexus.tag] = (Nexus *)EndianSwap32( (u_int32_t)&srb->srbPhys->nexus );
86: adapter->schedMailBox[mailBoxIndex++] = (Nexus *)EndianSwap32 ( (u_int32_t)&srb->srbPhys->nexus );
87:
88: [self Sym8xxSignalScript: srb];
89: break;
90:
91: case ksrbCmdResetSCSIBus:
92: [self Sym8xxSCSIBusReset: srb];
93: break;
94:
95: case ksrbCmdAbortReq:
96: case ksrbCmdBusDevReset:
97: [self Sym8xxAbortBdr: srb];
98: break;
99:
100: default:
101: ;
102: }
103: }
104: }
105:
106:
107: /*-----------------------------------------------------------------------------*
108: * Interrupts from the Symbios chipset are dispatched here at task time under the
109: * IOThread's context.
110: *-----------------------------------------------------------------------------*/
111: - (void) interruptOccurred
112: {
113: do
114: {
115: /*
116: * The chipset's ISTAT reg gives us the general interrupting condiditions,
117: * with DSTAT and SIST providing more detailed information.
118: */
119: istatReg = Sym8xxReadRegs( chipBaseAddr, ISTAT, ISTAT_SIZE );
120:
121: /* The INTF bit in ISTAT indicates that the script is signalling the driver
122: * that its IODone mailbox is full and that we should process a completed
123: * request. The script continues to run after posting this interrupt unlike
124: * other chipset interrupts which require the driver to restart the script
125: * engine.
126: */
127: if ( istatReg & INTF )
128: {
129: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, istatReg );
130: [self Sym8xxProcessIODone];
131: }
132:
133: /*
134: * Handle remaining interrupting conditions
135: */
136: if ( istatReg & (SIP | DIP) )
137: {
138: [self Sym8xxProcessInterrupt];
139: }
140: }
141: while ( istatReg & (SIP | DIP | INTF) );
142:
143: [self enableAllInterrupts];
144:
145: }
146:
147: /*-----------------------------------------------------------------------------*
148: * Process a request posted in the script's IODone mailbox.
149: *
150: *-----------------------------------------------------------------------------*/
151: - (void) Sym8xxProcessIODone
152: {
153: SRB *srb;
154: Nexus *nexus;
155: IODoneMailBox *pMailBox;
156:
157:
158: /*
159: * The IODone mailbox contains an index into our Nexus pointer tables.
160: *
161: * The Nexus struct is part of the SRB so we can get our SRB address
162: * by subtracting the offset of the Nexus struct in the SRB.
163: */
164: pMailBox = (IODoneMailBox *)&SCRIPT_VAR(R_ld_IOdone_mailbox);
165: nexus = adapter->nexusPtrsVirt[pMailBox->nexus];
166: srb = (SRB *)((u_int32_t)nexus - offsetof(SRB, nexus));
167:
168: /*
169: * If there was no request sense performed, then update the transfer
170: * counts in the SRB.
171: */
172: if ( srb->srbState == ksrbStateCDBDone )
173: {
174: [self Sym8xxUpdateXferOffset: srb];
175: }
176:
177: /*
178: * Clear the completed Nexus pointer from our tables and clear the
179: * IODone mailbox.
180: */
181: adapter->nexusPtrsVirt[pMailBox->nexus] = (Nexus *) -1;
182: adapter->nexusPtrsPhys[pMailBox->nexus] = (Nexus *) -1;
183: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
184:
185: /*
186: * Don't ask why we need to do this -- we shouldn't if the Indirect SCSI
187: * drivers worked properly!
188: *
189: */
190: if ( nexus->cdbData.cdb_opcode == C6OP_INQUIRY )
191: {
192: [self Sym8xxCheckInquiryData: srb];
193: }
194:
195: /*
196: * Wake up the client's thread to do post-processing
197: */
198: [srb->srbCmdLock unlockWith: ksrbCmdComplete];
199: }
200:
201: /*-----------------------------------------------------------------------------*
202: * General script interrupt processing
203: *
204: *-----------------------------------------------------------------------------*/
205: - (void) Sym8xxProcessInterrupt
206: {
207: SRB *srb = NULL;
208: Nexus *nexus = NULL;
209: u_int32_t nexusIndex;
210: u_int32_t scriptPhase;
211: u_int32_t fifoCnt = 0;
212: u_int32_t dspsReg = 0;
213: u_int32_t dspReg = 0;
214:
215:
216: /*
217: * Read DSTAT/SIST regs to determine why the script stopped.
218: */
219: dstatReg = Sym8xxReadRegs( chipBaseAddr, DSTAT, DSTAT_SIZE );
220: IODelay(5);
221: sistReg = Sym8xxReadRegs( chipBaseAddr, SIST, SIST_SIZE );
222:
223: // kprintf( "SCSI(Symbios8xx): SIST = %04x DSTAT = %02x\n\r", sistReg, dstatReg );
224:
225: /*
226: * This Script var tells us what the script thinks it was doing when the interrupt occurred.
227: */
228: scriptPhase = EndianSwap32( SCRIPT_VAR(R_ld_phase_flag) );
229:
230: /*
231: * SCSI Bus reset detected
232: *
233: * Clean up the carnage.
234: * Note: This may be either an adapter or target initiated reset.
235: */
236: if ( sistReg & RSTI )
237: {
238: [self Sym8xxProcessSCSIBusReset];
239: return;
240: }
241:
242: /*
243: * Calculate our current SRB/Nexus.
244: *
245: * Read a script var to determine the index of the nexus it was processing
246: * when the interrupt occurred. The script will invalidate the index if there
247: * is no target currently connected or the script cannot determine which target
248: * has reconnected.
249: */
250: nexusIndex = EndianSwap32(SCRIPT_VAR(R_ld_nexus_index));
251: if ( nexusIndex >= MAX_SCSI_TAG )
252: {
253: [self Sym8xxProcessNoNexus];
254: return;
255: }
256: nexus = adapter->nexusPtrsVirt[nexusIndex];
257: if ( nexus == (Nexus *) -1 )
258: {
259: [self Sym8xxProcessNoNexus];
260: return;
261: }
262: srb = (SRB *)((u_int32_t)nexus - offsetof(SRB, nexus));
263:
264: scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_phase_handler];
265:
266: /*
267: * Parity and SCSI Gross Errors.
268: *
269: * Abort the current connection. The abort completion will trigger
270: * clean-up of the current SRB/Nexus.
271: */
272: if ( sistReg & PAR )
273: {
274: srb->srbSCSIResult = SR_IOST_PARITY;
275: [self Sym8xxAbortCurrent: srb];
276: }
277:
278: else if ( sistReg & SGE )
279: {
280: srb->srbSCSIResult = SR_IOST_BV;
281: [self Sym8xxAbortCurrent: srb];
282: }
283:
284: /*
285: * Unexpected disconnect.
286: *
287: * If we were currently trying to abort this connection then mark the abort
288: * as completed. For all cases clean-up and wake-up the client thread.
289: */
290: else if ( sistReg & UDC )
291: {
292: if ( srb->srbSCSIResult == SR_IOST_GOOD )
293: {
294: srb->srbSCSIResult = SR_IOST_BV;
295: }
296: adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1;
297: adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1;
298:
299: if ( scriptPhase == A_kphase_ABORT_CURRENT )
300: {
301: abortCurrentSRB = NULL;
302: }
303:
304: [srb->srbCmdLock unlockWith: ksrbCmdComplete];
305:
306: scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_select_phase];
307: }
308:
309: /*
310: * Phase Mis-match
311: *
312: * If we are in MsgOut phase then calculate how much of the message we sent. For
313: * now, however, we dont handle the target rejecting messages, so the request is aborted.
314: *
315: * If we are in DataIn/DataOut phase. We update the SRB/Nexus with our current data
316: * pointers.
317: */
318: else if ( sistReg & MA )
319: {
320: if ( scriptPhase == A_kphase_MSG_OUT )
321: {
322: srb->srbMsgResid = [self Sym8xxCheckFifo:srb FifoCnt:&fifoCnt];
323: nexus->msg.ppData = EndianSwap32( EndianSwap32(nexus->msg.ppData) + EndianSwap32(nexus->msg.length)
324: - srb->srbMsgResid );
325: nexus->msg.length = EndianSwap32( srb->srbMsgResid );
326:
327: [self Sym8xxAbortCurrent: srb];
328: }
329: else if ( (scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_DATA_IN) )
330: {
331: [self Sym8xxAdjustDataPtrs:srb Nexus:nexus];
332: }
333: else
334: {
335: // kprintf("SCSI(Symbios8xx): Unexpected phase mismatch - scriptPhase = %08x\n\r", scriptPhase);
336: srb->srbSCSIResult = SR_IOST_BV;
337: [self Sym8xxAbortCurrent: srb];
338: }
339:
340: [self Sym8xxClearFifo];
341: }
342:
343: /*
344: * Selection Timeout.
345: *
346: * Clean-up the current request.
347: */
348: else if ( sistReg & STO )
349: {
350: srb->srbSCSIResult = SR_IOST_SELTO;
351:
352: adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1;
353: adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1;
354: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
355:
356: [srb->srbCmdLock unlockWith: ksrbCmdComplete];
357:
358: scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_select_phase];
359: }
360:
361: /*
362: * Handle script initiated interrupts
363: */
364: else if ( dstatReg & SIR )
365: {
366: dspsReg = Sym8xxReadRegs( chipBaseAddr, DSPS, DSPS_SIZE );
367:
368: switch ( dspsReg )
369: {
370: /*
371: * Non-zero SCSI status
372: *
373: * Send request sense CDB or complete request depending on SCSI status value
374: */
375: case A_status_error:
376: if ( [self Sym8xxProcessStatus:srb] == NO )
377: {
378: [self Sym8xxProcessIODone];
379: }
380: break;
381:
382: /*
383: * Received SDTR/WDTR message from target.
384: *
385: * Prepare reply message if we requested negotiation. Otherwise reject
386: * target initiated negotiation.
387: */
388: case A_negotiateSDTR:
389: [self Sym8xxNegotiateSDTR:srb Nexus: nexus];
390: break;
391:
392: case A_negotiateWDTR:
393: [self Sym8xxNegotiateWDTR:srb Nexus: nexus];
394: break;
395:
396: /*
397: * Partial SG List completed.
398: *
399: * Refresh the list from the remaining addresses to be transfered and set the
400: * script engine to branch into the list.
401: */
402: case A_sglist_complete:
403: [self Sym8xxUpdateSGList:srb];
404: scriptRestartAddr = (u_int32_t)&srb->srbPhys->nexus.sgListData[2];
405: break;
406:
407: /*
408: * Completed abort request
409: *
410: * Clean-up the aborted request.
411: */
412: case A_abort_current:
413: if ( srb->srbSCSIResult == SR_IOST_GOOD )
414: {
415: srb->srbSCSIResult = SR_IOST_BV;
416: }
417:
418: adapter->nexusPtrsVirt[nexusIndex] = (Nexus *) -1;
419: adapter->nexusPtrsPhys[nexusIndex] = (Nexus *) -1;
420:
421: abortCurrentSRB = NULL;
422:
423: [srb->srbCmdLock unlockWith: ksrbCmdComplete];
424:
425: scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_select_phase];
426: break;
427:
428: /*
429: * Script detected protocol errors
430: *
431: * Abort the current request.
432: */
433: case A_unknown_msg_reject:
434: case A_unknown_phase:
435: case A_unexpected_msg:
436: case A_unexpected_ext_msg:
437: srb->srbSCSIResult = SR_IOST_TABT;
438: [self Sym8xxAbortCurrent: srb];
439: break;
440:
441: default:
442: kprintf( "SCSI(Symbios8xx): Unknown Script Int = %08x\n\r", dspsReg );
443: srb->srbSCSIResult = SR_IOST_INT;
444: [self Sym8xxAbortCurrent: srb];
445: }
446: }
447:
448: /*
449: * Illegal script instruction.
450: *
451: * We're toast! Abort the current request and hope for the best!
452: */
453: else if ( dstatReg & IID )
454: {
455: dspReg = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE );
456:
457: kprintf("SCSI(Symbios8xx): Illegal script instruction - dsp = %08x srb=%08x\n\r", dspReg, (u_int32_t)srb );
458:
459: srb->srbSCSIResult = SR_IOST_INT;
460: [self Sym8xxAbortCurrent: srb];
461: }
462:
463: if ( scriptRestartAddr )
464: {
465: Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
466: }
467: }
468:
469: /*-----------------------------------------------------------------------------*
470: * Handle non-zero SCSI status
471: *
472: * Returns:
473: * NO - Clean-up request now.
474: * YES - Wait for request sense to complete.
475: *
476: * This routine filter's out BUSY and more arcane SCSI status conditions,
477: * leaving CHECK_CONDITION, for which it set's up a request sense operation.
478: *
479: *-----------------------------------------------------------------------------*/
480: - (BOOL) Sym8xxProcessStatus: (SRB *) srb;
481: {
482: IODoneMailBox *pMailBox;
483:
484: scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_select_phase];
485:
486: pMailBox = (IODoneMailBox *)&SCRIPT_VAR(R_ld_IOdone_mailbox);
487:
488: /*
489: * If a previous request sense failed, then clean-up the request now.
490: */
491: if ( srb->srbState != ksrbStateCDBDone )
492: {
493: if ( srb->srbSCSIResult == SR_IOST_GOOD )
494: {
495: srb->srbSCSIResult = SR_IOST_CHKSNV;
496: }
497: return NO;
498: }
499:
500: /*
501: * Update the SRB with our byte transferred count and SCSI status.
502: * This information needs to be captured before we issue the request
503: * sense.
504: */
505: srb->srbSCSIStatus = pMailBox->status;
506:
507: [self Sym8xxUpdateXferOffset: srb];
508:
509: if ( pMailBox->status != STAT_CHECK )
510: {
511: srb->srbSCSIResult = ST_IOST_BADST;
512: return NO;
513: }
514: if ( srb->senseData == NULL )
515: {
516: srb->srbSCSIResult = SR_IOST_CHKSNV;
517: return NO;
518: }
519:
520: [self Sym8xxIssueRequestSense: srb];
521:
522: return YES;
523: }
524:
525: /*-----------------------------------------------------------------------------*
526: * Prepare request sense request.
527: *
528: *-----------------------------------------------------------------------------*/
529: - (void) Sym8xxIssueRequestSense:(SRB *) srb
530: {
531: IODoneMailBox *pMailBox;
532: u_int32_t reqSenseMailBox;
533:
534: pMailBox = (IODoneMailBox *)&SCRIPT_VAR(R_ld_IOdone_mailbox);
535:
536: /*
537: * We put the request sense Nexus in the last completed script mailbox and
538: * back-up the script's mailbox pointer.
539: */
540: reqSenseMailBox = (u_int8_t)(EndianSwap32(SCRIPT_VAR(R_ld_counter)) - 1);
541: SCRIPT_VAR(R_ld_counter) = EndianSwap32( reqSenseMailBox );
542:
543: srb->srbTimeout = kReqSenseTimeoutMS / kSCSITimerIntervalMS + 1;
544:
545: srb->srbState = ksrbStateReqSenseDone;
546: srb->srbSCSIResult = SR_IOST_CHKSV;
547:
548: /*
549: * Reuse the original Nexus struct. The original CDB is not preserved. The
550: * original status and transfer counts and tag are kept in the SRB.
551: */
552: bzero( &srb->nexus.cdbData, 6 );
553: srb->nexus.cdbData.cdb_c6.c6_opcode = C6OP_REQSENSE;
554: srb->nexus.cdbData.cdb_c6.c6_lun = srb->lun;
555: srb->nexus.cdbData.cdb_c6.c6_len = srb->senseDataLength;
556: srb->nexus.cdb.length = EndianSwap32( 6 );
557:
558: /*
559: * Force renegotiation on request sense.
560: */
561: targets[srb->target].flags &= ~(kTFXferSync | kTFXferWide16);
562: srb->srbRequestFlags &= ~(ksrbRFCmdQueueAllowed | ksrbRFDisconnectAllowed);
563: [self Sym8xxCalcMsgs:srb];
564:
565: /*
566: * Create a new SG List for the request sense data
567: *
568: */
569: srb->xferOffset = 0;
570: srb->xferOffsetPrev = 0;
571: srb->xferClient = IOVmTaskSelf();
572: srb->xferBuffer = srb->senseData;
573: srb->xferCount = srb->senseDataLength;
574: srb->directionMask = 0x01000000;
575: srb->nexus.ppSGList = (SGEntry *)EndianSwap32((u_int32_t)&srb->srbPhys->nexus.sgListData[2]);
576: [self Sym8xxUpdateSGList: srb];
577:
578: /*
579: * If the original request was using cmd-queuing, we clean-up the original tagged request
580: * and convert it to a non-tagged request sense.
581: */
582: if ( srb->nexus.tag >= MIN_SCSI_TAG )
583: {
584: adapter->nexusPtrsVirt[pMailBox->nexus] = (Nexus *) -1;
585: adapter->nexusPtrsPhys[pMailBox->nexus] = (Nexus *) -1;
586:
587: srb->nexus.tag = (srb->target << 3) | srb->lun;
588: adapter->nexusPtrsVirt[srb->nexus.tag] = &srb->nexus;
589: adapter->nexusPtrsPhys[srb->nexus.tag] = (Nexus *)EndianSwap32( (u_int32_t)&srb->srbPhys->nexus );
590: }
591:
592: adapter->schedMailBox[reqSenseMailBox] = (Nexus *)EndianSwap32 ( (u_int32_t)&srb->srbPhys->nexus );
593:
594: [self Sym8xxSignalScript: srb];
595:
596: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
597: }
598:
599: /*-----------------------------------------------------------------------------*
600: * Current Data Pointer calculations
601: *
602: * To do data transfers the driver generates a list of script instructions
603: * in system storage to deliver data to the requested physical addresses. The
604: * script branches to the list when the target enters data transfer phase.
605: *
606: * When the target changes phase during a data transfer, data is left trapped
607: * inside the various script engine registers. This routine determines how much
608: * data was not actually transfered to/from the target and generates a new
609: * S/G List entry for the partial transfer and a branch back into the original
610: * S/G list. These script instructions are stored in two reserved slots at the
611: * top of the original S/G List.
612: *
613: *-----------------------------------------------------------------------------*/
614: - (void) Sym8xxAdjustDataPtrs:(SRB *) srb Nexus:(Nexus *) nexus
615: {
616: u_int32_t i;
617: u_int32_t sgResid;
618: u_int32_t fifoCnt;
619: u_int32_t dspReg;
620: u_int32_t sgDone;
621: u_int8_t scntl2Reg;
622: Nexus *nexusPhys;
623:
624: /*
625: * Determine SG element residual
626: *
627: * This routine returns how much of the current S/G List element the
628: * script was processing remains to be sent/received. All the information
629: * required to do this is stored in the script engine's registers.
630: */
631: sgResid = [self Sym8xxCheckFifo:srb FifoCnt:&fifoCnt];
632:
633: /*
634: * Determine which script instruction in our SGList we were executing when
635: * the target changed phase.
636: *
637: * The script engine's dspReg tells us where the script thinks it was. Based
638: * on the physical address of our current SRB/Nexus we can calculate
639: * an index into our S/G List.
640: */
641: dspReg = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE );
642:
643: i = ((dspReg - (u_int32_t)srb->srbPhys->nexus.sgListData) / sizeof(SGEntry)) - 1;
644:
645: if ( i > MAX_SGLIST_ENTRIES-1 )
646: {
647: kprintf("SCSI(Symbios8xx): Bad sgListIndex\n\r");
648: [self Sym8xxAbortCurrent: srb];
649: return;
650: }
651:
652: /*
653: * Wide/odd-byte transfers.
654: *
655: * When dealing with Wide data transfers, if a S/G List ends with an odd-transfer count, then a
656: * valid received data byte is left in the script engine's SWIDE register. The least painful way
657: * to recover this byte is to construct a small script thunk to transfer one additional byte. The
658: * script will automatically draw this byte from the SWIDE register rather than the SCSI bus.
659: * The script thunk then branches back to script's PhaseHandler entrypoint.
660: *
661: */
662: nexusPhys = &srb->srbPhys->nexus;
663:
664: scntl2Reg = Sym8xxReadRegs( chipBaseAddr, SCNTL2, SCNTL2_SIZE );
665: if ( scntl2Reg & WSR )
666: {
667: adapter->xferSWideInst[0] = EndianSwap32( srb->directionMask | 1 );
668: adapter->xferSWideInst[1] = nexus->sgListData[i].physAddr;
669: adapter->xferSWideInst[2] = EndianSwap32( 0x80080000 );
670: adapter->xferSWideInst[3] = EndianSwap32( (u_int32_t)&chipRamAddrPhys[Ent_phase_handler] );
671:
672: scriptRestartAddr = (u_int32_t) adapterPhys->xferSWideInst;
673:
674: /*
675: * Note: There is an assumption here that the sgResid count will be > 1. It appears
676: * that the script engine does not generate a phase-mismatch interrupt until
677: * we attempt to move > 1 byte from the SCSI bus and the only byte available is
678: * in SWIDE.
679: */
680: sgResid--;
681: }
682:
683: /*
684: * Calculate partial S/G List instruction and branch
685: *
686: * Fill in slots 0/1 of the SGList based on the SGList index (i) and SGList residual count
687: * (sgResid) calculated above.
688: *
689: */
690: sgDone = (EndianSwap32( nexus->sgListData[i].length ) & 0x00ffffff) - sgResid;
691:
692: nexus->sgListData[0].length = EndianSwap32( sgResid | srb->directionMask );
693: nexus->sgListData[0].physAddr = EndianSwap32( EndianSwap32(nexus->sgListData[i].physAddr) + sgDone );
694: /*
695: * If a previously calculated SGList 0 entry was interrupted again, we dont need to calculate
696: * a new branch address since the previous one is still valid.
697: */
698: if ( i != 0 )
699: {
700: nexus->sgListData[1].length = EndianSwap32( 0x80080000 );
701: nexus->sgListData[1].physAddr = EndianSwap32( (u_int32_t)&nexusPhys->sgListData[i+1] );
702: nexus->sgNextIndex = i + 1;
703: }
704: nexus->ppSGList = (SGEntry *)EndianSwap32( (u_int32_t) &nexusPhys->sgListData[0] );
705:
706: /*
707: * The script sets this Nexus variable to non-zero each time it calls the driver generated
708: * S/G list. This allows the driver's completion routines to differentiate between a successful
709: * transfer vs no data transfer at all.
710: */
711: nexus->dataXferCalled = 0;
712:
713: return;
714: }
715:
716: /*-----------------------------------------------------------------------------*
717: * Determine SG element residual
718: *
719: * This routine returns how much of the current S/G List element the
720: * script was processing remains to be sent/received. All the information
721: * required to do this is stored in the script engine's registers.
722: *
723: *-----------------------------------------------------------------------------*/
724: - (u_int32_t) Sym8xxCheckFifo: (SRB *) srb FifoCnt:(u_int32_t *)pfifoCnt
725: {
726: BOOL fSCSISend;
727: BOOL fXferSync;
728: u_int32_t scriptPhase = 0;
729: u_int32_t dbcReg = 0;
730: u_int32_t dfifoReg = 0;
731: u_int32_t ctest5Reg = 0;
732: u_int8_t sstat0Reg = 0;
733: u_int8_t sstat1Reg = 0;
734: u_int8_t sstat2Reg = 0;
735: u_int32_t fifoCnt = 0;
736: u_int32_t sgResid = 0;
737:
738: scriptPhase = EndianSwap32( SCRIPT_VAR(R_ld_phase_flag) );
739:
740: fSCSISend = (scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_MSG_OUT);
741:
742: fXferSync = ((scriptPhase == A_kphase_DATA_OUT) || (scriptPhase == A_kphase_DATA_IN))
743: && (srb->nexus.targetParms.sxferReg & 0x1F);
744:
745: dbcReg = Sym8xxReadRegs( chipBaseAddr, DBC, DBC_SIZE ) & 0x00ffffff;
746:
747: if ( !(dstatReg & DFE) )
748: {
749: ctest5Reg = Sym8xxReadRegs( chipBaseAddr, CTEST5, CTEST5_SIZE );
750: dfifoReg = Sym8xxReadRegs( chipBaseAddr, DFIFO, DFIFO_SIZE );
751:
752: if ( ctest5Reg & DFS )
753: {
754: fifoCnt = ((((ctest5Reg & 0x03) << 8) | dfifoReg) - dbcReg) & 0x3ff;
755: }
756: else
757: {
758: fifoCnt = (dfifoReg - dbcReg) & 0x7f;
759: }
760: }
761:
762: sstat0Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT0, SSTAT0_SIZE );
763: sstat2Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT2, SSTAT2_SIZE );
764:
765: if ( fSCSISend )
766: {
767: fifoCnt += (sstat0Reg & OLF ) ? 1 : 0;
768: fifoCnt += (sstat2Reg & OLF1) ? 1 : 0;
769:
770: if ( fXferSync )
771: {
772: fifoCnt += (sstat0Reg & ORF ) ? 1 : 0;
773: fifoCnt += (sstat2Reg & ORF1) ? 1 : 0;
774: }
775: }
776: else
777: {
778: if ( fXferSync )
779: {
780: sstat1Reg = Sym8xxReadRegs( chipBaseAddr, SSTAT0, SSTAT0_SIZE );
781: fifoCnt += (sstat1Reg >> 4) | (sstat2Reg & FF4);
782: }
783: else
784: {
785: fifoCnt += (sstat0Reg & ILF ) ? 1 : 0;
786: fifoCnt += (sstat2Reg & ILF1) ? 1 : 0;
787: }
788: }
789:
790: sgResid = dbcReg + fifoCnt;
791: *pfifoCnt = fifoCnt;
792:
793: return sgResid;
794: }
795:
796: /*-----------------------------------------------------------------------------*
797: * Calculate transfer counts.
798: *
799: * This routine updates srb->xferDone with the amount of data transferred
800: * by the last S/G List executed.
801: *
802: *-----------------------------------------------------------------------------*/
803: - (void) Sym8xxUpdateXferOffset:(SRB *) srb
804: {
805: u_int32_t i;
806: u_int32_t xferOffset;
807:
808: /*
809: * srb->xferOffset contains the client buffer offset INCLUDING the range
810: * covered by the current SGList.
811: */
812: xferOffset = srb->xferOffset;
813:
814: /*
815: * If script did not complete the current transfer list then we need to determine
816: * how much of the list was completed.
817: */
818: if ( srb->nexus.dataXferCalled == 0 )
819: {
820: /*
821: * srb->xferOffsetPrev contains the client buffer offset EXCLUDING the
822: * range covered by the current SGList.
823: */
824: xferOffset = srb->xferOffsetPrev;
825:
826: /*
827: * Calculate bytes transferred for partially completed list.
828: *
829: * To calculate the amount of this list completed, we sum the residual amount
830: * in SGList Slot 0 and the completed list elements 2 to sgNextIndex-1.
831: */
832: if ( srb->nexus.sgNextIndex != 0 )
833: {
834: xferOffset += EndianSwap32( srb->nexus.sgListData[srb->nexus.sgNextIndex-1].length )
835: - EndianSwap32( srb->nexus.sgListData[0].length );
836:
837: for ( i=2; i < srb->nexus.sgNextIndex-1; i++ )
838: {
839: xferOffset += EndianSwap32( srb->nexus.sgListData[i].length ) & 0x00ffffff;
840: }
841: }
842: }
843:
844: /*
845: * The script leaves the result of any Ignore Wide Residual message received from the target
846: * during the transfer.
847: */
848: xferOffset -= srb->nexus.wideResidCount;
849:
850:
851: #if 0
852: {
853: u_int32_t resid = srb->xferOffset - xferOffset;
854: if ( resid )
855: {
856: kprintf( "SCSI(Symbios8xx): Incomplete transfer - Req Count = %08x Act Count = %08x - srb = %08x\n\r",
857: srb->xferCount, xferOffset, (u_int32_t)srb );
858: }
859: }
860: #endif
861:
862: srb->xferDone = xferOffset;
863: }
864:
865: /*-----------------------------------------------------------------------------*
866: * No SRB/Nexus Processing.
867: *
868: * In some cases (mainly Aborts) not having a SRB/Nexus is normal. In other
869: * cases it indicates a problem such a reconnection from a target that we
870: * have no record of.
871: *
872: *-----------------------------------------------------------------------------*/
873: - (void) Sym8xxProcessNoNexus
874: {
875: u_int32_t dspsReg;
876: u_int32_t dspReg = 0;
877: u_int32_t scriptPhase = -1 ;
878:
879: scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_select_phase];
880:
881: dspsReg = Sym8xxReadRegs( chipBaseAddr, DSPS, DSPS_SIZE );
882:
883: scriptPhase = EndianSwap32( SCRIPT_VAR(R_ld_phase_flag) );
884:
885: /*
886: * If we were trying to abort or disconnect a target and the bus
887: * is now free we consider the abort to have completed.
888: */
889: if ( sistReg & UDC )
890: {
891: if ( (scriptPhase == A_kphase_ABORT_MAILBOX) && abortSRB )
892: {
893: [abortSRB->srbCmdLock unlockWith: ksrbCmdComplete];
894: abortSRB = (SRB *) NULL;
895: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
896: }
897: else if ( scriptPhase == A_kphase_ABORT_CURRENT )
898: {
899: abortCurrentSRB = NULL;
900: }
901: }
902: /*
903: * If we were trying to connect to a target to send it an abort message, and
904: * we timed out, we consider the abort as completed.
905: *
906: * Note: In this case the target may be hung, but at least its not on the bus.
907: */
908: else if ( sistReg & STO )
909: {
910: if ( (scriptPhase == A_kphase_ABORT_MAILBOX) && abortSRB )
911: {
912: [abortSRB->srbCmdLock unlockWith: ksrbCmdComplete];
913: abortSRB = (SRB *) NULL;
914: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
915: }
916: }
917:
918: /*
919: * If the script died, without a vaild nexusIndex, we abort anything that is currently
920: * connected and hope for the best!
921: */
922: else if ( dstatReg & IID )
923: {
924: dspReg = Sym8xxReadRegs( chipBaseAddr, DSP, DSP_SIZE );
925: kprintf("SCSI(Symbios8xx): Illegal script instruction - dsp = %08x srb=0\n\r", dspReg );
926: [self Sym8xxAbortCurrent: (SRB *) -1];
927: }
928:
929: /*
930: * Script signaled conditions
931: */
932: else if ( dstatReg & SIR )
933: {
934: switch ( dspsReg )
935: {
936: case A_abort_current:
937: abortCurrentSRB = NULL;
938: break;
939:
940: case A_abort_mailbox:
941: [abortSRB->srbCmdLock unlockWith: ksrbCmdComplete];
942: abortSRB = (SRB *) NULL;
943: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
944: break;
945:
946: default:
947: [self Sym8xxAbortCurrent: (SRB *)-1];
948: }
949: }
950: else
951: {
952: [self Sym8xxAbortCurrent: (SRB *)-1];
953: }
954:
955: if ( scriptRestartAddr )
956: {
957: Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
958: }
959: }
960:
961:
962: /*-----------------------------------------------------------------------------*
963: * Abort currently connected target.
964: *
965: *-----------------------------------------------------------------------------*/
966: - (void) Sym8xxAbortCurrent:(SRB *)srb
967: {
968: if ( abortCurrentSRB )
969: {
970: if ( abortCurrentSRB != srb )
971: {
972: // kprintf("SCSI(Symbios8xx): Multiple abort immediate SRBs - resetting\n\r");
973: [self Sym8xxSCSIBusReset: (SRB *)NULL];
974: }
975: return;
976: }
977:
978: abortCurrentSRB = srb;
979: abortCurrentSRBTimeout = kAbortTimeoutMS / kSCSITimerIntervalMS + 1;
980:
981: /*
982: * Issue abort or abort tag depending on whether the is a tagged request
983: */
984: SCRIPT_VAR(R_ld_AbortCode) = EndianSwap32( ((srb != (SRB *)-1) && (srb->nexus.tag >= MIN_SCSI_TAG)) ? 0x0d : 0x06 );
985: scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_issueAbort_BDR];
986:
987: [self Sym8xxClearFifo];
988: }
989:
990: /*-----------------------------------------------------------------------------*
991: * This routine clears the script engine's SCSI and DMA fifos.
992: *
993: *-----------------------------------------------------------------------------*/
994: - (void) Sym8xxClearFifo
995: {
996: u_int8_t ctest3Reg;
997: u_int8_t stest2Reg;
998: u_int8_t stest3Reg;
999:
1000: stest2Reg = Sym8xxReadRegs( chipBaseAddr, STEST2, STEST2_SIZE );
1001: if ( stest2Reg & ROF )
1002: {
1003: Sym8xxWriteRegs( chipBaseAddr, STEST2, STEST2_SIZE, stest2Reg );
1004: }
1005:
1006: ctest3Reg = Sym8xxReadRegs( chipBaseAddr, CTEST3, CTEST3_SIZE );
1007: ctest3Reg |= CLF;
1008: Sym8xxWriteRegs( chipBaseAddr, CTEST3, CTEST3_SIZE, ctest3Reg );
1009:
1010: stest3Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE );
1011: stest3Reg |= CSF;
1012: Sym8xxWriteRegs( chipBaseAddr,STEST3, STEST3_SIZE, stest3Reg );
1013:
1014: do
1015: {
1016: ctest3Reg = Sym8xxReadRegs( chipBaseAddr, CTEST3, CTEST3_SIZE );
1017: stest2Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE );
1018: stest3Reg = Sym8xxReadRegs( chipBaseAddr, STEST3, STEST3_SIZE );
1019: }
1020: while( (ctest3Reg & CLF) || (stest3Reg & CSF) || (stest2Reg & ROF) );
1021: }
1022:
1023: /*-----------------------------------------------------------------------------*
1024: * This routine processes the target's response to our SDTR message.
1025: *
1026: * We calculate the values for the script engine's timing registers
1027: * for synchronous registers, and update our tables indicating that
1028: * requested data transfer mode is in-effect.
1029: *
1030: *-----------------------------------------------------------------------------*/
1031: - (void) Sym8xxNegotiateSDTR:(SRB *) srb Nexus:(Nexus *)nexus
1032: {
1033: u_int32_t x;
1034: u_int8_t *pMsg;
1035: u_int32_t syncPeriod;
1036:
1037: /*
1038: * If we were not negotiating, the send MsgReject to targets negotiation
1039: * attempt.
1040: */
1041: if ( !(srb->srbRequestFlags & ksrbRFNegotiateSync) )
1042: {
1043: [self Sym8xxSendMsgReject: srb];
1044: return;
1045: }
1046:
1047: /*
1048: * Get pointer to negotiation message received from target.
1049: */
1050: pMsg = (u_int8_t *) &SCRIPT_VAR(R_ld_message);
1051:
1052: /*
1053: * The target's SDTR response contains the (transfer period / 4).
1054: *
1055: * We set our sync clock divisor to 1, 2, or 4 giving us a clock rates
1056: * of:
1057: * 80Mhz (Period = 12.5ns),
1058: * 40Mhz (Period = 25.0ns)
1059: * 20Mhz (Period = 50.0ns)
1060: *
1061: * This is further divided by the value in the sxfer reg to give us the final sync clock rate.
1062: *
1063: * The requested sync period is scaled up by 1000 and the clock periods are scaled up by 10
1064: * giving a result scaled up by 100. This is rounded-up and converted to sxfer reg values.
1065: */
1066: syncPeriod = (u_int32_t)pMsg[3] << 2;
1067: if ( syncPeriod < 100 )
1068: {
1069: nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_ULTRA;
1070: x = (syncPeriod * 1000) / 125;
1071: }
1072: else if ( syncPeriod < 200 )
1073: {
1074: nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_FAST;
1075: x = (syncPeriod * 1000) / 250;
1076: }
1077: else
1078: {
1079: nexus->targetParms.scntl3Reg |= SCNTL3_INIT_875_SLOW;
1080: x = (syncPeriod * 1000) / 500;
1081: }
1082:
1083: if ( x % 100 ) x += 100;
1084:
1085: /*
1086: * sxferReg Bits: 5-0 - Transfer offset
1087: * 7-6 - Sync Clock Divisor (0 = sync clock / 4)
1088: */
1089: nexus->targetParms.sxferReg = ((x/100 - 4) << 5) | pMsg[4];
1090:
1091: /*
1092: * Update our per-target tables and set-up the hardware regs for this request.
1093: *
1094: * On reconnection attempts, the script will use our per-target tables to set-up
1095: * the scntl3 and sxfer registers in the script engine.
1096: */
1097: adapter->targetClocks[srb->target].sxferReg = nexus->targetParms.sxferReg;
1098: adapter->targetClocks[srb->target].scntl3Reg = nexus->targetParms.scntl3Reg;
1099:
1100: Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, nexus->targetParms.scntl3Reg );
1101: Sym8xxWriteRegs( chipBaseAddr, SXFER, SXFER_SIZE, nexus->targetParms.sxferReg );
1102:
1103: targets[srb->target].flags |= kTFXferSync;
1104:
1105: scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_clearACK];
1106: }
1107:
1108: /*-----------------------------------------------------------------------------*
1109: * This routine processes the target's response to our WDTR message.
1110: *
1111: * In addition, if there is a pending SDTR message, this routine sends it
1112: * to the target.
1113: *
1114: *-----------------------------------------------------------------------------*/
1115: - (void) Sym8xxNegotiateWDTR:(SRB *) srb Nexus:(Nexus *)nexus
1116: {
1117: u_int8_t *pMsg;
1118: u_int32_t msgBytesSent;
1119: u_int32_t msgBytesLeft;
1120:
1121: /*
1122: * If we were not negotiating, the send MsgReject to targets negotiation
1123: * attempt.
1124: */
1125: if ( !(srb->srbRequestFlags & ksrbRFNegotiateWide) )
1126: {
1127: [self Sym8xxSendMsgReject: srb];
1128: return;
1129: }
1130:
1131: /*
1132: * Set Wide (16-bit) vs Narrow (8-bit) data transfer mode based on target's response.
1133: */
1134: pMsg = (u_int8_t *) &SCRIPT_VAR(R_ld_message);
1135:
1136: if ( pMsg[3] == 1 )
1137: {
1138: nexus->targetParms.scntl3Reg |= EWS;
1139: }
1140: else
1141: {
1142: nexus->targetParms.scntl3Reg &= ~EWS;
1143: }
1144:
1145: /*
1146: * Update our per-target tables and set-up the hardware regs for this request.
1147: *
1148: * On reconnection attempts, the script will use our per-target tables to set-up
1149: * the scntl3 and sxfer registers in the script engine.
1150: */
1151:
1152: adapter->targetClocks[srb->target].scntl3Reg = nexus->targetParms.scntl3Reg;
1153: Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, nexus->targetParms.scntl3Reg );
1154:
1155: targets[srb->target].flags |= kTFXferWide16;
1156:
1157: /*
1158: * If there any pending messages left for the target, send them now,
1159: */
1160: msgBytesSent = EndianSwap32( nexus->msg.length );
1161: msgBytesLeft = srb->srbMsgLength - msgBytesSent;
1162: if ( msgBytesLeft )
1163: {
1164: nexus->msg.length = EndianSwap32( msgBytesLeft );
1165: nexus->msg.ppData = EndianSwap32( EndianSwap32( nexus->msg.ppData ) + msgBytesSent );
1166: scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_issueMessageOut];
1167: }
1168:
1169: /*
1170: * Otherwise, tell the script we're done with MsgOut phase.
1171: */
1172: else
1173: {
1174: scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_clearACK];
1175: }
1176: }
1177:
1178: /*-----------------------------------------------------------------------------*
1179: * Reject message received from target.
1180: *
1181: *-----------------------------------------------------------------------------*/
1182: - (void) Sym8xxSendMsgReject:(SRB *) srb
1183: {
1184: srb->nexus.msg.ppData = EndianSwap32((u_int32_t)&srb->srbPhys->nexus.msgData);
1185: srb->nexus.msg.length = EndianSwap32(0x01);
1186: srb->nexus.msgData[0] = 0x07;
1187:
1188: scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_issueMessageOut];
1189: }
1190:
1191: /*-----------------------------------------------------------------------------*
1192: * This routine snoops inquiry data.
1193: *
1194: * The indirect SCSI Disk driver in driverKit, does not bother to check the target's
1195: * capabilities before enabling Synchronous Negotiation or Cmd Queueing. If things
1196: * were left to themselves, targets that did not support tags would be broken since
1197: * the request comming from driverKit always indicate that tags are allowed.
1198: *
1199: *-----------------------------------------------------------------------------*/
1200: - (void) Sym8xxCheckInquiryData: (SRB *)srb
1201: {
1202: IOMemoryDescriptor *mem;
1203: inquiry_reply_t inqData;
1204: u_int32_t inqSize;
1205:
1206: bzero( &inqData, sizeof(inqData) );
1207:
1208: inqSize = (srb->xferDone < sizeof(inqData)) ? srb->xferDone : sizeof(inqData);
1209:
1210: mem = [[ IOSimpleMemoryDescriptor alloc ] initWithAddress: (void *)srb->xferBuffer length: inqSize ];
1211: [mem setClient: srb->xferClient];
1212:
1213: do
1214: {
1215: if ( srb->srbSCSIResult != SR_IOST_GOOD )
1216: {
1217: continue;
1218: }
1219: if ( srb->xferDone < offsetof(inquiry_reply_t, ir_vendorid) )
1220: {
1221: continue;
1222: }
1223:
1224: if ( [mem readFromClient: (void *) &inqData count: inqSize] != inqSize )
1225: {
1226: continue;
1227: }
1228: if ( inqData.ir_qual != DEVQUAL_OK )
1229: {
1230: continue;
1231: }
1232:
1233: if ( inqData.ir_wbus16 )
1234: {
1235: targets[srb->target].flags |= kTFXferWide16Supported;
1236: }
1237: if ( inqData.ir_sync )
1238: {
1239: targets[srb->target].flags |= kTFXferSyncSupported;
1240: }
1241: if ( inqData.ir_cmdque )
1242: {
1243: targets[srb->target].flags |= kTFCmdQueueSupported;
1244: }
1245: }
1246: while ( 0 );
1247: [mem release];
1248: }
1249:
1250:
1251: /*-----------------------------------------------------------------------------*
1252: * This routine initiates a SCSI Bus Reset.
1253: *
1254: * This may be an internally generated request as part of error recovery or
1255: * a client's bus reset request.
1256: *
1257: *-----------------------------------------------------------------------------*/
1258: - (void) Sym8xxSCSIBusReset: (SRB *)srb
1259: {
1260: if ( srb )
1261: {
1262: if ( resetSRB )
1263: {
1264: srb->srbSCSIResult = SR_IOST_CMDREJ;
1265: [srb->srbCmdLock unlockWith: ksrbCmdComplete];
1266: return;
1267: }
1268: resetSRB = srb;
1269: }
1270:
1271: Sym8xxWriteRegs( chipBaseAddr, SCNTL1, SCNTL1_SIZE, SCNTL1_SCSI_RST );
1272: IODelay( 25 );
1273: Sym8xxWriteRegs( chipBaseAddr, SCNTL1, SCNTL1_SIZE, SCNTL1_INIT );
1274: }
1275:
1276: /*-----------------------------------------------------------------------------*
1277: * This routine handles a SCSI Bus Reset interrupt.
1278: *
1279: * The SCSI Bus reset may be generated by a target on the bus, internally from
1280: * the driver's error recovery or from a client request.
1281: *
1282: * Once the reset is detected we establish a settle period where new client requests
1283: * are blocked in the client thread. In addition we flush all currently executing
1284: * scsi requests back to the client.
1285: *
1286: *-----------------------------------------------------------------------------*/
1287: - (void) Sym8xxProcessSCSIBusReset
1288: {
1289: SRB *srb = 0;
1290: Nexus *nexus = 0;
1291: u_int32_t i;
1292:
1293: /*
1294: * If we got another bus reset event during the settle period we extend the settle
1295: * period accordingly.
1296: */
1297: if ( resetQuiesceTimer )
1298: {
1299: resetQuiesceTimer = kResetQuiesceDelayMS / kSCSITimerIntervalMS + 1;
1300: return;
1301: }
1302:
1303: resetSeqNum = srbSeqNum;
1304: // kprintf("SCSI(Symbios8xx): Reset Started - SRB Seq = %d\n\r", resetSeqNum);
1305:
1306: /*
1307: * We take the resetQuiesceSem lock which will block new client thread requests.
1308: *
1309: * Note: The client thread checks resetQuiesceTimer for <> 0 before taking this lock.
1310: */
1311: [resetQuiesceSem lock];
1312: resetQuiesceTimer = kResetQuiesceDelayMS / kSCSITimerIntervalMS + 1;
1313:
1314: /*
1315: * We end any aborts currently in progress
1316: */
1317: abortCurrentSRB = (SRB *)NULL;
1318:
1319: if ( abortSRB )
1320: {
1321: [abortSRB->srbCmdLock unlockWith: ksrbCmdComplete];
1322: abortSRB = (SRB *) NULL;
1323: }
1324:
1325: [self Sym8xxClearFifo];
1326:
1327: /*
1328: * We return anything in our Nexus table back to the client
1329: */
1330: for ( i=0; i < MAX_SCSI_TAG; i++ )
1331: {
1332: nexus = adapter->nexusPtrsVirt[i];
1333: if ( nexus == (Nexus *) -1 )
1334: {
1335: continue;
1336: }
1337:
1338: srb = (SRB *)((u_int32_t)nexus - offsetof(SRB, nexus));
1339:
1340: srb->srbSCSIResult = SR_IOST_RESET;
1341:
1342: adapter->nexusPtrsVirt[i] = (Nexus *) -1;
1343: adapter->nexusPtrsPhys[i] = (Nexus *) -1;
1344:
1345: [srb->srbCmdLock unlockWith: ksrbCmdComplete];
1346: }
1347:
1348: /*
1349: * We clear the script's request mailboxes. Any work in the script mailboxes is
1350: * already in the NexusPtr tables so we have already have handled the SRB/Nexus
1351: * cleanup.
1352: */
1353: for ( i=0; i < MAX_SCHED_MAILBOXES; i++ )
1354: {
1355: adapter->schedMailBox[i] = 0;
1356: }
1357:
1358: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
1359: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
1360: SCRIPT_VAR(R_ld_counter) = 0;
1361: mailBoxIndex = 0;
1362:
1363: /*
1364: * Reset the data transfer mode/clocks in our per-target tables back to Async/Narrow 8-bit
1365: */
1366: for ( i=0; i < MAX_SCSI_TARGETS; i++ )
1367: {
1368: targets[i].flags &= ~(kTFXferSync | kTFXferWide16);
1369:
1370: adapter->targetClocks[i].scntl3Reg = SCNTL3_INIT_875;
1371: adapter->targetClocks[i].sxferReg = 0;
1372: }
1373:
1374: scriptRestartAddr = (u_int32_t) &chipRamAddrPhys[Ent_select_phase];
1375: Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
1376:
1377: }
1378:
1379: /*-----------------------------------------------------------------------------*
1380: * This routine sets the SIGP bit in the script engine's ISTAT
1381: * register. This signals the script to wake-up for a WAIT for
1382: * reselection instruction. The script will then check the mailboxes
1383: * for work to do.
1384: *
1385: *-----------------------------------------------------------------------------*/
1386: - (void) Sym8xxSignalScript:(SRB *)srb
1387: {
1388: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, SIGP );
1389: }
1390:
1391: /*-----------------------------------------------------------------------------*
1392: * Timeout handler.
1393: *
1394: * This routine is scheduled and implements timeouts for the driver.
1395: *
1396: * The following items are timed:
1397: *
1398: * - Reset settle period.
1399: * - Aborts
1400: * - SRBs
1401: *
1402: *-----------------------------------------------------------------------------*/
1403: - (void) timeoutOccurred
1404: {
1405: SRB *srb;
1406: Nexus *nexus;
1407: u_int32_t i;
1408: u_int32_t nexusIndex;
1409: u_int32_t mailboxNexusIndex = -1;
1410:
1411: if ( SCRIPT_VAR( R_ld_IOdone_mailbox ) )
1412: {
1413: mailboxNexusIndex = ((IODoneMailBox *)&SCRIPT_VAR(R_ld_IOdone_mailbox))->nexus;
1414: }
1415:
1416: nexusIndex = EndianSwap32( SCRIPT_VAR(R_ld_nexus_index) );
1417:
1418: /*
1419: * If we are in a reset settle period, suspend all other timing.
1420: *
1421: * When the reset settle period completes, return the SRB if the
1422: * client requested the bus reset. Also unlock the reset semaphore.
1423: */
1424: if ( resetQuiesceTimer )
1425: {
1426: if ( --resetQuiesceTimer )
1427: {
1428: goto timeoutOccurred_Exit;
1429: }
1430:
1431: if ( resetSRB )
1432: {
1433: [resetSRB->srbCmdLock unlockWith: ksrbCmdComplete];
1434: resetSRB = (SRB *) NULL;
1435: }
1436: // kprintf("SCSI(Symbios8xx): Reset Ended - SRB Seq = %d\n\r", srbSeqNum);
1437: [resetQuiesceSem unlock];
1438: }
1439:
1440: /*
1441: * Check whether an abort timed out. If it does, then its likely that a target is
1442: * hung on the bus. In this case the only recourse is to issue a SCSI Bus reset.
1443: */
1444: if ( abortCurrentSRB && abortCurrentSRBTimeout )
1445: {
1446: if ( !(--abortCurrentSRBTimeout) )
1447: {
1448: // kprintf("SCSI(Symbios8xx): Abort Current SRB failed - resetting\n\r");
1449: [self Sym8xxSCSIBusReset: (SRB *)NULL];
1450: goto timeoutOccurred_Exit;
1451: }
1452: }
1453:
1454: if ( abortSRB && abortSRBTimeout )
1455: {
1456: if ( !(--abortSRBTimeout) )
1457: {
1458: // kprintf("SCSI(Symbios8xx): MailBox abort failed - resetting\n\r");
1459: [self Sym8xxSCSIBusReset: (SRB *)NULL];
1460: goto timeoutOccurred_Exit;
1461: }
1462: }
1463:
1464: /*
1465: * Scan the Nexus pointer table looking for SRBs to timeout
1466: */
1467: for ( i=0; i < MAX_SCSI_TAG; i++ )
1468: {
1469: nexus = adapter->nexusPtrsVirt[i];
1470: if ( nexus == (Nexus *) -1 )
1471: {
1472: continue;
1473: }
1474:
1475: srb = (SRB *)((u_int32_t)nexus - offsetof(SRB, nexus));
1476: if ( srb->srbTimeout )
1477: {
1478: if ( !(--srb->srbTimeout) )
1479: {
1480: // kprintf("SCSI(Symbios8xx): Timeout - Target = %d SRB = %08x SRB Seq = %d\n\r",
1481: // srb->target, (u_int32_t)srb, srb->srbSeqNum );
1482:
1483: /* If the SRB we're timing out is in the script's IODone mailbox, then
1484: * clear the mailbox in addition to timing out the request.
1485: */
1486: if ( i == mailboxNexusIndex )
1487: {
1488: SCRIPT_VAR(R_ld_IOdone_mailbox) = 0;
1489: }
1490:
1491: /*
1492: * If the target for the SRB we're timing out is currently connected on
1493: * the SCSI Bus, then issue an abort. Since it is likely that the script
1494: * is running in this scenario, we call a Sym8xxAbortScript to shutdown the
1495: * script engine in an orderly fashion.
1496: */
1497: if ( i == nexusIndex )
1498: {
1499: [self Sym8xxAbortScript];
1500: srb->srbSCSIResult = SR_IOST_IOTO;
1501: [self Sym8xxAbortCurrent: srb];
1502: Sym8xxWriteRegs( chipBaseAddr, DSP, DSP_SIZE, scriptRestartAddr );
1503: }
1504:
1505: /*
1506: * If target for the SRB we're timing out is not on the SCSI bus, then
1507: * we mark the request as requiring an Abort and return it to the client
1508: * thread. The client thread will then schedule the abort.
1509: */
1510: else
1511: {
1512: adapter->nexusPtrsVirt[i] = (Nexus *) -1;
1513: adapter->nexusPtrsPhys[i] = (Nexus *) -1;
1514:
1515: srb->srbSCSIResult = SR_IOST_IOTO;
1516: srb->srbCmd = ksrbCmdProcessTimeout;
1517: [srb->srbCmdLock unlockWith: ksrbCmdComplete];
1518: }
1519: }
1520: }
1521: }
1522:
1523:
1524: timeoutOccurred_Exit: ;
1525: /*
1526: * Reschedule the next timer interval.
1527: */
1528: ns_timeout((func) Sym8xxTimerReq, (void *) self, (ns_time_t) kSCSITimerIntervalMS * 1000 * 1000, (int)CALLOUT_PRI_THREAD);
1529: }
1530:
1531: /*-----------------------------------------------------------------------------*
1532: * This routine does a mailbox abort.
1533: *
1534: * This type of abort is used for targets not currently connected to the SCSI Bus.
1535: *
1536: * The script will select the target and send a tag (if required) followed by the
1537: * appropriate abort message (abort/abort-tag)
1538: *
1539: *-----------------------------------------------------------------------------*/
1540: - (void) Sym8xxAbortBdr:(SRB *) srb
1541: {
1542: IOAbortBdrMailBox abortMailBox;
1543:
1544: abortSRB = srb;
1545: abortSRBTimeout = kAbortTimeoutMS / kSCSITimerIntervalMS + 1;
1546:
1547: /*
1548: * Setup a script variable containing the abort information.
1549: */
1550: abortMailBox.message = ( srb->nexus.tag < MIN_SCSI_TAG) ? 0x06 : 0x0d;
1551: abortMailBox.identify = srb->lun | 0xC0 ;
1552: abortMailBox.scsi_id = srb->target;
1553: abortMailBox.tag = ( srb->nexus.tag < MIN_SCSI_TAG) ? 0 : srb->nexus.tag;
1554:
1555: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = *(u_int32_t *) &abortMailBox;
1556:
1557: [self Sym8xxSignalScript: srb];
1558: }
1559:
1560: /*-----------------------------------------------------------------------------*
1561: * This routine is used to shutdown the script engine in an orderly fashion.
1562: *
1563: * Normally the script engine automatically stops when an interrupt is generated. However,
1564: * in the case of timeouts we need to change the script engine's dsp reg (instruction pointer).
1565: * to issue an abort.
1566: *
1567: *-----------------------------------------------------------------------------*/
1568: - (void) Sym8xxAbortScript
1569: {
1570: ns_time_t currentTime;
1571: ns_time_t endTime;
1572:
1573: [self disableAllInterrupts];
1574:
1575: /*
1576: * We set the ABRT bit in ISTAT and spin until the script engine acknowledges the
1577: * abort or we timeout.
1578: */
1579: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, ABRT );
1580:
1581: IOGetTimestamp( &endTime );
1582:
1583: endTime += (kAbortScriptTimeoutMS * 1000 * 1000);
1584:
1585: do
1586: {
1587: IOGetTimestamp( ¤tTime );
1588:
1589: istatReg = Sym8xxReadRegs( chipBaseAddr, ISTAT, ISTAT_SIZE );
1590:
1591: if ( istatReg & SIP )
1592: {
1593: Sym8xxReadRegs( chipBaseAddr, SIST, SIST_SIZE );
1594: continue;
1595: }
1596:
1597: if ( istatReg & DIP )
1598: {
1599: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, 0x00 );
1600: Sym8xxReadRegs( chipBaseAddr, DSTAT, DSTAT_SIZE );
1601: break;
1602: }
1603: }
1604: while ( currentTime < endTime );
1605:
1606: istatReg = SIGP;
1607: Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, istatReg );
1608:
1609: [self enableAllInterrupts];
1610:
1611: if ( currentTime >= endTime )
1612: {
1613: // kprintf( "SCSI(Symbios8xx): Abort script failed - resetting bus\n\r" );
1614: [self Sym8xxSCSIBusReset: NULL];
1615: }
1616:
1617: }
1618:
1619: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.