|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22:
23: /* Sym8xxClient.m created by russb2 on Sat 30-May-1998 */
24:
25: #include "Sym8xxController.h"
26:
27: extern pmap_t kernel_pmap;
28:
29:
30: /*-----------------------------------------------------------------------------*
31: *
32: *-----------------------------------------------------------------------------*/
33: void Sym8xxSCSIController::executeCommand( IOSCSICommand *scsiCommand )
34: {
35: SRB *srb = NULL;
36: SCSICDBInfo scsiCDB;
37: SCSITargetLun targetLun;
38: Nexus *nexus;
39: Nexus *nexusPhys;
40: UInt32 len;
41: bool isWrite;
42:
43: srb = (SRB *) scsiCommand->getCommandData();
44: bzero( srb, sizeof(SRB) );
45:
46: srb->srbPhys = (SRB *) pmap_extract( kernel_pmap, (vm_offset_t) srb );
47: srb->scsiCommand = scsiCommand;
48:
49: scsiCommand->getCDB( &scsiCDB );
50: scsiCommand->getTargetLun( &targetLun );
51:
52: nexus = &srb->nexus;
53: nexusPhys = &srb->srbPhys->nexus;
54:
55: srb->target = targetLun.target;
56: srb->lun = targetLun.lun;
57: srb->srbCDBFlags = scsiCDB.cdbFlags;
58:
59: /*
60: * Setup the Nexus struct. This part of the SRB is read/written both by the
61: * script and the driver.
62: */
63: nexus->targetParms.target = srb->target;
64:
65: // printf( "SCSI(Symbios8xx): executeCommand: T/L = %d:%d Cmd = %08x CmdType = %d\n\r",
66: // targetLun.target, targetLun.lun, (int)scsiCommand, scsiCommand->getCmdType() );
67:
68: switch ( scsiCommand->getCmdType() )
69: {
70: case kSCSICommandAbort:
71: case kSCSICommandAbortAll:
72: case kSCSICommandDeviceReset:
73: Sym8xxAbortCommand( scsiCommand );
74: return;
75:
76: default:
77: ;
78: }
79:
80: /*
81: * Set client data buffer pointers in the SRB
82: */
83: scsiCommand->getPointers( &srb->xferDesc, &srb->xferCount, &isWrite );
84:
85: srb->directionMask = (isWrite) ? 0x00000000 :0x01000000;
86:
87: nexus->cdb.ppData = OSSwapHostToLittleInt32((UInt32)&nexusPhys->cdbData);
88:
89: len = scsiCDB.cdbLength;
90:
91: nexus->cdb.length = OSSwapHostToLittleInt32( len );
92: nexus->cdbData = scsiCDB.cdb;
93:
94: Sym8xxCalcMsgs( scsiCommand );
95:
96: /*
97: * Setup initial data transfer list (SGList)
98: */
99: nexus->ppSGList = (SGEntry *)OSSwapHostToLittleInt32((UInt32)&nexusPhys->sgListData[2]);
100: Sym8xxUpdateSGList( srb );
101:
102: Sym8xxStartSRB( srb );
103: }
104:
105:
106: /*-----------------------------------------------------------------------------*
107: * This routine queues an SRB to reset the SCSI Bus
108: *
109: *-----------------------------------------------------------------------------*/
110: void Sym8xxSCSIController::resetCommand( IOSCSICommand *scsiCommand )
111: {
112: SRB *srb;
113:
114: // printf( "SCSI(Symbios8xx): resetCommand\n\r" );
115:
116: srb = (SRB *) scsiCommand->getCommandData();
117: bzero( srb, sizeof(SRB) );
118:
119: srb->srbPhys = (SRB *) pmap_extract( kernel_pmap, (vm_offset_t) srb );
120: srb->scsiCommand = scsiCommand;
121:
122: Sym8xxSCSIBusReset( srb );
123: }
124:
125: /*-----------------------------------------------------------------------------*
126: *
127: *-----------------------------------------------------------------------------*/
128: void Sym8xxSCSIController::cancelCommand( IOSCSICommand *scsiCommand )
129: {
130: IOSCSICommand *origCommand;
131: SRB *srb;
132: SCSITargetLun targetLun;
133: SCSIResults scsiResults;
134:
135: origCommand = scsiCommand->getOriginalCmd();
136: srb = (SRB *)origCommand->getCommandData();
137:
138: switch ( origCommand->getCmdType() )
139: {
140: case kSCSICommandAbort:
141: case kSCSICommandAbortAll:
142: case kSCSICommandDeviceReset:
143: if ( abortSRB == srb )
144: {
145: SCRIPT_VAR(R_ld_AbortBdr_mailbox) = 0;
146: abortSRB = 0;
147:
148: origCommand->complete();
149: }
150: break;
151:
152: default:
153:
154: if ( adapter->nexusPtrsVirt[srb->nexus.tag] == &srb->nexus )
155: {
156: adapter->nexusPtrsVirt[srb->nexus.tag] = (Nexus *) -1;
157: adapter->nexusPtrsPhys[srb->nexus.tag] = (Nexus *) -1;
158:
159: origCommand->complete();
160: }
161: else
162: {
163: origCommand->getTargetLun( &targetLun );
164: origCommand->complete();
165:
166: IOLog( "SCSI(Symbios8xx): Aborted SRB not found - T/L = %d:%d\n\r", targetLun.target, targetLun.lun );
167: }
168: }
169:
170: bzero( &scsiResults, sizeof(scsiResults) );
171: scsiCommand->setResults( &scsiResults );
172: scsiCommand->complete();
173: }
174:
175: /*-----------------------------------------------------------------------------*
176: *
177: *
178: *
179: *
180: *-----------------------------------------------------------------------------*/
181: void Sym8xxSCSIController::Sym8xxAbortCommand( IOSCSICommand *scsiCommand )
182: {
183: SRB *srb;
184: SCSICDBInfo scsiCDB;
185: SCSITargetLun targetLun;
186:
187:
188: scsiCommand->getTargetLun( &targetLun );
189:
190: switch ( scsiCommand->getCmdType() )
191: {
192: case kSCSICommandAbort:
193: srb = (SRB *)scsiCommand->getOriginalCmd()->getCommandData();
194: Sym8xxCancelMailBox( &srb->srbPhys->nexus );
195: break;
196:
197: case kSCSICommandAbortAll:
198: Sym8xxCancelMailBox( targetLun.target, targetLun.lun, false );
199: break;
200:
201: case kSCSICommandDeviceReset:
202: Sym8xxCancelMailBox( targetLun.target, (UInt32) -1, false );
203: break;
204:
205: default:
206: ;
207: }
208:
209: if ( abortSRB )
210: {
211: abortReqPending = true;
212:
213: rescheduleCommand( scsiCommand );
214: disableCommands();
215: return;
216: }
217:
218: scsiCommand->getCDB( &scsiCDB );
219:
220: srb = (SRB *) scsiCommand->getCommandData();
221:
222: srb->nexus.msgData[0] = srb->lun | ((srb->srbCDBFlags & kCDBFlagsNoDisconnect ) ? 0x80 : 0xC0);
223:
224: if ( scsiCDB.cdbTagMsg != 0 )
225: {
226: srb->nexus.tag = scsiCDB.cdbTag + 128;
227: srb->nexus.msgData[1] = srb->nexus.tag;
228: }
229: else
230: {
231: srb->nexus.tag = ((UInt32)srb->target << 3) | srb->lun;
232: srb->nexus.msgData[1] = 0;
233: }
234: srb->tag = srb->nexus.tag;
235:
236: srb->nexus.msgData[2] = scsiCDB.cdbAbortMsg;
237:
238: Sym8xxAbortBdr( srb );
239: }
240:
241:
242: /*-----------------------------------------------------------------------------*
243: * This routine creates SCSI messages to send during the initial connection
244: * to the target. It is called during client request processing and also by
245: * the I/O thread when a request sense operation is required.
246: *
247: * Outbound messages are setup in the MsgOut buffer in the Nexus structure of
248: * the SRB.
249: *
250: *-----------------------------------------------------------------------------*/
251: void Sym8xxSCSIController::Sym8xxCalcMsgs( IOSCSICommand *scsiCommand )
252: {
253: SRB *srb;
254: Nexus *nexus;
255: Nexus *nexusPhys;
256: UInt32 msgIndex;
257: SCSICDBInfo scsiCDB;
258: SCSITargetParms targetParms;
259: UInt32 i;
260: UInt32 tw;
261:
262:
263: srb = (SRB *)scsiCommand->getCommandData();
264: nexus = &srb->nexus;
265: nexusPhys = &srb->srbPhys->nexus;
266:
267: scsiCommand->getCDB( &scsiCDB );
268:
269: /*
270: * Setup Identify message
271: */
272: msgIndex = 0;
273: nexus->msg.ppData = OSSwapHostToLittleInt32((UInt32)&nexusPhys->msgData);
274: nexus->msgData[msgIndex++] = srb->lun | (( scsiCDB.cdbFlags & kCDBFlagsNoDisconnect ) ? 0x80 : 0xC0);
275:
276: /*
277: * Allocate tag for request.
278: *
279: * For non-tagged requests a pseudo-tag is created consisting of target*16+lun. For tagged
280: * requests a tag in the range 128-255 is allocated.
281: *
282: * If a pseudo-tag is inuse for a non-tagged command or there are no tags available for
283: * a tagged request, then the command is blocked until a tag becomes available.
284: *
285: * Note: If we are being called during request sense processing (srbState != ksrbStateCDBDone)
286: * then a tag has already been allocated to the request.
287: */
288: if ( scsiCDB.cdbTagMsg != 0 )
289: {
290: nexus->msgData[msgIndex++] = scsiCDB.cdbTagMsg;
291: nexus->msgData[msgIndex++] = srb->tag = srb->nexus.tag = scsiCDB.cdbTag + 128;
292: }
293: else
294: {
295: srb->tag = srb->nexus.tag = ((UInt32)srb->target << 3) | srb->lun;
296: }
297: /*
298: * Setup to negotiate for Wide (16-bit) data transfers
299: *
300: * Note: There is no provision to negotiate back to narrow transfers although
301: * SCSI does support this.
302: */
303:
304: scsiCommand->getDevice(kIOSCSIDevice)->getTargetParms( &targetParms );
305:
306: if ( scsiCDB.cdbFlags & kCDBFlagsNegotiateWDTR )
307: {
308: nexus->msgData[msgIndex++] = kSCSIMsgExtended;
309: nexus->msgData[msgIndex++] = 2;
310: nexus->msgData[msgIndex++] = kSCSIMsgWideDataXferReq;
311:
312: for ( tw = targetParms.transferWidth, i = (UInt32)-1;
313: tw;
314: tw >>= 1, i++ )
315: ;
316:
317: nexus->msgData[msgIndex++] = i;
318: }
319:
320: /*
321: * Setup to negotiate for Synchronous data transfers.
322: *
323: * Note: We can negotiate back to async based on the flags in the command.
324: */
325:
326: if ( scsiCDB.cdbFlags & kCDBFlagsNegotiateSDTR )
327: {
328: nexus->msgData[msgIndex++] = kSCSIMsgExtended;
329: nexus->msgData[msgIndex++] = 3;
330: nexus->msgData[msgIndex++] = kSCSIMsgSyncXferReq;
331: if ( targetParms.transferOffset != 0 )
332: {
333: nexus->msgData[msgIndex++] = targetParms.transferPeriodpS / 4000;
334: nexus->msgData[msgIndex++] = targetParms.transferOffset;
335: }
336: else
337: {
338: nexus->msgData[msgIndex++] = 0;
339: nexus->msgData[msgIndex++] = 0;
340: }
341:
342: }
343:
344: /*
345: * If we are negotiating for both Sync and Wide data transfers, we setup both messages
346: * in the Nexus msgOut buffer. However, after each message the script needs to wait for
347: * a reply message from the target. In this case, we set the msgOut length to include
348: * bytes upto the end of the Wide message. When we get the reply from the target, the
349: * routine handling the WDTR will setup the Nexus pointers/counts to send the remaining
350: * message bytes. See Sym8xxExecute.m(Sym8xxNegotiateWDTR).
351: */
352: srb->srbMsgLength = msgIndex;
353:
354: if ((scsiCDB.cdbFlags & (kCDBFlagsNegotiateWDTR | kCDBFlagsNegotiateSDTR))
355: == (kCDBFlagsNegotiateWDTR | kCDBFlagsNegotiateSDTR))
356: {
357: msgIndex -= 5;
358: }
359:
360: nexus->msg.length = OSSwapHostToLittleInt32( msgIndex );
361:
362: srb->srbCDBFlags = scsiCDB.cdbFlags;
363: }
364:
365: /*-----------------------------------------------------------------------------*
366: * This routine sets up the data transfer SG list for the client's buffer in the
367: * Nexus structure.
368: *
369: * The SGList actually consists of script instructions. The script will branch
370: * to the SGList when the target enters data transfer phase. When the SGList completes
371: * it will either execute a script INT instruction if there are more segments of the
372: * user buffer that need to be transferred or will execute a script RETURN instruction
373: * to return to the script.
374: *
375: * The first two slots in the SGList are reserved for partial data transfers. See
376: * Sym8xxExecute.m(Sym8xxAdjustDataPtrs).
377: *
378: *-----------------------------------------------------------------------------*/
379:
380:
381: /*-----------------------------------------------------------------------------*
382: * Build SG list based on an IOMemoryDescriptor object.
383: *
384: *-----------------------------------------------------------------------------*/
385: bool Sym8xxSCSIController::Sym8xxUpdateSGList( SRB *srb )
386: {
387: IOPhysicalSegment range;
388: UInt32 actRanges;
389: UInt32 offset;
390: UInt32 bytesLeft;
391: UInt32 i;
392: IOReturn rc = true;
393:
394: offset = srb->xferOffset;
395: bytesLeft = srb->xferCount - srb->xferOffset;
396:
397: if ( bytesLeft == 0 ) return rc;
398:
399: i = 2;
400:
401: while ( (bytesLeft > 0) && (i < MAX_SGLIST_ENTRIES-1))
402: {
403: actRanges = memoryCursor->getPhysicalSegments( srb->xferDesc,
404: offset,
405: &range,
406: 1 );
407:
408: if ( actRanges != 1 )
409: {
410: rc = false;
411: break;
412: }
413:
414: /*
415: * Note: The script instruction(s) to transfer data to/from the scsi bus
416: * have the same format as a typical SGList with the transfer length
417: * as the first word and the physical transfer address as the second.
418: * The data transfer direction is specified by a bit or'd into the
419: * high byte of the SG entry's length field.
420: */
421: srb->nexus.sgListData[i].physAddr = OSSwapHostToLittleInt32( (UInt32)range.location );
422: srb->nexus.sgListData[i].length = OSSwapHostToLittleInt32( range.length | srb->directionMask );
423:
424: bytesLeft -= range.length;
425: offset += range.length;
426: i++;
427: }
428:
429: if ( !bytesLeft )
430: {
431: srb->nexus.sgListData[i].length = OSSwapHostToLittleInt32( 0x90080000 );
432: srb->nexus.sgListData[i].physAddr = OSSwapHostToLittleInt32( 0x00000000 );
433: }
434: else
435: {
436: srb->nexus.sgListData[i].length = OSSwapHostToLittleInt32( 0x98080000 );
437: srb->nexus.sgListData[i].physAddr = OSSwapHostToLittleInt32( A_sglist_complete );
438: }
439:
440: srb->xferOffsetPrev = srb->xferOffset;
441: srb->xferOffset = offset;
442:
443: return rc;
444: }
445:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.