Leaked source code of windows server 2003
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.

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