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