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