MptScsi.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  1. /** @file
  2. This driver produces Extended SCSI Pass Thru Protocol instances for
  3. LSI Fusion MPT SCSI devices.
  4. Copyright (C) 2020, Oracle and/or its affiliates.
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include <IndustryStandard/FusionMptScsi.h>
  8. #include <IndustryStandard/Pci.h>
  9. #include <Library/BaseLib.h>
  10. #include <Library/BaseMemoryLib.h>
  11. #include <Library/DebugLib.h>
  12. #include <Library/MemoryAllocationLib.h>
  13. #include <Library/PcdLib.h>
  14. #include <Library/UefiBootServicesTableLib.h>
  15. #include <Library/UefiLib.h>
  16. #include <Protocol/PciIo.h>
  17. #include <Protocol/PciRootBridgeIo.h>
  18. #include <Protocol/ScsiPassThruExt.h>
  19. #include <Uefi/UefiSpec.h>
  20. //
  21. // Higher versions will be used before lower, 0x10-0xffffffef is the version
  22. // range for IVH (Indie Hardware Vendors)
  23. //
  24. #define MPT_SCSI_BINDING_VERSION 0x10
  25. //
  26. // Runtime Structures
  27. //
  28. typedef struct {
  29. MPT_SCSI_REQUEST_ALIGNED IoRequest;
  30. MPT_SCSI_IO_REPLY_ALIGNED IoReply;
  31. //
  32. // As EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.SenseDataLength is defined
  33. // as UINT8, defining here SenseData size to MAX_UINT8 will guarantee it
  34. // cannot overflow when passed to device.
  35. //
  36. UINT8 Sense[MAX_UINT8];
  37. //
  38. // This size of the data is arbitrarily chosen.
  39. // It seems to be sufficient for all I/O requests sent through
  40. // EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() for common boot scenarios.
  41. //
  42. UINT8 Data[0x2000];
  43. } MPT_SCSI_DMA_BUFFER;
  44. #define MPT_SCSI_DEV_SIGNATURE SIGNATURE_32 ('M','P','T','S')
  45. typedef struct {
  46. UINT32 Signature;
  47. EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
  48. EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode;
  49. UINT8 MaxTarget;
  50. UINT32 StallPerPollUsec;
  51. EFI_PCI_IO_PROTOCOL *PciIo;
  52. UINT64 OriginalPciAttributes;
  53. EFI_EVENT ExitBoot;
  54. MPT_SCSI_DMA_BUFFER *Dma;
  55. EFI_PHYSICAL_ADDRESS DmaPhysical;
  56. VOID *DmaMapping;
  57. BOOLEAN IoReplyEnqueued;
  58. } MPT_SCSI_DEV;
  59. #define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \
  60. CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)
  61. #define MPT_SCSI_DMA_ADDR(Dev, MemberName) \
  62. (Dev->DmaPhysical + OFFSET_OF (MPT_SCSI_DMA_BUFFER, MemberName))
  63. #define MPT_SCSI_DMA_ADDR_HIGH(Dev, MemberName) \
  64. ((UINT32)RShiftU64 (MPT_SCSI_DMA_ADDR (Dev, MemberName), 32))
  65. #define MPT_SCSI_DMA_ADDR_LOW(Dev, MemberName) \
  66. ((UINT32)MPT_SCSI_DMA_ADDR (Dev, MemberName))
  67. //
  68. // Hardware functions
  69. //
  70. STATIC
  71. EFI_STATUS
  72. Out32 (
  73. IN MPT_SCSI_DEV *Dev,
  74. IN UINT32 Addr,
  75. IN UINT32 Data
  76. )
  77. {
  78. return Dev->PciIo->Io.Write (
  79. Dev->PciIo,
  80. EfiPciIoWidthUint32,
  81. PCI_BAR_IDX0,
  82. Addr,
  83. 1,
  84. &Data
  85. );
  86. }
  87. STATIC
  88. EFI_STATUS
  89. In32 (
  90. IN MPT_SCSI_DEV *Dev,
  91. IN UINT32 Addr,
  92. OUT UINT32 *Data
  93. )
  94. {
  95. return Dev->PciIo->Io.Read (
  96. Dev->PciIo,
  97. EfiPciIoWidthUint32,
  98. PCI_BAR_IDX0,
  99. Addr,
  100. 1,
  101. Data
  102. );
  103. }
  104. STATIC
  105. EFI_STATUS
  106. MptDoorbell (
  107. IN MPT_SCSI_DEV *Dev,
  108. IN UINT8 DoorbellFunc,
  109. IN UINT8 DoorbellArg
  110. )
  111. {
  112. return Out32 (
  113. Dev,
  114. MPT_REG_DOORBELL,
  115. (((UINT32)DoorbellFunc) << 24) | (DoorbellArg << 16)
  116. );
  117. }
  118. STATIC
  119. EFI_STATUS
  120. MptScsiReset (
  121. IN MPT_SCSI_DEV *Dev
  122. )
  123. {
  124. EFI_STATUS Status;
  125. //
  126. // Reset hardware
  127. //
  128. Status = MptDoorbell (Dev, MPT_DOORBELL_RESET, 0);
  129. if (EFI_ERROR (Status)) {
  130. return Status;
  131. }
  132. //
  133. // Mask interrupts
  134. //
  135. Status = Out32 (Dev, MPT_REG_IMASK, MPT_IMASK_DOORBELL | MPT_IMASK_REPLY);
  136. if (EFI_ERROR (Status)) {
  137. return Status;
  138. }
  139. //
  140. // Clear interrupt status
  141. //
  142. Status = Out32 (Dev, MPT_REG_ISTATUS, 0);
  143. if (EFI_ERROR (Status)) {
  144. return Status;
  145. }
  146. return EFI_SUCCESS;
  147. }
  148. STATIC
  149. EFI_STATUS
  150. MptScsiInit (
  151. IN MPT_SCSI_DEV *Dev
  152. )
  153. {
  154. EFI_STATUS Status;
  155. union {
  156. MPT_IO_CONTROLLER_INIT_REQUEST Data;
  157. UINT32 Uint32;
  158. } AlignedReq;
  159. MPT_IO_CONTROLLER_INIT_REQUEST *Req;
  160. MPT_IO_CONTROLLER_INIT_REPLY Reply;
  161. UINT8 *ReplyBytes;
  162. UINT32 ReplyWord;
  163. Req = &AlignedReq.Data;
  164. Status = MptScsiReset (Dev);
  165. if (EFI_ERROR (Status)) {
  166. return Status;
  167. }
  168. ZeroMem (Req, sizeof (*Req));
  169. ZeroMem (&Reply, sizeof (Reply));
  170. Req->WhoInit = MPT_IOC_WHOINIT_ROM_BIOS;
  171. Req->Function = MPT_MESSAGE_HDR_FUNCTION_IOC_INIT;
  172. STATIC_ASSERT (
  173. FixedPcdGet8 (PcdMptScsiMaxTargetLimit) < 255,
  174. "Req supports 255 targets only (max target is 254)"
  175. );
  176. Req->MaxDevices = Dev->MaxTarget + 1;
  177. Req->MaxBuses = 1;
  178. Req->ReplyFrameSize = sizeof Dev->Dma->IoReply.Data;
  179. Req->HostMfaHighAddr = MPT_SCSI_DMA_ADDR_HIGH (Dev, IoRequest);
  180. Req->SenseBufferHighAddr = MPT_SCSI_DMA_ADDR_HIGH (Dev, Sense);
  181. //
  182. // Send controller init through doorbell
  183. //
  184. STATIC_ASSERT (
  185. sizeof (*Req) % sizeof (UINT32) == 0,
  186. "Req must be multiple of UINT32"
  187. );
  188. STATIC_ASSERT (
  189. sizeof (*Req) / sizeof (UINT32) <= MAX_UINT8,
  190. "Req must fit in MAX_UINT8 Dwords"
  191. );
  192. Status = MptDoorbell (
  193. Dev,
  194. MPT_DOORBELL_HANDSHAKE,
  195. (UINT8)(sizeof (*Req) / sizeof (UINT32))
  196. );
  197. if (EFI_ERROR (Status)) {
  198. return Status;
  199. }
  200. Status = Dev->PciIo->Io.Write (
  201. Dev->PciIo,
  202. EfiPciIoWidthFifoUint32,
  203. PCI_BAR_IDX0,
  204. MPT_REG_DOORBELL,
  205. sizeof (*Req) / sizeof (UINT32),
  206. Req
  207. );
  208. if (EFI_ERROR (Status)) {
  209. return Status;
  210. }
  211. //
  212. // Read reply through doorbell
  213. // Each 32bit (Dword) read produces 16bit (Word) of data
  214. //
  215. // The reply is read back to complete the doorbell function but it
  216. // isn't useful because it doesn't contain relevant data or status
  217. // codes.
  218. //
  219. STATIC_ASSERT (
  220. sizeof (Reply) % sizeof (UINT16) == 0,
  221. "Reply must be multiple of UINT16"
  222. );
  223. ReplyBytes = (UINT8 *)&Reply;
  224. while (ReplyBytes != (UINT8 *)(&Reply + 1)) {
  225. Status = In32 (Dev, MPT_REG_DOORBELL, &ReplyWord);
  226. if (EFI_ERROR (Status)) {
  227. return Status;
  228. }
  229. CopyMem (ReplyBytes, &ReplyWord, sizeof (UINT16));
  230. ReplyBytes += sizeof (UINT16);
  231. }
  232. //
  233. // Clear interrupts generated by doorbell reply
  234. //
  235. Status = Out32 (Dev, MPT_REG_ISTATUS, 0);
  236. if (EFI_ERROR (Status)) {
  237. return Status;
  238. }
  239. return EFI_SUCCESS;
  240. }
  241. STATIC
  242. EFI_STATUS
  243. ReportHostAdapterError (
  244. OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
  245. )
  246. {
  247. DEBUG ((DEBUG_ERROR, "%a: fatal error in scsi request\n", __FUNCTION__));
  248. Packet->InTransferLength = 0;
  249. Packet->OutTransferLength = 0;
  250. Packet->SenseDataLength = 0;
  251. Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
  252. Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED;
  253. return EFI_DEVICE_ERROR;
  254. }
  255. STATIC
  256. EFI_STATUS
  257. ReportHostAdapterOverrunError (
  258. OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
  259. )
  260. {
  261. Packet->SenseDataLength = 0;
  262. Packet->HostAdapterStatus =
  263. EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
  264. Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
  265. return EFI_BAD_BUFFER_SIZE;
  266. }
  267. STATIC
  268. EFI_STATUS
  269. MptScsiPopulateRequest (
  270. IN MPT_SCSI_DEV *Dev,
  271. IN UINT8 Target,
  272. IN UINT64 Lun,
  273. IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
  274. )
  275. {
  276. MPT_SCSI_REQUEST_WITH_SG *Request;
  277. Request = &Dev->Dma->IoRequest.Data;
  278. if ((Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
  279. ((Packet->InTransferLength > 0) && (Packet->OutTransferLength > 0)) ||
  280. (Packet->CdbLength > sizeof (Request->Header.Cdb)))
  281. {
  282. return EFI_UNSUPPORTED;
  283. }
  284. if ((Target > Dev->MaxTarget) || (Lun > 0) ||
  285. (Packet->DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
  286. //
  287. // Trying to receive, but destination pointer is NULL, or contradicting
  288. // transfer direction
  289. //
  290. ((Packet->InTransferLength > 0) &&
  291. ((Packet->InDataBuffer == NULL) ||
  292. (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE)
  293. )
  294. ) ||
  295. //
  296. // Trying to send, but source pointer is NULL, or contradicting transfer
  297. // direction
  298. //
  299. ((Packet->OutTransferLength > 0) &&
  300. ((Packet->OutDataBuffer == NULL) ||
  301. (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ)
  302. )
  303. )
  304. )
  305. {
  306. return EFI_INVALID_PARAMETER;
  307. }
  308. if (Packet->InTransferLength > sizeof (Dev->Dma->Data)) {
  309. Packet->InTransferLength = sizeof (Dev->Dma->Data);
  310. return ReportHostAdapterOverrunError (Packet);
  311. }
  312. if (Packet->OutTransferLength > sizeof (Dev->Dma->Data)) {
  313. Packet->OutTransferLength = sizeof (Dev->Dma->Data);
  314. return ReportHostAdapterOverrunError (Packet);
  315. }
  316. ZeroMem (Request, sizeof (*Request));
  317. Request->Header.TargetId = Target;
  318. //
  319. // Only LUN 0 is currently supported, hence the cast is safe
  320. //
  321. Request->Header.Lun[1] = (UINT8)Lun;
  322. Request->Header.Function = MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST;
  323. Request->Header.MessageContext = 1; // We handle one request at a time
  324. Request->Header.CdbLength = Packet->CdbLength;
  325. CopyMem (Request->Header.Cdb, Packet->Cdb, Packet->CdbLength);
  326. //
  327. // SenseDataLength is UINT8, Sense[] is MAX_UINT8, so we can't overflow
  328. //
  329. ZeroMem (Dev->Dma->Sense, Packet->SenseDataLength);
  330. Request->Header.SenseBufferLength = Packet->SenseDataLength;
  331. Request->Header.SenseBufferLowAddress = MPT_SCSI_DMA_ADDR_LOW (Dev, Sense);
  332. Request->Sg.EndOfList = 1;
  333. Request->Sg.EndOfBuffer = 1;
  334. Request->Sg.LastElement = 1;
  335. Request->Sg.ElementType = MPT_SG_ENTRY_TYPE_SIMPLE;
  336. Request->Sg.Is64BitAddress = 1;
  337. Request->Sg.DataBufferAddress = MPT_SCSI_DMA_ADDR (Dev, Data);
  338. //
  339. // "MPT_SG_ENTRY_SIMPLE.Length" is a 24-bit quantity.
  340. //
  341. STATIC_ASSERT (
  342. sizeof (Dev->Dma->Data) < SIZE_16MB,
  343. "MPT_SCSI_DMA_BUFFER.Data must be smaller than 16MB"
  344. );
  345. if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
  346. Request->Header.DataLength = Packet->InTransferLength;
  347. Request->Sg.Length = Packet->InTransferLength;
  348. Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ;
  349. } else {
  350. Request->Header.DataLength = Packet->OutTransferLength;
  351. Request->Sg.Length = Packet->OutTransferLength;
  352. Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE;
  353. CopyMem (Dev->Dma->Data, Packet->OutDataBuffer, Packet->OutTransferLength);
  354. Request->Sg.BufferContainsData = 1;
  355. }
  356. if (Request->Header.DataLength == 0) {
  357. Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE;
  358. }
  359. return EFI_SUCCESS;
  360. }
  361. STATIC
  362. EFI_STATUS
  363. MptScsiSendRequest (
  364. IN MPT_SCSI_DEV *Dev,
  365. IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
  366. )
  367. {
  368. EFI_STATUS Status;
  369. if (!Dev->IoReplyEnqueued) {
  370. //
  371. // Put one free reply frame on the reply queue, the hardware may use it to
  372. // report an error to us.
  373. //
  374. Status = Out32 (Dev, MPT_REG_REP_Q, MPT_SCSI_DMA_ADDR_LOW (Dev, IoReply));
  375. if (EFI_ERROR (Status)) {
  376. return EFI_DEVICE_ERROR;
  377. }
  378. Dev->IoReplyEnqueued = TRUE;
  379. }
  380. Status = Out32 (Dev, MPT_REG_REQ_Q, MPT_SCSI_DMA_ADDR_LOW (Dev, IoRequest));
  381. if (EFI_ERROR (Status)) {
  382. return EFI_DEVICE_ERROR;
  383. }
  384. return EFI_SUCCESS;
  385. }
  386. STATIC
  387. EFI_STATUS
  388. MptScsiGetReply (
  389. IN MPT_SCSI_DEV *Dev,
  390. OUT UINT32 *Reply
  391. )
  392. {
  393. EFI_STATUS Status;
  394. UINT32 Istatus;
  395. UINT32 EmptyReply;
  396. //
  397. // Timeouts are not supported for
  398. // EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() in this implementation.
  399. //
  400. for ( ; ;) {
  401. Status = In32 (Dev, MPT_REG_ISTATUS, &Istatus);
  402. if (EFI_ERROR (Status)) {
  403. return Status;
  404. }
  405. //
  406. // Interrupt raised
  407. //
  408. if (Istatus & MPT_IMASK_REPLY) {
  409. break;
  410. }
  411. gBS->Stall (Dev->StallPerPollUsec);
  412. }
  413. Status = In32 (Dev, MPT_REG_REP_Q, Reply);
  414. if (EFI_ERROR (Status)) {
  415. return Status;
  416. }
  417. //
  418. // The driver is supposed to fetch replies until 0xffffffff is returned, which
  419. // will reset the interrupt status. We put only one request, so we expect the
  420. // next read reply to be the last.
  421. //
  422. Status = In32 (Dev, MPT_REG_REP_Q, &EmptyReply);
  423. if (EFI_ERROR (Status) || (EmptyReply != MAX_UINT32)) {
  424. return EFI_DEVICE_ERROR;
  425. }
  426. return EFI_SUCCESS;
  427. }
  428. STATIC
  429. EFI_STATUS
  430. MptScsiHandleReply (
  431. IN MPT_SCSI_DEV *Dev,
  432. IN UINT32 Reply,
  433. OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
  434. )
  435. {
  436. if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
  437. CopyMem (Packet->InDataBuffer, Dev->Dma->Data, Packet->InTransferLength);
  438. }
  439. if (Reply == Dev->Dma->IoRequest.Data.Header.MessageContext) {
  440. //
  441. // This is a turbo reply, everything is good
  442. //
  443. Packet->SenseDataLength = 0;
  444. Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
  445. Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
  446. } else if ((Reply & BIT31) != 0) {
  447. DEBUG ((DEBUG_INFO, "%a: Full reply returned\n", __FUNCTION__));
  448. //
  449. // When reply MSB is set, we got a full reply. Since we submitted only one
  450. // reply frame, we know it's IoReply.
  451. //
  452. Dev->IoReplyEnqueued = FALSE;
  453. Packet->TargetStatus = Dev->Dma->IoReply.Data.ScsiStatus;
  454. //
  455. // Make sure device only lowers SenseDataLength before copying sense
  456. //
  457. ASSERT (Dev->Dma->IoReply.Data.SenseCount <= Packet->SenseDataLength);
  458. Packet->SenseDataLength =
  459. (UINT8)MIN (Dev->Dma->IoReply.Data.SenseCount, Packet->SenseDataLength);
  460. CopyMem (Packet->SenseData, Dev->Dma->Sense, Packet->SenseDataLength);
  461. if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
  462. Packet->InTransferLength = Dev->Dma->IoReply.Data.TransferCount;
  463. } else {
  464. Packet->OutTransferLength = Dev->Dma->IoReply.Data.TransferCount;
  465. }
  466. switch (Dev->Dma->IoReply.Data.IocStatus) {
  467. case MPT_SCSI_IOCSTATUS_SUCCESS:
  468. Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
  469. break;
  470. case MPT_SCSI_IOCSTATUS_DEVICE_NOT_THERE:
  471. Packet->HostAdapterStatus =
  472. EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
  473. return EFI_TIMEOUT;
  474. case MPT_SCSI_IOCSTATUS_DATA_UNDERRUN:
  475. case MPT_SCSI_IOCSTATUS_DATA_OVERRUN:
  476. Packet->HostAdapterStatus =
  477. EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
  478. break;
  479. default:
  480. Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
  481. return EFI_DEVICE_ERROR;
  482. }
  483. } else {
  484. DEBUG ((DEBUG_ERROR, "%a: unexpected reply (%x)\n", __FUNCTION__, Reply));
  485. return ReportHostAdapterError (Packet);
  486. }
  487. return EFI_SUCCESS;
  488. }
  489. //
  490. // Ext SCSI Pass Thru
  491. //
  492. STATIC
  493. EFI_STATUS
  494. EFIAPI
  495. MptScsiPassThru (
  496. IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
  497. IN UINT8 *Target,
  498. IN UINT64 Lun,
  499. IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
  500. IN EFI_EVENT Event OPTIONAL
  501. )
  502. {
  503. EFI_STATUS Status;
  504. MPT_SCSI_DEV *Dev;
  505. UINT32 Reply;
  506. Dev = MPT_SCSI_FROM_PASS_THRU (This);
  507. //
  508. // We only use first byte of target identifer
  509. //
  510. Status = MptScsiPopulateRequest (Dev, *Target, Lun, Packet);
  511. if (EFI_ERROR (Status)) {
  512. //
  513. // MptScsiPopulateRequest modified packet according to the error
  514. //
  515. return Status;
  516. }
  517. Status = MptScsiSendRequest (Dev, Packet);
  518. if (EFI_ERROR (Status)) {
  519. return ReportHostAdapterError (Packet);
  520. }
  521. Status = MptScsiGetReply (Dev, &Reply);
  522. if (EFI_ERROR (Status)) {
  523. return ReportHostAdapterError (Packet);
  524. }
  525. return MptScsiHandleReply (Dev, Reply, Packet);
  526. }
  527. STATIC
  528. BOOLEAN
  529. IsTargetInitialized (
  530. IN UINT8 *Target
  531. )
  532. {
  533. UINTN Idx;
  534. for (Idx = 0; Idx < TARGET_MAX_BYTES; ++Idx) {
  535. if (Target[Idx] != 0xFF) {
  536. return TRUE;
  537. }
  538. }
  539. return FALSE;
  540. }
  541. STATIC
  542. EFI_STATUS
  543. EFIAPI
  544. MptScsiGetNextTargetLun (
  545. IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
  546. IN OUT UINT8 **Target,
  547. IN OUT UINT64 *Lun
  548. )
  549. {
  550. MPT_SCSI_DEV *Dev;
  551. Dev = MPT_SCSI_FROM_PASS_THRU (This);
  552. //
  553. // Currently support only LUN 0, so hardcode it
  554. //
  555. if (!IsTargetInitialized (*Target)) {
  556. ZeroMem (*Target, TARGET_MAX_BYTES);
  557. *Lun = 0;
  558. } else if ((**Target > Dev->MaxTarget) || (*Lun > 0)) {
  559. return EFI_INVALID_PARAMETER;
  560. } else if (**Target < Dev->MaxTarget) {
  561. //
  562. // This device interface support 256 targets only, so it's enough to
  563. // increment the LSB of Target, as it will never overflow.
  564. //
  565. **Target += 1;
  566. } else {
  567. return EFI_NOT_FOUND;
  568. }
  569. return EFI_SUCCESS;
  570. }
  571. STATIC
  572. EFI_STATUS
  573. EFIAPI
  574. MptScsiGetNextTarget (
  575. IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
  576. IN OUT UINT8 **Target
  577. )
  578. {
  579. MPT_SCSI_DEV *Dev;
  580. Dev = MPT_SCSI_FROM_PASS_THRU (This);
  581. if (!IsTargetInitialized (*Target)) {
  582. ZeroMem (*Target, TARGET_MAX_BYTES);
  583. } else if (**Target > Dev->MaxTarget) {
  584. return EFI_INVALID_PARAMETER;
  585. } else if (**Target < Dev->MaxTarget) {
  586. //
  587. // This device interface support 256 targets only, so it's enough to
  588. // increment the LSB of Target, as it will never overflow.
  589. //
  590. **Target += 1;
  591. } else {
  592. return EFI_NOT_FOUND;
  593. }
  594. return EFI_SUCCESS;
  595. }
  596. STATIC
  597. EFI_STATUS
  598. EFIAPI
  599. MptScsiBuildDevicePath (
  600. IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
  601. IN UINT8 *Target,
  602. IN UINT64 Lun,
  603. IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
  604. )
  605. {
  606. MPT_SCSI_DEV *Dev;
  607. SCSI_DEVICE_PATH *ScsiDevicePath;
  608. if (DevicePath == NULL) {
  609. return EFI_INVALID_PARAMETER;
  610. }
  611. //
  612. // This device support 256 targets only, so it's enough to dereference
  613. // the LSB of Target.
  614. //
  615. Dev = MPT_SCSI_FROM_PASS_THRU (This);
  616. if ((*Target > Dev->MaxTarget) || (Lun > 0)) {
  617. return EFI_NOT_FOUND;
  618. }
  619. ScsiDevicePath = AllocateZeroPool (sizeof (*ScsiDevicePath));
  620. if (ScsiDevicePath == NULL) {
  621. return EFI_OUT_OF_RESOURCES;
  622. }
  623. ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;
  624. ScsiDevicePath->Header.SubType = MSG_SCSI_DP;
  625. ScsiDevicePath->Header.Length[0] = (UINT8)sizeof (*ScsiDevicePath);
  626. ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof (*ScsiDevicePath) >> 8);
  627. ScsiDevicePath->Pun = *Target;
  628. ScsiDevicePath->Lun = (UINT16)Lun;
  629. *DevicePath = &ScsiDevicePath->Header;
  630. return EFI_SUCCESS;
  631. }
  632. STATIC
  633. EFI_STATUS
  634. EFIAPI
  635. MptScsiGetTargetLun (
  636. IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
  637. IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  638. OUT UINT8 **Target,
  639. OUT UINT64 *Lun
  640. )
  641. {
  642. MPT_SCSI_DEV *Dev;
  643. SCSI_DEVICE_PATH *ScsiDevicePath;
  644. if ((DevicePath == NULL) ||
  645. (Target == NULL) || (*Target == NULL) || (Lun == NULL))
  646. {
  647. return EFI_INVALID_PARAMETER;
  648. }
  649. if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
  650. (DevicePath->SubType != MSG_SCSI_DP))
  651. {
  652. return EFI_UNSUPPORTED;
  653. }
  654. Dev = MPT_SCSI_FROM_PASS_THRU (This);
  655. ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;
  656. if ((ScsiDevicePath->Pun > Dev->MaxTarget) ||
  657. (ScsiDevicePath->Lun > 0))
  658. {
  659. return EFI_NOT_FOUND;
  660. }
  661. ZeroMem (*Target, TARGET_MAX_BYTES);
  662. //
  663. // This device support 256 targets only, so it's enough to set the LSB
  664. // of Target.
  665. //
  666. **Target = (UINT8)ScsiDevicePath->Pun;
  667. *Lun = ScsiDevicePath->Lun;
  668. return EFI_SUCCESS;
  669. }
  670. STATIC
  671. EFI_STATUS
  672. EFIAPI
  673. MptScsiResetChannel (
  674. IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
  675. )
  676. {
  677. return EFI_UNSUPPORTED;
  678. }
  679. STATIC
  680. VOID
  681. EFIAPI
  682. MptScsiExitBoot (
  683. IN EFI_EVENT Event,
  684. IN VOID *Context
  685. )
  686. {
  687. MPT_SCSI_DEV *Dev;
  688. Dev = Context;
  689. DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));
  690. MptScsiReset (Dev);
  691. }
  692. STATIC
  693. EFI_STATUS
  694. EFIAPI
  695. MptScsiResetTargetLun (
  696. IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
  697. IN UINT8 *Target,
  698. IN UINT64 Lun
  699. )
  700. {
  701. return EFI_UNSUPPORTED;
  702. }
  703. //
  704. // Driver Binding
  705. //
  706. STATIC
  707. EFI_STATUS
  708. EFIAPI
  709. MptScsiControllerSupported (
  710. IN EFI_DRIVER_BINDING_PROTOCOL *This,
  711. IN EFI_HANDLE ControllerHandle,
  712. IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
  713. )
  714. {
  715. EFI_STATUS Status;
  716. EFI_PCI_IO_PROTOCOL *PciIo;
  717. PCI_TYPE00 Pci;
  718. Status = gBS->OpenProtocol (
  719. ControllerHandle,
  720. &gEfiPciIoProtocolGuid,
  721. (VOID **)&PciIo,
  722. This->DriverBindingHandle,
  723. ControllerHandle,
  724. EFI_OPEN_PROTOCOL_BY_DRIVER
  725. );
  726. if (EFI_ERROR (Status)) {
  727. return Status;
  728. }
  729. Status = PciIo->Pci.Read (
  730. PciIo,
  731. EfiPciIoWidthUint32,
  732. 0,
  733. sizeof (Pci) / sizeof (UINT32),
  734. &Pci
  735. );
  736. if (EFI_ERROR (Status)) {
  737. goto Done;
  738. }
  739. if ((Pci.Hdr.VendorId == LSI_LOGIC_PCI_VENDOR_ID) &&
  740. ((Pci.Hdr.DeviceId == LSI_53C1030_PCI_DEVICE_ID) ||
  741. (Pci.Hdr.DeviceId == LSI_SAS1068_PCI_DEVICE_ID) ||
  742. (Pci.Hdr.DeviceId == LSI_SAS1068E_PCI_DEVICE_ID)))
  743. {
  744. Status = EFI_SUCCESS;
  745. } else {
  746. Status = EFI_UNSUPPORTED;
  747. }
  748. Done:
  749. gBS->CloseProtocol (
  750. ControllerHandle,
  751. &gEfiPciIoProtocolGuid,
  752. This->DriverBindingHandle,
  753. ControllerHandle
  754. );
  755. return Status;
  756. }
  757. STATIC
  758. EFI_STATUS
  759. EFIAPI
  760. MptScsiControllerStart (
  761. IN EFI_DRIVER_BINDING_PROTOCOL *This,
  762. IN EFI_HANDLE ControllerHandle,
  763. IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
  764. )
  765. {
  766. EFI_STATUS Status;
  767. MPT_SCSI_DEV *Dev;
  768. UINTN Pages;
  769. UINTN BytesMapped;
  770. Dev = AllocateZeroPool (sizeof (*Dev));
  771. if (Dev == NULL) {
  772. return EFI_OUT_OF_RESOURCES;
  773. }
  774. Dev->Signature = MPT_SCSI_DEV_SIGNATURE;
  775. Dev->MaxTarget = PcdGet8 (PcdMptScsiMaxTargetLimit);
  776. Dev->StallPerPollUsec = PcdGet32 (PcdMptScsiStallPerPollUsec);
  777. Status = gBS->OpenProtocol (
  778. ControllerHandle,
  779. &gEfiPciIoProtocolGuid,
  780. (VOID **)&Dev->PciIo,
  781. This->DriverBindingHandle,
  782. ControllerHandle,
  783. EFI_OPEN_PROTOCOL_BY_DRIVER
  784. );
  785. if (EFI_ERROR (Status)) {
  786. goto FreePool;
  787. }
  788. Status = Dev->PciIo->Attributes (
  789. Dev->PciIo,
  790. EfiPciIoAttributeOperationGet,
  791. 0,
  792. &Dev->OriginalPciAttributes
  793. );
  794. if (EFI_ERROR (Status)) {
  795. goto CloseProtocol;
  796. }
  797. //
  798. // Enable I/O Space & Bus-Mastering
  799. //
  800. Status = Dev->PciIo->Attributes (
  801. Dev->PciIo,
  802. EfiPciIoAttributeOperationEnable,
  803. (EFI_PCI_IO_ATTRIBUTE_IO |
  804. EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
  805. NULL
  806. );
  807. if (EFI_ERROR (Status)) {
  808. goto CloseProtocol;
  809. }
  810. //
  811. // Signal device supports 64-bit DMA addresses
  812. //
  813. Status = Dev->PciIo->Attributes (
  814. Dev->PciIo,
  815. EfiPciIoAttributeOperationEnable,
  816. EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
  817. NULL
  818. );
  819. if (EFI_ERROR (Status)) {
  820. //
  821. // Warn user that device will only be using 32-bit DMA addresses.
  822. //
  823. // Note that this does not prevent the device/driver from working
  824. // and therefore we only warn and continue as usual.
  825. //
  826. DEBUG ((
  827. DEBUG_WARN,
  828. "%a: failed to enable 64-bit DMA addresses\n",
  829. __FUNCTION__
  830. ));
  831. }
  832. //
  833. // Create buffers for data transfer
  834. //
  835. Pages = EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma));
  836. Status = Dev->PciIo->AllocateBuffer (
  837. Dev->PciIo,
  838. AllocateAnyPages,
  839. EfiBootServicesData,
  840. Pages,
  841. (VOID **)&Dev->Dma,
  842. EFI_PCI_ATTRIBUTE_MEMORY_CACHED
  843. );
  844. if (EFI_ERROR (Status)) {
  845. goto RestoreAttributes;
  846. }
  847. BytesMapped = EFI_PAGES_TO_SIZE (Pages);
  848. Status = Dev->PciIo->Map (
  849. Dev->PciIo,
  850. EfiPciIoOperationBusMasterCommonBuffer,
  851. Dev->Dma,
  852. &BytesMapped,
  853. &Dev->DmaPhysical,
  854. &Dev->DmaMapping
  855. );
  856. if (EFI_ERROR (Status)) {
  857. goto FreeBuffer;
  858. }
  859. if (BytesMapped != EFI_PAGES_TO_SIZE (Pages)) {
  860. Status = EFI_OUT_OF_RESOURCES;
  861. goto Unmap;
  862. }
  863. Status = MptScsiInit (Dev);
  864. if (EFI_ERROR (Status)) {
  865. goto Unmap;
  866. }
  867. Status = gBS->CreateEvent (
  868. EVT_SIGNAL_EXIT_BOOT_SERVICES,
  869. TPL_CALLBACK,
  870. &MptScsiExitBoot,
  871. Dev,
  872. &Dev->ExitBoot
  873. );
  874. if (EFI_ERROR (Status)) {
  875. goto UninitDev;
  876. }
  877. //
  878. // Host adapter channel, doesn't exist
  879. //
  880. Dev->PassThruMode.AdapterId = MAX_UINT32;
  881. Dev->PassThruMode.Attributes =
  882. EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
  883. EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
  884. Dev->PassThru.Mode = &Dev->PassThruMode;
  885. Dev->PassThru.PassThru = &MptScsiPassThru;
  886. Dev->PassThru.GetNextTargetLun = &MptScsiGetNextTargetLun;
  887. Dev->PassThru.BuildDevicePath = &MptScsiBuildDevicePath;
  888. Dev->PassThru.GetTargetLun = &MptScsiGetTargetLun;
  889. Dev->PassThru.ResetChannel = &MptScsiResetChannel;
  890. Dev->PassThru.ResetTargetLun = &MptScsiResetTargetLun;
  891. Dev->PassThru.GetNextTarget = &MptScsiGetNextTarget;
  892. Status = gBS->InstallProtocolInterface (
  893. &ControllerHandle,
  894. &gEfiExtScsiPassThruProtocolGuid,
  895. EFI_NATIVE_INTERFACE,
  896. &Dev->PassThru
  897. );
  898. if (EFI_ERROR (Status)) {
  899. goto CloseExitBoot;
  900. }
  901. return EFI_SUCCESS;
  902. CloseExitBoot:
  903. gBS->CloseEvent (Dev->ExitBoot);
  904. UninitDev:
  905. MptScsiReset (Dev);
  906. Unmap:
  907. Dev->PciIo->Unmap (
  908. Dev->PciIo,
  909. Dev->DmaMapping
  910. );
  911. FreeBuffer:
  912. Dev->PciIo->FreeBuffer (
  913. Dev->PciIo,
  914. Pages,
  915. Dev->Dma
  916. );
  917. RestoreAttributes:
  918. Dev->PciIo->Attributes (
  919. Dev->PciIo,
  920. EfiPciIoAttributeOperationSet,
  921. Dev->OriginalPciAttributes,
  922. NULL
  923. );
  924. CloseProtocol:
  925. gBS->CloseProtocol (
  926. ControllerHandle,
  927. &gEfiPciIoProtocolGuid,
  928. This->DriverBindingHandle,
  929. ControllerHandle
  930. );
  931. FreePool:
  932. FreePool (Dev);
  933. return Status;
  934. }
  935. STATIC
  936. EFI_STATUS
  937. EFIAPI
  938. MptScsiControllerStop (
  939. IN EFI_DRIVER_BINDING_PROTOCOL *This,
  940. IN EFI_HANDLE ControllerHandle,
  941. IN UINTN NumberOfChildren,
  942. IN EFI_HANDLE *ChildHandleBuffer
  943. )
  944. {
  945. EFI_STATUS Status;
  946. EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
  947. MPT_SCSI_DEV *Dev;
  948. Status = gBS->OpenProtocol (
  949. ControllerHandle,
  950. &gEfiExtScsiPassThruProtocolGuid,
  951. (VOID **)&PassThru,
  952. This->DriverBindingHandle,
  953. ControllerHandle,
  954. EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
  955. );
  956. if (EFI_ERROR (Status)) {
  957. return Status;
  958. }
  959. Dev = MPT_SCSI_FROM_PASS_THRU (PassThru);
  960. Status = gBS->UninstallProtocolInterface (
  961. ControllerHandle,
  962. &gEfiExtScsiPassThruProtocolGuid,
  963. &Dev->PassThru
  964. );
  965. if (EFI_ERROR (Status)) {
  966. return Status;
  967. }
  968. gBS->CloseEvent (Dev->ExitBoot);
  969. MptScsiReset (Dev);
  970. Dev->PciIo->Unmap (
  971. Dev->PciIo,
  972. Dev->DmaMapping
  973. );
  974. Dev->PciIo->FreeBuffer (
  975. Dev->PciIo,
  976. EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma)),
  977. Dev->Dma
  978. );
  979. Dev->PciIo->Attributes (
  980. Dev->PciIo,
  981. EfiPciIoAttributeOperationSet,
  982. Dev->OriginalPciAttributes,
  983. NULL
  984. );
  985. gBS->CloseProtocol (
  986. ControllerHandle,
  987. &gEfiPciIoProtocolGuid,
  988. This->DriverBindingHandle,
  989. ControllerHandle
  990. );
  991. FreePool (Dev);
  992. return Status;
  993. }
  994. STATIC
  995. EFI_DRIVER_BINDING_PROTOCOL mMptScsiDriverBinding = {
  996. &MptScsiControllerSupported,
  997. &MptScsiControllerStart,
  998. &MptScsiControllerStop,
  999. MPT_SCSI_BINDING_VERSION,
  1000. NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2
  1001. NULL, // DriverBindingHandle, filled as well
  1002. };
  1003. //
  1004. // Component Name
  1005. //
  1006. STATIC
  1007. EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
  1008. { "eng;en", L"LSI Fusion MPT SCSI Driver" },
  1009. { NULL, NULL }
  1010. };
  1011. STATIC
  1012. EFI_COMPONENT_NAME_PROTOCOL mComponentName;
  1013. EFI_STATUS
  1014. EFIAPI
  1015. MptScsiGetDriverName (
  1016. IN EFI_COMPONENT_NAME_PROTOCOL *This,
  1017. IN CHAR8 *Language,
  1018. OUT CHAR16 **DriverName
  1019. )
  1020. {
  1021. return LookupUnicodeString2 (
  1022. Language,
  1023. This->SupportedLanguages,
  1024. mDriverNameTable,
  1025. DriverName,
  1026. (BOOLEAN)(This == &mComponentName) // Iso639Language
  1027. );
  1028. }
  1029. EFI_STATUS
  1030. EFIAPI
  1031. MptScsiGetDeviceName (
  1032. IN EFI_COMPONENT_NAME_PROTOCOL *This,
  1033. IN EFI_HANDLE DeviceHandle,
  1034. IN EFI_HANDLE ChildHandle,
  1035. IN CHAR8 *Language,
  1036. OUT CHAR16 **ControllerName
  1037. )
  1038. {
  1039. return EFI_UNSUPPORTED;
  1040. }
  1041. STATIC
  1042. EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
  1043. &MptScsiGetDriverName,
  1044. &MptScsiGetDeviceName,
  1045. "eng" // SupportedLanguages, ISO 639-2 language codes
  1046. };
  1047. STATIC
  1048. EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
  1049. (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&MptScsiGetDriverName,
  1050. (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&MptScsiGetDeviceName,
  1051. "en" // SupportedLanguages, RFC 4646 language codes
  1052. };
  1053. //
  1054. // Entry Point
  1055. //
  1056. EFI_STATUS
  1057. EFIAPI
  1058. MptScsiEntryPoint (
  1059. IN EFI_HANDLE ImageHandle,
  1060. IN EFI_SYSTEM_TABLE *SystemTable
  1061. )
  1062. {
  1063. return EfiLibInstallDriverBindingComponentName2 (
  1064. ImageHandle,
  1065. SystemTable,
  1066. &mMptScsiDriverBinding,
  1067. ImageHandle, // The handle to install onto
  1068. &mComponentName,
  1069. &mComponentName2
  1070. );
  1071. }