Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / pdisk / DoSCSICommand.c
blobea9cd49a373835fec8b03c581e0d918831ea1359
1 /*
2 * DoScsiCommand.c
4 * This is the common entry to the original and asynchronous SCSI Manager calls:
5 * if the asynchronous SCSI Manager is requested, it calls it. Otherwise, it
6 * calls the original SCSI Manager and executes Request Sense if necessary.
8 * This function returns "autosense" in the SCSI_Sense_Data area. This will
9 * be formatted in the senseMessage string.
13 * Copyright 1992, 1993, 1997, 1998 by Apple Computer, Inc.
14 * All Rights Reserved
16 * Permission to use, copy, modify, and distribute this software and
17 * its documentation for any purpose and without fee is hereby granted,
18 * provided that the above copyright notice appears in all copies and
19 * that both the copyright notice and this permission notice appear in
20 * supporting documentation.
22 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
23 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE.
26 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
27 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
28 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
29 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
30 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33 #include "DoScsiCommand.h"
34 #include "util.h"
38 // Defines
40 #define kSCSICommandTimeout (5 * 1000L) /* Five seconds */
42 * This is the maximum number of times we try to grab the SCSI Bus
44 #define kMaxSCSIRetries 40 /* 10 seconds, 4 times/sec */
46 * This test is TRUE if the SCSI bus status indicates "busy" (which is the case
47 * if either the BSY or SEL bit is set).
49 #ifndef kScsiStatBSY
50 #define kScsiStatBSY (1 << 6)
51 #endif
52 #ifndef kScsiStatSEL
53 #define kScsiStatSEL (1 << 1)
54 #endif
55 #define ScsiBusBusy() ((SCSIStat() & (kScsiStatBSY | kScsiStatSEL)) != 0)
59 // Types
64 // Global Constants
69 // Global Variables
71 int gSCSIHiBusID;
72 SCSIExecIOPB *gSCSIExecIOPBPtr;
73 UInt32 gSCSIExecIOPBPtrLen;
77 // Forward declarations
79 UInt16 GetCommandLength(const SCSI_CommandPtr cmdPtr);
80 Boolean IsVirtualMemoryRunning(void);
82 OSErr OriginalSCSI(
83 DeviceIdent scsiDevice,
84 const SCSI_CommandPtr scsiCommand,
85 UInt8 scsiCommandLen,
86 Ptr dataBuffer,
87 ByteCount dataLength,
88 UInt32 scsiFlags,
89 ByteCount *actualTransferCount,
90 UInt8 *scsiStatusByte
93 OSErr DoOriginalSCSICommand(
94 DeviceIdent scsiDevice,
95 const SCSI_CommandPtr theSCSICommand,
96 unsigned short cmdBlockLength,
97 Ptr dataBuffer,
98 ByteCount dataLength,
99 UInt32 scsiFlags,
100 ByteCount *actualTransferCount,
101 SCSI_Sense_Data *sensePtr
106 // Routines
110 * This returns TRUE if the command failed with "Illegal Request." We need this
111 * so we can ignore LogSense or ReadDefectData if the device doesn't support
112 * these functions.
114 Boolean
115 IsIllegalRequest(
116 OSErr scsiStatus,
117 const SCSI_Sense_Data *senseDataPtr
120 Boolean result;
121 #define SENSE (*senseDataPtr)
123 result = FALSE;
124 if (scsiStatus == scsiNonZeroStatus
125 && (SENSE.senseKey & kScsiSenseKeyMask) == kScsiSenseIllegalReq
126 && SENSE.additionalSenseLength >= 4) {
127 switch ((SENSE.additionalSenseCode << 8) | SENSE.additionalSenseQualifier) {
128 case 0x0000:
129 case 0x2000:
130 case 0x2022: /* Obsolete */
131 result = TRUE;
132 break;
133 default:
134 break;
137 return (result);
138 #undef SENSE
143 * This returns TRUE if the command failed with Device Not Ready (No Media Present)
145 Boolean
146 IsNoMedia(
147 OSErr scsiStatus,
148 const SCSI_Sense_Data *senseDataPtr
151 Boolean result;
152 #define SENSE (*senseDataPtr)
154 result = FALSE;
155 if (scsiStatus == scsiNonZeroStatus
156 && (SENSE.senseKey & kScsiSenseKeyMask) == kScsiSenseNotReady
157 && SENSE.additionalSenseLength >= 4) {
158 switch ((SENSE.additionalSenseCode << 8) | SENSE.additionalSenseQualifier) {
159 case 0x0000:
160 case 0x3A00:
161 result = TRUE;
162 break;
163 default:
164 break;
167 return (result);
168 #undef SENSE
173 * Do one SCSI Command. If the device returns Check Condition, issue Request Sense
174 * (original SCSI Manager only) and interpret the sense data. The original SCSI
175 * command status is in SCB.status. If it is statusErr or scsiNonZeroStatus,
176 * the sense data is in SCB.sense and the Request Sense status is in
177 * SCB.requestSenseStatus.
179 * If sensePtr[0] is non-zero, there is a message.
181 OSErr
182 DoSCSICommand(
183 DeviceIdent scsiDevice,
184 ConstStr255Param currentAction,
185 const SCSI_CommandPtr callerSCSICommand,
186 Ptr dataBuffer,
187 ByteCount dataLength,
188 UInt32 scsiFlags,
189 ByteCount *actualTransferCount,
190 SCSI_Sense_Data *sensePtr,
191 StringPtr senseMessage
194 OSErr status;
195 SCSI_Command theSCSICommand;
196 unsigned short cmdBlockLength;
198 // SpinSpinner(&gCurrentInfoPtr->spinnerRecord);
199 // ShowProgressAction(currentAction);
201 * Store the LUN information in the command block - this is needed
202 * for devices that only examine the command block for LUN values.
203 * (On SCSI-II, the asynchronous SCSI Manager also includes the
204 * LUN in the identify message).
206 theSCSICommand = *callerSCSICommand;
207 theSCSICommand.scsi[1] &= ~0xE0;
208 theSCSICommand.scsi[1] |= (scsiDevice.LUN & 0x03) << 5;
209 cmdBlockLength = GetCommandLength(&theSCSICommand);
210 if (senseMessage != NULL)
211 senseMessage[0] = 0;
212 if (sensePtr != NULL)
213 sensePtr->errorCode = 0;
214 if (scsiDevice.bus == kOriginalSCSIBusAdaptor) {
215 status = DoOriginalSCSICommand(
216 scsiDevice,
217 &theSCSICommand,
218 cmdBlockLength,
219 dataBuffer,
220 dataLength,
221 scsiFlags,
222 actualTransferCount,
223 sensePtr
226 else {
227 clear_memory(gSCSIExecIOPBPtr, gSCSIExecIOPBPtrLen);
228 #define PB (*gSCSIExecIOPBPtr)
229 PB.scsiPBLength = gSCSIExecIOPBPtrLen;
230 PB.scsiFunctionCode = SCSIExecIO;
231 PB.scsiDevice = scsiDevice;
232 PB.scsiTimeout = kSCSICommandTimeout;
234 * Fiddle the flags so they're the least disruptive possible.
236 PB.scsiFlags = scsiFlags | (scsiSIMQNoFreeze | scsiDontDisconnect);
237 if (sensePtr != NULL) {
238 PB.scsiSensePtr = (UInt8 *) sensePtr;
239 PB.scsiSenseLength = sizeof *sensePtr;
241 BlockMoveData(&theSCSICommand, &PB.scsiCDB.cdbBytes[0], cmdBlockLength);
242 PB.scsiCDBLength = cmdBlockLength;
243 if (dataBuffer != NULL) {
244 PB.scsiDataPtr = (UInt8 *) dataBuffer;
245 PB.scsiDataLength = dataLength;
246 PB.scsiDataType = scsiDataBuffer;
247 PB.scsiTransferType = scsiTransferPolled;
249 status = SCSIAction((SCSI_PB *) &PB);
250 if (status == noErr)
251 status = PB.scsiResult;
252 if (status == scsiSelectTimeout)
253 status = scsiDeviceNotThere;
254 if (actualTransferCount != NULL) {
256 * Make sure that the actual transfer count does not exceed
257 * the allocation count (some devices spit extra data at us!)
259 *actualTransferCount = dataLength - PB.scsiDataResidual;
260 if (*actualTransferCount > dataLength)
261 *actualTransferCount = dataLength;
263 #undef PB
265 if (status == scsiNonZeroStatus
266 && sensePtr != NULL
267 && sensePtr->errorCode != 0
268 && senseMessage != NULL) {
269 // FormatSenseMessage(sensePtr, senseMessage);
270 // ShowProgressAction(senseMessage);
272 return (status);
277 * Do a command with autosense using the original SCSI manager.
279 OSErr
280 DoOriginalSCSICommand(
281 DeviceIdent scsiDevice,
282 const SCSI_CommandPtr theSCSICommand,
283 unsigned short cmdBlockLength,
284 Ptr dataBuffer,
285 ByteCount dataLength,
286 UInt32 scsiFlags,
287 ByteCount *actualTransferCount,
288 SCSI_Sense_Data *sensePtr
291 OSErr status;
292 UInt8 scsiStatusByte;
293 SCSI_Command scsiStatusCommand;
295 status = OriginalSCSI(
296 scsiDevice,
297 theSCSICommand,
298 cmdBlockLength,
299 dataBuffer,
300 dataLength,
301 scsiFlags,
302 actualTransferCount,
303 &scsiStatusByte
305 if (status == scsiNonZeroStatus
306 && scsiStatusByte == kScsiStatusCheckCondition
307 && sensePtr != NULL) {
308 CLEAR(scsiStatusCommand);
309 CLEAR(*sensePtr);
310 scsiStatusCommand.scsi6.opcode = kScsiCmdRequestSense;
311 scsiStatusCommand.scsi[1] |= (scsiDevice.LUN & 0x03) << 5;
312 scsiStatusCommand.scsi6.len = sizeof *sensePtr;
313 status = OriginalSCSI(
314 scsiDevice,
315 &scsiStatusCommand,
316 sizeof scsiStatusCommand.scsi6,
317 (Ptr) sensePtr,
318 sizeof *sensePtr,
319 scsiDirectionIn,
320 NULL,
321 &scsiStatusByte
323 if (status != noErr && status != scsiDataRunError) {
324 #ifdef notdef
325 if (gDebugOnError && scsiStatusByte != kScsiStatusCheckCondition) {
326 Str255 work;
328 pstrcpy(work, "\pAutosense failed ");
329 AppendSigned(work, status);
330 AppendChar(work, ' ');
331 AppendHexLeadingZeros(work, scsiStatusByte, 2);
332 DebugStr(work);
334 #endif
335 sensePtr->errorCode = 0;
336 status = scsiAutosenseFailed;
338 else {
339 status = scsiNonZeroStatus;
342 return (status);
346 OSErr
347 OriginalSCSI(
348 DeviceIdent scsiDevice,
349 const SCSI_CommandPtr scsiCommand,
350 UInt8 scsiCommandLen,
351 Ptr dataBuffer,
352 ByteCount dataLength,
353 UInt32 scsiFlags,
354 ByteCount *actualTransferCount,
355 UInt8 *scsiStatusBytePtr
358 OSErr status; /* Final status */
359 OSErr completionStatus; /* Status from ScsiComplete */
360 short totalTries; /* Get/Select retries */
361 short getTries; /* Get retries */
362 short iCount; /* Bus free counter */
363 unsigned long watchdog; /* Timeout after this */
364 unsigned long myTransferCount; /* Gets TIB loop counter */
365 short scsiStatusByte; /* Gets SCSIComplete result */
366 short scsiMsgByte; /* Gets SCSIComplete result */
367 Boolean bufferHoldFlag;
369 * The TIB has the following format:
370 * [0] scInc user buffer transferQuantum or transferSize
371 * [1] scAdd &theTransferCount 1
372 * [2] scLoop -> tib[0] transferSize / transferQuantum
373 * [3] scStop
374 * The intent of this is to return, in actualTransferCount, the number
375 * of times we cycled through the tib[] loop. This will be the actual
376 * transfer count if transferQuantum equals one, or the number of
377 * "blocks" if transferQuantum is the length of one sector.
379 SCSIInstr tib[4]; /* Current TIB */
381 status = noErr;
382 bufferHoldFlag = FALSE;
383 scsiStatusByte = 0xFF;
384 scsiMsgByte = 0xFF;
385 myTransferCount = 0;
387 * If there is a data transfer, setup the tib.
389 if (dataBuffer != NULL) {
390 tib[0].scOpcode = scInc;
391 tib[0].scParam1 = (unsigned long) dataBuffer;
392 tib[0].scParam2 = 1;
393 tib[1].scOpcode = scAdd;
394 tib[1].scParam1 = (unsigned long) &myTransferCount;
395 tib[1].scParam2 = 1;
396 tib[2].scOpcode = scLoop;
397 tib[2].scParam1 = (-2 * sizeof (SCSIInstr));
398 tib[2].scParam2 = dataLength / tib[0].scParam2;
399 tib[3].scOpcode = scStop;
400 tib[3].scParam1 = 0;
401 tib[3].scParam2 = 0;
403 if (IsVirtualMemoryRunning() && dataBuffer != NULL) {
405 * Lock down the user buffer, if any. In a real-world application
406 * or driver, this would be done before calling the SCSI interface.
408 #ifdef notdef
409 FailOSErr(
410 HoldMemory(dataBuffer, dataLength),
411 "\pCan't lock data buffer in physical memory"
413 #else
414 HoldMemory(dataBuffer, dataLength);
415 #endif
416 bufferHoldFlag = TRUE;
419 * Arbitrate for the scsi bus. This will fail if some other device is
420 * accessing the bus at this time (which is unlikely).
422 *** Do not set breakpoints or call any functions that may require device
423 *** I/O (such as display code that accesses font resources between
424 *** SCSIGet and SCSIComplete,
427 for (totalTries = 0; totalTries < kMaxSCSIRetries; totalTries++) {
428 for (getTries = 0; getTries < 4; getTries++) {
430 * Wait for the bus to go free.
432 watchdog = TickCount() + 300; /* 5 second timeout */
433 while (ScsiBusBusy()) {
434 if (/*gStopNow || StopNow() ||*/ TickCount() > watchdog) {
435 status = scsiBusy;
436 goto exit;
440 * The bus is free, try to grab it
442 for (iCount = 0; iCount < 4; iCount++) {
443 if ((status = SCSIGet()) == noErr)
444 break;
446 if (status == noErr) {
447 break; /* Success: we have the bus */
450 * The bus became busy again. Try to wait for it to go free.
452 for (iCount = 0;
453 /*gStopNow == FALSE && StopNow() == FALSE &&*/ iCount < 100 && ScsiBusBusy();
454 iCount++)
456 } /* The getTries loop */
457 if (status != noErr) {
459 * The SCSI Manager thinks the bus is not busy and not selected,
460 * but "someone" has set its internal semaphore that signals
461 * that the SCSI Manager itself is busy. The application will have
462 * to handle this problem. (We tried getTries * 4 times).
464 status = scsiBusy;
465 goto exit;
468 * We now own the SCSI bus. Try to select the device.
470 if ((status = SCSISelect(scsiDevice.targetID)) != noErr) {
471 switch (status) {
473 * We get scBadParmsErr if we try to arbitrate for the initiator.
475 case scBadParmsErr: status = scsiTIDInvalid; break;
476 case scCommErr: status = scsiDeviceNotThere; break;
477 case scArbNBErr: status = scsiBusy; break;
478 case scSequenceErr: status = scsiRequestInvalid; break;
480 goto exit;
483 * From this point on, we must exit through SCSIComplete() even if an
484 * error is detected. Send a command to the selected device. There are
485 * several failure modes, including an illegal command (such as a
486 * write to a read-only device). If the command failed because of
487 * "device busy", we will try it again.
489 status = SCSICmd((Ptr) scsiCommand, scsiCommandLen);
490 if (status != noErr) {
491 switch (status) {
492 case scCommErr: status = scsiCommandTimeout; break;
493 case scPhaseErr: status = scsiSequenceFailed; break;
496 if (status == noErr && dataBuffer != NULL) {
498 * This command requires a data transfer.
500 if (scsiFlags == scsiDirectionOut) {
501 status = SCSIWrite((Ptr) tib);
502 } else {
503 status = SCSIRead((Ptr) tib);
505 switch (status) {
506 case scCommErr: status = scsiCommandTimeout; break;
507 case scBadParmsErr: status = scsiRequestInvalid; break;
508 case scPhaseErr: status = noErr; /* Don't care */ break;
509 case scCompareErr: /* Can't happen */ break;
513 * SCSIComplete "runs" the bus-phase algorithm until the bitter end,
514 * returning the status and command-completion message bytes..
516 completionStatus = SCSIComplete(
517 &scsiStatusByte,
518 &scsiMsgByte,
519 5 * 60L
521 if (status == noErr && completionStatus != noErr) {
522 switch (completionStatus) {
523 case scCommErr: status = scsiCommandTimeout; break;
524 case scPhaseErr: status = scsiSequenceFailed; break;
525 case scComplPhaseErr: status = scsiSequenceFailed; break;
528 if (completionStatus == noErr && scsiStatusByte == kScsiStatusBusy) {
530 * ScsiComplete is happy. If the device is busy,
531 * pause for 1/4 second and try again.
533 watchdog = TickCount() + 15;
534 while (TickCount() < watchdog)
536 continue; /* Do next totalTries attempt */
539 * This is the normal exit (success) or final failure exit.
541 break;
542 } /* totalTries loop */
543 exit:
545 if (bufferHoldFlag) {
546 (void) UnholdMemory(dataBuffer, dataLength);
549 * Return the number of bytes transferred to the caller. If the caller
550 * supplied an actual count and the count is no greater than the maximum,
551 * ignore any phase errors.
553 if (actualTransferCount != NULL) {
554 *actualTransferCount = myTransferCount;
555 if (*actualTransferCount > dataLength) {
556 *actualTransferCount = dataLength;
560 * Also, there is a bug in the combination of System 7.0.1 and the 53C96
561 * that may cause the real SCSI Status Byte to be in the Message byte.
563 if (scsiStatusByte == kScsiStatusGood
564 && scsiMsgByte == kScsiStatusCheckCondition) {
565 scsiStatusByte = kScsiStatusCheckCondition;
567 if (status == noErr) {
568 switch (scsiStatusByte) {
569 case kScsiStatusGood: break;
570 case kScsiStatusBusy: status = scsiBusy; break;
571 case 0xFF: status = scsiProvideFail; break;
572 default: status = scsiNonZeroStatus; break;
575 if (status == noErr
576 && (scsiFlags & scsiDirectionMask) != scsiDirectionNone
577 && myTransferCount != dataLength) {
578 status = scsiDataRunError;
580 if (scsiStatusBytePtr != NULL) {
581 *scsiStatusBytePtr = scsiStatusByte;
583 return (status);
587 UInt16
588 GetCommandLength(
589 const SCSI_CommandPtr cmdPtr
592 unsigned short result;
594 * Look at the "group code" in the command operation. Return zero
595 * error for the reserved (3, 4) and vendor-specific command (6, 7)
596 * command groups. Otherwise, set the command length from the group code
597 * value as specified in the SCSI-II spec.
599 switch (cmdPtr->scsi6.opcode & 0xE0) {
600 case (0 << 5): result = 6; break;
601 case (1 << 5):
602 case (2 << 5): result = 10; break;
603 case (5 << 5): result = 12; break;
604 default: result = 0; break;
606 return (result);
610 Boolean
611 IsVirtualMemoryRunning(void)
613 OSErr status;
614 long response;
616 status = Gestalt(gestaltVMAttr, &response);
618 * VM is active iff Gestalt succeeded and the response is appropriate.
620 return (status == noErr && ((response & (1 << gestaltVMPresent)) != 0));
624 void
625 AllocatePB()
627 OSErr status;
628 SCSIBusInquiryPB busInquiryPB;
629 #define PB (busInquiryPB)
631 if (gSCSIExecIOPBPtr == NULL) {
632 CLEAR(PB);
633 PB.scsiPBLength = sizeof PB;
634 PB.scsiFunctionCode = SCSIBusInquiry;
635 PB.scsiDevice.bus = 0xFF; /* Get info about the XPT */
636 status = SCSIAction((SCSI_PB *) &PB);
637 if (status == noErr)
638 status = PB.scsiResult;
639 if (PB.scsiHiBusID == 0xFF) {
640 gSCSIHiBusID = -1;
641 } else {
642 gSCSIHiBusID = PB.scsiHiBusID;
644 gSCSIExecIOPBPtrLen = PB.scsiMaxIOpbSize;
645 if (gSCSIExecIOPBPtrLen != 0)
646 gSCSIExecIOPBPtr = (SCSIExecIOPB *) NewPtrClear(gSCSIExecIOPBPtrLen);
648 #undef PB