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

498 lines
16 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: rbc.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "wdm.h"
  11. #include "ntddstor.h"
  12. #include "rbc.h"
  13. NTSTATUS
  14. Rbc_Scsi_Conversion(
  15. IN PSCSI_REQUEST_BLOCK Srb,
  16. IN PSCSI_REQUEST_BLOCK *OriginalSrb,
  17. IN PMODE_RBC_DEVICE_PARAMETERS_HEADER_AND_PAGE RbcHeaderAndPage,
  18. IN BOOLEAN OutgoingRequest,
  19. IN BOOLEAN RemovableMedia
  20. )
  21. /*++
  22. Routine Description:
  23. It translates scsi commands to their RBC equivalents, ONLY if they differ in each spec
  24. The translation is done before request is issued and in some cases, after the request is
  25. completed.
  26. On requests that have been completed it will check the Original Cdb (must be passed in)
  27. and try to use information from the RBC device parameters page, the caller retrieved
  28. prior to this call, from the device, and make up SCSI_MODE pages requested in the original
  29. request
  30. On request that are outgoing, the function will determine if it needs to save the original
  31. cdb and completely replace it with an RBC equivalent. In that case it will return a pointer
  32. to pool, allocated as aplaceholder for the original cdb, that the caller must free, after
  33. the request is complete..
  34. Arguments:
  35. DeviceExtension - Sbp2 extension
  36. Srb - Pointer To scsi request block.
  37. DeviceParamsPage - Used only on completed requests. Contains device RBC single mode page
  38. OutgoingRequest - IF set to TRUE, this srb has not been issued yet
  39. Return Value:
  40. --*/
  41. {
  42. BOOLEAN wcd;
  43. UCHAR pageCode;
  44. PCDB_RBC cdbRbc;
  45. PCDB cdb;
  46. PMODE_PARAMETER_HEADER modeHeader=NULL;
  47. PMODE_PARAMETER_BLOCK blockDescriptor;
  48. PMODE_CACHING_PAGE cachePage;
  49. ULONG modeHeaderLength ;
  50. ULONG availLength;
  51. NTSTATUS status = STATUS_PENDING;
  52. if (!OutgoingRequest) {
  53. //
  54. // completed request translation
  55. //
  56. if (*OriginalSrb) {
  57. cdb = (PCDB) &(*OriginalSrb)->Cdb[0];
  58. } else {
  59. cdb = (PCDB) &Srb->Cdb[0];
  60. }
  61. //
  62. // If there was an error then unwind any MODE_SENSE hacks
  63. //
  64. if (Srb->SrbStatus != SRB_STATUS_SUCCESS) {
  65. if (*OriginalSrb != NULL &&
  66. cdb->CDB10.OperationCode == SCSIOP_MODE_SENSE) {
  67. if ((*OriginalSrb)->OriginalRequest !=
  68. ((PIRP) Srb->OriginalRequest)->MdlAddress) {
  69. IoFreeMdl (((PIRP) Srb->OriginalRequest)->MdlAddress);
  70. ((PIRP) Srb->OriginalRequest)->MdlAddress =
  71. (*OriginalSrb)->OriginalRequest;
  72. Srb->DataBuffer = (*OriginalSrb)->DataBuffer;
  73. Srb->DataTransferLength =
  74. cdb->MODE_SENSE.AllocationLength;
  75. }
  76. // NOTE: *OriginalSrb will be freed by caller
  77. }
  78. return STATUS_UNSUCCESSFUL;
  79. }
  80. modeHeaderLength = sizeof(MODE_PARAMETER_HEADER)+sizeof(MODE_PARAMETER_BLOCK);
  81. switch (cdb->CDB10.OperationCode) {
  82. case SCSIOP_MODE_SENSE:
  83. if (cdb->MODE_SENSE.PageCode != MODE_PAGE_RBC_DEVICE_PARAMETERS) {
  84. if (*OriginalSrb == NULL) {
  85. return STATUS_UNSUCCESSFUL;
  86. }
  87. //
  88. // If we used the RbcHeaderAndPage buffer then free the
  89. // mdl we alloc'd & restore the original mdl & data buf addrs
  90. //
  91. // Else copy the data returned in the original buffer to
  92. // the RbcHeaderandPage buffer so we can safely reference
  93. // it while munging
  94. //
  95. if (((PIRP) Srb->OriginalRequest)->MdlAddress !=
  96. (*OriginalSrb)->OriginalRequest) {
  97. IoFreeMdl (((PIRP) Srb->OriginalRequest)->MdlAddress);
  98. ((PIRP) Srb->OriginalRequest)->MdlAddress =
  99. (*OriginalSrb)->OriginalRequest;
  100. Srb->DataBuffer = (*OriginalSrb)->DataBuffer;
  101. } else {
  102. RtlCopyMemory(
  103. RbcHeaderAndPage,
  104. Srb->DataBuffer,
  105. sizeof (*RbcHeaderAndPage)
  106. );
  107. }
  108. availLength = cdb->MODE_SENSE.AllocationLength;
  109. Srb->DataTransferLength = availLength;
  110. //
  111. // Put back together the data the class driver expects to get
  112. // from the RBC device. IF it requested for 0x3f all pages,
  113. // we need to make block descriptors...
  114. //
  115. if (cdb->MODE_SENSE.Dbd == 0) {
  116. //
  117. // make mode header and block...
  118. //
  119. if (availLength >= modeHeaderLength) {
  120. modeHeader = (PMODE_PARAMETER_HEADER) Srb->DataBuffer;
  121. modeHeader->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
  122. modeHeader->MediumType = 0x00;
  123. modeHeader->ModeDataLength = 0 ;
  124. //
  125. // This means we have a removable medium otherwise
  126. // all bits are 0
  127. //
  128. modeHeader->DeviceSpecificParameter =
  129. (RbcHeaderAndPage->Page.WriteDisabled) << 7;
  130. modeHeader->DeviceSpecificParameter |=
  131. (!RbcHeaderAndPage->Page.WriteCacheDisable) << 4;
  132. //
  133. // make the parameter block
  134. //
  135. blockDescriptor = (PMODE_PARAMETER_BLOCK)modeHeader;
  136. (ULONG_PTR)blockDescriptor += sizeof(MODE_PARAMETER_HEADER);
  137. blockDescriptor->DensityCode = 0x00;
  138. blockDescriptor->BlockLength[2] =
  139. RbcHeaderAndPage->Page.LogicalBlockSize[1]; //LSB
  140. blockDescriptor->BlockLength[1] =
  141. RbcHeaderAndPage->Page.LogicalBlockSize[0]; //MSB
  142. blockDescriptor->BlockLength[0] = 0;
  143. RtlCopyMemory(
  144. &blockDescriptor->NumberOfBlocks[0],
  145. &RbcHeaderAndPage->Page.NumberOfLogicalBlocks[2],
  146. 3
  147. ); //LSB
  148. //
  149. // put in the returned data a bunch of mode pages...
  150. //
  151. availLength -= modeHeaderLength;
  152. }
  153. }
  154. //
  155. // right now i only support cache page.
  156. // add here support for more pages...
  157. //
  158. if ((availLength >= sizeof(MODE_CACHING_PAGE)) && ((cdb->MODE_SENSE.PageCode == 0x3f) ||
  159. (cdb->MODE_SENSE.PageCode == MODE_PAGE_CACHING))){
  160. availLength -= sizeof(MODE_CACHING_PAGE);
  161. //
  162. // create cache page..
  163. //
  164. if (modeHeader) {
  165. modeHeader->ModeDataLength += sizeof(MODE_CACHING_PAGE);
  166. cachePage = (PMODE_CACHING_PAGE)blockDescriptor;
  167. (ULONG_PTR)cachePage += sizeof(MODE_PARAMETER_BLOCK);
  168. } else {
  169. cachePage = (PMODE_CACHING_PAGE)Srb->DataBuffer;
  170. }
  171. RtlZeroMemory(&cachePage->DisablePrefetchTransfer[0],sizeof(MODE_CACHING_PAGE));
  172. cachePage->PageCode = MODE_PAGE_CACHING;
  173. cachePage->PageLength = sizeof(MODE_CACHING_PAGE);
  174. cachePage->WriteCacheEnable = (!RbcHeaderAndPage->Page.WriteCacheDisable);
  175. cachePage->PageSavable = 1;
  176. cachePage->WriteRetensionPriority = 0;
  177. cachePage->ReadRetensionPriority = 0;
  178. cachePage->MultiplicationFactor = 0;
  179. cachePage->ReadDisableCache = 0;
  180. }
  181. }
  182. break;
  183. case SCSIOP_MODE_SELECT:
  184. if (Srb->DataTransferLength ==
  185. sizeof(MODE_RBC_DEVICE_PARAMETERS_HEADER_AND_PAGE)) {
  186. RbcHeaderAndPage->Page.WriteCacheDisable =
  187. ((PMODE_RBC_DEVICE_PARAMETERS_HEADER_AND_PAGE)
  188. Srb->DataBuffer)->Page.WriteCacheDisable;
  189. }
  190. break;
  191. }
  192. } else {
  193. //
  194. // outgoing request translation
  195. //
  196. modeHeaderLength = sizeof(MODE_PARAMETER_HEADER)+sizeof(MODE_PARAMETER_BLOCK);
  197. cdbRbc = (PCDB_RBC)Srb->Cdb;
  198. cdb = (PCDB)Srb->Cdb;
  199. switch (cdb->CDB10.OperationCode) {
  200. case SCSIOP_START_STOP_UNIT:
  201. if (cdbRbc->START_STOP_RBC.Start) {
  202. //
  203. // power on
  204. //
  205. cdbRbc->START_STOP_RBC.PowerConditions = START_STOP_RBC_POWER_CND_ACTIVE;
  206. } else {
  207. cdbRbc->START_STOP_RBC.PowerConditions = START_STOP_RBC_POWER_CND_STANDBY;
  208. }
  209. if (cdbRbc->START_STOP_RBC.LoadEject) {
  210. cdbRbc->START_STOP_RBC.PowerConditions = 0;
  211. }
  212. break;
  213. case SCSIOP_MODE_SELECT:
  214. cdb->MODE_SELECT.PFBit = 1;
  215. cdb->MODE_SELECT.SPBit = 1;
  216. //
  217. // we need to ficure out what page is the driver trying to write, check if that page
  218. // has relevant bits that need to be changed in the single RBC page, the change this
  219. // mode select to actually write the RBC mode page..
  220. //
  221. cachePage = (PMODE_CACHING_PAGE) Srb->DataBuffer;
  222. (ULONG_PTR)cachePage += modeHeaderLength;
  223. //
  224. // the length of the request has to change also, however the RBC page
  225. // is always less than the size of the header blocks + any scsi mode page..
  226. //
  227. if (Srb->DataTransferLength >=
  228. sizeof(MODE_RBC_DEVICE_PARAMETERS_HEADER_AND_PAGE)) {
  229. pageCode = cachePage->PageCode;
  230. if (pageCode == MODE_PAGE_CACHING) {
  231. wcd = !cachePage->WriteCacheEnable;
  232. }
  233. cdb->MODE_SELECT.ParameterListLength = (UCHAR)
  234. (Srb->DataTransferLength =
  235. sizeof(MODE_RBC_DEVICE_PARAMETERS_HEADER_AND_PAGE));
  236. RtlCopyMemory(
  237. Srb->DataBuffer,
  238. RbcHeaderAndPage,
  239. sizeof(MODE_RBC_DEVICE_PARAMETERS_HEADER_AND_PAGE)
  240. );
  241. modeHeader = (PMODE_PARAMETER_HEADER) Srb->DataBuffer;
  242. modeHeader->ModeDataLength = // per SPC-2
  243. modeHeader->MediumType = // per RBC
  244. modeHeader->DeviceSpecificParameter = // per RBC
  245. modeHeader->BlockDescriptorLength = 0; // per RBC
  246. if (pageCode == MODE_PAGE_CACHING) {
  247. ((PMODE_RBC_DEVICE_PARAMETERS_HEADER_AND_PAGE) modeHeader)
  248. ->Page.WriteCacheDisable = wcd;
  249. }
  250. }
  251. break;
  252. case SCSIOP_MODE_SENSE:
  253. //
  254. // mode senses are complicated since RBC differs ALOT from scsi.
  255. // We have to save the original cdb, requst fromt he device the RBC mode page
  256. // then upon succesful completion, re-create the data, the class drivers expect.
  257. //
  258. if (cdb->MODE_SENSE.PageCode != MODE_PAGE_RBC_DEVICE_PARAMETERS) {
  259. //
  260. // RBC devices only support requests for the RBC dev params
  261. // page, so we need to convert any other page requests
  262. //
  263. if (!RemovableMedia &&
  264. Srb->DataTransferLength == (sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK))) {
  265. //
  266. // They just want the mode header and mode block, so
  267. // fill it in here from our cached RBC page
  268. //
  269. modeHeader = (PMODE_PARAMETER_HEADER) Srb->DataBuffer;
  270. modeHeader->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
  271. modeHeader->MediumType = 0x00;
  272. modeHeader->ModeDataLength = 0 ;
  273. //
  274. // this means we have a removable medium otherwise all bits are 0
  275. //
  276. modeHeader->DeviceSpecificParameter =
  277. RbcHeaderAndPage->Page.WriteDisabled << 7;
  278. modeHeader->DeviceSpecificParameter |=
  279. (!RbcHeaderAndPage->Page.WriteCacheDisable) << 4;
  280. //
  281. // make the parameter block
  282. //
  283. blockDescriptor = (PMODE_PARAMETER_BLOCK)modeHeader;
  284. (ULONG_PTR)blockDescriptor += sizeof(MODE_PARAMETER_HEADER);
  285. blockDescriptor->DensityCode = 0x00;
  286. blockDescriptor->BlockLength[2] =
  287. RbcHeaderAndPage->Page.LogicalBlockSize[1]; //LSB
  288. blockDescriptor->BlockLength[1] =
  289. RbcHeaderAndPage->Page.LogicalBlockSize[0]; //MSB
  290. blockDescriptor->BlockLength[0] = 0;
  291. RtlCopyMemory(
  292. &blockDescriptor->NumberOfBlocks[0],
  293. &RbcHeaderAndPage->Page.NumberOfLogicalBlocks[2],
  294. 3
  295. ); //LSB
  296. status = STATUS_SUCCESS;
  297. } else {
  298. //
  299. // Allocate an intermediate srb that we can store some
  300. // of the original request info in
  301. //
  302. *OriginalSrb = ExAllocatePoolWithTag(
  303. NonPagedPool,
  304. sizeof (**OriginalSrb),
  305. '2pbs'
  306. );
  307. if (*OriginalSrb == NULL) {
  308. return STATUS_INSUFFICIENT_RESOURCES;
  309. }
  310. //
  311. // If the data buffer isn't large enough to contain the
  312. // rbc header & page then we'll use the passed-in
  313. // RbcHeaderAndPage buffer to retreive the data
  314. //
  315. (*OriginalSrb)->OriginalRequest =
  316. ((PIRP) Srb->OriginalRequest)->MdlAddress;
  317. if (Srb->DataTransferLength < sizeof (*RbcHeaderAndPage)) {
  318. ((PIRP) Srb->OriginalRequest)->MdlAddress =
  319. IoAllocateMdl(
  320. RbcHeaderAndPage,
  321. sizeof (*RbcHeaderAndPage),
  322. FALSE,
  323. FALSE,
  324. NULL
  325. );
  326. if (((PIRP) Srb->OriginalRequest)->MdlAddress ==NULL) {
  327. ExFreePool (*OriginalSrb);
  328. *OriginalSrb = NULL;
  329. return STATUS_INSUFFICIENT_RESOURCES;
  330. }
  331. MmBuildMdlForNonPagedPool(
  332. ((PIRP) Srb->OriginalRequest)->MdlAddress
  333. );
  334. (*OriginalSrb)->DataBuffer = Srb->DataBuffer;
  335. Srb->DataBuffer = RbcHeaderAndPage;
  336. }
  337. //
  338. // Save the original cdb values
  339. //
  340. RtlCopyMemory ((*OriginalSrb)->Cdb, cdb, Srb->CdbLength);
  341. //
  342. // Now munge the cdb as needed to get the rbc header & page
  343. //
  344. cdb->MODE_SENSE.Dbd = 1;
  345. cdb->MODE_SENSE.PageCode = MODE_PAGE_RBC_DEVICE_PARAMETERS;
  346. cdb->MODE_SENSE.AllocationLength = (UCHAR)
  347. (Srb->DataTransferLength = sizeof(*RbcHeaderAndPage));
  348. }
  349. }
  350. break;
  351. }
  352. }
  353. return status;
  354. }