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.

3798 lines
95 KiB

  1. #if defined(JAZZ) || defined(i386) || defined(_ALPHA_) || defined(_IA64_)
  2. /*++
  3. Copyright (c) 1990 Microsoft Corporation
  4. Module Name:
  5. scsidisk.c
  6. Abstract:
  7. This module implements the hard disk boot driver for the Jazz system.
  8. Author:
  9. Jeff Havens (jhavens) 8-12-1991
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. Vijay Jayaseelan (vijayj) 2-April-2000
  14. - Add GPT support
  15. --*/
  16. #ifdef MIPS
  17. #include "..\fw\mips\fwp.h"
  18. #undef KeGetDcacheFillSize
  19. #define KeGetDcacheFillSize() BlDcacheFillSize
  20. #elif defined(_ALPHA_)
  21. #include "..\fw\alpha\fwp.h"
  22. #undef KeGetDcacheFillSize
  23. #define KeGetDcacheFillSize() BlDcacheFillSize
  24. #elif defined(_IA64_)
  25. #include "bootia64.h"
  26. #else
  27. #include "bootx86.h"
  28. #undef KeGetDcacheFillSize
  29. #define KeGetDcacheFillSize() 4
  30. #endif
  31. #include "ntdddisk.h"
  32. #include "scsi.h"
  33. #include "scsiboot.h"
  34. #include "stdio.h"
  35. #include "string.h"
  36. #if defined(SETUP) && i386
  37. #include "spscsi.h"
  38. #endif
  39. //
  40. // SCSI driver constants.
  41. //
  42. #define MAXIMUM_NUMBER_SECTORS 128 // maximum number of transfer sector
  43. #define MAXIMUM_NUMBER_RETRIES 8 // maximum number of read/write retries
  44. #define MAXIMUM_SECTOR_SIZE 2048 // define the maximum supported sector size
  45. #define MODE_DATA_SIZE 192
  46. #define HITACHI_MODE_DATA_SIZE 12
  47. CHAR ScsiTempBuffer[MAXIMUM_SECTOR_SIZE + 128];
  48. //
  49. // Define device driver prototypes.
  50. //
  51. NTSTATUS
  52. ScsiDiskBootPartitionOpen(
  53. IN ULONG FileId,
  54. IN UCHAR DeviceUnit,
  55. IN UCHAR PartitionNumber
  56. );
  57. NTSTATUS
  58. ScsiGPTDiskBootPartitionOpen(
  59. IN ULONG FileId,
  60. IN UCHAR DeviceUnit,
  61. IN UCHAR PartitionNumber
  62. );
  63. ARC_STATUS
  64. ScsiDiskClose (
  65. IN ULONG FileId
  66. );
  67. ARC_STATUS
  68. ScsiDiskMount (
  69. IN PCHAR MountPath,
  70. IN MOUNT_OPERATION Operation
  71. );
  72. ARC_STATUS
  73. ScsiDiskOpen (
  74. IN PCHAR OpenPath,
  75. IN OPEN_MODE OpenMode,
  76. OUT PULONG FileId
  77. );
  78. ARC_STATUS
  79. ScsiDiskRead (
  80. IN ULONG FileId,
  81. IN PVOID Buffer,
  82. IN ULONG Length,
  83. OUT PULONG Count
  84. );
  85. ARC_STATUS
  86. ScsiDiskGetReadStatus (
  87. IN ULONG FileId
  88. );
  89. ARC_STATUS
  90. ScsiDiskSeek (
  91. IN ULONG FileId,
  92. IN PLARGE_INTEGER Offset,
  93. IN SEEK_MODE SeekMode
  94. );
  95. ARC_STATUS
  96. ScsiDiskWrite (
  97. IN ULONG FileId,
  98. IN PVOID Buffer,
  99. IN ULONG Length,
  100. OUT PULONG Count
  101. );
  102. ARC_STATUS
  103. ScsiDiskGetFileInformation (
  104. IN ULONG FileId,
  105. OUT PFILE_INFORMATION Finfo
  106. );
  107. NTSTATUS
  108. ScsiDiskBootIO (
  109. IN PMDL MdlAddress,
  110. IN ULONG LogicalBlock,
  111. IN PPARTITION_CONTEXT PartitionContext,
  112. IN BOOLEAN Operation
  113. );
  114. VOID
  115. ScsiDiskBootSetup (
  116. VOID
  117. );
  118. VOID
  119. ScsiPortExecute(
  120. IN PDEVICE_OBJECT DeviceObject,
  121. IN PIRP Irp
  122. );
  123. VOID
  124. ScsiDiskStartUnit(
  125. IN PPARTITION_CONTEXT PartitionContext
  126. );
  127. VOID
  128. ScsiDiskFilterBad(
  129. IN PPARTITION_CONTEXT PartitionContext
  130. );
  131. ULONG
  132. ClassModeSense(
  133. IN PPARTITION_CONTEXT Context,
  134. IN PCHAR ModeSenseBuffer,
  135. IN ULONG Length,
  136. IN UCHAR PageMode
  137. );
  138. PVOID
  139. ClassFindModePage(
  140. IN PCHAR ModeSenseBuffer,
  141. IN ULONG Length,
  142. IN UCHAR PageMode
  143. );
  144. BOOLEAN
  145. IsFloppyDevice(
  146. PPARTITION_CONTEXT Context
  147. );
  148. BOOLEAN
  149. CheckFileId(
  150. ULONG FileId
  151. );
  152. VOID
  153. ScsiPortInitializeMdlPages (
  154. IN OUT PMDL Mdl
  155. );
  156. //
  157. // Define static data.
  158. //
  159. BL_DEVICE_ENTRY_TABLE ScsiDiskEntryTable = {
  160. ScsiDiskClose,
  161. ScsiDiskMount,
  162. ScsiDiskOpen,
  163. ScsiDiskRead,
  164. ScsiDiskGetReadStatus,
  165. ScsiDiskSeek,
  166. ScsiDiskWrite,
  167. ScsiDiskGetFileInformation,
  168. (PARC_SET_FILE_INFO_ROUTINE)NULL
  169. };
  170. //
  171. // Global poiter for buffers.
  172. //
  173. PREAD_CAPACITY_DATA ReadCapacityBuffer;
  174. PUCHAR SenseInfoBuffer;
  175. #define SECTORS_IN_LOGICAL_VOLUME 0x20
  176. ARC_STATUS
  177. ScsiDiskGetFileInformation (
  178. IN ULONG FileId,
  179. OUT PFILE_INFORMATION Finfo
  180. )
  181. /*++
  182. Routine Description:
  183. This routine returns information on the scsi partition.
  184. Arguments:
  185. FileId - Supplies the file table index.
  186. Finfo - Supplies a pointer to where the File Informatino is stored.
  187. Return Value:
  188. ESUCCESS is returned.
  189. --*/
  190. {
  191. PPARTITION_CONTEXT Context;
  192. RtlZeroMemory(Finfo, sizeof(FILE_INFORMATION));
  193. Context = &BlFileTable[FileId].u.PartitionContext;
  194. Finfo->StartingAddress.QuadPart = Context->StartingSector;
  195. Finfo->StartingAddress.QuadPart <<= Context->SectorShift;
  196. Finfo->EndingAddress.QuadPart = Finfo->StartingAddress.QuadPart + Context->PartitionLength.QuadPart;
  197. Finfo->Type = DiskPeripheral;
  198. return ESUCCESS;
  199. }
  200. ARC_STATUS
  201. ScsiDiskClose (
  202. IN ULONG FileId
  203. )
  204. /*++
  205. Routine Description:
  206. This function closes the file table entry specified by the file id.
  207. Arguments:
  208. FileId - Supplies the file table index.
  209. Return Value:
  210. ESUCCESS is returned.
  211. --*/
  212. {
  213. BlFileTable[FileId].Flags.Open = 0;
  214. return ESUCCESS;
  215. }
  216. ARC_STATUS
  217. ScsiDiskMount (
  218. IN PCHAR MountPath,
  219. IN MOUNT_OPERATION Operation
  220. )
  221. /*++
  222. Routine Description:
  223. Arguments:
  224. Return Value:
  225. --*/
  226. {
  227. return ESUCCESS;
  228. }
  229. #ifdef EFI_PARTITION_SUPPORT
  230. #define STR_PREFIX
  231. #define DBG_PRINT(x)
  232. /*
  233. #if defined(_IA64_)
  234. #define STR_PREFIX L
  235. #define DBG_PRINT(x) DbgOut(x);
  236. #else
  237. #define STR_PREFIX
  238. #define DBG_PRINT(x) \
  239. {\
  240. BlPrint(x); \
  241. while (!BlGetKey()); \
  242. }
  243. #endif // _IA64_
  244. */
  245. #endif
  246. ARC_STATUS
  247. ScsiDiskOpen (
  248. IN PCHAR OpenPath,
  249. IN OPEN_MODE OpenMode,
  250. OUT PULONG FileId
  251. )
  252. /*++
  253. Routine Description:
  254. This routine fills in the file table entry. In particular the Scsi address
  255. of the device is determined from the name. The block size of device is
  256. queried from the target controller, and the partition information is read
  257. from the device.
  258. Arguments:
  259. OpenPath - Supplies the name of the device being opened.
  260. OpenMode - Unused.
  261. FileId - Supplies the index to the file table entry to be initialized.
  262. Return Value:
  263. Retruns the arc status of the operation.
  264. --*/
  265. {
  266. ULONG Partition;
  267. ULONG Id;
  268. BOOLEAN IsCdRom;
  269. BOOLEAN IsFloppy;
  270. PPARTITION_CONTEXT Context;
  271. Context = &BlFileTable[*FileId].u.PartitionContext;
  272. //
  273. // Determine the scsi port device object.
  274. //
  275. if (FwGetPathMnemonicKey(OpenPath, "signature", &Id)) {
  276. if (FwGetPathMnemonicKey(OpenPath, "scsi", &Id)) {
  277. return ENODEV;
  278. }
  279. } else {
  280. PCHAR DiskStart = strstr(OpenPath, ")disk");
  281. if (DiskStart) {
  282. DiskStart++;
  283. strcpy(OpenPath, "scsi(0)");
  284. strcat(OpenPath, DiskStart);
  285. }
  286. Id = 0; // only the first SCSI card is supported
  287. }
  288. if (ScsiPortDeviceObject[Id] == NULL) {
  289. return ENODEV;
  290. }
  291. Context->PortDeviceObject = ScsiPortDeviceObject[Id];
  292. //
  293. // Get the logical unit, path Id and target id from the name.
  294. // NOTE: FwGetPathMnemonicKey returns 0 for success.
  295. //
  296. if (FwGetPathMnemonicKey(OpenPath, "rdisk", &Id)) {
  297. if (FwGetPathMnemonicKey(OpenPath, "fdisk", &Id)) {
  298. return ENODEV;
  299. } else {
  300. IsFloppy = TRUE;
  301. }
  302. } else {
  303. IsFloppy = FALSE;
  304. }
  305. //
  306. // Booting is only allowed on LUN 0 since the scsibus
  307. // scan in the loader only searches for LUN 0.
  308. //
  309. if (Id != 0) {
  310. return ENODEV;
  311. }
  312. Context->DiskId = (UCHAR)Id;
  313. if (!FwGetPathMnemonicKey(OpenPath, "cdrom", &Id)) {
  314. IsCdRom = TRUE;
  315. } else if (!FwGetPathMnemonicKey(OpenPath, "disk", &Id)) {
  316. IsCdRom = FALSE;
  317. } else {
  318. return ENODEV;
  319. }
  320. SCSI_DECODE_BUS_TARGET( Id, Context->PathId, Context->TargetId );
  321. //
  322. // Initialize any bad devices.
  323. //
  324. ScsiDiskFilterBad(Context);
  325. //
  326. // Read the capacity of the disk to determine the block size.
  327. //
  328. if (ReadDriveCapacity(Context)) {
  329. return ENODEV;
  330. }
  331. //
  332. // This is all that needs to be done for floppies and harddisks.
  333. //
  334. if (IsCdRom || IsFloppy) {
  335. return(ESUCCESS);
  336. }
  337. if (FwGetPathMnemonicKey(OpenPath,
  338. "partition",
  339. &Partition
  340. )) {
  341. return ENODEV;
  342. }
  343. if (Partition != 0) {
  344. //
  345. // First try to open the MBR partition
  346. //
  347. DBG_PRINT(STR_PREFIX"Trying to open SCSI MBR partition\r\n");
  348. if (ScsiDiskBootPartitionOpen(*FileId,0,(UCHAR)Partition) != STATUS_SUCCESS) {
  349. #ifdef EFI_PARTITION_SUPPORT
  350. //
  351. // Since we failed with MBR open now try GPT partition
  352. //
  353. DBG_PRINT(STR_PREFIX"Trying to open SCSI GPT partition\r\n");
  354. if (ScsiGPTDiskBootPartitionOpen(*FileId,0,(UCHAR)(Partition -1)) != STATUS_SUCCESS) {
  355. return ENODEV;
  356. }
  357. #else
  358. return ENODEV;
  359. #endif // EFI_PARTITION_SUPPORT
  360. }
  361. }
  362. DBG_PRINT(STR_PREFIX"Opened the SCSI partition successfully\r\n");
  363. //
  364. // Initialize partition table
  365. //
  366. return ESUCCESS;
  367. }
  368. ARC_STATUS
  369. ScsiDiskRead (
  370. IN ULONG FileId,
  371. IN PVOID Buffer,
  372. IN ULONG Length,
  373. OUT PULONG Count
  374. )
  375. /*++
  376. Routine Description:
  377. This function reads data from the hard disk starting at the position
  378. specified in the file table.
  379. Arguments:
  380. FileId - Supplies the file table index.
  381. Buffer - Supplies a poiner to the buffer that receives the data
  382. read.
  383. Length - Supplies the number of bytes to be read.
  384. Count - Supplies a pointer to a variable that receives the number of
  385. bytes actually read.
  386. Return Value:
  387. The read operation is performed and the read completion status is
  388. returned.
  389. --*/
  390. {
  391. ARC_STATUS ArcStatus;
  392. ULONG Index;
  393. ULONG Limit;
  394. PMDL MdlAddress;
  395. UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)];
  396. NTSTATUS NtStatus;
  397. ULONG NumberOfPages;
  398. ULONG Offset;
  399. LARGE_INTEGER Position;
  400. LARGE_INTEGER LogicalBlock;
  401. PCHAR TempPointer;
  402. PIO_SCSI_CAPABILITIES PortCapabilities;
  403. ULONG adapterLimit;
  404. ULONG alignmentMask;
  405. ULONG SectorSize;
  406. ULONG TransferCount;
  407. ULONG BytesToTransfer;
  408. //
  409. // If the requested size of the transfer is zero return ESUCCESS
  410. //
  411. if (Length==0) {
  412. return ESUCCESS;
  413. }
  414. if (!CheckFileId(FileId)) {
  415. return(ENODEV);
  416. }
  417. //
  418. // Compute a Dcache aligned pointer into the temporary buffer.
  419. //
  420. TempPointer = (PVOID)((ULONG_PTR)(ScsiTempBuffer +
  421. KeGetDcacheFillSize() - 1) & ~((LONG)KeGetDcacheFillSize() - 1));
  422. //
  423. // Calculate the actual sector size.
  424. //
  425. SectorSize = 1 << BlFileTable[FileId].u.PartitionContext.SectorShift;
  426. ArcStatus = GetAdapterCapabilities(
  427. BlFileTable[FileId].u.PartitionContext.PortDeviceObject,
  428. &PortCapabilities
  429. );
  430. if (ArcStatus != ESUCCESS) {
  431. adapterLimit = 0x10000;
  432. alignmentMask = KeGetDcacheFillSize();
  433. } else {
  434. if (PortCapabilities->MaximumTransferLength < 0x1000 ||
  435. PortCapabilities->MaximumTransferLength > 0x10000) {
  436. adapterLimit = 0x10000;
  437. } else {
  438. adapterLimit = PortCapabilities->MaximumTransferLength;
  439. }
  440. alignmentMask = PortCapabilities->AlignmentMask;
  441. }
  442. //
  443. // If the current position is not at a sector boundary or if the data
  444. // buffer is not properly aligned, then read the first sector separately
  445. // and copy the data.
  446. //
  447. Offset = BlFileTable[FileId].Position.LowPart & (SectorSize - 1);
  448. *Count = 0;
  449. while (Offset != 0 || (ULONG_PTR) Buffer & alignmentMask) {
  450. Position = BlFileTable[FileId].Position;
  451. BlFileTable[FileId].Position.QuadPart = Position.QuadPart - Offset;
  452. ArcStatus = ScsiDiskRead(FileId, TempPointer, SectorSize, &TransferCount);
  453. if (ArcStatus != ESUCCESS) {
  454. BlFileTable[FileId].Position = Position;
  455. return ArcStatus;
  456. }
  457. //
  458. // Copy the data to the specified buffer.
  459. //
  460. if ((SectorSize - Offset) > Length) {
  461. Limit = Offset + Length;
  462. } else {
  463. Limit = SectorSize;
  464. }
  465. for (Index = Offset; Index < Limit; Index += 1) {
  466. ((PCHAR)Buffer)[Index - Offset] = TempPointer[Index];
  467. }
  468. //
  469. // Update transfer parameters.
  470. //
  471. *Count += Limit - Offset;
  472. Length -= Limit - Offset;
  473. Buffer = (PVOID)((PCHAR)Buffer + Limit - Offset);
  474. BlFileTable[FileId].Position.QuadPart = Position.QuadPart + (Limit - Offset);
  475. Offset = BlFileTable[FileId].Position.LowPart & (SectorSize - 1);
  476. if (Length == 0) {
  477. break;
  478. }
  479. }
  480. //
  481. // The position is aligned on a sector boundary. Read as many sectors
  482. // as possible in a contiguous run in 64Kb chunks.
  483. //
  484. BytesToTransfer = Length & (~(SectorSize - 1));
  485. while (BytesToTransfer != 0) {
  486. //
  487. // The scsi controller doesn't support transfers bigger than 64Kb.
  488. // Transfer the maximum number of bytes possible.
  489. //
  490. Limit = (BytesToTransfer > adapterLimit ? adapterLimit : BytesToTransfer);
  491. //
  492. // Build the memory descriptor list.
  493. //
  494. MdlAddress = (PMDL)&MdlBuffer[0];
  495. MdlAddress->Next = NULL;
  496. MdlAddress->Size = (CSHORT)(sizeof(MDL) +
  497. ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Limit) * sizeof(ULONG));
  498. MdlAddress->MdlFlags = 0;
  499. MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer);
  500. MdlAddress->ByteCount = Limit;
  501. MdlAddress->ByteOffset = BYTE_OFFSET(Buffer);
  502. ScsiPortInitializeMdlPages (MdlAddress);
  503. //
  504. // Flush I/O buffers and read from the boot device.
  505. //
  506. KeFlushIoBuffers(MdlAddress, TRUE, TRUE);
  507. LogicalBlock.QuadPart = BlFileTable[FileId].Position.QuadPart >>
  508. BlFileTable[FileId].u.PartitionContext.SectorShift;
  509. LogicalBlock.LowPart += BlFileTable[FileId].u.PartitionContext.StartingSector;
  510. NtStatus = ScsiDiskBootIO(MdlAddress,
  511. LogicalBlock.LowPart,
  512. &BlFileTable[FileId].u.PartitionContext,
  513. TRUE);
  514. if (NtStatus != ESUCCESS) {
  515. return EIO;
  516. }
  517. *Count += Limit;
  518. Length -= Limit;
  519. Buffer = (PVOID)((PCHAR)Buffer + Limit);
  520. BytesToTransfer -= Limit;
  521. BlFileTable[FileId].Position.QuadPart = BlFileTable[FileId].Position.QuadPart + Limit;
  522. }
  523. //
  524. // If there is any residual data to read, then read the last sector
  525. // separately and copy the data.
  526. //
  527. if (Length != 0) {
  528. Position = BlFileTable[FileId].Position;
  529. ArcStatus = ScsiDiskRead(FileId, TempPointer, SectorSize, &TransferCount);
  530. if (ArcStatus != ESUCCESS) {
  531. BlFileTable[FileId].Position = Position;
  532. return ArcStatus;
  533. }
  534. //
  535. // Copy the data to the specified buffer.
  536. //
  537. RtlCopyMemory(Buffer,TempPointer,Length);
  538. //
  539. // Update transfer parameters.
  540. //
  541. *Count += Length;
  542. BlFileTable[FileId].Position.QuadPart = Position.QuadPart + Length;
  543. }
  544. return ESUCCESS;
  545. }
  546. ARC_STATUS
  547. ScsiDiskGetReadStatus (
  548. IN ULONG FileId
  549. )
  550. /*++
  551. Routine Description:
  552. Arguments:
  553. Return Value:
  554. --*/
  555. {
  556. return ESUCCESS;
  557. }
  558. ARC_STATUS
  559. ScsiDiskSeek (
  560. IN ULONG FileId,
  561. IN PLARGE_INTEGER Offset,
  562. IN SEEK_MODE SeekMode
  563. )
  564. /*++
  565. Routine Description:
  566. This function sets the device position to the specified offset for
  567. the specified file id.
  568. Arguments:
  569. FileId - Supplies the file table index.
  570. Offset - Supplies to new device position.
  571. SeekMode - Supplies the mode for the position.
  572. Return Value:
  573. ESUCCESS is returned.
  574. --*/
  575. {
  576. //
  577. // Set the current device position as specifed by the seek mode.
  578. //
  579. if (SeekMode == SeekAbsolute) {
  580. BlFileTable[FileId].Position = *Offset;
  581. } else if (SeekMode == SeekRelative) {
  582. BlFileTable[FileId].Position.QuadPart = BlFileTable[FileId].Position.QuadPart + Offset->QuadPart;
  583. }
  584. return ESUCCESS;
  585. }
  586. ARC_STATUS
  587. ScsiDiskWrite (
  588. IN ULONG FileId,
  589. IN PVOID Buffer,
  590. IN ULONG Length,
  591. OUT PULONG Count
  592. )
  593. /*++
  594. Routine Description:
  595. This function writes data to the hard disk starting at the position
  596. specified in the file table.
  597. Arguments:
  598. FileId - Supplies the file table index.
  599. Buffer - Supplies a poiner to the buffer that contains the write data.
  600. Length - Supplies the number of bytes to be written.
  601. Count - Supplies a pointer to a variable that receives the number of
  602. bytes actually written.
  603. Return Value:
  604. The write operation is performed and the write completion status is
  605. returned.
  606. --*/
  607. {
  608. ARC_STATUS ArcStatus;
  609. ULONG Index;
  610. ULONG Limit;
  611. PMDL MdlAddress;
  612. UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)];
  613. NTSTATUS NtStatus;
  614. ULONG Offset;
  615. LARGE_INTEGER Position;
  616. LARGE_INTEGER WritePosition;
  617. LARGE_INTEGER LogicalBlock;
  618. CHAR TempBuffer[MAXIMUM_SECTOR_SIZE + 128];
  619. PIO_SCSI_CAPABILITIES PortCapabilities;
  620. ULONG adapterLimit;
  621. PCHAR TempPointer;
  622. ULONG SectorSize;
  623. ULONG TransferCount;
  624. ULONG BytesToTransfer;
  625. ULONG alignmentMask;
  626. //
  627. // If the requested size of the transfer is zero return ESUCCESS
  628. //
  629. if (Length==0) {
  630. return ESUCCESS;
  631. }
  632. if (!CheckFileId(FileId)) {
  633. return(ENODEV);
  634. }
  635. //
  636. // Compute a Dcache aligned pointer into the temporary buffer.
  637. //
  638. TempPointer = (PVOID)((ULONG_PTR)(TempBuffer +
  639. KeGetDcacheFillSize() - 1) & ~((LONG)KeGetDcacheFillSize() - 1));
  640. //
  641. // Calculate the actual sector size.
  642. //
  643. SectorSize = 1 << BlFileTable[FileId].u.PartitionContext.SectorShift;
  644. ArcStatus = GetAdapterCapabilities(
  645. BlFileTable[FileId].u.PartitionContext.PortDeviceObject,
  646. &PortCapabilities
  647. );
  648. if (ArcStatus != ESUCCESS) {
  649. adapterLimit = 0x10000;
  650. alignmentMask = KeGetDcacheFillSize();
  651. } else {
  652. if (PortCapabilities->MaximumTransferLength < 0x1000 ||
  653. PortCapabilities->MaximumTransferLength > 0x10000) {
  654. adapterLimit = 0x10000;
  655. } else {
  656. adapterLimit = PortCapabilities->MaximumTransferLength;
  657. }
  658. alignmentMask = PortCapabilities->AlignmentMask;
  659. }
  660. //
  661. // If the current position is not at a sector boundary or if the data
  662. // buffer is not properly aligned, then read the first sector separately
  663. // and copy the data.
  664. //
  665. Offset = BlFileTable[FileId].Position.LowPart & (SectorSize - 1);
  666. *Count = 0;
  667. while (Offset != 0 || (ULONG_PTR) Buffer & alignmentMask) {
  668. Position = BlFileTable[FileId].Position;
  669. BlFileTable[FileId].Position.QuadPart = Position.QuadPart - Offset;
  670. WritePosition = BlFileTable[FileId].Position;
  671. ArcStatus = ScsiDiskRead(FileId, TempPointer, SectorSize, &TransferCount);
  672. if (ArcStatus != ESUCCESS) {
  673. BlFileTable[FileId].Position = Position;
  674. return ArcStatus;
  675. }
  676. //
  677. // Reset the position as it was before the read.
  678. //
  679. BlFileTable[FileId].Position = WritePosition;
  680. //
  681. // If the length of write is less than the number of bytes from
  682. // the offset to the end of the sector, then copy only the number
  683. // of bytes required to fulfil the request. Otherwise copy to the end
  684. // of the sector and, read the remaining data.
  685. //
  686. if ((SectorSize - Offset) > Length) {
  687. Limit = Offset + Length;
  688. } else {
  689. Limit = SectorSize;
  690. }
  691. //
  692. // Merge the data from the specified buffer.
  693. //
  694. for (Index = Offset; Index < Limit; Index += 1) {
  695. TempPointer[Index] = ((PCHAR)Buffer)[Index-Offset];
  696. }
  697. //
  698. // Write the modified sector.
  699. //
  700. ArcStatus = ScsiDiskWrite(FileId, TempPointer, SectorSize, &TransferCount);
  701. if (ArcStatus != ESUCCESS) {
  702. return ArcStatus;
  703. }
  704. //
  705. // Update transfer parameters.
  706. //
  707. *Count += Limit - Offset;
  708. Length -= Limit - Offset;
  709. Buffer = (PVOID)((PCHAR)Buffer + Limit - Offset);
  710. BlFileTable[FileId].Position.QuadPart = Position.QuadPart + (Limit - Offset);
  711. Offset = BlFileTable[FileId].Position.LowPart & (SectorSize - 1);
  712. if (Length == 0) {
  713. break;
  714. }
  715. }
  716. //
  717. // The position is aligned on a sector boundary. Write as many sectors
  718. // as possible in a contiguous run.
  719. //
  720. BytesToTransfer = Length & (~(SectorSize - 1));
  721. while (BytesToTransfer != 0) {
  722. //
  723. // The scsi controller doesn't support transfers bigger than 64Kb.
  724. // Transfer the maximum number of bytes possible.
  725. //
  726. Limit = (BytesToTransfer > adapterLimit ? adapterLimit : BytesToTransfer);
  727. //
  728. // Build the memory descriptor list.
  729. //
  730. MdlAddress = (PMDL)&MdlBuffer[0];
  731. MdlAddress->Next = NULL;
  732. MdlAddress->Size = (CSHORT)(sizeof(MDL) +
  733. ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Limit) * sizeof(ULONG));
  734. MdlAddress->MdlFlags = 0;
  735. MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer);
  736. MdlAddress->ByteCount = Limit;
  737. MdlAddress->ByteOffset = BYTE_OFFSET(Buffer);
  738. ScsiPortInitializeMdlPages (MdlAddress);
  739. //
  740. // Flush I/O buffers and write to the boot device.
  741. //
  742. KeFlushIoBuffers(MdlAddress, FALSE, TRUE);
  743. LogicalBlock.QuadPart = BlFileTable[FileId].Position.QuadPart >>
  744. BlFileTable[FileId].u.PartitionContext.SectorShift;
  745. LogicalBlock.LowPart += BlFileTable[FileId].u.PartitionContext.StartingSector;
  746. NtStatus = ScsiDiskBootIO(MdlAddress,
  747. LogicalBlock.LowPart,
  748. &BlFileTable[FileId].u.PartitionContext,
  749. FALSE);
  750. if (NtStatus != ESUCCESS) {
  751. return EIO;
  752. }
  753. *Count += Limit;
  754. Length -= Limit;
  755. Buffer = (PVOID)((PCHAR)Buffer + Limit);
  756. BytesToTransfer -= Limit;
  757. BlFileTable[FileId].Position.QuadPart = BlFileTable[FileId].Position.QuadPart + Limit;
  758. }
  759. //
  760. // If there is any residual data to write, then read the last sector
  761. // separately merge the write data and write it.
  762. //
  763. if (Length != 0) {
  764. Position = BlFileTable[FileId].Position;
  765. ArcStatus = ScsiDiskRead(FileId, TempPointer, SectorSize, &TransferCount);
  766. //
  767. // Reset the position as it was before the read.
  768. //
  769. BlFileTable[FileId].Position = Position;
  770. if (ArcStatus != ESUCCESS) {
  771. return ArcStatus;
  772. }
  773. //
  774. // Merge the data with the read sector from the buffer.
  775. //
  776. for (Index = 0; Index < Length; Index += 1) {
  777. TempPointer[Index] = ((PCHAR)Buffer)[Index];
  778. }
  779. //
  780. // Write the merged sector
  781. //
  782. ArcStatus = ScsiDiskWrite(FileId, TempPointer, SectorSize, &TransferCount);
  783. //
  784. // Reset the postion.
  785. //
  786. BlFileTable[FileId].Position = Position;
  787. //
  788. // Update transfer parameters.
  789. //
  790. *Count += Length;
  791. //
  792. // Position is aligned to a sector boundary and Length is less than
  793. // a sector, therefore the addition will never overflow.
  794. //
  795. BlFileTable[FileId].Position.LowPart += Length;
  796. }
  797. return ESUCCESS;
  798. }
  799. #ifdef EFI_PARTITION_SUPPORT
  800. BOOLEAN
  801. ScsiGPTDiskReadCallback(
  802. ULONGLONG StartingLBA,
  803. ULONG BytesToRead,
  804. PVOID pContext,
  805. UNALIGNED PVOID OutputBuffer
  806. )
  807. {
  808. PMDL MdlAddress;
  809. PUSHORT DataPointer;
  810. ULONG DummyMdl[(sizeof(MDL) + 16) / sizeof(ULONG)];
  811. NTSTATUS Status;
  812. ULONG PartitionOffset;
  813. PPARTITION_CONTEXT Context;
  814. DBG_PRINT(STR_PREFIX"Trying to read SCSI GPT partition\r\n");
  815. Context = (PPARTITION_CONTEXT)pContext;
  816. DataPointer = OutputBuffer;
  817. //
  818. // Initialize a memory descriptor list to read the master boot record
  819. // from the specified hard disk drive.
  820. //
  821. MdlAddress = (PMDL)&DummyMdl[0];
  822. MdlAddress->StartVa = (PVOID)(((ULONG_PTR)DataPointer) & (~(PAGE_SIZE - 1)));
  823. MdlAddress->ByteCount = BytesToRead;
  824. MdlAddress->ByteOffset = (ULONG)((ULONG_PTR)DataPointer & (PAGE_SIZE - 1));
  825. ScsiPortInitializeMdlPages(MdlAddress);
  826. //
  827. // cast this to a ULONG because that's all we support in this stack.
  828. //
  829. PartitionOffset = (ULONG)StartingLBA;
  830. DBG_PRINT(STR_PREFIX"Reading SCSI GPT block\r\n");
  831. Status = ScsiDiskBootIO(MdlAddress, PartitionOffset, Context, TRUE);
  832. return(NT_SUCCESS(Status) != FALSE);
  833. }
  834. #define DATA_BUFF_SIZE ((MAXIMUM_SECTOR_SIZE * 2 / sizeof(USHORT)) + 128)
  835. NTSTATUS
  836. ScsiGPTDiskBootPartitionOpen(
  837. IN ULONG FileId,
  838. IN UCHAR DeviceUnit,
  839. IN UCHAR PartitionNumber
  840. )
  841. {
  842. PMDL MdlAddress;
  843. UNALIGNED USHORT DataBuffer[DATA_BUFF_SIZE];
  844. PUSHORT DataPointer;
  845. ULONG DummyMdl[(sizeof(MDL) + 16) / sizeof(ULONG)];
  846. PPARTITION_CONTEXT Context;
  847. NTSTATUS Status;
  848. ULONG PartitionOffset;
  849. ULONG SectorSize;
  850. UCHAR ValidPartitions;
  851. UCHAR PartitionCount;
  852. UCHAR PartitionsPerSector = 0;
  853. UCHAR NullGuid[16] = {0};
  854. DBG_PRINT(STR_PREFIX"Trying to open SCSI GPT partition\r\n");
  855. Context = &BlFileTable[FileId].u.PartitionContext;
  856. if (PartitionNumber > 128)
  857. return EINVAL;
  858. //
  859. // Calculate the actual sector size
  860. //
  861. SectorSize = 1 << Context->SectorShift;
  862. RtlZeroMemory(DataBuffer, sizeof(DataBuffer));
  863. //
  864. // Make the sector size the minimum of 512 or the sector size.
  865. //
  866. if (SectorSize < 512) {
  867. SectorSize = 512;
  868. }
  869. //
  870. // Align the buffer on a Dcache line size.
  871. //
  872. DataPointer = (PVOID) ((ULONG_PTR) ((PCHAR) DataBuffer +
  873. KeGetDcacheFillSize() - 1) & ~((LONG)KeGetDcacheFillSize() - 1));
  874. //
  875. // Initialize a memory descriptor list to read the master boot record
  876. // from the specified hard disk drive.
  877. //
  878. MdlAddress = (PMDL)&DummyMdl[0];
  879. MdlAddress->StartVa = (PVOID)(((ULONG_PTR)DataPointer) & (~(PAGE_SIZE - 1)));
  880. MdlAddress->ByteCount = SectorSize;
  881. MdlAddress->ByteOffset = (ULONG)((ULONG_PTR)DataPointer & (PAGE_SIZE - 1));
  882. ScsiPortInitializeMdlPages(MdlAddress);
  883. PartitionOffset = 1;
  884. DBG_PRINT(STR_PREFIX"Reading SCSI GPT block 1\r\n");
  885. Status = ScsiDiskBootIO(MdlAddress, PartitionOffset, Context, TRUE);
  886. if (NT_SUCCESS(Status) != FALSE) {
  887. UNALIGNED EFI_PARTITION_TABLE *EfiHdr;
  888. ULONGLONG StartLBA;
  889. EfiHdr = (UNALIGNED EFI_PARTITION_TABLE *)DataPointer;
  890. if (!BlIsValidGUIDPartitionTable(
  891. EfiHdr,
  892. 1,
  893. Context,
  894. ScsiGPTDiskReadCallback)) {
  895. Status = STATUS_UNSUCCESSFUL;
  896. return Status;
  897. }
  898. //
  899. // Read the partition entries
  900. //
  901. StartLBA = EfiHdr->PartitionEntryLBA;
  902. PartitionOffset = (ULONG)StartLBA;
  903. ValidPartitions = 0;
  904. PartitionCount = 0;
  905. PartitionsPerSector = (UCHAR)(SectorSize / sizeof(EFI_PARTITION_ENTRY));
  906. while ((PartitionCount < 128)) {
  907. #if 0
  908. BlPrint("Reading %d at %d block offset of blk size %d %d \r\n",
  909. MdlAddress->ByteCount, PartitionOffset, SectorSize,
  910. PartitionsPerSector);
  911. #endif
  912. RtlZeroMemory(DataPointer, SectorSize);
  913. DBG_PRINT(STR_PREFIX"Reading GPT partition entries\r\n");
  914. Status = ScsiDiskBootIO(MdlAddress, PartitionOffset, Context, TRUE);
  915. if (NT_SUCCESS(Status)) {
  916. UNALIGNED EFI_PARTITION_ENTRY *PartEntry = NULL;
  917. RtlZeroMemory(EfiPartitionBuffer, SectorSize);
  918. //
  919. // Move the read content to EfiPartitionBuffer
  920. //
  921. RtlCopyMemory(EfiPartitionBuffer, DataPointer, SectorSize);
  922. DBG_PRINT(STR_PREFIX"Locating the requested GPT partition\r\n");
  923. //
  924. // Locate the GPT partition requested
  925. //
  926. PartEntry = (UNALIGNED EFI_PARTITION_ENTRY *)
  927. BlLocateGPTPartition(PartitionNumber,
  928. PartitionsPerSector,
  929. &ValidPartitions);
  930. if (PartEntry) {
  931. PPARTITION_CONTEXT PartContext = &(BlFileTable[FileId].u.PartitionContext);
  932. ULONG SectorCount = (ULONG)(PartEntry->EndingLBA - PartEntry->StartingLBA);
  933. DBG_PRINT(STR_PREFIX"Initializing GPT Partition Entry Context\r\n");
  934. //
  935. // Fill the partition context structure
  936. //
  937. PartContext->PartitionLength.QuadPart = SectorCount * SECTOR_SIZE;
  938. PartContext->StartingSector = (ULONG)(PartEntry->StartingLBA);
  939. PartContext->EndingSector = (ULONG)(PartEntry->EndingLBA);
  940. #if 0
  941. BlPrint("Start:%d,End:%d\r\n", PartContext->StartingSector,
  942. PartContext->EndingSector);
  943. while (!BlGetKey());
  944. #endif
  945. BlFileTable[FileId].Position.QuadPart = 0;
  946. Status = ESUCCESS;
  947. break;
  948. } else {
  949. //
  950. // Get hold of the next set of
  951. // partition entries in the next block
  952. //
  953. PartitionCount += PartitionsPerSector;
  954. PartitionOffset++;
  955. }
  956. } else {
  957. break; // I/O Error
  958. }
  959. }
  960. }
  961. DBG_PRINT(STR_PREFIX"Returning from ScsiGPTDiskBootPartitionOpen(...)\r\n");
  962. return Status;
  963. }
  964. #endif // for EFI_PARTITION_SUPPORT
  965. NTSTATUS
  966. ScsiDiskBootPartitionOpen(
  967. IN ULONG FileId,
  968. IN UCHAR DeviceUnit,
  969. IN UCHAR PartitionNumber
  970. )
  971. /*++
  972. Routine Description:
  973. This is the initialization routine for the hard disk boot driver
  974. for the given partition. It sets the partition info in the
  975. FileTable at the specified index and initializes the Device entry
  976. table to point to the table of ScsiDisk routines.
  977. It reads the partition information until the requested partition
  978. is found or no more partitions are defined.
  979. Arguments:
  980. FileId - Supplies the file id for the file table entry.
  981. DeviceUnit - Supplies the device number in the scis bus.
  982. PartitionNumber - Supplies the partition number must be bigger than zero.
  983. To get the size of the disk call ReadDriveCapacity.
  984. Return Value:
  985. If a valid FAT file system structure is found on the hard disk, then
  986. STATUS_SUCCESS is returned. Otherwise, STATUS_UNSUCCESSFUL is returned.
  987. --*/
  988. {
  989. PMDL MdlAddress;
  990. USHORT DataBuffer[MAXIMUM_SECTOR_SIZE / sizeof(USHORT) + 128];
  991. PUSHORT DataPointer;
  992. ULONG DummyMdl[(sizeof(MDL) + 16) / sizeof(ULONG)];
  993. PPARTITION_DESCRIPTOR Partition;
  994. PPARTITION_CONTEXT Context;
  995. ULONG PartitionLength;
  996. ULONG StartingSector;
  997. ULONG VolumeOffset;
  998. NTSTATUS Status;
  999. BOOLEAN PrimaryPartitionTable;
  1000. ULONG PartitionOffset=0;
  1001. ULONG PartitionIndex,PartitionCount=0;
  1002. ULONG SectorSize;
  1003. BlFileTable[FileId].Position.LowPart = 0;
  1004. BlFileTable[FileId].Position.HighPart = 0;
  1005. VolumeOffset=0;
  1006. PrimaryPartitionTable=TRUE;
  1007. Context = &BlFileTable[FileId].u.PartitionContext;
  1008. //
  1009. // Calculate the actual sector size
  1010. //
  1011. SectorSize = 1 << Context->SectorShift;
  1012. RtlZeroMemory(DataBuffer, sizeof(DataBuffer));
  1013. //
  1014. // Make the sector size the minimum of 512 or the sector size.
  1015. //
  1016. if (SectorSize < 512) {
  1017. SectorSize = 512;
  1018. }
  1019. //
  1020. // Align the buffer on a Dcache line size.
  1021. //
  1022. DataPointer = (PVOID) ((ULONG_PTR) ((PCHAR) DataBuffer +
  1023. KeGetDcacheFillSize() - 1) & ~((LONG)KeGetDcacheFillSize() - 1));
  1024. //
  1025. // Initialize a memory descriptor list to read the master boot record
  1026. // from the specified hard disk drive.
  1027. //
  1028. MdlAddress = (PMDL)&DummyMdl[0];
  1029. MdlAddress->StartVa = (PVOID)(((ULONG_PTR)DataPointer) & (~(PAGE_SIZE - 1)));
  1030. MdlAddress->ByteCount = SectorSize;
  1031. MdlAddress->ByteOffset = (ULONG)((ULONG_PTR)DataPointer & (PAGE_SIZE - 1));
  1032. ScsiPortInitializeMdlPages (MdlAddress);
  1033. do {
  1034. Status = ScsiDiskBootIO(MdlAddress,PartitionOffset,Context,TRUE);
  1035. if (NT_SUCCESS(Status) != FALSE) {
  1036. //
  1037. // If sector zero is not a master boot record, then return failure
  1038. // status. Otherwise return success.
  1039. //
  1040. if (*(DataPointer + BOOT_SIGNATURE_OFFSET) != BOOT_RECORD_SIGNATURE) {
  1041. // This DbgPrint has been commented out. On IA64 and AXP64,
  1042. // it crashes unless booted with a boot debugger.
  1043. //DbgPrint("Boot record signature not found\n");
  1044. return STATUS_UNSUCCESSFUL;
  1045. }
  1046. //
  1047. // Read the partition information until the four entries are
  1048. // checked or until we found the requested one.
  1049. //
  1050. Partition = (PPARTITION_DESCRIPTOR)(DataPointer+PARTITION_TABLE_OFFSET);
  1051. for (PartitionIndex=0;
  1052. PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
  1053. PartitionIndex++,Partition++) {
  1054. //
  1055. // Count first the partitions in the MBR. The units
  1056. // inside the extended partition are counted later.
  1057. //
  1058. if (!IsContainerPartition(Partition->PartitionType) &&
  1059. (Partition->PartitionType != STALE_GPT_PARTITION_ENTRY) &&
  1060. (Partition->PartitionType != PARTITION_ENTRY_UNUSED)) {
  1061. PartitionCount++; // another partition found.
  1062. }
  1063. //
  1064. // Check if the requested partition has already been found.
  1065. // set the partition info in the file table and return.
  1066. //
  1067. if (PartitionCount == (ULONG)PartitionNumber) {
  1068. StartingSector = (ULONG)(Partition->StartingSectorLsb0) |
  1069. (ULONG)(Partition->StartingSectorLsb1 << 8) |
  1070. (ULONG)(Partition->StartingSectorMsb0 << 16) |
  1071. (ULONG)(Partition->StartingSectorMsb1 << 24);
  1072. PartitionLength = (ULONG)(Partition->PartitionLengthLsb0) |
  1073. (ULONG)(Partition->PartitionLengthLsb1 << 8) |
  1074. (ULONG)(Partition->PartitionLengthMsb0 << 16) |
  1075. (ULONG)(Partition->PartitionLengthMsb1 << 24);
  1076. Context->PartitionLength.QuadPart = PartitionLength;
  1077. Context->PartitionLength.QuadPart <<= Context->SectorShift;
  1078. Context->StartingSector = PartitionOffset + StartingSector;
  1079. Context->EndingSector = Context->StartingSector + PartitionLength;
  1080. return Status;
  1081. }
  1082. }
  1083. //
  1084. // If requested partition was not yet found.
  1085. // Look for an extended partition.
  1086. //
  1087. Partition = (PPARTITION_DESCRIPTOR)(DataPointer + PARTITION_TABLE_OFFSET);
  1088. PartitionOffset = 0;
  1089. for (PartitionIndex=0;
  1090. PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
  1091. PartitionIndex++,Partition++) {
  1092. if (IsContainerPartition(Partition->PartitionType)) {
  1093. StartingSector = (ULONG)(Partition->StartingSectorLsb0) |
  1094. (ULONG)(Partition->StartingSectorLsb1 << 8) |
  1095. (ULONG)(Partition->StartingSectorMsb0 << 16) |
  1096. (ULONG)(Partition->StartingSectorMsb1 << 24);
  1097. PartitionOffset = VolumeOffset+StartingSector;
  1098. if (PrimaryPartitionTable) {
  1099. VolumeOffset = StartingSector;
  1100. }
  1101. break; // only one partition can be extended.
  1102. }
  1103. }
  1104. }
  1105. PrimaryPartitionTable=FALSE;
  1106. } while (PartitionOffset != 0);
  1107. return STATUS_UNSUCCESSFUL;
  1108. }
  1109. VOID
  1110. ScsiPortInitializeMdlPages (
  1111. IN OUT PMDL Mdl
  1112. )
  1113. /*++
  1114. Routine Description:
  1115. This routine fills in the physical pages numbers for the virtual
  1116. addresses specified in the passed in Mdl.
  1117. Arguments:
  1118. Mdl - On input contains the StartVa, ByteCount and ByteOffset
  1119. of the Mdl.
  1120. Return Value:
  1121. Mdl - The physical page array referenced by the mdl is completed
  1122. --*/
  1123. {
  1124. PULONG PageFrame;
  1125. PUCHAR PageVa;
  1126. ULONG Index;
  1127. ULONG NumberOfPages;
  1128. PageFrame = (PULONG)(Mdl + 1);
  1129. PageVa = (PUCHAR) Mdl->StartVa;
  1130. NumberOfPages = (Mdl->ByteCount + Mdl->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
  1131. for (Index = 0; Index < NumberOfPages; Index += 1) {
  1132. PageFrame[Index] = (ULONG)(MmGetPhysicalAddress(PageVa).QuadPart >> PAGE_SHIFT);
  1133. PageVa += PAGE_SIZE;
  1134. }
  1135. }
  1136. BOOLEAN
  1137. ScsiGetDevicePath(
  1138. IN ULONG ScsiNumber,
  1139. IN PCONFIGURATION_COMPONENT TargetComponent,
  1140. IN PCONFIGURATION_COMPONENT LunComponent,
  1141. OUT PCHAR DevicePath
  1142. )
  1143. /*++
  1144. Routine Description:
  1145. This routine constructs the device path for the device identified
  1146. by the supplied parameters.
  1147. Arguments:
  1148. ScsiNumber - Identifies the scis bus on which the device resides.
  1149. TargetComponent - Points to a CONFIGURATION_COMPONENT structure that
  1150. describes the target.
  1151. LunComponent - Points to a CONFIGURATION_COMPONENT structure that
  1152. describes the lun.
  1153. DevicePath - Points to the output buffer into which the device path
  1154. is copied.
  1155. Return Value:
  1156. TRUE if a valid device path is copied into the output buffer.
  1157. FALSE if the supplied parameters do not represent a valid device. If
  1158. the return value is FALSE, nothing copied into the output buffer.
  1159. --*/
  1160. {
  1161. if (TargetComponent->Type == DiskController) {
  1162. //
  1163. // This is either a hard disk or a floppy floppy disk. Construct
  1164. // the appropriate device path depending on which.
  1165. //
  1166. if (LunComponent->Type == FloppyDiskPeripheral) {
  1167. sprintf(DevicePath, "scsi(%d)disk(%d)fdisk(%d)",
  1168. ScsiNumber,
  1169. TargetComponent->Key,
  1170. LunComponent->Key);
  1171. } else if (LunComponent->Type == DiskPeripheral) {
  1172. sprintf(DevicePath, "scsi(%d)disk(%d)rdisk(%d)",
  1173. ScsiNumber,
  1174. TargetComponent->Key,
  1175. LunComponent->Key);
  1176. } else {
  1177. ASSERT(FALSE);
  1178. return FALSE;
  1179. }
  1180. } else if (TargetComponent->Type == CdromController) {
  1181. //
  1182. // This is a cdrom device. Construct an appropriate device path.
  1183. //
  1184. sprintf(DevicePath, "scsi(%d)cdrom(%d)fdisk(%d)",
  1185. ScsiNumber,
  1186. TargetComponent->Key,
  1187. LunComponent->Key);
  1188. } else {
  1189. //
  1190. // Unexpected device path.
  1191. //
  1192. ASSERT(FALSE);
  1193. return FALSE;
  1194. }
  1195. return TRUE;
  1196. }
  1197. PCONFIGURATION_COMPONENT
  1198. ScsiGetNextConfiguredLunComponent(
  1199. IN PCONFIGURATION_COMPONENT LunComponent
  1200. )
  1201. /*++
  1202. Routine Description:
  1203. Given a lun that exists on one of the system's SCSI buses, this
  1204. routine returns the next sequential lun identified on the same
  1205. target.
  1206. Arguments:
  1207. LunComponent - Pointer to a CONFIGURATION_COMPONENT structure that
  1208. describes an existing lun.
  1209. Return Value:
  1210. If one or more luns were identified on the same target as supplied
  1211. lun, this function returns a pointer to a CONFIGURATION_COMPONTENT
  1212. structure that describes the next sequential lun on the same target.
  1213. --*/
  1214. {
  1215. PCONFIGURATION_COMPONENT nextLunComponent;
  1216. nextLunComponent = FwGetPeer(LunComponent);
  1217. if (nextLunComponent != NULL) {
  1218. if (nextLunComponent->Type != FloppyDiskPeripheral &&
  1219. nextLunComponent->Type != DiskPeripheral) {
  1220. nextLunComponent = NULL;
  1221. }
  1222. }
  1223. return nextLunComponent;
  1224. }
  1225. PCONFIGURATION_COMPONENT
  1226. ScsiGetFirstConfiguredLunComponent(
  1227. IN PCONFIGURATION_COMPONENT TargetComponent
  1228. )
  1229. /*++
  1230. Routine Description:
  1231. Given a target that exists on one of the system's SCSI buses, this
  1232. routine returns the first LUN identified on that target.
  1233. Arguments:
  1234. TargetComponent - Pointer to a CONFIGURATION_COMPONENT structure that
  1235. describes an existing SCSI target.
  1236. Return Value:
  1237. If any lun was identified on given target, this function returns a pointer
  1238. to a CONFIGURATION_COMPONENT structure that describes the lun. If no
  1239. LUNs were found on the target, NULL is returned.
  1240. --*/
  1241. {
  1242. PCONFIGURATION_COMPONENT lunComponent;
  1243. lunComponent = FwGetChild(TargetComponent);
  1244. if (lunComponent != NULL) {
  1245. if (lunComponent->Type != FloppyDiskPeripheral &&
  1246. lunComponent->Type != DiskPeripheral) {
  1247. lunComponent = NULL;
  1248. }
  1249. }
  1250. return lunComponent;
  1251. }
  1252. PCONFIGURATION_COMPONENT
  1253. ScsiGetNextConfiguredTargetComponent(
  1254. IN PCONFIGURATION_COMPONENT TargetComponent
  1255. )
  1256. /*++
  1257. Routine Description:
  1258. Given a target that exists on one of the system's SCSI buses, this
  1259. routine returns the next numerically sequestial target found on the
  1260. same bus.
  1261. Arguments:
  1262. TargetComponent - Pointer to a CONFIGURATION_COMPONENT structure
  1263. that describes a SCSI target.
  1264. Return Value:
  1265. If one or more targets were identified on the same SCSI bus as the
  1266. supplied target, a pointer to a CONFIGURATION_COMPONENT structure
  1267. that describes the next sequential target is returned. If there
  1268. are no targets following the one supplied, NULL is returned.
  1269. --*/
  1270. {
  1271. PCONFIGURATION_COMPONENT nextTarget;
  1272. nextTarget = FwGetPeer(TargetComponent);
  1273. if (nextTarget != NULL) {
  1274. if (nextTarget->Type != DiskController &&
  1275. nextTarget->Type != CdromController) {
  1276. nextTarget = NULL;
  1277. }
  1278. }
  1279. return nextTarget;
  1280. }
  1281. PCONFIGURATION_COMPONENT
  1282. ScsiGetFirstConfiguredTargetComponent(
  1283. ULONG ScsiNumber
  1284. )
  1285. /*++
  1286. Routine Description:
  1287. This routine returns the first configured target on the specified SCSI bus.
  1288. Arguments:
  1289. ScsiNumber - Identifies the SCSI bus for which the first target is requested.
  1290. Return Value:
  1291. If any target was detected on the specified bus, a pointer to a
  1292. CONFIGURATION_COMPONENT structure describing the target is returned. If no
  1293. targets were detected on the speicified bus, the funtion returns NULL.
  1294. --*/
  1295. {
  1296. PCONFIGURATION_COMPONENT scsiComponent;
  1297. PCONFIGURATION_COMPONENT controllerComponent;
  1298. CHAR componentPath[10];
  1299. //
  1300. // Get the requested scsi adapter component. If no match, return NULL.
  1301. //
  1302. sprintf(componentPath, "scsi(%1d)", ScsiNumber);
  1303. scsiComponent = FwGetComponent(componentPath);
  1304. if (scsiComponent == NULL) {
  1305. return NULL;
  1306. }
  1307. //
  1308. // If returned the component is not a SCSI adapter, return NULL.
  1309. //
  1310. if (scsiComponent->Type != ScsiAdapter) {
  1311. return NULL;
  1312. }
  1313. //
  1314. // Get the first configured target on the adapter.
  1315. //
  1316. controllerComponent = FwGetChild(scsiComponent);
  1317. if ((controllerComponent != NULL) &&
  1318. ((controllerComponent->Type == DiskController) ||
  1319. (controllerComponent->Type == CdromController))) {
  1320. return controllerComponent;
  1321. } else {
  1322. //
  1323. // We got back an unexpected controller type.
  1324. //
  1325. ASSERT(FALSE);
  1326. }
  1327. return NULL;
  1328. }
  1329. //
  1330. // This callback messes a lot of things up. There is no clean definition
  1331. // for it anywhere, so it has to be defined in all modules that reference it.
  1332. //
  1333. #ifndef SCSI_INFO_CALLBACK_DEFINED
  1334. typedef
  1335. VOID
  1336. (*PSCSI_INFO_CALLBACK_ROUTINE) (
  1337. IN ULONG AdapterNumber,
  1338. IN ULONG ScsiId,
  1339. IN ULONG Lun,
  1340. IN BOOLEAN Cdrom
  1341. );
  1342. #endif
  1343. VOID
  1344. HardDiskInitialize(
  1345. IN OUT PDRIVER_LOOKUP_ENTRY LookupTable,
  1346. IN ULONG Entries,
  1347. IN PSCSI_INFO_CALLBACK_ROUTINE DeviceFound
  1348. )
  1349. /*++
  1350. Routine Description:
  1351. This routine initializes the scsi controller and the
  1352. device entry table for the scsi driver.
  1353. Arguments:
  1354. None.
  1355. Return Value:
  1356. None.
  1357. --*/
  1358. {
  1359. ULONG lookupTableIndex = 0;
  1360. ULONG scsiNumber;
  1361. ULONG busNumber;
  1362. PCHAR Identifier;
  1363. PLUNINFO lunInfo;
  1364. PSCSI_CONFIGURATION_INFO configInfo;
  1365. PSCSI_BUS_SCAN_DATA busScanData;
  1366. PDEVICE_EXTENSION scsiPort;
  1367. PINQUIRYDATA inquiryData;
  1368. PCONFIGURATION_COMPONENT RootComponent;
  1369. PCONFIGURATION_COMPONENT ScsiComponent;
  1370. PCONFIGURATION_COMPONENT ControllerComponent;
  1371. PCONFIGURATION_COMPONENT PeripheralComponent;
  1372. PCONFIGURATION_COMPONENT NextComponent;
  1373. CHAR ComponentPath[10];
  1374. CONFIGURATION_COMPONENT ControllerEntry;
  1375. CONFIGURATION_COMPONENT AdapterEntry;
  1376. CONFIGURATION_COMPONENT PeripheralEntry;
  1377. PARTITION_CONTEXT Context;
  1378. BOOLEAN IsFloppy;
  1379. RtlZeroMemory(&Context, sizeof(PARTITION_CONTEXT));
  1380. //
  1381. // Initialize the common buffers.
  1382. //
  1383. ReadCapacityBuffer = ExAllocatePool( NonPagedPool, sizeof(READ_CAPACITY_DATA));
  1384. SenseInfoBuffer = ExAllocatePool( NonPagedPool, SENSE_BUFFER_SIZE);
  1385. if (ReadCapacityBuffer == NULL || SenseInfoBuffer == NULL) {
  1386. return;
  1387. }
  1388. //
  1389. // Scan the scsi ports looking for disk devices.
  1390. //
  1391. for (scsiNumber = 0; ScsiPortDeviceObject[scsiNumber]; scsiNumber++) {
  1392. scsiPort = ScsiPortDeviceObject[scsiNumber]->DeviceExtension;
  1393. configInfo = scsiPort->ScsiInfo;
  1394. Context.PortDeviceObject = ScsiPortDeviceObject[scsiNumber];
  1395. //
  1396. // Search the configuration database for scsi disk and cdrom devices and
  1397. // delete them.
  1398. //
  1399. sprintf(ComponentPath,"scsi(%1d)", scsiNumber);
  1400. ScsiComponent = FwGetComponent(ComponentPath);
  1401. if (ScsiComponent != NULL) {
  1402. if (ScsiComponent->Type == ScsiAdapter) {
  1403. ControllerComponent = FwGetChild(ScsiComponent);
  1404. while (ControllerComponent != NULL) {
  1405. NextComponent = FwGetPeer(ControllerComponent);
  1406. if ((ControllerComponent->Type == DiskController) ||
  1407. (ControllerComponent->Type == CdromController)) {
  1408. PeripheralComponent = FwGetChild(ControllerComponent);
  1409. if (FwDeleteComponent(PeripheralComponent) == ESUCCESS) {
  1410. FwDeleteComponent(ControllerComponent);
  1411. }
  1412. }
  1413. ControllerComponent = NextComponent;
  1414. }
  1415. } else {
  1416. RootComponent = FwGetChild(NULL);
  1417. AdapterEntry.Class = AdapterClass;
  1418. AdapterEntry.Type = ScsiAdapter;
  1419. AdapterEntry.Flags.ReadOnly = 0;
  1420. AdapterEntry.Flags.Removable = 0;
  1421. AdapterEntry.Flags.ConsoleIn = 0;
  1422. AdapterEntry.Flags.ConsoleOut = 0;
  1423. AdapterEntry.Flags.Output = 1;
  1424. AdapterEntry.Flags.Input = 1;
  1425. AdapterEntry.Version = 0;
  1426. AdapterEntry.Revision = 0;
  1427. AdapterEntry.Key = scsiNumber;
  1428. AdapterEntry.AffinityMask = 0xffffffff;
  1429. AdapterEntry.ConfigurationDataLength = 0;
  1430. AdapterEntry.IdentifierLength = 0;
  1431. AdapterEntry.Identifier = 0;
  1432. ScsiComponent = FwAddChild(RootComponent, &AdapterEntry, NULL);
  1433. }
  1434. }
  1435. for (busNumber=0; busNumber < (ULONG)configInfo->NumberOfBuses; busNumber++) {
  1436. busScanData = configInfo->BusScanData[busNumber];
  1437. //
  1438. // Set LunInfo to beginning of list.
  1439. //
  1440. lunInfo = busScanData->LunInfoList;
  1441. while (lunInfo != NULL) {
  1442. inquiryData = (PVOID)lunInfo->InquiryData;
  1443. ScsiDebugPrint(3,"FindScsiDevices: Inquiry data at %lx\n",
  1444. inquiryData);
  1445. if ((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE
  1446. || inquiryData->DeviceType == OPTICAL_DEVICE) &&
  1447. !lunInfo->DeviceClaimed) {
  1448. ScsiDebugPrint(1,
  1449. "FindScsiDevices: Vendor string is %.24s\n",
  1450. inquiryData->VendorId);
  1451. IsFloppy = FALSE;
  1452. //
  1453. // Create a dummy paritition context so that I/O can be
  1454. // done on the device. SendSrbSynchronous only uses the
  1455. // port device object pointer and the scsi address of the
  1456. // logical unit.
  1457. //
  1458. Context.PathId = lunInfo->PathId;
  1459. Context.TargetId = lunInfo->TargetId;
  1460. Context.DiskId = lunInfo->Lun;
  1461. //
  1462. // Create name for disk object.
  1463. //
  1464. LookupTable->DevicePath =
  1465. ExAllocatePool(NonPagedPool,
  1466. sizeof("scsi(%d)disk(%d)rdisk(%d)"));
  1467. if (LookupTable->DevicePath == NULL) {
  1468. return;
  1469. }
  1470. //
  1471. // If this is a removable. Check to see if the device is
  1472. // a floppy.
  1473. //
  1474. if (inquiryData->RemovableMedia &&
  1475. inquiryData->DeviceType == DIRECT_ACCESS_DEVICE &&
  1476. IsFloppyDevice(&Context) ) {
  1477. sprintf(LookupTable->DevicePath,
  1478. "scsi(%d)disk(%d)fdisk(%d)",
  1479. scsiNumber,
  1480. SCSI_COMBINE_BUS_TARGET( lunInfo->PathId, lunInfo->TargetId ),
  1481. lunInfo->Lun
  1482. );
  1483. IsFloppy = TRUE;
  1484. } else {
  1485. sprintf(LookupTable->DevicePath,
  1486. "scsi(%d)disk(%d)rdisk(%d)",
  1487. scsiNumber,
  1488. SCSI_COMBINE_BUS_TARGET( lunInfo->PathId, lunInfo->TargetId ),
  1489. lunInfo->Lun
  1490. );
  1491. if (DeviceFound) {
  1492. DeviceFound( scsiNumber,
  1493. SCSI_COMBINE_BUS_TARGET( lunInfo->PathId, lunInfo->TargetId ),
  1494. lunInfo->Lun,
  1495. FALSE
  1496. );
  1497. }
  1498. }
  1499. LookupTable->DispatchTable = &ScsiDiskEntryTable;
  1500. //
  1501. // If the disk controller entry does not exist, add it to
  1502. // the configuration database.
  1503. //
  1504. ControllerComponent = FwGetComponent(LookupTable->DevicePath);
  1505. if (ControllerComponent != NULL) {
  1506. if (ControllerComponent->Type != DiskController) {
  1507. ControllerEntry.Class = ControllerClass;
  1508. ControllerEntry.Type = DiskController;
  1509. ControllerEntry.Flags.Failed = 0;
  1510. ControllerEntry.Flags.ReadOnly = 0;
  1511. ControllerEntry.Flags.Removable = 0;
  1512. ControllerEntry.Flags.ConsoleIn = 0;
  1513. ControllerEntry.Flags.ConsoleOut = 0;
  1514. ControllerEntry.Flags.Output = 1;
  1515. ControllerEntry.Flags.Input = 1;
  1516. ControllerEntry.Version = 0;
  1517. ControllerEntry.Revision = 0;
  1518. ControllerEntry.Key = SCSI_COMBINE_BUS_TARGET( lunInfo->PathId, lunInfo->TargetId );
  1519. ControllerEntry.AffinityMask = 0xffffffff;
  1520. ControllerEntry.ConfigurationDataLength = 0;
  1521. Identifier =
  1522. ExAllocatePool(NonPagedPool,
  1523. strlen(inquiryData->VendorId)
  1524. );
  1525. if (Identifier == NULL) {
  1526. return;
  1527. }
  1528. sprintf(Identifier,
  1529. "%s",
  1530. inquiryData->VendorId
  1531. );
  1532. ControllerEntry.IdentifierLength = strlen(Identifier);
  1533. ControllerEntry.Identifier = Identifier;
  1534. ControllerComponent = FwAddChild(ScsiComponent, &ControllerEntry, NULL);
  1535. }
  1536. }
  1537. //
  1538. // Add disk peripheral entry to the configuration database.
  1539. //
  1540. PeripheralEntry.Class = PeripheralClass;
  1541. PeripheralEntry.Type = IsFloppy ? FloppyDiskPeripheral : DiskPeripheral;
  1542. PeripheralEntry.Flags.Failed = 0;
  1543. PeripheralEntry.Flags.ReadOnly = 0;
  1544. PeripheralEntry.Flags.Removable = IsFloppy;
  1545. PeripheralEntry.Flags.ConsoleIn = 0;
  1546. PeripheralEntry.Flags.ConsoleOut = 0;
  1547. PeripheralEntry.Flags.Output = 1;
  1548. PeripheralEntry.Flags.Input = 1;
  1549. PeripheralEntry.Version = 0;
  1550. PeripheralEntry.Revision = 0;
  1551. PeripheralEntry.Key = lunInfo->Lun;
  1552. PeripheralEntry.AffinityMask = 0xffffffff;
  1553. PeripheralEntry.ConfigurationDataLength = 0;
  1554. PeripheralEntry.IdentifierLength = 0;
  1555. PeripheralEntry.Identifier = NULL;
  1556. FwAddChild(ControllerComponent, &PeripheralEntry, NULL);
  1557. //
  1558. // Increment to the next entry.
  1559. //
  1560. LookupTable++;
  1561. lookupTableIndex++;
  1562. if (lookupTableIndex >= Entries) {
  1563. //
  1564. // There is no more space in the caller provided buffer
  1565. // for disk information. Return.
  1566. //
  1567. return;
  1568. }
  1569. //
  1570. // Claim disk device by marking configuration
  1571. // record owned.
  1572. //
  1573. lunInfo->DeviceClaimed = TRUE;
  1574. }
  1575. if ((inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
  1576. (!lunInfo->DeviceClaimed)) {
  1577. ScsiDebugPrint(1,"FindScsiDevices: Vendor string is %s\n", inquiryData->VendorId);
  1578. //
  1579. // Create name for cdrom object.
  1580. //
  1581. LookupTable->DevicePath =
  1582. ExAllocatePool( NonPagedPool, sizeof("scsi(%d)cdrom(%d)fdisk(%d)"));
  1583. if (LookupTable->DevicePath == NULL) {
  1584. return;
  1585. }
  1586. sprintf(LookupTable->DevicePath,
  1587. "scsi(%d)cdrom(%d)fdisk(%d)",
  1588. scsiNumber,
  1589. SCSI_COMBINE_BUS_TARGET( lunInfo->PathId, lunInfo->TargetId ),
  1590. lunInfo->Lun
  1591. );
  1592. LookupTable->DispatchTable = &ScsiDiskEntryTable;
  1593. if (DeviceFound) {
  1594. DeviceFound( scsiNumber,
  1595. SCSI_COMBINE_BUS_TARGET( lunInfo->PathId, lunInfo->TargetId ),
  1596. lunInfo->Lun,
  1597. TRUE
  1598. );
  1599. }
  1600. //
  1601. // If the cdrom controller entry does not exist, add it to
  1602. // the configuration database.
  1603. //
  1604. ControllerComponent = FwGetComponent(LookupTable->DevicePath);
  1605. if (ControllerComponent != NULL) {
  1606. if (ControllerComponent->Type != CdromController) {
  1607. ControllerEntry.Class = ControllerClass;
  1608. ControllerEntry.Type = CdromController;
  1609. ControllerEntry.Flags.Failed = 0;
  1610. ControllerEntry.Flags.ReadOnly = 1;
  1611. ControllerEntry.Flags.Removable = 1;
  1612. ControllerEntry.Flags.ConsoleIn = 0;
  1613. ControllerEntry.Flags.ConsoleOut = 0;
  1614. ControllerEntry.Flags.Output = 0;
  1615. ControllerEntry.Flags.Input = 1;
  1616. ControllerEntry.Version = 0;
  1617. ControllerEntry.Revision = 0;
  1618. ControllerEntry.Key = SCSI_COMBINE_BUS_TARGET( lunInfo->PathId, lunInfo->TargetId );
  1619. ControllerEntry.AffinityMask = 0xffffffff;
  1620. ControllerEntry.ConfigurationDataLength = 0;
  1621. Identifier =
  1622. ExAllocatePool( NonPagedPool,
  1623. strlen(inquiryData->VendorId)
  1624. );
  1625. if (Identifier == NULL) {
  1626. return;
  1627. }
  1628. sprintf(Identifier,
  1629. inquiryData->VendorId
  1630. );
  1631. ControllerEntry.IdentifierLength = strlen(Identifier);
  1632. ControllerEntry.Identifier = Identifier;
  1633. ControllerComponent = FwAddChild(ScsiComponent, &ControllerEntry, NULL);
  1634. }
  1635. }
  1636. //
  1637. // Add disk peripheral entry to the configuration database.
  1638. //
  1639. PeripheralEntry.Class = PeripheralClass;
  1640. PeripheralEntry.Type = FloppyDiskPeripheral;
  1641. PeripheralEntry.Flags.Failed = 0;
  1642. PeripheralEntry.Flags.ReadOnly = 1;
  1643. PeripheralEntry.Flags.Removable = 1;
  1644. PeripheralEntry.Flags.ConsoleIn = 0;
  1645. PeripheralEntry.Flags.ConsoleOut = 0;
  1646. PeripheralEntry.Flags.Output = 0;
  1647. PeripheralEntry.Flags.Input = 1;
  1648. PeripheralEntry.Version = 0;
  1649. PeripheralEntry.Revision = 0;
  1650. PeripheralEntry.Key = lunInfo->Lun;
  1651. PeripheralEntry.AffinityMask = 0xffffffff;
  1652. PeripheralEntry.ConfigurationDataLength = 0;
  1653. PeripheralEntry.IdentifierLength = 0;
  1654. PeripheralEntry.Identifier = NULL;
  1655. FwAddChild(ControllerComponent, &PeripheralEntry, NULL);
  1656. //
  1657. // Increment to the next entry.
  1658. //
  1659. LookupTable++;
  1660. lookupTableIndex++;
  1661. if (lookupTableIndex >= Entries) {
  1662. //
  1663. // There is no more space in the caller provided buffer
  1664. // for disk information. Return.
  1665. //
  1666. return;
  1667. }
  1668. //
  1669. // Claim disk device by marking configuration
  1670. // record owned.
  1671. //
  1672. lunInfo->DeviceClaimed = TRUE;
  1673. }
  1674. //
  1675. // Get next LunInfo.
  1676. //
  1677. lunInfo = lunInfo->NextLunInfo;
  1678. }
  1679. }
  1680. }
  1681. // ScsiDebugPrint(1,"FindScsiDevices: Hit any key\n");
  1682. // PAUSE;
  1683. }
  1684. NTSTATUS
  1685. ScsiDiskBootIO (
  1686. IN PMDL MdlAddress,
  1687. IN ULONG LogicalBlock,
  1688. IN PPARTITION_CONTEXT PartitionContext,
  1689. IN BOOLEAN Operation
  1690. )
  1691. /*++
  1692. Routine Description:
  1693. This routine is the read/write routine for the hard disk boot driver.
  1694. Arguments:
  1695. MdlAddress - Supplies a pointer to an MDL for the IO operation.
  1696. LogicalBlock - Supplies the starting block number.
  1697. DeviceUnit - Supplies the SCSI Id number.
  1698. Operation - Specifies the IO operation to perform
  1699. TRUE = SCSI_READ
  1700. FALSE = SCSI_WRITE.
  1701. Return Value:
  1702. The final status of the read operation (STATUS_UNSUCCESSFUL or
  1703. STATUS_SUCCESS).
  1704. --*/
  1705. {
  1706. ARC_STATUS Status;
  1707. PIRP Irp;
  1708. PIO_STACK_LOCATION NextIrpStack;
  1709. PSCSI_REQUEST_BLOCK Srb;
  1710. ULONG RetryCount = MAXIMUM_RETRIES;
  1711. //
  1712. // Check that the request is within the limits of the partition.
  1713. //
  1714. if (PartitionContext->StartingSector > LogicalBlock) {
  1715. return STATUS_UNSUCCESSFUL;
  1716. }
  1717. if (PartitionContext->EndingSector <
  1718. LogicalBlock + (MdlAddress->ByteCount >> PartitionContext->SectorShift)) {
  1719. return STATUS_UNSUCCESSFUL;
  1720. }
  1721. Retry:
  1722. //
  1723. // Build the I/O Request.
  1724. //
  1725. Irp = BuildRequest(PartitionContext, MdlAddress, LogicalBlock, Operation);
  1726. NextIrpStack = IoGetNextIrpStackLocation(Irp);
  1727. Srb = NextIrpStack->Parameters.Others.Argument1;
  1728. //
  1729. // Call the port driver.
  1730. //
  1731. IoCallDriver(PartitionContext->PortDeviceObject, Irp);
  1732. //
  1733. // Check the status.
  1734. //
  1735. if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  1736. //
  1737. // Determine the cause of the error.
  1738. //
  1739. if (InterpretSenseInfo(Srb, &Status, PartitionContext) && RetryCount--) {
  1740. goto Retry;
  1741. }
  1742. if (Status == EAGAIN) {
  1743. Status = EIO;
  1744. }
  1745. DebugPrint((1, "SCSI: Read request failed. Arc Status: %d, Srb Status: %x\n",
  1746. Status,
  1747. Srb->SrbStatus
  1748. ));
  1749. } else {
  1750. Status = ESUCCESS;
  1751. }
  1752. return(Status);
  1753. }
  1754. ARC_STATUS
  1755. ReadDriveCapacity(
  1756. IN PPARTITION_CONTEXT PartitionContext
  1757. )
  1758. /*++
  1759. Routine Description:
  1760. This routine sends a read capacity to a target id and returns
  1761. when it is complete.
  1762. Arguments:
  1763. Return Value:
  1764. Status is returned.
  1765. --*/
  1766. {
  1767. PCDB Cdb;
  1768. PSCSI_REQUEST_BLOCK Srb = &PrimarySrb.Srb;
  1769. ULONG LastSector;
  1770. ULONG retries = 1;
  1771. ARC_STATUS status;
  1772. ULONG BytesPerSector;
  1773. ScsiDebugPrint(3,"SCSI ReadCapacity: Enter routine\n");
  1774. //
  1775. // Build the read capacity CDB.
  1776. //
  1777. Srb->CdbLength = 10;
  1778. Cdb = (PCDB)Srb->Cdb;
  1779. //
  1780. // Zero CDB in SRB on stack.
  1781. //
  1782. RtlZeroMemory(Cdb, MAXIMUM_CDB_SIZE);
  1783. Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
  1784. Retry:
  1785. status = SendSrbSynchronous(PartitionContext,
  1786. Srb,
  1787. ReadCapacityBuffer,
  1788. sizeof(READ_CAPACITY_DATA),
  1789. FALSE);
  1790. if (status == ESUCCESS) {
  1791. #if 0
  1792. //
  1793. // Copy sector size from read capacity buffer to device extension
  1794. // in reverse byte order.
  1795. //
  1796. deviceExtension->DiskGeometry->BytesPerSector = 0;
  1797. ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte0 =
  1798. ((PFOUR_BYTE)&ReadCapacityBuffer->BytesPerBlock)->Byte3;
  1799. ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte1 =
  1800. ((PFOUR_BYTE)&ReadCapacityBuffer->BytesPerBlock)->Byte2;
  1801. if (BytesPerSector == 0) {
  1802. //
  1803. // Assume this is a bad cd-rom and the sector size is 2048.
  1804. //
  1805. BytesPerSector = 2048;
  1806. }
  1807. //
  1808. // Make sure the sector size is less than the maximum expected.
  1809. //
  1810. ASSERT(BytesPerSector <= MAXIMUM_SECTOR_SIZE);
  1811. if (BytesPerSector > MAXIMUM_SECTOR_SIZE) {
  1812. return(EINVAL);
  1813. }
  1814. //
  1815. // Copy last sector in reverse byte order.
  1816. //
  1817. ((PFOUR_BYTE)&LastSector)->Byte0 =
  1818. ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte3;
  1819. ((PFOUR_BYTE)&LastSector)->Byte1 =
  1820. ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte2;
  1821. ((PFOUR_BYTE)&LastSector)->Byte2 =
  1822. ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte1;
  1823. ((PFOUR_BYTE)&LastSector)->Byte3 =
  1824. ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte0;
  1825. //
  1826. // Calculate sector to byte shift.
  1827. //
  1828. WHICH_BIT(deviceExtension->DiskGeometry->BytesPerSector, deviceExtension->SectorShift);
  1829. ScsiDebugPrint(2,"SCSI ReadDriveCapacity: Sector size is %d\n",
  1830. deviceExtension->DiskGeometry->BytesPerSector);
  1831. ScsiDebugPrint(2,"SCSI ReadDriveCapacity: Number of Sectors is %d\n",
  1832. LastSector + 1);
  1833. //
  1834. // Calculate media capacity in bytes.
  1835. //
  1836. deviceExtension->PartitionLength = LastSector + 1;
  1837. deviceExtension->PartitionLength.QuadPart <<= deviceExtension->SectorShift.QuadPart;
  1838. //
  1839. // Assume media type is fixed disk.
  1840. //
  1841. deviceExtension->DiskGeometry->MediaType = FixedMedia;
  1842. //
  1843. // Assume sectors per track are 32;
  1844. //
  1845. deviceExtension->DiskGeometry->SectorsPerTrack = 32;
  1846. //
  1847. // Assume tracks per cylinder (number of heads) is 64.
  1848. //
  1849. deviceExtension->DiskGeometry->TracksPerCylinder = 64;
  1850. #else
  1851. BytesPerSector = 0;
  1852. //
  1853. // Copy sector size from read capacity buffer to device extension
  1854. // in reverse byte order.
  1855. //
  1856. ((PFOUR_BYTE)&BytesPerSector)->Byte0 =
  1857. ((PFOUR_BYTE)&ReadCapacityBuffer->BytesPerBlock)->Byte3;
  1858. ((PFOUR_BYTE)&BytesPerSector)->Byte1 =
  1859. ((PFOUR_BYTE)&ReadCapacityBuffer->BytesPerBlock)->Byte2;
  1860. if (BytesPerSector == 0) {
  1861. //
  1862. // Assume this is a bad cd-rom and the sector size is 2048.
  1863. //
  1864. BytesPerSector = 2048;
  1865. }
  1866. //
  1867. // Calculate sector to byte shift.
  1868. //
  1869. WHICH_BIT(BytesPerSector, PartitionContext->SectorShift);
  1870. //
  1871. // Copy last sector in reverse byte order.
  1872. //
  1873. ((PFOUR_BYTE)&LastSector)->Byte0 =
  1874. ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte3;
  1875. ((PFOUR_BYTE)&LastSector)->Byte1 =
  1876. ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte2;
  1877. ((PFOUR_BYTE)&LastSector)->Byte2 =
  1878. ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte1;
  1879. ((PFOUR_BYTE)&LastSector)->Byte3 =
  1880. ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte0;
  1881. PartitionContext->PartitionLength.QuadPart = LastSector + 1;
  1882. PartitionContext->PartitionLength.QuadPart <<= PartitionContext->SectorShift;
  1883. PartitionContext->StartingSector=0;
  1884. PartitionContext->EndingSector = LastSector + 1;
  1885. ScsiDebugPrint(2,"SCSI ReadDriveCapacity: Sector size is %d\n",
  1886. BytesPerSector);
  1887. ScsiDebugPrint(2,"SCSI ReadDriveCapacity: Number of Sectors is %d\n",
  1888. LastSector + 1);
  1889. #endif
  1890. }
  1891. if (status == EAGAIN || status == EBUSY) {
  1892. if (retries--) {
  1893. //
  1894. // Retry request.
  1895. //
  1896. goto Retry;
  1897. }
  1898. }
  1899. return status;
  1900. } // end ReadDriveCapacity()
  1901. ARC_STATUS
  1902. SendSrbSynchronous(
  1903. PPARTITION_CONTEXT PartitionContext,
  1904. PSCSI_REQUEST_BLOCK Srb,
  1905. PVOID BufferAddress,
  1906. ULONG BufferLength,
  1907. BOOLEAN WriteToDevice
  1908. )
  1909. /*++
  1910. Routine Description:
  1911. This routine is called by SCSI device controls to complete an
  1912. SRB and send it to the port driver synchronously (ie wait for
  1913. completion).
  1914. The CDB is already completed along with the SRB CDB size and
  1915. request timeout value.
  1916. Arguments:
  1917. PartitionContext
  1918. SRB
  1919. Buffer address and length (if transfer)
  1920. WriteToDevice - Indicates the direction of the transfer.
  1921. Return Value:
  1922. ARC_STATUS
  1923. --*/
  1924. {
  1925. PIRP Irp;
  1926. PIO_STACK_LOCATION IrpStack;
  1927. ULONG retryCount = 1;
  1928. ARC_STATUS status;
  1929. //
  1930. // Write length to SRB.
  1931. //
  1932. Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  1933. //
  1934. // Set SCSI bus address.
  1935. //
  1936. Srb->PathId = PartitionContext->PathId;
  1937. Srb->TargetId = PartitionContext->TargetId;
  1938. Srb->Lun = PartitionContext->DiskId;
  1939. Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  1940. //
  1941. // Enable auto request sense.
  1942. //
  1943. Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  1944. if (SenseInfoBuffer == NULL) {
  1945. // This DbgPrint has been commented out. On IA64 and AXP64,
  1946. // it crashes unless booted with a boot debugger.
  1947. //("SendSrbSynchronous: Can't allocate request sense buffer\n");
  1948. return(ENOMEM);
  1949. }
  1950. Srb->SenseInfoBuffer = SenseInfoBuffer;
  1951. Srb->DataBuffer = BufferAddress;
  1952. //
  1953. // Start retries here.
  1954. //
  1955. retry:
  1956. Irp = InitializeIrp(
  1957. &PrimarySrb,
  1958. IRP_MJ_SCSI,
  1959. PartitionContext->PortDeviceObject,
  1960. BufferAddress,
  1961. BufferLength
  1962. );
  1963. if (BufferAddress != NULL) {
  1964. if (WriteToDevice) {
  1965. Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
  1966. } else {
  1967. Srb->SrbFlags = SRB_FLAGS_DATA_IN;
  1968. }
  1969. } else {
  1970. //
  1971. // Clear flags.
  1972. //
  1973. Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
  1974. }
  1975. //
  1976. // Disable synchronous transfers.
  1977. //
  1978. Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  1979. //
  1980. // Set the transfer length.
  1981. //
  1982. Srb->DataTransferLength = BufferLength;
  1983. //
  1984. // Zero out status.
  1985. //
  1986. Srb->ScsiStatus = Srb->SrbStatus = 0;
  1987. //
  1988. // Get next stack location and
  1989. // set major function code.
  1990. //
  1991. IrpStack = IoGetNextIrpStackLocation(Irp);
  1992. //
  1993. // Set up SRB for execute scsi request.
  1994. // Save SRB address in next stack for port driver.
  1995. //
  1996. IrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
  1997. //
  1998. // Set up IRP Address.
  1999. //
  2000. Srb->OriginalRequest = Irp;
  2001. Srb->NextSrb = 0;
  2002. //
  2003. // No need to check the following 2 returned statuses as
  2004. // SRB will have ending status.
  2005. //
  2006. (VOID)IoCallDriver(PartitionContext->PortDeviceObject, Irp);
  2007. //
  2008. // Check that request completed without error.
  2009. //
  2010. if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  2011. //
  2012. // Update status and determine if request should be retried.
  2013. //
  2014. if (InterpretSenseInfo(Srb, &status, PartitionContext)) {
  2015. //
  2016. // If retries are not exhausted then
  2017. // retry this operation.
  2018. //
  2019. if (retryCount--) {
  2020. goto retry;
  2021. }
  2022. }
  2023. } else {
  2024. status = ESUCCESS;
  2025. }
  2026. return status;
  2027. } // end SendSrbSynchronous()
  2028. BOOLEAN
  2029. InterpretSenseInfo(
  2030. IN PSCSI_REQUEST_BLOCK Srb,
  2031. OUT ARC_STATUS *Status,
  2032. PPARTITION_CONTEXT PartitionContext
  2033. )
  2034. /*++
  2035. Routine Description:
  2036. This routine interprets the data returned from the SCSI
  2037. request sense. It determines the status to return in the
  2038. IRP and whether this request can be retried.
  2039. Arguments:
  2040. DeviceObject
  2041. SRB
  2042. ARC_STATUS to update IRP
  2043. Return Value:
  2044. BOOLEAN TRUE: Drivers should retry this request.
  2045. FALSE: Drivers should not retry this request.
  2046. --*/
  2047. {
  2048. PSENSE_DATA SenseBuffer = Srb->SenseInfoBuffer;
  2049. BOOLEAN retry;
  2050. //
  2051. // Check that request sense buffer is valid.
  2052. //
  2053. if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
  2054. ScsiDebugPrint(2,"InterpretSenseInfo: Error code is %x\n",
  2055. SenseBuffer->ErrorCode);
  2056. ScsiDebugPrint(2,"InterpretSenseInfo: Sense key is %x\n",
  2057. SenseBuffer->SenseKey);
  2058. ScsiDebugPrint(2,"InterpretSenseInfo: Additional sense code is %x\n",
  2059. SenseBuffer->AdditionalSenseCode);
  2060. ScsiDebugPrint(2,"InterpretSenseInfo: Additional sense code qualifier is %x\n",
  2061. SenseBuffer->AdditionalSenseCodeQualifier);
  2062. switch (SenseBuffer->SenseKey) {
  2063. case SCSI_SENSE_NOT_READY:
  2064. ScsiDebugPrint(1,"InterpretSenseInfo: Device not ready\n");
  2065. ScsiDebugPrint(1,"InterpretSenseInfo: Waiting for device\n");
  2066. *Status = EBUSY;
  2067. retry = TRUE;
  2068. switch (SenseBuffer->AdditionalSenseCode) {
  2069. case SCSI_ADSENSE_LUN_NOT_READY:
  2070. ScsiDebugPrint(1,"InterpretSenseInfo: Lun not ready\n");
  2071. switch (SenseBuffer->AdditionalSenseCodeQualifier) {
  2072. case SCSI_SENSEQ_BECOMING_READY:
  2073. ScsiDebugPrint(1,
  2074. "InterpretSenseInfo:"
  2075. " In process of becoming ready\n");
  2076. FwStallExecution( 1000 * 1000 * 3 );
  2077. break;
  2078. case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
  2079. ScsiDebugPrint(1,
  2080. "InterpretSenseInfo:"
  2081. " Manual intervention required\n");
  2082. *Status = (ARC_STATUS)STATUS_NO_MEDIA_IN_DEVICE;
  2083. retry = FALSE;
  2084. break;
  2085. case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
  2086. ScsiDebugPrint(1,
  2087. "InterpretSenseInfo:"
  2088. " Format in progress\n");
  2089. retry = FALSE;
  2090. break;
  2091. default:
  2092. FwStallExecution( 1000 * 1000 * 3 );
  2093. //
  2094. // Try a start unit too.
  2095. //
  2096. case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
  2097. ScsiDebugPrint(1,
  2098. "InterpretSenseInfo:"
  2099. " Initializing command required\n");
  2100. //
  2101. // This sense code/additional sense code
  2102. // combination may indicate that the device
  2103. // needs to be started.
  2104. //
  2105. ScsiDiskStartUnit(PartitionContext);
  2106. break;
  2107. }
  2108. } // end switch
  2109. break;
  2110. case SCSI_SENSE_DATA_PROTECT:
  2111. ScsiDebugPrint(1,"InterpretSenseInfo: Media write protected\n");
  2112. *Status = EACCES;
  2113. retry = FALSE;
  2114. break;
  2115. case SCSI_SENSE_MEDIUM_ERROR:
  2116. ScsiDebugPrint(1,"InterpretSenseInfo: Bad media\n");
  2117. *Status = EIO;
  2118. retry = TRUE;
  2119. break;
  2120. case SCSI_SENSE_HARDWARE_ERROR:
  2121. ScsiDebugPrint(1,"InterpretSenseInfo: Hardware error\n");
  2122. *Status = EIO;
  2123. retry = TRUE;
  2124. break;
  2125. case SCSI_SENSE_ILLEGAL_REQUEST:
  2126. ScsiDebugPrint(1,"InterpretSenseInfo: Illegal SCSI request\n");
  2127. switch (SenseBuffer->AdditionalSenseCode) {
  2128. case SCSI_ADSENSE_ILLEGAL_COMMAND:
  2129. ScsiDebugPrint(1,"InterpretSenseInfo: Illegal command\n");
  2130. break;
  2131. case SCSI_ADSENSE_ILLEGAL_BLOCK:
  2132. ScsiDebugPrint(1,"InterpretSenseInfo: Illegal block address\n");
  2133. break;
  2134. case SCSI_ADSENSE_INVALID_LUN:
  2135. ScsiDebugPrint(1,"InterpretSenseInfo: Invalid LUN\n");
  2136. break;
  2137. case SCSI_ADSENSE_MUSIC_AREA:
  2138. ScsiDebugPrint(1,"InterpretSenseInfo: Music area\n");
  2139. break;
  2140. case SCSI_ADSENSE_DATA_AREA:
  2141. ScsiDebugPrint(1,"InterpretSenseInfo: Data area\n");
  2142. break;
  2143. case SCSI_ADSENSE_VOLUME_OVERFLOW:
  2144. ScsiDebugPrint(1,"InterpretSenseInfo: Volume overflow\n");
  2145. } // end switch ...
  2146. *Status = EINVAL;
  2147. retry = FALSE;
  2148. break;
  2149. case SCSI_SENSE_UNIT_ATTENTION:
  2150. ScsiDebugPrint(3,"InterpretSenseInfo: Unit attention\n");
  2151. switch (SenseBuffer->AdditionalSenseCode) {
  2152. case SCSI_ADSENSE_MEDIUM_CHANGED:
  2153. ScsiDebugPrint(1,"InterpretSenseInfo: Media changed\n");
  2154. break;
  2155. case SCSI_ADSENSE_BUS_RESET:
  2156. ScsiDebugPrint(1,"InterpretSenseInfo: Bus reset\n");
  2157. }
  2158. *Status = EAGAIN;
  2159. retry = TRUE;
  2160. break;
  2161. case SCSI_SENSE_ABORTED_COMMAND:
  2162. ScsiDebugPrint(1,"InterpretSenseInfo: Command aborted\n");
  2163. *Status = EIO;
  2164. retry = TRUE;
  2165. break;
  2166. case SCSI_SENSE_NO_SENSE:
  2167. ScsiDebugPrint(1,"InterpretSenseInfo: No specific sense key\n");
  2168. *Status = EIO;
  2169. retry = TRUE;
  2170. break;
  2171. default:
  2172. ScsiDebugPrint(1,"InterpretSenseInfo: Unrecognized sense code\n");
  2173. *Status = (ARC_STATUS)STATUS_UNSUCCESSFUL;
  2174. retry = TRUE;
  2175. } // end switch
  2176. } else {
  2177. //
  2178. // Request sense buffer not valid. No sense information
  2179. // to pinpoint the error. Return general request fail.
  2180. //
  2181. ScsiDebugPrint(1,"InterpretSenseInfo: Request sense info not valid\n");
  2182. *Status = EIO;
  2183. retry = TRUE;
  2184. }
  2185. //
  2186. // If this is the primary srb, then reinitialize any bad scsi devices.
  2187. //
  2188. if (Srb == &PrimarySrb.Srb) {
  2189. ScsiDiskFilterBad(PartitionContext);
  2190. }
  2191. return retry;
  2192. } // end InterpretSenseInfo()
  2193. VOID
  2194. RetryRequest(
  2195. PPARTITION_CONTEXT PartitionContext,
  2196. PIRP Irp
  2197. )
  2198. /*++
  2199. Routine Description:
  2200. Arguments:
  2201. Return Value:
  2202. --*/
  2203. {
  2204. PIO_STACK_LOCATION NextIrpStack = IoGetNextIrpStackLocation(Irp);
  2205. PSCSI_REQUEST_BLOCK Srb = &PrimarySrb.Srb;
  2206. PMDL Mdl = Irp->MdlAddress;
  2207. ULONG TransferByteCount = Mdl->ByteCount;
  2208. //
  2209. // Reset byte count of transfer in SRB Extension.
  2210. //
  2211. Srb->DataTransferLength = TransferByteCount;
  2212. //
  2213. // Zero SRB statuses.
  2214. //
  2215. Srb->SrbStatus = Srb->ScsiStatus = 0;
  2216. //
  2217. // Set up major SCSI function.
  2218. //
  2219. NextIrpStack->MajorFunction = IRP_MJ_SCSI;
  2220. //
  2221. // Save SRB address in next stack for port driver.
  2222. //
  2223. NextIrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
  2224. //
  2225. // Return the results of the call to the port driver.
  2226. //
  2227. (PVOID)IoCallDriver(PartitionContext->PortDeviceObject, Irp);
  2228. return;
  2229. } // end RetryRequest()
  2230. PIRP
  2231. BuildRequest(
  2232. IN PPARTITION_CONTEXT PartitionContext,
  2233. IN PMDL Mdl,
  2234. IN ULONG LogicalBlockAddress,
  2235. IN BOOLEAN Operation
  2236. )
  2237. /*++
  2238. Routine Description:
  2239. Arguments:
  2240. Note:
  2241. If the IRP is for a disk transfer, the byteoffset field
  2242. will already have been adjusted to make it relative to
  2243. the beginning of the disk. In this way, this routine can
  2244. be shared between the disk and cdrom class drivers.
  2245. - Operation TRUE specifies that this is a READ operation
  2246. FALSE specifies that this is a WRITE operation
  2247. Return Value:
  2248. --*/
  2249. {
  2250. PIRP Irp = &PrimarySrb.Irp;
  2251. PIO_STACK_LOCATION NextIrpStack;
  2252. PSCSI_REQUEST_BLOCK Srb = &PrimarySrb.Srb;
  2253. PCDB Cdb;
  2254. USHORT TransferBlocks;
  2255. //
  2256. // Initialize the rest of the IRP.
  2257. //
  2258. Irp->MdlAddress = Mdl;
  2259. Irp->Tail.Overlay.CurrentStackLocation = &PrimarySrb.IrpStack[IRP_STACK_SIZE];
  2260. NextIrpStack = IoGetNextIrpStackLocation(Irp);
  2261. //
  2262. // Write length to SRB.
  2263. //
  2264. Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  2265. //
  2266. // Set up IRP Address.
  2267. //
  2268. Srb->OriginalRequest = Irp;
  2269. Srb->NextSrb = 0;
  2270. //
  2271. // Set up target id and logical unit number.
  2272. //
  2273. Srb->PathId = PartitionContext->PathId;
  2274. Srb->TargetId = PartitionContext->TargetId;
  2275. Srb->Lun = PartitionContext->DiskId;
  2276. Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  2277. Srb->DataBuffer = MmGetMdlVirtualAddress(Mdl);
  2278. //
  2279. // Save byte count of transfer in SRB Extension.
  2280. //
  2281. Srb->DataTransferLength = Mdl->ByteCount;
  2282. //
  2283. // Indicate auto request sense by specifying buffer and size.
  2284. //
  2285. Srb->SenseInfoBuffer = SenseInfoBuffer;
  2286. Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  2287. //
  2288. // Set timeout value in seconds.
  2289. //
  2290. Srb->TimeOutValue = SCSI_DISK_TIMEOUT;
  2291. //
  2292. // Zero statuses.
  2293. //
  2294. Srb->SrbStatus = Srb->ScsiStatus = 0;
  2295. //
  2296. // Indicate that 10-byte CDB's will be used.
  2297. //
  2298. Srb->CdbLength = 10;
  2299. //
  2300. // Fill in CDB fields.
  2301. //
  2302. Cdb = (PCDB)Srb->Cdb;
  2303. Cdb->CDB10.LogicalUnitNumber = PartitionContext->DiskId;
  2304. TransferBlocks = (USHORT)(Mdl->ByteCount >> PartitionContext->SectorShift);
  2305. //
  2306. // Move little endian values into CDB in big endian format.
  2307. //
  2308. Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte3;
  2309. Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte2;
  2310. Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte1;
  2311. Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte0;
  2312. Cdb->CDB10.Reserved2 = 0;
  2313. Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&TransferBlocks)->Byte1;
  2314. Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&TransferBlocks)->Byte0;
  2315. Cdb->CDB10.Control = 0;
  2316. //
  2317. // Set transfer direction flag and Cdb command.
  2318. //
  2319. if (Operation) {
  2320. ScsiDebugPrint(3, "BuildRequest: Read Command\n");
  2321. Srb->SrbFlags = SRB_FLAGS_DATA_IN;
  2322. Cdb->CDB10.OperationCode = SCSIOP_READ;
  2323. } else {
  2324. ScsiDebugPrint(3, "BuildRequest: Write Command\n");
  2325. Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
  2326. Cdb->CDB10.OperationCode = SCSIOP_WRITE;
  2327. }
  2328. //
  2329. // Disable synchronous transfers.
  2330. //
  2331. Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  2332. //
  2333. // Set up major SCSI function.
  2334. //
  2335. NextIrpStack->MajorFunction = IRP_MJ_SCSI;
  2336. //
  2337. // Save SRB address in next stack for port driver.
  2338. //
  2339. NextIrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
  2340. return(Irp);
  2341. } // end BuildRequest()
  2342. VOID
  2343. ScsiDiskStartUnit(
  2344. IN PPARTITION_CONTEXT PartitionContext
  2345. )
  2346. /*++
  2347. Routine Description:
  2348. Send command to SCSI unit to start or power up.
  2349. Because this command is issued asynchronounsly, that is without
  2350. waiting on it to complete, the IMMEDIATE flag is not set. This
  2351. means that the CDB will not return until the drive has powered up.
  2352. This should keep subsequent requests from being submitted to the
  2353. device before it has completely spun up.
  2354. This routine is called from the InterpretSense routine, when a
  2355. request sense returns data indicating that a drive must be
  2356. powered up.
  2357. Arguments:
  2358. PartitionContext - structure containing pointer to port device driver.
  2359. Return Value:
  2360. None.
  2361. --*/
  2362. {
  2363. PIO_STACK_LOCATION irpStack;
  2364. PIRP irp;
  2365. PSCSI_REQUEST_BLOCK srb = &AbortSrb.Srb;
  2366. PSCSI_REQUEST_BLOCK originalSrb = &PrimarySrb.Srb;
  2367. PCDB cdb;
  2368. ScsiDebugPrint(1,"StartUnit: Enter routine\n");
  2369. //
  2370. // Write length to SRB.
  2371. //
  2372. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  2373. //
  2374. // Set up SCSI bus address.
  2375. //
  2376. srb->PathId = originalSrb->PathId;
  2377. srb->TargetId = originalSrb->TargetId;
  2378. srb->Lun = originalSrb->Lun;
  2379. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  2380. //
  2381. // Zero out status.
  2382. //
  2383. srb->ScsiStatus = srb->SrbStatus = 0;
  2384. //
  2385. // Set timeout value large enough for drive to spin up.
  2386. // NOTE: This value is arbitrary.
  2387. //
  2388. srb->TimeOutValue = 30;
  2389. //
  2390. // Set the transfer length.
  2391. //
  2392. srb->DataTransferLength = 0;
  2393. srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE;
  2394. srb->SenseInfoBufferLength = 0;
  2395. srb->SenseInfoBuffer = NULL;
  2396. //
  2397. // Build the start unit CDB.
  2398. //
  2399. srb->CdbLength = 6;
  2400. cdb = (PCDB)srb->Cdb;
  2401. RtlZeroMemory(cdb, sizeof(CDB));
  2402. cdb->CDB10.OperationCode = SCSIOP_START_STOP_UNIT;
  2403. cdb->START_STOP.Start = 1;
  2404. //
  2405. // Build the IRP
  2406. // to be sent to the port driver.
  2407. //
  2408. irp = InitializeIrp(
  2409. &AbortSrb,
  2410. IRP_MJ_SCSI,
  2411. PartitionContext->PortDeviceObject,
  2412. NULL,
  2413. 0
  2414. );
  2415. irpStack = IoGetNextIrpStackLocation(irp);
  2416. irpStack->MajorFunction = IRP_MJ_SCSI;
  2417. srb->OriginalRequest = irp;
  2418. //
  2419. // Save SRB address in next stack for port driver.
  2420. //
  2421. irpStack->Parameters.Others.Argument1 = srb;
  2422. //
  2423. // No need to check the following 2 returned statuses as
  2424. // SRB will have ending status.
  2425. //
  2426. IoCallDriver(PartitionContext->PortDeviceObject, irp);
  2427. } // end StartUnit()
  2428. ULONG
  2429. ClassModeSense(
  2430. IN PPARTITION_CONTEXT Context,
  2431. IN PCHAR ModeSenseBuffer,
  2432. IN ULONG Length,
  2433. IN UCHAR PageMode
  2434. )
  2435. /*++
  2436. Routine Description:
  2437. This routine sends a mode sense command to a target id and returns
  2438. when it is complete.
  2439. Arguments:
  2440. Return Value:
  2441. Length of the transferred data is returned.
  2442. --*/
  2443. {
  2444. PCDB cdb;
  2445. PSCSI_REQUEST_BLOCK Srb = &PrimarySrb.Srb;
  2446. ULONG retries = 1;
  2447. NTSTATUS status;
  2448. DebugPrint((3,"SCSI ModeSense: Enter routine\n"));
  2449. //
  2450. // Build the read capacity CDB.
  2451. //
  2452. Srb->CdbLength = 6;
  2453. cdb = (PCDB)Srb->Cdb;
  2454. //
  2455. // Set timeout value.
  2456. //
  2457. Srb->TimeOutValue = 2;
  2458. RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE);
  2459. cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  2460. cdb->MODE_SENSE.PageCode = PageMode;
  2461. cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
  2462. Retry:
  2463. status = SendSrbSynchronous(Context,
  2464. Srb,
  2465. ModeSenseBuffer,
  2466. Length,
  2467. FALSE);
  2468. if (status == EAGAIN || status == EBUSY) {
  2469. //
  2470. // Routine SendSrbSynchronous does not retry
  2471. // requests returned with this status.
  2472. // Read Capacities should be retried
  2473. // anyway.
  2474. //
  2475. if (retries--) {
  2476. //
  2477. // Retry request.
  2478. //
  2479. goto Retry;
  2480. }
  2481. } else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  2482. status = STATUS_SUCCESS;
  2483. }
  2484. if (NT_SUCCESS(status)) {
  2485. return(Srb->DataTransferLength);
  2486. } else {
  2487. return(0);
  2488. }
  2489. } // end ClassModeSense()
  2490. PVOID
  2491. ClassFindModePage(
  2492. IN PCHAR ModeSenseBuffer,
  2493. IN ULONG Length,
  2494. IN UCHAR PageMode
  2495. )
  2496. /*++
  2497. Routine Description:
  2498. This routine scans through the mode sense data and finds the requested
  2499. mode sense page code.
  2500. Arguments:
  2501. ModeSenseBuffer - Supplies a pointer to the mode sense data.
  2502. Length - Indicates the length of valid data.
  2503. PageMode - Supplies the page mode to be searched for.
  2504. Return Value:
  2505. A pointer to the the requested mode page. If the mode page was not found
  2506. then NULL is return.
  2507. --*/
  2508. {
  2509. PUCHAR limit;
  2510. limit = ModeSenseBuffer + Length;
  2511. //
  2512. // Skip the mode select header and block descriptors.
  2513. //
  2514. if (Length < sizeof(MODE_PARAMETER_HEADER)) {
  2515. return(NULL);
  2516. }
  2517. ModeSenseBuffer += sizeof(MODE_PARAMETER_HEADER) +
  2518. ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength;
  2519. //
  2520. // ModeSenseBuffer now points at pages walk the pages looking for the
  2521. // requested page until the limit is reached.
  2522. //
  2523. while (ModeSenseBuffer < limit) {
  2524. if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) {
  2525. return(ModeSenseBuffer);
  2526. }
  2527. //
  2528. // Adavance to the next page.
  2529. //
  2530. ModeSenseBuffer += ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 2;
  2531. }
  2532. return(NULL);
  2533. }
  2534. BOOLEAN
  2535. IsFloppyDevice(
  2536. PPARTITION_CONTEXT Context
  2537. )
  2538. /*++
  2539. Routine Description:
  2540. The routine performs the necessary functioons to determinee if a device is
  2541. really a floppy rather than a harddisk. This is done by a mode sense
  2542. command. First, a check is made to see if the medimum type is set. Second
  2543. a check is made for the flexible parameters mode page.
  2544. Arguments:
  2545. Context - Supplies the device object to be tested.
  2546. Return Value:
  2547. Return TRUE if the indicated device is a floppy.
  2548. --*/
  2549. {
  2550. PVOID modeData;
  2551. PUCHAR pageData;
  2552. ULONG length;
  2553. modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
  2554. if (modeData == NULL) {
  2555. return(FALSE);
  2556. }
  2557. RtlZeroMemory(modeData, MODE_DATA_SIZE);
  2558. length = ClassModeSense(Context,
  2559. modeData,
  2560. MODE_DATA_SIZE,
  2561. MODE_SENSE_RETURN_ALL);
  2562. if (length < sizeof(MODE_PARAMETER_HEADER)) {
  2563. //
  2564. // Retry the request in case of a check condition.
  2565. //
  2566. length = ClassModeSense(Context,
  2567. modeData,
  2568. MODE_DATA_SIZE,
  2569. MODE_SENSE_RETURN_ALL);
  2570. if (length < sizeof(MODE_PARAMETER_HEADER)) {
  2571. ExFreePool(modeData);
  2572. return(FALSE);
  2573. }
  2574. }
  2575. #if 0
  2576. if (((PMODE_PARAMETER_HEADER) modeData)->MediumType >= MODE_FD_SINGLE_SIDE
  2577. && ((PMODE_PARAMETER_HEADER) modeData)->MediumType <= MODE_FD_MAXIMUM_TYPE) {
  2578. DebugPrint((1, "Scsidisk: MediumType value %2x, This is a floppy.\n", ((PMODE_PARAMETER_HEADER) modeData)->MediumType));
  2579. ExFreePool(modeData);
  2580. return(TRUE);
  2581. }
  2582. #endif
  2583. //
  2584. // Look for the flexible disk mode page.
  2585. //
  2586. pageData = ClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE);
  2587. if (pageData != NULL) {
  2588. DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
  2589. ExFreePool(modeData);
  2590. return(TRUE);
  2591. }
  2592. ExFreePool(modeData);
  2593. return(FALSE);
  2594. } // end IsFloppyDevice()
  2595. VOID
  2596. ScsiDiskFilterBad(
  2597. IN PPARTITION_CONTEXT PartitionContext
  2598. )
  2599. /*++
  2600. Routine Description:
  2601. This routine looks for SCSI units which need special initialization
  2602. to operate correctly.
  2603. Arguments:
  2604. PartitionContext - structure containing pointer to port device driver.
  2605. Return Value:
  2606. None.
  2607. --*/
  2608. {
  2609. PSCSI_REQUEST_BLOCK srb = &AbortSrb.Srb;
  2610. PCDB cdb;
  2611. PDEVICE_EXTENSION scsiPort;
  2612. PSCSI_CONFIGURATION_INFO configInfo;
  2613. PSCSI_BUS_SCAN_DATA busScanData;
  2614. PUCHAR modePage;
  2615. ULONG busNumber;
  2616. PLUNINFO lunInfo;
  2617. PINQUIRYDATA inquiryData;
  2618. ScsiDebugPrint(3,"FilterBad: Enter routine\n");
  2619. scsiPort = PartitionContext->PortDeviceObject->DeviceExtension;
  2620. configInfo = scsiPort->ScsiInfo;
  2621. //
  2622. // Search the configuration database for scsi disk and cdrom devices
  2623. // which require special initializaion.
  2624. //
  2625. for (busNumber=0; busNumber < (ULONG)configInfo->NumberOfBuses; busNumber++) {
  2626. busScanData = configInfo->BusScanData[busNumber];
  2627. //
  2628. // Set LunInfo to beginning of list.
  2629. //
  2630. lunInfo = busScanData->LunInfoList;
  2631. while (lunInfo != NULL) {
  2632. inquiryData = (PVOID)lunInfo->InquiryData;
  2633. //
  2634. // Determin if this is the correct lun.
  2635. //
  2636. if (PartitionContext->PathId == lunInfo->PathId &&
  2637. PartitionContext->TargetId == lunInfo->TargetId &&
  2638. PartitionContext->DiskId == lunInfo->Lun) {
  2639. goto FoundOne;
  2640. }
  2641. //
  2642. // Get next LunInfo.
  2643. //
  2644. lunInfo = lunInfo->NextLunInfo;
  2645. }
  2646. }
  2647. return;
  2648. FoundOne:
  2649. //
  2650. // Zero out status.
  2651. //
  2652. srb->ScsiStatus = srb->SrbStatus = 0;
  2653. //
  2654. // Set timeout value.
  2655. //
  2656. srb->TimeOutValue = 2;
  2657. //
  2658. // Look for a bad devices.
  2659. //
  2660. if (strncmp(inquiryData->VendorId, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
  2661. strncmp(inquiryData->VendorId, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0) {
  2662. ScsiDebugPrint(1, "ScsiDiskFilterBad: Found Hitachi CDR-1750S.\n");
  2663. //
  2664. // Found a bad HITACHI cd-rom. These devices do not work with PIO
  2665. // adapters when read-ahead is enabled. Read-ahead is disabled by
  2666. // a mode select command. The mode select page code is zero and the
  2667. // length is 6 bytes. All of the other bytes should be zero.
  2668. //
  2669. modePage = ExAllocatePool(NonPagedPool, HITACHI_MODE_DATA_SIZE);
  2670. if (modePage == NULL) {
  2671. return;
  2672. }
  2673. RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE);
  2674. //
  2675. // Set the page length field to 6.
  2676. //
  2677. modePage[5] = 6;
  2678. //
  2679. // Build the mode select CDB.
  2680. //
  2681. srb->CdbLength = 6;
  2682. cdb = (PCDB)srb->Cdb;
  2683. RtlZeroMemory(cdb, sizeof(CDB));
  2684. cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
  2685. cdb->MODE_SELECT.ParameterListLength = HITACHI_MODE_DATA_SIZE;
  2686. //
  2687. // Send the request to the device.
  2688. //
  2689. SendSrbSynchronous(PartitionContext,
  2690. srb,
  2691. modePage,
  2692. HITACHI_MODE_DATA_SIZE,
  2693. TRUE);
  2694. ExFreePool(modePage);
  2695. }
  2696. } // end ScsiDiskFilterBad()
  2697. BOOLEAN
  2698. CheckFileId(
  2699. ULONG FileId
  2700. )
  2701. {
  2702. if (BlFileTable[FileId].u.PartitionContext.PortDeviceObject != NULL) {
  2703. return TRUE;
  2704. }
  2705. #if 0
  2706. DbgPrint("\n\rScsidisk: Bad file id passed to read or write. FileId = %lx\n", FileId);
  2707. DbgPrint("Start sector = %lx; Ending sector = %lx; Disk Id = %x; DeviceUnit = %x\n",
  2708. BlFileTable[FileId].u.PartitionContext.StartingSector,
  2709. BlFileTable[FileId].u.PartitionContext.EndingSector,
  2710. BlFileTable[FileId].u.PartitionContext.DiskId,
  2711. BlFileTable[FileId].u.PartitionContext.DeviceUnit
  2712. );
  2713. DbgPrint("Target Id = %d; Path Id = %d; Sector Shift = %lx; Size = %lx\n",
  2714. BlFileTable[FileId].u.PartitionContext.TargetId,
  2715. BlFileTable[FileId].u.PartitionContext.PathId,
  2716. BlFileTable[FileId].u.PartitionContext.SectorShift,
  2717. BlFileTable[FileId].u.PartitionContext.Size
  2718. );
  2719. DbgPrint("Hit any key\n");
  2720. while(!GET_KEY()); // DEBUG ONLY!
  2721. #endif
  2722. return FALSE;
  2723. }
  2724. #endif