Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1007 lines
26 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. spt.c
  5. Abstract:
  6. A user mode library that allows simple commands to be sent to a
  7. selected scsi device.
  8. Environment:
  9. User mode only
  10. Revision History:
  11. 4/10/2000 - created
  12. --*/
  13. #include "sptlibp.h"
  14. BOOL
  15. SptUtilValidateCdbLength(
  16. IN PCDB Cdb,
  17. IN UCHAR CdbSize
  18. )
  19. {
  20. UCHAR commandGroup = (Cdb->AsByte[0] >> 5) & 0x7;
  21. switch (commandGroup) {
  22. case 0:
  23. return (CdbSize == 6);
  24. case 1:
  25. case 2:
  26. return (CdbSize == 10);
  27. case 5:
  28. return (CdbSize == 12);
  29. default:
  30. return TRUE;
  31. }
  32. }
  33. BOOL
  34. SptSendCdbToDevice(
  35. IN HANDLE DeviceHandle,
  36. IN PCDB Cdb,
  37. IN UCHAR CdbSize,
  38. IN PUCHAR Buffer,
  39. IN OUT PDWORD BufferSize,
  40. IN BOOLEAN GetDataFromDevice
  41. )
  42. {
  43. return SptSendCdbToDeviceEx(DeviceHandle,
  44. Cdb,
  45. CdbSize,
  46. Buffer,
  47. BufferSize,
  48. NULL,
  49. 0,
  50. GetDataFromDevice,
  51. SPT_DEFAULT_TIMEOUT
  52. );
  53. }
  54. /*++
  55. Routine Description:
  56. Arguments:
  57. Return Value:
  58. --*/
  59. BOOL
  60. SptSendCdbToDeviceEx(
  61. IN HANDLE DeviceHandle,
  62. IN PCDB Cdb,
  63. IN UCHAR CdbSize,
  64. IN OUT PUCHAR Buffer,
  65. IN OUT PDWORD BufferSize,
  66. OUT PSENSE_DATA SenseData OPTIONAL,
  67. IN UCHAR SenseDataSize,
  68. IN BOOLEAN GetDataFromDevice,
  69. IN DWORD TimeOut // in seconds
  70. )
  71. {
  72. PSPT_WITH_BUFFERS p;
  73. DWORD packetSize;
  74. DWORD returnedBytes;
  75. BOOL returnValue;
  76. PSENSE_DATA senseBuffer;
  77. BOOL copyData;
  78. if ((SenseDataSize == 0) && (SenseData != NULL)) {
  79. SetLastError(ERROR_INVALID_PARAMETER);
  80. return FALSE;
  81. }
  82. if ((SenseDataSize != 0) && (SenseData == NULL)) {
  83. SetLastError(ERROR_INVALID_PARAMETER);
  84. return FALSE;
  85. }
  86. if (SenseData && SenseDataSize) {
  87. RtlZeroMemory(SenseData, SenseDataSize);
  88. }
  89. if (Cdb == NULL) {
  90. // cannot send NULL cdb
  91. SetLastError(ERROR_INVALID_PARAMETER);
  92. return FALSE;
  93. }
  94. if (CdbSize < 1 || CdbSize > 16) {
  95. // Cdb size too large or too small for this library currently
  96. SetLastError(ERROR_INVALID_PARAMETER);
  97. return FALSE;
  98. }
  99. if (!SptUtilValidateCdbLength(Cdb, CdbSize)) {
  100. // OpCode Cdb->AsByte[0] is not size CdbSize
  101. SetLastError(ERROR_INVALID_PARAMETER);
  102. return FALSE;
  103. }
  104. if (BufferSize == NULL) {
  105. // BufferSize pointer cannot be NULL
  106. SetLastError(ERROR_INVALID_PARAMETER);
  107. return FALSE;
  108. }
  109. if ((*BufferSize != 0) && (Buffer == NULL)) {
  110. // buffer cannot be NULL if *BufferSize is non-zero
  111. SetLastError(ERROR_INVALID_PARAMETER);
  112. return FALSE;
  113. }
  114. if ((*BufferSize == 0) && (Buffer != NULL)) {
  115. // buffer must be NULL if *BufferSize is zero
  116. SetLastError(ERROR_INVALID_PARAMETER);
  117. return FALSE;
  118. }
  119. if ((*BufferSize) && GetDataFromDevice) {
  120. //
  121. // pre-zero output buffer (not input buffer)
  122. //
  123. memset(Buffer, 0, (*BufferSize));
  124. }
  125. packetSize = sizeof(SPT_WITH_BUFFERS) + (*BufferSize);
  126. p = (PSPT_WITH_BUFFERS)LocalAlloc(LPTR, packetSize);
  127. if (p == NULL) {
  128. // could not allocate memory for pass-through
  129. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  130. return FALSE;
  131. }
  132. //
  133. // this has the side effect of pre-zeroing the output buffer
  134. // if DataIn is TRUE, the SenseData (always), etc.
  135. //
  136. memset(p, 0, packetSize);
  137. memcpy(p->Spt.Cdb, Cdb, CdbSize);
  138. p->Spt.Length = sizeof(SCSI_PASS_THROUGH);
  139. p->Spt.CdbLength = CdbSize;
  140. p->Spt.SenseInfoLength = SENSE_BUFFER_SIZE;
  141. p->Spt.DataIn = (GetDataFromDevice ? 1 : 0);
  142. p->Spt.DataTransferLength = (*BufferSize);
  143. p->Spt.TimeOutValue = TimeOut;
  144. p->Spt.SenseInfoOffset =
  145. FIELD_OFFSET(SPT_WITH_BUFFERS, SenseInfoBuffer[0]);
  146. p->Spt.DataBufferOffset =
  147. FIELD_OFFSET(SPT_WITH_BUFFERS, DataBuffer[0]);
  148. if ((*BufferSize != 0) && (!GetDataFromDevice)) {
  149. //
  150. // if we're sending the device data, copy the user's buffer
  151. //
  152. RtlCopyMemory(&(p->DataBuffer[0]), Buffer, *BufferSize);
  153. }
  154. returnedBytes = 0;
  155. returnValue = DeviceIoControl(DeviceHandle,
  156. IOCTL_SCSI_PASS_THROUGH,
  157. p,
  158. packetSize,
  159. p,
  160. packetSize,
  161. &returnedBytes,
  162. FALSE);
  163. senseBuffer = (PSENSE_DATA)p->SenseInfoBuffer;
  164. copyData = FALSE;
  165. if (senseBuffer->SenseKey & 0xf) {
  166. UCHAR length;
  167. // determine appropriate length to return
  168. length = senseBuffer->AdditionalSenseLength;
  169. length += RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength);
  170. if (length > SENSE_BUFFER_SIZE) {
  171. length = SENSE_BUFFER_SIZE;
  172. }
  173. length = min(length, SenseDataSize);
  174. // copy the sense data back to the user regardless
  175. RtlCopyMemory(SenseData, senseBuffer, length);
  176. returnValue = FALSE; // some error (possibly recovered) occurred
  177. copyData = TRUE; // copy data anyways
  178. } else if (p->Spt.ScsiStatus != 0) { // scsi protocol error
  179. returnValue = FALSE; // command failed
  180. } else if (!returnValue) {
  181. // returnValue = returnValue;
  182. } else {
  183. copyData = TRUE;
  184. }
  185. if (copyData && GetDataFromDevice) {
  186. //
  187. // upon successful completion of a command getting data from the
  188. // device, copy the returned data back to the user.
  189. //
  190. if (*BufferSize > p->Spt.DataTransferLength) {
  191. *BufferSize = p->Spt.DataTransferLength;
  192. }
  193. memcpy(Buffer, p->DataBuffer, *BufferSize);
  194. }
  195. //
  196. // free our memory and return
  197. //
  198. LocalFree(p);
  199. return returnValue;
  200. }
  201. /*++
  202. Routine Description:
  203. Arguments:
  204. Return Value:
  205. --*/
  206. VOID
  207. SptDeleteModePageInfo(
  208. IN PSPT_MODE_PAGE_INFO ModePageInfo
  209. )
  210. {
  211. // ASSERT(ModePageInfo != NULL); BUGBUG
  212. // ASSERT(ModePageInfo->Signature == SPT_MODE_PAGE_INFO_SIGNATURE); BUGBUG
  213. LocalFree(ModePageInfo);
  214. return;
  215. }
  216. /*++
  217. Routine Description:
  218. Arguments:
  219. Return Value:
  220. --*/
  221. BOOL
  222. SptUpdateModePageInfo(
  223. IN HANDLE DeviceHandle,
  224. IN PSPT_MODE_PAGE_INFO ModePageInfo
  225. )
  226. {
  227. SENSE_DATA senseData;
  228. BOOLEAN retry = FALSE;
  229. DWORD error;
  230. DWORD delay;
  231. CDB cdb;
  232. DWORD attemptNumber = 0;
  233. BOOL success;
  234. if ((DeviceHandle == INVALID_HANDLE_VALUE) ||
  235. (ModePageInfo == NULL) ||
  236. (!ModePageInfo->IsInitialized) ||
  237. (ModePageInfo->Signature != SPT_MODE_PAGE_INFO_SIGNATURE)) {
  238. SetLastError(ERROR_INVALID_PARAMETER);
  239. return FALSE;
  240. }
  241. if ((ModePageInfo->ModePageSize != SptModePageSizeModeSense6) &&
  242. (ModePageInfo->ModePageSize != SptModePageSizeModeSense10)) {
  243. SetLastError(ERROR_INVALID_PARAMETER);
  244. return FALSE;
  245. }
  246. RetryUpdateModePage:
  247. attemptNumber ++;
  248. RtlZeroMemory(&cdb, sizeof(CDB));
  249. RtlZeroMemory(&senseData, sizeof(SENSE_DATA));
  250. if (ModePageInfo->ModePageSize == SptModePageSizeModeSense6) {
  251. DWORD sizeToGet = sizeof(MODE_PARAMETER_HEADER);
  252. cdb.MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  253. cdb.MODE_SENSE.PageCode = 0x3f;
  254. cdb.MODE_SENSE.AllocationLength = sizeof(MODE_PARAMETER_HEADER);
  255. success = SptSendCdbToDeviceEx(DeviceHandle,
  256. &cdb,
  257. 6,
  258. &(ModePageInfo->H.AsChar),
  259. &sizeToGet,
  260. &senseData,
  261. sizeof(SENSE_DATA),
  262. TRUE,
  263. SPT_MODE_SENSE_TIMEOUT);
  264. } else {
  265. DWORD sizeToGet = sizeof(MODE_PARAMETER_HEADER10);
  266. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  267. cdb.MODE_SENSE10.PageCode = 0x3f;
  268. cdb.MODE_SENSE10.AllocationLength[0] = sizeof(MODE_PARAMETER_HEADER10);
  269. success = SptSendCdbToDeviceEx(DeviceHandle,
  270. &cdb,
  271. 10,
  272. &(ModePageInfo->H.AsChar),
  273. &sizeToGet,
  274. &senseData,
  275. sizeof(SENSE_DATA),
  276. TRUE,
  277. SPT_MODE_SENSE_TIMEOUT);
  278. }
  279. if (!success) {
  280. return FALSE;
  281. }
  282. //
  283. // if the pass-through succeeded, we need to still determine if the
  284. // actual CDB succeeded. use the InterpretSenseInfo() routine.
  285. //
  286. SptUtilInterpretSenseInfo(&senseData,
  287. sizeof(SENSE_DATA),
  288. &error,
  289. &retry,
  290. &delay);
  291. if (error != ERROR_SUCCESS) {
  292. if (retry && (attemptNumber < MAXIMUM_DEFAULT_RETRIES)) {
  293. if (delay != 0) {
  294. // sleep?
  295. }
  296. goto RetryUpdateModePage;
  297. }
  298. // else the error was not worth retrying, or we've retried too often.
  299. SetLastError(error);
  300. return FALSE;
  301. }
  302. //
  303. // the command succeeded.
  304. //
  305. if (ModePageInfo->ModePageSize == SptModePageSizeModeSense6) {
  306. ModePageInfo->H.Header6.ModeDataLength = 0;
  307. } else {
  308. ModePageInfo->H.Header10.ModeDataLength[0] = 0;
  309. ModePageInfo->H.Header10.ModeDataLength[1] = 0;
  310. }
  311. return TRUE;
  312. }
  313. /*++
  314. Routine Description:
  315. Arguments:
  316. Return Value:
  317. --*/
  318. PSPT_MODE_PAGE_INFO
  319. SptInitializeModePageInfo(
  320. IN HANDLE DeviceHandle
  321. )
  322. {
  323. PSPT_MODE_PAGE_INFO localInfo;
  324. DWORD i;
  325. localInfo = LocalAlloc(LPTR, sizeof(SPT_MODE_PAGE_INFO));
  326. if (localInfo == NULL) {
  327. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  328. return FALSE;
  329. }
  330. //
  331. // try both 10 and 6 byte mode sense commands
  332. //
  333. for (i = 0; i < 2; i++) {
  334. RtlZeroMemory(localInfo, sizeof(SPT_MODE_PAGE_INFO));
  335. localInfo->IsInitialized = TRUE;
  336. localInfo->Signature = SPT_MODE_PAGE_INFO_SIGNATURE;
  337. if ( i == 0 ) {
  338. localInfo->ModePageSize = SptModePageSizeModeSense10;
  339. } else {
  340. localInfo->ModePageSize = SptModePageSizeModeSense6;
  341. }
  342. if (SptUpdateModePageInfo(DeviceHandle, localInfo)) {
  343. return localInfo;
  344. }
  345. }
  346. LocalFree(localInfo);
  347. return NULL;
  348. }
  349. /*++
  350. Routine Description:
  351. Arguments:
  352. Return Value:
  353. --*/
  354. BOOL
  355. SptGetModePage(
  356. IN HANDLE DeviceHandle,
  357. IN PSPT_MODE_PAGE_INFO ModePageInfo,
  358. IN UCHAR ModePage,
  359. OUT PUCHAR Buffer,
  360. IN OUT PDWORD BufferSize,
  361. OUT PDWORD AvailableModePageData OPTIONAL
  362. )
  363. {
  364. PUCHAR localBuffer = NULL;
  365. DWORD localBufferSize = 0;
  366. SENSE_DATA senseData;
  367. CDB cdb;
  368. DWORD thisAttempt = 0;
  369. BOOL success;
  370. DWORD finalPageSize;
  371. PUCHAR finalPageStart;
  372. if ((DeviceHandle == INVALID_HANDLE_VALUE) ||
  373. (ModePageInfo == NULL) ||
  374. (!ModePageInfo->IsInitialized) ||
  375. (ModePageInfo->Signature != SPT_MODE_PAGE_INFO_SIGNATURE) ||
  376. (ModePageInfo->ModePageSize == SptModePageSizeUndefined) ||
  377. (ModePage & 0xC0)) {
  378. SetLastError(ERROR_INVALID_PARAMETER);
  379. return FALSE;
  380. }
  381. if (((BufferSize == 0) && (Buffer != NULL)) ||
  382. ((BufferSize != 0) && (Buffer == NULL))) {
  383. SetLastError(ERROR_INVALID_PARAMETER);
  384. return FALSE;
  385. }
  386. if ((ModePageInfo->ModePageSize != SptModePageSizeModeSense6) &&
  387. (ModePageInfo->ModePageSize != SptModePageSizeModeSense10)) {
  388. SetLastError(ERROR_INVALID_PARAMETER);
  389. return FALSE;
  390. }
  391. localBufferSize = 0;
  392. if (BufferSize != NULL) {
  393. localBufferSize += *BufferSize;
  394. }
  395. if (ModePageInfo->ModePageSize == SptModePageSizeModeSense6) {
  396. localBufferSize += sizeof(MODE_PARAMETER_HEADER);
  397. localBufferSize += ModePageInfo->H.Header6.BlockDescriptorLength;
  398. if (localBufferSize > 0xff) {
  399. SetLastError(ERROR_INVALID_PARAMETER);
  400. return FALSE;
  401. }
  402. } else {
  403. localBufferSize += sizeof(MODE_PARAMETER_HEADER);
  404. localBufferSize += ModePageInfo->H.Header10.BlockDescriptorLength[0] * 256;
  405. localBufferSize += ModePageInfo->H.Header10.BlockDescriptorLength[1];
  406. if (localBufferSize > 0xffff) {
  407. SetLastError(ERROR_INVALID_PARAMETER);
  408. return FALSE;
  409. }
  410. }
  411. localBuffer = LocalAlloc(LPTR, localBufferSize);
  412. if (localBuffer == NULL) {
  413. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  414. return FALSE;
  415. }
  416. RetryGetModePage:
  417. thisAttempt ++;
  418. RtlZeroMemory(&cdb, sizeof(CDB));
  419. RtlZeroMemory(&senseData, sizeof(SENSE_DATA));
  420. RtlZeroMemory(localBuffer, localBufferSize);
  421. if (ModePageInfo->ModePageSize == SptModePageSizeModeSense6) {
  422. DWORD sizeToGet = localBufferSize;
  423. cdb.MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  424. cdb.MODE_SENSE.PageCode = ModePage;
  425. cdb.MODE_SENSE.AllocationLength = (UCHAR)localBufferSize;
  426. success = SptSendCdbToDeviceEx(DeviceHandle,
  427. &cdb,
  428. 6,
  429. localBuffer,
  430. &sizeToGet,
  431. &senseData,
  432. sizeof(SENSE_DATA),
  433. TRUE,
  434. SPT_MODE_SENSE_TIMEOUT);
  435. } else {
  436. DWORD sizeToGet = localBufferSize;
  437. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  438. cdb.MODE_SENSE10.PageCode = ModePage;
  439. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(localBufferSize >> 8);
  440. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(localBufferSize & 0xff);
  441. success = SptSendCdbToDeviceEx(DeviceHandle,
  442. &cdb,
  443. 10,
  444. localBuffer,
  445. &sizeToGet,
  446. &senseData,
  447. sizeof(SENSE_DATA),
  448. TRUE,
  449. SPT_MODE_SENSE_TIMEOUT);
  450. }
  451. //
  452. // if the pass-through failed, we need to still determine if the
  453. // actual CDB succeeded. use the InterpretSenseInfo() routine.
  454. //
  455. if (!success) {
  456. LocalFree( localBuffer );
  457. return FALSE;
  458. }
  459. {
  460. DWORD interpretedError;
  461. BOOLEAN retry;
  462. DWORD delay;
  463. SptUtilInterpretSenseInfo(&senseData,
  464. sizeof(SENSE_DATA),
  465. &interpretedError,
  466. &retry,
  467. &delay);
  468. if (interpretedError != ERROR_SUCCESS) {
  469. if ((retry == FALSE) || (thisAttempt > MAXIMUM_DEFAULT_RETRIES)){
  470. SetLastError(interpretedError);
  471. LocalFree( localBuffer );
  472. return FALSE;
  473. }
  474. // BUGBUG - sleep?
  475. goto RetryGetModePage;
  476. }
  477. }
  478. //
  479. // the transfer succeeded. now to transfer the info back to
  480. // the caller.
  481. //
  482. if (ModePageInfo->ModePageSize == SptModePageSizeModeSense6) {
  483. PMODE_PARAMETER_HEADER header6 = (PMODE_PARAMETER_HEADER)localBuffer;
  484. finalPageSize = header6->ModeDataLength + 1; // length field itself.
  485. finalPageStart = localBuffer;
  486. finalPageStart += sizeof(MODE_PARAMETER_HEADER);
  487. finalPageSize -= sizeof(MODE_PARAMETER_HEADER);
  488. finalPageStart += header6->BlockDescriptorLength;
  489. finalPageSize -= header6->BlockDescriptorLength;
  490. } else {
  491. PMODE_PARAMETER_HEADER10 header10 = (PMODE_PARAMETER_HEADER10)localBuffer;
  492. finalPageSize = header10->ModeDataLength[0] * 256;
  493. finalPageSize += header10->ModeDataLength[1];
  494. finalPageSize += 2; // length field itself.
  495. finalPageStart = localBuffer;
  496. finalPageStart += sizeof(MODE_PARAMETER_HEADER10);
  497. finalPageSize -= sizeof(MODE_PARAMETER_HEADER10);
  498. finalPageStart += header10->BlockDescriptorLength[0] * 256;
  499. finalPageStart += header10->BlockDescriptorLength[1];
  500. finalPageSize -= header10->BlockDescriptorLength[0] * 256;
  501. finalPageSize -= header10->BlockDescriptorLength[1];
  502. }
  503. //
  504. // finalPageStart now points to the page start
  505. // finalPageSize says how much of the data is valid
  506. //
  507. //
  508. // allow the user to distinguish between available data
  509. // and the amount we actually returned that was usable.
  510. //
  511. if (AvailableModePageData != NULL) {
  512. *AvailableModePageData = finalPageSize;
  513. }
  514. //
  515. // if the expected buffer size is greater than the device
  516. // returned, update the user's available size info
  517. //
  518. if (*BufferSize > finalPageSize) {
  519. *BufferSize = finalPageSize;
  520. }
  521. //
  522. // finally, copy whatever data is available to the user's buffer.
  523. //
  524. if (*BufferSize != 0) {
  525. RtlCopyMemory(Buffer, localBuffer, *BufferSize);
  526. }
  527. return TRUE;
  528. }
  529. /*++
  530. Routine Description:
  531. Arguments:
  532. Return Value:
  533. --*/
  534. BOOL
  535. SptSetModePage(
  536. IN HANDLE DeviceHandle,
  537. IN PSPT_MODE_PAGE_INFO ModePageSize,
  538. IN SPT_MODE_PAGE_TYPE ModePageType,
  539. IN UCHAR ModePage,
  540. OUT PUCHAR Buffer,
  541. IN OUT PDWORD BufferSize
  542. )
  543. {
  544. SetLastError(ERROR_INVALID_FUNCTION);
  545. return FALSE;
  546. }
  547. /*++
  548. Routine Description:
  549. NOTE: we default to RETRY==TRUE except for known error classes
  550. Arguments:
  551. Return Value:
  552. --*/
  553. VOID
  554. SptUtilInterpretSenseInfo(
  555. IN PSENSE_DATA SenseData,
  556. IN UCHAR SenseDataSize,
  557. OUT PDWORD ErrorValue, // from WinError.h
  558. OUT PBOOLEAN SuggestRetry OPTIONAL,
  559. OUT PDWORD SuggestRetryDelay OPTIONAL
  560. )
  561. {
  562. DWORD error;
  563. DWORD retryDelay;
  564. BOOLEAN retry;
  565. UCHAR senseKey;
  566. UCHAR asc;
  567. UCHAR ascq;
  568. if (SenseDataSize == 0) {
  569. retry = FALSE;
  570. retryDelay = 0;
  571. error = ERROR_IO_DEVICE;
  572. goto SetAndExit;
  573. }
  574. //
  575. // default to suggesting a retry in 1/10 of a second,
  576. // with a status of ERROR_IO_DEVICE.
  577. //
  578. retry = TRUE;
  579. retryDelay = 1;
  580. error = ERROR_IO_DEVICE;
  581. //
  582. // if the device didn't provide any sense this time, return.
  583. //
  584. if ((SenseData->SenseKey & 0xf) == 0) {
  585. retry = FALSE;
  586. retryDelay = 0;
  587. error = ERROR_SUCCESS;
  588. goto SetAndExit;
  589. }
  590. //
  591. // if we can't even see the sense key, just return.
  592. // can't use bitfields in these macros, so use next field.
  593. //
  594. if (SenseDataSize < FIELD_OFFSET(SENSE_DATA, Information)) {
  595. goto SetAndExit;
  596. }
  597. senseKey = SenseData->SenseKey;
  598. { // set the size to what's actually useful.
  599. UCHAR validLength;
  600. // figure out what we could have gotten with a large sense buffer
  601. if (SenseDataSize <
  602. RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength)) {
  603. validLength = SenseDataSize;
  604. } else {
  605. validLength =
  606. RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength);
  607. validLength += SenseData->AdditionalSenseLength;
  608. }
  609. // use the smaller of the two values.
  610. SenseDataSize = min(SenseDataSize, validLength);
  611. }
  612. if (SenseDataSize <
  613. RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode)) {
  614. asc = SCSI_ADSENSE_NO_SENSE;
  615. } else {
  616. asc = SenseData->AdditionalSenseCode;
  617. }
  618. if (SenseDataSize <
  619. RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier)) {
  620. ascq = SCSI_SENSEQ_CAUSE_NOT_REPORTABLE; // 0x00
  621. } else {
  622. ascq = SenseData->AdditionalSenseCodeQualifier;
  623. }
  624. //
  625. // interpret :P
  626. //
  627. switch (senseKey & 0xf) {
  628. case SCSI_SENSE_RECOVERED_ERROR: { // 0x01
  629. if (SenseData->IncorrectLength) {
  630. error = ERROR_INVALID_BLOCK_LENGTH;
  631. } else {
  632. error = ERROR_SUCCESS;
  633. }
  634. retry = FALSE;
  635. break;
  636. } // end SCSI_SENSE_RECOVERED_ERROR
  637. case SCSI_SENSE_NOT_READY: { // 0x02
  638. error = ERROR_NOT_READY;
  639. switch (asc) {
  640. case SCSI_ADSENSE_LUN_NOT_READY: {
  641. switch (ascq) {
  642. case SCSI_SENSEQ_BECOMING_READY:
  643. case SCSI_SENSEQ_OPERATION_IN_PROGRESS: {
  644. retryDelay = SPT_NOT_READY_RETRY_INTERVAL;
  645. break;
  646. }
  647. case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE:
  648. case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
  649. case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS: {
  650. retry = FALSE;
  651. break;
  652. }
  653. case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: {
  654. retry = FALSE;
  655. break;
  656. }
  657. } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
  658. break;
  659. }
  660. case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: {
  661. error = ERROR_NOT_READY;
  662. retry = FALSE;
  663. break;
  664. }
  665. } // end switch (senseBuffer->AdditionalSenseCode)
  666. break;
  667. } // end SCSI_SENSE_NOT_READY
  668. case SCSI_SENSE_MEDIUM_ERROR: { // 0x03
  669. error = ERROR_CRC;
  670. retry = FALSE;
  671. //
  672. // Check if this error is due to unknown format
  673. //
  674. if (asc == SCSI_ADSENSE_INVALID_MEDIA) {
  675. switch (ascq) {
  676. case SCSI_SENSEQ_UNKNOWN_FORMAT: {
  677. error = ERROR_UNRECOGNIZED_MEDIA;
  678. break;
  679. }
  680. case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED: {
  681. error = ERROR_UNRECOGNIZED_MEDIA;
  682. //error = ERROR_CLEANER_CARTRIDGE_INSTALLED;
  683. break;
  684. }
  685. } // end switch AdditionalSenseCodeQualifier
  686. } // end SCSI_ADSENSE_INVALID_MEDIA
  687. break;
  688. } // end SCSI_SENSE_MEDIUM_ERROR
  689. case SCSI_SENSE_ILLEGAL_REQUEST: { // 0x05
  690. error = ERROR_INVALID_FUNCTION;
  691. retry = FALSE;
  692. switch (asc) {
  693. case SCSI_ADSENSE_ILLEGAL_BLOCK: {
  694. error = ERROR_SECTOR_NOT_FOUND;
  695. break;
  696. }
  697. case SCSI_ADSENSE_INVALID_LUN: {
  698. error = ERROR_FILE_NOT_FOUND;
  699. break;
  700. }
  701. case SCSI_ADSENSE_COPY_PROTECTION_FAILURE: {
  702. error = ERROR_FILE_ENCRYPTED;
  703. //error = ERROR_SPT_LIB_COPY_PROTECTION_FAILURE;
  704. switch (ascq) {
  705. case SCSI_SENSEQ_AUTHENTICATION_FAILURE:
  706. //error = ERROR_SPT_LIB_AUTHENTICATION_FAILURE;
  707. break;
  708. case SCSI_SENSEQ_KEY_NOT_PRESENT:
  709. //error = ERROR_SPT_LIB_KEY_NOT_PRESENT;
  710. break;
  711. case SCSI_SENSEQ_KEY_NOT_ESTABLISHED:
  712. //error = ERROR_SPT_LIB_KEY_NOT_ESTABLISHED;
  713. break;
  714. case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION:
  715. //error = ERROR_SPT_LIB_SCRAMBLED_SECTOR;
  716. break;
  717. case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT:
  718. //error = ERROR_SPT_LIB_REGION_MISMATCH;
  719. break;
  720. case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR:
  721. //error = ERROR_SPT_LIB_RESETS_EXHAUSTED;
  722. break;
  723. } // end switch of ASCQ for COPY_PROTECTION_FAILURE
  724. break;
  725. }
  726. } // end switch (senseBuffer->AdditionalSenseCode)
  727. break;
  728. } // end SCSI_SENSE_ILLEGAL_REQUEST
  729. case SCSI_SENSE_DATA_PROTECT: { // 0x07
  730. error = ERROR_WRITE_PROTECT;
  731. retry = FALSE;
  732. break;
  733. } // end SCSI_SENSE_DATA_PROTECT
  734. case SCSI_SENSE_BLANK_CHECK: { // 0x08
  735. error = ERROR_NO_DATA_DETECTED;
  736. break;
  737. } // end SCSI_SENSE_BLANK_CHECK
  738. case SCSI_SENSE_NO_SENSE: { // 0x00
  739. if (SenseData->IncorrectLength) {
  740. error = ERROR_INVALID_BLOCK_LENGTH;
  741. retry = FALSE;
  742. } else {
  743. error = ERROR_IO_DEVICE;
  744. }
  745. break;
  746. } // end SCSI_SENSE_NO_SENSE
  747. case SCSI_SENSE_HARDWARE_ERROR: // 0x04
  748. case SCSI_SENSE_UNIT_ATTENTION: // 0x06
  749. case SCSI_SENSE_UNIQUE: // 0x09
  750. case SCSI_SENSE_COPY_ABORTED: // 0x0A
  751. case SCSI_SENSE_ABORTED_COMMAND: // 0x0B
  752. case SCSI_SENSE_EQUAL: // 0x0C
  753. case SCSI_SENSE_VOL_OVERFLOW: // 0x0D
  754. case SCSI_SENSE_MISCOMPARE: // 0x0E
  755. case SCSI_SENSE_RESERVED: // 0x0F
  756. default: {
  757. error = ERROR_IO_DEVICE;
  758. break;
  759. }
  760. } // end switch(SenseKey)
  761. SetAndExit:
  762. if (ARGUMENT_PRESENT(SuggestRetry)) {
  763. *SuggestRetry = retry;
  764. }
  765. if (ARGUMENT_PRESENT(SuggestRetryDelay)) {
  766. *SuggestRetryDelay = retryDelay;
  767. }
  768. *ErrorValue = error;
  769. return;
  770. }
  771. /*++
  772. Routine Description:
  773. Arguments:
  774. Return Value:
  775. --*/