]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
MdeModulePkg/ScsiBusDxe: Clean up Peripheral Type check
[mirror_edk2.git] / MdeModulePkg / Bus / Scsi / ScsiBusDxe / ScsiBus.c
CommitLineData
3b2dbece 1/** @file\r
2 SCSI Bus driver that layers on every SCSI Pass Thru and\r
3 Extended SCSI Pass Thru protocol in the system.\r
3a10d471 4\r
1ff7ed2c 5Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
3a10d471 7\r
3b2dbece 8**/\r
3a10d471 9\r
ed7748fe 10\r
3a10d471 11#include "ScsiBus.h"\r
12\r
9beb888e 13\r
3a10d471 14EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = {\r
15 SCSIBusDriverBindingSupported,\r
16 SCSIBusDriverBindingStart,\r
17 SCSIBusDriverBindingStop,\r
18 0xa,\r
19 NULL,\r
20 NULL\r
21};\r
22\r
9beb888e 23VOID *mWorkingBuffer;\r
24\r
25/**\r
26 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.\r
70c94b3b 27\r
9beb888e 28 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET\r
29 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
30\r
31**/\r
70c94b3b 32EFI_STATUS\r
33EFIAPI\r
34ScsiioToPassThruPacket (\r
35 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,\r
9beb888e 36 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket\r
ed66e1bc 37 );\r
70c94b3b 38\r
9beb888e 39/**\r
40 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.\r
41\r
42 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
43 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET\r
70c94b3b 44\r
9beb888e 45**/\r
70c94b3b 46EFI_STATUS\r
47EFIAPI\r
48PassThruToScsiioPacket (\r
49 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,\r
9beb888e 50 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet\r
ed66e1bc 51 );\r
9beb888e 52\r
53/**\r
54 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0\r
55 SCSI IO Packet.\r
56\r
57 @param Event The instance of EFI_EVENT.\r
58 @param Context The parameter passed in.\r
59\r
60**/\r
70c94b3b 61VOID\r
62EFIAPI\r
63NotifyFunction (\r
9beb888e 64 IN EFI_EVENT Event,\r
65 IN VOID *Context\r
ed66e1bc 66 );\r
70c94b3b 67\r
957fe093
SZ
68/**\r
69 Allocates an aligned buffer for SCSI device.\r
70\r
71 This function allocates an aligned buffer for the SCSI device to perform\r
72 SCSI pass through operations. The alignment requirement is from SCSI pass\r
73 through interface.\r
74\r
75 @param ScsiIoDevice The SCSI child device involved for the operation.\r
76 @param BufferSize The request buffer size.\r
77\r
78 @return A pointer to the aligned buffer or NULL if the allocation fails.\r
79\r
80**/\r
81VOID *\r
82AllocateAlignedBuffer (\r
83 IN SCSI_IO_DEV *ScsiIoDevice,\r
84 IN UINTN BufferSize\r
85 )\r
86{\r
87 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiIoDevice->ScsiIo.IoAlign);\r
88}\r
89\r
90/**\r
91 Frees an aligned buffer for SCSI device.\r
92\r
93 This function frees an aligned buffer for the SCSI device to perform\r
94 SCSI pass through operations.\r
95\r
96 @param Buffer The aligned buffer to be freed.\r
97 @param BufferSize The request buffer size.\r
98\r
99**/\r
100VOID\r
101FreeAlignedBuffer (\r
102 IN VOID *Buffer,\r
103 IN UINTN BufferSize\r
104 )\r
105{\r
106 if (Buffer != NULL) {\r
107 FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));\r
108 }\r
109}\r
110\r
3a10d471 111/**\r
112 The user Entry Point for module ScsiBus. The user code starts with this function.\r
113\r
9beb888e 114 @param ImageHandle The firmware allocated handle for the EFI image.\r
115 @param SystemTable A pointer to the EFI System Table.\r
c52fa98c 116\r
9beb888e 117 @retval EFI_SUCCESS The entry point is executed successfully.\r
118 @retval other Some error occurs when executing this entry point.\r
3a10d471 119\r
120**/\r
121EFI_STATUS\r
122EFIAPI\r
123InitializeScsiBus(\r
124 IN EFI_HANDLE ImageHandle,\r
125 IN EFI_SYSTEM_TABLE *SystemTable\r
126 )\r
127{\r
128 EFI_STATUS Status;\r
129\r
130 //\r
131 // Install driver model protocol(s).\r
132 //\r
70da5bc2 133 Status = EfiLibInstallDriverBindingComponentName2 (\r
3a10d471 134 ImageHandle,\r
135 SystemTable,\r
136 &gSCSIBusDriverBinding,\r
137 ImageHandle,\r
138 &gScsiBusComponentName,\r
70da5bc2 139 &gScsiBusComponentName2\r
3a10d471 140 );\r
141 ASSERT_EFI_ERROR (Status);\r
142\r
3a10d471 143 return Status;\r
144}\r
145\r
9beb888e 146\r
147/**\r
148 Test to see if this driver supports ControllerHandle.\r
149\r
150 This service is called by the EFI boot service ConnectController(). In order\r
151 to make drivers as small as possible, there are a few calling restrictions for\r
152 this service. ConnectController() must follow these calling restrictions. If\r
153 any other agent wishes to call Supported() it must also follow these calling\r
154 restrictions.\r
155\r
156 @param This Protocol instance pointer.\r
157 @param ControllerHandle Handle of device to test\r
158 @param RemainingDevicePath Optional parameter use to pick a specific child\r
159 device to start.\r
160\r
161 @retval EFI_SUCCESS This driver supports this device\r
162 @retval EFI_ALREADY_STARTED This driver is already running on this device\r
163 @retval other This driver does not support this device\r
164\r
165**/\r
3a10d471 166EFI_STATUS\r
167EFIAPI\r
168SCSIBusDriverBindingSupported (\r
169 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
170 IN EFI_HANDLE Controller,\r
171 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
172 )\r
3a10d471 173{\r
af4a6385 174 EFI_STATUS Status;\r
175 EFI_SCSI_PASS_THRU_PROTOCOL *PassThru;\r
70c94b3b 176 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtPassThru;\r
d548f0a1 177 UINT64 Lun;\r
178 UINT8 *TargetId;\r
179 SCSI_TARGET_ID ScsiTargetId;\r
af4a6385 180\r
d548f0a1 181 TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];\r
182 SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);\r
183\r
184 //\r
d1102dba 185 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as\r
d548f0a1 186 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly\r
187 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.\r
188 //\r
189 Status = gBS->OpenProtocol (\r
190 Controller,\r
191 &gEfiExtScsiPassThruProtocolGuid,\r
192 (VOID **)&ExtPassThru,\r
193 This->DriverBindingHandle,\r
194 Controller,\r
195 EFI_OPEN_PROTOCOL_BY_DRIVER\r
196 );\r
197\r
198 if (Status == EFI_ALREADY_STARTED) {\r
199 return EFI_SUCCESS;\r
200 } else if (!EFI_ERROR(Status)) {\r
af4a6385 201 //\r
d548f0a1 202 // Check if RemainingDevicePath is NULL or the End of Device Path Node,\r
203 // if yes, return EFI_SUCCESS.\r
af4a6385 204 //\r
d548f0a1 205 if ((RemainingDevicePath == NULL) || IsDevicePathEnd (RemainingDevicePath)) {\r
67f7e376 206 //\r
207 // Close protocol regardless of RemainingDevicePath validation\r
208 //\r
209 gBS->CloseProtocol (\r
210 Controller,\r
211 &gEfiExtScsiPassThruProtocolGuid,\r
212 This->DriverBindingHandle,\r
213 Controller\r
d1102dba 214 );\r
d548f0a1 215 return EFI_SUCCESS;\r
216 } else {\r
217 //\r
218 // If RemainingDevicePath isn't the End of Device Path Node, check its validation\r
219 //\r
220 Status = ExtPassThru->GetTargetLun (ExtPassThru, RemainingDevicePath, &TargetId, &Lun);\r
af4a6385 221 //\r
d548f0a1 222 // Close protocol regardless of RemainingDevicePath validation\r
af4a6385 223 //\r
d548f0a1 224 gBS->CloseProtocol (\r
225 Controller,\r
226 &gEfiExtScsiPassThruProtocolGuid,\r
227 This->DriverBindingHandle,\r
228 Controller\r
d1102dba 229 );\r
d548f0a1 230 if (!EFI_ERROR(Status)) {\r
231 return EFI_SUCCESS;\r
af4a6385 232 }\r
233 }\r
234 }\r
235\r
3a10d471 236 //\r
d1102dba 237 // Come here in 2 condition:\r
d548f0a1 238 // 1. ExtPassThru doesn't exist.\r
239 // 2. ExtPassThru exists but RemainingDevicePath is invalid.\r
3a10d471 240 //\r
241 Status = gBS->OpenProtocol (\r
242 Controller,\r
d548f0a1 243 &gEfiScsiPassThruProtocolGuid,\r
244 (VOID **)&PassThru,\r
3a10d471 245 This->DriverBindingHandle,\r
246 Controller,\r
70c94b3b 247 EFI_OPEN_PROTOCOL_BY_DRIVER\r
3a10d471 248 );\r
d1102dba 249\r
70c94b3b 250 if (Status == EFI_ALREADY_STARTED) {\r
251 return EFI_SUCCESS;\r
252 }\r
d1102dba 253\r
70c94b3b 254 if (EFI_ERROR (Status)) {\r
d548f0a1 255 return Status;\r
3a10d471 256 }\r
d1102dba 257\r
af4a6385 258 //\r
d548f0a1 259 // Test RemainingDevicePath is valid or not.\r
af4a6385 260 //\r
d548f0a1 261 if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
262 Status = PassThru->GetTargetLun (PassThru, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);\r
263 }\r
d1102dba 264\r
70c94b3b 265 gBS->CloseProtocol (\r
d548f0a1 266 Controller,\r
267 &gEfiScsiPassThruProtocolGuid,\r
268 This->DriverBindingHandle,\r
269 Controller\r
270 );\r
271 return Status;\r
3a10d471 272}\r
273\r
9beb888e 274\r
275/**\r
276 Start this driver on ControllerHandle.\r
277\r
278 This service is called by the EFI boot service ConnectController(). In order\r
279 to make drivers as small as possible, there are a few calling restrictions for\r
280 this service. ConnectController() must follow these calling restrictions. If\r
281 any other agent wishes to call Start() it must also follow these calling\r
282 restrictions.\r
283\r
284 @param This Protocol instance pointer.\r
285 @param ControllerHandle Handle of device to bind driver to\r
286 @param RemainingDevicePath Optional parameter use to pick a specific child\r
287 device to start.\r
288\r
289 @retval EFI_SUCCESS This driver is added to ControllerHandle\r
290 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
291 @retval other This driver does not support this device\r
292\r
293**/\r
3a10d471 294EFI_STATUS\r
295EFIAPI\r
296SCSIBusDriverBindingStart (\r
297 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
298 IN EFI_HANDLE Controller,\r
299 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
300 )\r
3a10d471 301{\r
f36d6e66 302 UINT64 Lun;\r
303 UINT8 *TargetId;\r
304 BOOLEAN ScanOtherPuns;\r
305 BOOLEAN FromFirstTarget;\r
306 BOOLEAN ExtScsiSupport;\r
307 EFI_STATUS Status;\r
308 EFI_STATUS DevicePathStatus;\r
309 EFI_STATUS PassThruStatus;\r
310 SCSI_BUS_DEVICE *ScsiBusDev;\r
d548f0a1 311 SCSI_TARGET_ID ScsiTargetId;\r
f36d6e66 312 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
313 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiInterface;\r
314 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiInterface;\r
315 EFI_SCSI_BUS_PROTOCOL *BusIdentify;\r
316\r
317 TargetId = NULL;\r
f36d6e66 318 ScanOtherPuns = TRUE;\r
70c94b3b 319 FromFirstTarget = FALSE;\r
f36d6e66 320 ExtScsiSupport = FALSE;\r
321 PassThruStatus = EFI_SUCCESS;\r
d1102dba 322\r
d548f0a1 323 TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];\r
324 SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);\r
d1102dba 325\r
f36d6e66 326 DevicePathStatus = gBS->OpenProtocol (\r
327 Controller,\r
328 &gEfiDevicePathProtocolGuid,\r
329 (VOID **) &ParentDevicePath,\r
330 This->DriverBindingHandle,\r
331 Controller,\r
332 EFI_OPEN_PROTOCOL_BY_DRIVER\r
333 );\r
334 if (EFI_ERROR (DevicePathStatus) && (DevicePathStatus != EFI_ALREADY_STARTED)) {\r
335 return DevicePathStatus;\r
3a10d471 336 }\r
337\r
37623a5c 338 //\r
339 // Report Status Code to indicate SCSI bus starts\r
340 //\r
341 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
342 EFI_PROGRESS_CODE,\r
343 (EFI_IO_BUS_SCSI | EFI_IOB_PC_INIT),\r
344 ParentDevicePath\r
d1102dba 345 );\r
37623a5c 346\r
3a10d471 347 //\r
d1102dba 348 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as\r
f36d6e66 349 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly\r
350 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.\r
3a10d471 351 //\r
352 Status = gBS->OpenProtocol (\r
353 Controller,\r
70c94b3b 354 &gEfiExtScsiPassThruProtocolGuid,\r
f36d6e66 355 (VOID **) &ExtScsiInterface,\r
3a10d471 356 This->DriverBindingHandle,\r
357 Controller,\r
358 EFI_OPEN_PROTOCOL_BY_DRIVER\r
359 );\r
f36d6e66 360 //\r
361 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.\r
362 //\r
363 if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {\r
70c94b3b 364 Status = gBS->OpenProtocol (\r
365 Controller,\r
366 &gEfiScsiPassThruProtocolGuid,\r
f36d6e66 367 (VOID **) &ScsiInterface,\r
70c94b3b 368 This->DriverBindingHandle,\r
369 Controller,\r
370 EFI_OPEN_PROTOCOL_BY_DRIVER\r
371 );\r
f36d6e66 372 //\r
373 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.\r
374 //\r
375 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
376 if (!EFI_ERROR(DevicePathStatus)) {\r
377 gBS->CloseProtocol (\r
378 Controller,\r
379 &gEfiDevicePathProtocolGuid,\r
380 This->DriverBindingHandle,\r
381 Controller\r
382 );\r
d1102dba 383 }\r
70c94b3b 384 return Status;\r
d1102dba 385 }\r
70c94b3b 386 } else {\r
f36d6e66 387 //\r
d1102dba
LG
388 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol\r
389 // with BY_DRIVER if it is also present on the handle. The intent is to prevent\r
f36d6e66 390 // another SCSI Bus Driver to work on the same host handle.\r
391 //\r
392 ExtScsiSupport = TRUE;\r
393 PassThruStatus = gBS->OpenProtocol (\r
394 Controller,\r
395 &gEfiScsiPassThruProtocolGuid,\r
396 (VOID **) &ScsiInterface,\r
397 This->DriverBindingHandle,\r
398 Controller,\r
399 EFI_OPEN_PROTOCOL_BY_DRIVER\r
400 );\r
70c94b3b 401 }\r
d1102dba 402\r
f36d6e66 403 if (Status != EFI_ALREADY_STARTED) {\r
404 //\r
405 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened\r
406 // on this handle for this time. Then construct Host controller private data.\r
407 //\r
408 ScsiBusDev = NULL;\r
409 ScsiBusDev = AllocateZeroPool(sizeof(SCSI_BUS_DEVICE));\r
410 if (ScsiBusDev == NULL) {\r
411 Status = EFI_OUT_OF_RESOURCES;\r
412 goto ErrorExit;\r
413 }\r
414 ScsiBusDev->Signature = SCSI_BUS_DEVICE_SIGNATURE;\r
415 ScsiBusDev->ExtScsiSupport = ExtScsiSupport;\r
416 ScsiBusDev->DevicePath = ParentDevicePath;\r
70c94b3b 417 if (ScsiBusDev->ExtScsiSupport) {\r
f36d6e66 418 ScsiBusDev->ExtScsiInterface = ExtScsiInterface;\r
70c94b3b 419 } else {\r
d1102dba 420 ScsiBusDev->ScsiInterface = ScsiInterface;\r
70c94b3b 421 }\r
f36d6e66 422\r
423 //\r
424 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be\r
425 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru\r
426 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.\r
d1102dba 427 //\r
f36d6e66 428 Status = gBS->InstallProtocolInterface (\r
429 &Controller,\r
c8ad2d7a 430 &gEfiCallerIdGuid,\r
f36d6e66 431 EFI_NATIVE_INTERFACE,\r
432 &ScsiBusDev->BusIdentify\r
433 );\r
434 if (EFI_ERROR (Status)) {\r
435 goto ErrorExit;\r
436 }\r
437 } else {\r
438 //\r
439 // Go through here means Start() is re-invoked again, nothing special is required to do except\r
440 // picking up Host controller private information.\r
441 //\r
442 Status = gBS->OpenProtocol (\r
443 Controller,\r
c8ad2d7a 444 &gEfiCallerIdGuid,\r
f36d6e66 445 (VOID **) &BusIdentify,\r
446 This->DriverBindingHandle,\r
447 Controller,\r
448 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
449 );\r
450\r
451 if (EFI_ERROR (Status)) {\r
452 return Status;\r
453 }\r
454 ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify);\r
3a10d471 455 }\r
456\r
37623a5c 457 //\r
458 // Report Status Code to indicate detecting devices on bus\r
459 //\r
460 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
461 EFI_PROGRESS_CODE,\r
462 (EFI_IO_BUS_SCSI | EFI_IOB_PC_DETECT),\r
463 ParentDevicePath\r
464 );\r
465\r
af4a6385 466 Lun = 0;\r
3a10d471 467 if (RemainingDevicePath == NULL) {\r
af4a6385 468 //\r
d1102dba 469 // If RemainingDevicePath is NULL,\r
af4a6385 470 // must enumerate all SCSI devices anyway\r
471 //\r
70c94b3b 472 FromFirstTarget = TRUE;\r
af4a6385 473 } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
474 //\r
d1102dba 475 // If RemainingDevicePath isn't the End of Device Path Node,\r
af4a6385 476 // only scan the specified device by RemainingDevicePath\r
477 //\r
70c94b3b 478 if (ScsiBusDev->ExtScsiSupport) {\r
d1102dba 479 Status = ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun);\r
70c94b3b 480 } else {\r
d10a41e6 481 Status = ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);\r
70c94b3b 482 }\r
af4a6385 483\r
d10a41e6 484 if (EFI_ERROR (Status)) {\r
485 return Status;\r
486 }\r
af4a6385 487 } else {\r
488 //\r
489 // If RemainingDevicePath is the End of Device Path Node,\r
490 // skip enumerate any device and return EFI_SUCESSS\r
d1102dba 491 //\r
af4a6385 492 ScanOtherPuns = FALSE;\r
3a10d471 493 }\r
494\r
70c94b3b 495 while(ScanOtherPuns) {\r
496 if (FromFirstTarget) {\r
3a10d471 497 //\r
498 // Remaining Device Path is NULL, scan all the possible Puns in the\r
499 // SCSI Channel.\r
500 //\r
70c94b3b 501 if (ScsiBusDev->ExtScsiSupport) {\r
502 Status = ScsiBusDev->ExtScsiInterface->GetNextTargetLun (ScsiBusDev->ExtScsiInterface, &TargetId, &Lun);\r
503 } else {\r
d548f0a1 504 Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId.ScsiId.Scsi, &Lun);\r
70c94b3b 505 }\r
3a10d471 506 if (EFI_ERROR (Status)) {\r
507 //\r
508 // no legal Pun and Lun found any more\r
509 //\r
510 break;\r
511 }\r
512 } else {\r
3a10d471 513 ScanOtherPuns = FALSE;\r
514 }\r
3a10d471 515 //\r
516 // Avoid creating handle for the host adapter.\r
517 //\r
70c94b3b 518 if (ScsiBusDev->ExtScsiSupport) {\r
d548f0a1 519 if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) {\r
70c94b3b 520 continue;\r
521 }\r
522 } else {\r
d548f0a1 523 if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) {\r
70c94b3b 524 continue;\r
525 }\r
3a10d471 526 }\r
3a10d471 527 //\r
528 // Scan for the scsi device, if it attaches to the scsi bus,\r
529 // then create handle and install scsi i/o protocol.\r
530 //\r
d548f0a1 531 Status = ScsiScanCreateDevice (This, Controller, &ScsiTargetId, Lun, ScsiBusDev);\r
3a10d471 532 }\r
f36d6e66 533 return EFI_SUCCESS;\r
9b38ff34 534\r
f36d6e66 535ErrorExit:\r
d1102dba 536\r
f36d6e66 537 if (ScsiBusDev != NULL) {\r
9b38ff34 538 FreePool (ScsiBusDev);\r
f36d6e66 539 }\r
d1102dba 540\r
f36d6e66 541 if (ExtScsiSupport) {\r
542 gBS->CloseProtocol (\r
543 Controller,\r
544 &gEfiExtScsiPassThruProtocolGuid,\r
545 This->DriverBindingHandle,\r
546 Controller\r
547 );\r
548 if (!EFI_ERROR (PassThruStatus)) {\r
549 gBS->CloseProtocol (\r
550 Controller,\r
551 &gEfiScsiPassThruProtocolGuid,\r
552 This->DriverBindingHandle,\r
553 Controller\r
554 );\r
555 }\r
556 } else {\r
557 gBS->CloseProtocol (\r
558 Controller,\r
559 &gEfiScsiPassThruProtocolGuid,\r
560 This->DriverBindingHandle,\r
561 Controller\r
562 );\r
563 }\r
3a10d471 564 return Status;\r
565}\r
566\r
9beb888e 567/**\r
568 Stop this driver on ControllerHandle.\r
569\r
570 This service is called by the EFI boot service DisconnectController().\r
571 In order to make drivers as small as possible, there are a few calling\r
572 restrictions for this service. DisconnectController() must follow these\r
573 calling restrictions. If any other agent wishes to call Stop() it must also\r
574 follow these calling restrictions.\r
d1102dba 575\r
9beb888e 576 @param This Protocol instance pointer.\r
577 @param ControllerHandle Handle of device to stop driver on\r
578 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
579 children is zero stop the entire bus driver.\r
580 @param ChildHandleBuffer List of Child Handles to Stop.\r
581\r
582 @retval EFI_SUCCESS This driver is removed ControllerHandle\r
583 @retval other This driver was not removed from this device\r
584\r
585**/\r
3a10d471 586EFI_STATUS\r
587EFIAPI\r
588SCSIBusDriverBindingStop (\r
589 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
590 IN EFI_HANDLE Controller,\r
591 IN UINTN NumberOfChildren,\r
592 IN EFI_HANDLE *ChildHandleBuffer\r
593 )\r
3a10d471 594{\r
595 EFI_STATUS Status;\r
596 BOOLEAN AllChildrenStopped;\r
597 UINTN Index;\r
598 EFI_SCSI_IO_PROTOCOL *ScsiIo;\r
599 SCSI_IO_DEV *ScsiIoDevice;\r
70c94b3b 600 VOID *ScsiPassThru;\r
601 EFI_SCSI_BUS_PROTOCOL *Scsidentifier;\r
602 SCSI_BUS_DEVICE *ScsiBusDev;\r
3a10d471 603\r
604 if (NumberOfChildren == 0) {\r
70c94b3b 605 //\r
606 // Get the SCSI_BUS_DEVICE\r
607 //\r
608 Status = gBS->OpenProtocol (\r
609 Controller,\r
c8ad2d7a 610 &gEfiCallerIdGuid,\r
70c94b3b 611 (VOID **) &Scsidentifier,\r
612 This->DriverBindingHandle,\r
613 Controller,\r
614 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
615 );\r
c52fa98c 616\r
70c94b3b 617 if (EFI_ERROR (Status)) {\r
618 return EFI_DEVICE_ERROR;\r
619 }\r
620\r
621 ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier);\r
622\r
623 //\r
624 // Uninstall SCSI Bus Protocol\r
625 //\r
626 gBS->UninstallProtocolInterface (\r
627 Controller,\r
c8ad2d7a 628 &gEfiCallerIdGuid,\r
70c94b3b 629 &ScsiBusDev->BusIdentify\r
630 );\r
c52fa98c 631\r
3a10d471 632 //\r
633 // Close the bus driver\r
634 //\r
70c94b3b 635 if (ScsiBusDev->ExtScsiSupport) {\r
1e5914b5 636 //\r
637 // Close ExtPassThru Protocol from this controller handle\r
638 //\r
70c94b3b 639 gBS->CloseProtocol (\r
640 Controller,\r
641 &gEfiExtScsiPassThruProtocolGuid,\r
642 This->DriverBindingHandle,\r
643 Controller\r
644 );\r
1e5914b5 645 //\r
646 // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.\r
d1102dba 647 // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle.\r
1e5914b5 648 // So Stop() needs to try to close PassThru if present here.\r
649 //\r
650 gBS->CloseProtocol (\r
651 Controller,\r
652 &gEfiScsiPassThruProtocolGuid,\r
653 This->DriverBindingHandle,\r
654 Controller\r
655 );\r
70c94b3b 656 } else {\r
657 gBS->CloseProtocol (\r
658 Controller,\r
659 &gEfiScsiPassThruProtocolGuid,\r
660 This->DriverBindingHandle,\r
661 Controller\r
662 );\r
663 }\r
3a10d471 664\r
70c94b3b 665 gBS->CloseProtocol (\r
666 Controller,\r
667 &gEfiDevicePathProtocolGuid,\r
668 This->DriverBindingHandle,\r
669 Controller\r
670 );\r
6c94a00d 671 FreePool (ScsiBusDev);\r
3a10d471 672 return EFI_SUCCESS;\r
673 }\r
674\r
675 AllChildrenStopped = TRUE;\r
676\r
677 for (Index = 0; Index < NumberOfChildren; Index++) {\r
678\r
679 Status = gBS->OpenProtocol (\r
680 ChildHandleBuffer[Index],\r
681 &gEfiScsiIoProtocolGuid,\r
682 (VOID **) &ScsiIo,\r
683 This->DriverBindingHandle,\r
684 Controller,\r
685 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
686 );\r
687 if (EFI_ERROR (Status)) {\r
688 AllChildrenStopped = FALSE;\r
689 continue;\r
690 }\r
691\r
692 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (ScsiIo);\r
693 //\r
694 // Close the child handle\r
695 //\r
70c94b3b 696 if (ScsiIoDevice->ExtScsiSupport) {\r
697 Status = gBS->CloseProtocol (\r
698 Controller,\r
699 &gEfiExtScsiPassThruProtocolGuid,\r
700 This->DriverBindingHandle,\r
701 ChildHandleBuffer[Index]\r
702 );\r
703\r
704 } else {\r
705 Status = gBS->CloseProtocol (\r
706 Controller,\r
707 &gEfiScsiPassThruProtocolGuid,\r
708 This->DriverBindingHandle,\r
709 ChildHandleBuffer[Index]\r
710 );\r
711 }\r
3a10d471 712\r
713 Status = gBS->UninstallMultipleProtocolInterfaces (\r
714 ChildHandleBuffer[Index],\r
715 &gEfiDevicePathProtocolGuid,\r
716 ScsiIoDevice->DevicePath,\r
717 &gEfiScsiIoProtocolGuid,\r
718 &ScsiIoDevice->ScsiIo,\r
719 NULL\r
720 );\r
721 if (EFI_ERROR (Status)) {\r
722 AllChildrenStopped = FALSE;\r
70c94b3b 723 if (ScsiIoDevice->ExtScsiSupport) {\r
724 gBS->OpenProtocol (\r
725 Controller,\r
726 &gEfiExtScsiPassThruProtocolGuid,\r
84b5c78e 727 &ScsiPassThru,\r
70c94b3b 728 This->DriverBindingHandle,\r
729 ChildHandleBuffer[Index],\r
730 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
731 );\r
732 } else {\r
733 gBS->OpenProtocol (\r
734 Controller,\r
735 &gEfiScsiPassThruProtocolGuid,\r
84b5c78e 736 &ScsiPassThru,\r
70c94b3b 737 This->DriverBindingHandle,\r
738 ChildHandleBuffer[Index],\r
739 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
740 );\r
741 }\r
3a10d471 742 } else {\r
6c94a00d 743 FreePool (ScsiIoDevice);\r
3a10d471 744 }\r
745 }\r
746\r
747 if (!AllChildrenStopped) {\r
748 return EFI_DEVICE_ERROR;\r
749 }\r
750\r
751 return EFI_SUCCESS;\r
752}\r
753\r
9beb888e 754\r
755/**\r
756 Retrieves the device type information of the SCSI Controller.\r
757\r
758 @param This Protocol instance pointer.\r
759 @param DeviceType A pointer to the device type information retrieved from\r
d1102dba 760 the SCSI Controller.\r
9beb888e 761\r
762 @retval EFI_SUCCESS Retrieves the device type information successfully.\r
763 @retval EFI_INVALID_PARAMETER The DeviceType is NULL.\r
d1102dba 764\r
9beb888e 765**/\r
3a10d471 766EFI_STATUS\r
767EFIAPI\r
768ScsiGetDeviceType (\r
769 IN EFI_SCSI_IO_PROTOCOL *This,\r
770 OUT UINT8 *DeviceType\r
771 )\r
3a10d471 772{\r
773 SCSI_IO_DEV *ScsiIoDevice;\r
774\r
775 if (DeviceType == NULL) {\r
776 return EFI_INVALID_PARAMETER;\r
777 }\r
778\r
779 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
780 *DeviceType = ScsiIoDevice->ScsiDeviceType;\r
781 return EFI_SUCCESS;\r
782}\r
783\r
9beb888e 784\r
785/**\r
786 Retrieves the device location in the SCSI channel.\r
787\r
788 @param This Protocol instance pointer.\r
789 @param Target A pointer to the Target ID of a SCSI device\r
790 on the SCSI channel.\r
791 @param Lun A pointer to the LUN of the SCSI device on\r
792 the SCSI channel.\r
793\r
794 @retval EFI_SUCCESS Retrieves the device location successfully.\r
795 @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.\r
796\r
797**/\r
3a10d471 798EFI_STATUS\r
799EFIAPI\r
800ScsiGetDeviceLocation (\r
801 IN EFI_SCSI_IO_PROTOCOL *This,\r
70c94b3b 802 IN OUT UINT8 **Target,\r
3a10d471 803 OUT UINT64 *Lun\r
804 )\r
3a10d471 805{\r
806 SCSI_IO_DEV *ScsiIoDevice;\r
807\r
808 if (Target == NULL || Lun == NULL) {\r
809 return EFI_INVALID_PARAMETER;\r
810 }\r
811\r
f36d6e66 812 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
3a10d471 813\r
70c94b3b 814 CopyMem (*Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);\r
815\r
f36d6e66 816 *Lun = ScsiIoDevice->Lun;\r
3a10d471 817\r
818 return EFI_SUCCESS;\r
819}\r
820\r
9beb888e 821/**\r
822 Resets the SCSI Bus that the SCSI Controller is attached to.\r
823\r
824 @param This Protocol instance pointer.\r
825\r
826 @retval EFI_SUCCESS The SCSI bus is reset successfully.\r
827 @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus.\r
828 @retval EFI_UNSUPPORTED The bus reset operation is not supported by the\r
829 SCSI Host Controller.\r
d1102dba 830 @retval EFI_TIMEOUT A timeout occurred while attempting to reset\r
9beb888e 831 the SCSI bus.\r
832**/\r
3a10d471 833EFI_STATUS\r
834EFIAPI\r
835ScsiResetBus (\r
836 IN EFI_SCSI_IO_PROTOCOL *This\r
837 )\r
3a10d471 838{\r
839 SCSI_IO_DEV *ScsiIoDevice;\r
840\r
841 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
842\r
37623a5c 843 //\r
844 // Report Status Code to indicate reset happens\r
845 //\r
846 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
847 EFI_PROGRESS_CODE,\r
848 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),\r
849 ScsiIoDevice->ScsiBusDeviceData->DevicePath\r
850 );\r
851\r
70c94b3b 852 if (ScsiIoDevice->ExtScsiSupport){\r
853 return ScsiIoDevice->ExtScsiPassThru->ResetChannel (ScsiIoDevice->ExtScsiPassThru);\r
854 } else {\r
855 return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru);\r
856 }\r
3a10d471 857}\r
858\r
9beb888e 859\r
860/**\r
861 Resets the SCSI Controller that the device handle specifies.\r
862\r
863 @param This Protocol instance pointer.\r
864\r
865 @retval EFI_SUCCESS Reset the SCSI controller successfully.\r
866 @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.\r
867 @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.\r
868 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the\r
869 SCSI Controller.\r
870**/\r
3a10d471 871EFI_STATUS\r
872EFIAPI\r
873ScsiResetDevice (\r
874 IN EFI_SCSI_IO_PROTOCOL *This\r
875 )\r
3a10d471 876{\r
f36d6e66 877 SCSI_IO_DEV *ScsiIoDevice;\r
70c94b3b 878 UINT8 Target[TARGET_MAX_BYTES];\r
3a10d471 879\r
880 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
37623a5c 881\r
882 //\r
883 // Report Status Code to indicate reset happens\r
884 //\r
885 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
886 EFI_PROGRESS_CODE,\r
887 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),\r
888 ScsiIoDevice->ScsiBusDeviceData->DevicePath\r
889 );\r
d1102dba 890\r
70c94b3b 891 CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);\r
892\r
3a10d471 893\r
70c94b3b 894 if (ScsiIoDevice->ExtScsiSupport) {\r
895 return ScsiIoDevice->ExtScsiPassThru->ResetTargetLun (\r
896 ScsiIoDevice->ExtScsiPassThru,\r
897 Target,\r
898 ScsiIoDevice->Lun\r
899 );\r
900 } else {\r
901 return ScsiIoDevice->ScsiPassThru->ResetTarget (\r
902 ScsiIoDevice->ScsiPassThru,\r
903 ScsiIoDevice->Pun.ScsiId.Scsi,\r
904 ScsiIoDevice->Lun\r
905 );\r
906 }\r
3a10d471 907}\r
908\r
f36d6e66 909\r
9beb888e 910/**\r
f36d6e66 911 Sends a SCSI Request Packet to the SCSI Controller for execution.\r
f36d6e66 912\r
9beb888e 913 @param This Protocol instance pointer.\r
d1102dba 914 @param CommandPacket The SCSI request packet to send to the SCSI\r
f36d6e66 915 Controller specified by the device handle.\r
9beb888e 916 @param Event If the SCSI bus where the SCSI device is attached\r
d1102dba
LG
917 does not support non-blocking I/O, then Event is\r
918 ignored, and blocking I/O is performed.\r
f36d6e66 919 If Event is NULL, then blocking I/O is performed.\r
d1102dba 920 If Event is not NULL and non-blocking I/O is\r
f36d6e66 921 supported, then non-blocking I/O is performed,\r
922 and Event will be signaled when the SCSI Request\r
923 Packet completes.\r
9beb888e 924\r
d1102dba
LG
925 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host\r
926 successfully, and TransferLength bytes were\r
927 transferred to/from DataBuffer.See\r
928 HostAdapterStatus, TargetStatus,\r
9beb888e 929 SenseDataLength, and SenseData in that order\r
930 for additional status information.\r
d1102dba 931 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,\r
9beb888e 932 but the entire DataBuffer could not be transferred.\r
933 The actual number of bytes transferred is returned\r
d1102dba
LG
934 in TransferLength. See HostAdapterStatus,\r
935 TargetStatus, SenseDataLength, and SenseData in\r
9beb888e 936 that order for additional status information.\r
d1102dba
LG
937 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because\r
938 there are too many SCSI Command Packets already\r
9beb888e 939 queued.The caller may retry again later.\r
d1102dba
LG
940 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send\r
941 the SCSI Request Packet. See HostAdapterStatus,\r
942 TargetStatus, SenseDataLength, and SenseData in\r
9beb888e 943 that order for additional status information.\r
d1102dba
LG
944 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid.\r
945 The SCSI Request Packet was not sent, so no\r
9beb888e 946 additional status information is available.\r
947 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet\r
d1102dba 948 is not supported by the SCSI initiator(i.e., SCSI\r
9beb888e 949 Host Controller). The SCSI Request Packet was not\r
d1102dba 950 sent, so no additional status information is\r
9beb888e 951 available.\r
d1102dba 952 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI\r
9beb888e 953 Request Packet to execute. See HostAdapterStatus,\r
d1102dba 954 TargetStatus, SenseDataLength, and SenseData in\r
9beb888e 955 that order for additional status information.\r
956**/\r
957EFI_STATUS\r
958EFIAPI\r
959ScsiExecuteSCSICommand (\r
960 IN EFI_SCSI_IO_PROTOCOL *This,\r
961 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,\r
962 IN EFI_EVENT Event OPTIONAL\r
963 )\r
3a10d471 964{\r
f36d6e66 965 SCSI_IO_DEV *ScsiIoDevice;\r
966 EFI_STATUS Status;\r
70c94b3b 967 UINT8 Target[TARGET_MAX_BYTES];\r
968 EFI_EVENT PacketEvent;\r
969 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ExtRequestPacket;\r
d1102dba 970 SCSI_EVENT_DATA EventData;\r
3a10d471 971\r
70c94b3b 972 PacketEvent = NULL;\r
d1102dba 973\r
3a10d471 974 if (Packet == NULL) {\r
975 return EFI_INVALID_PARAMETER;\r
976 }\r
977\r
978 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
70c94b3b 979 CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);\r
c52fa98c 980\r
70c94b3b 981 if (ScsiIoDevice->ExtScsiSupport) {\r
982 ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;\r
0d12e6a0
HW
983\r
984 if (((ScsiIoDevice->ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) {\r
985 Status = ScsiIoDevice->ExtScsiPassThru->PassThru (\r
986 ScsiIoDevice->ExtScsiPassThru,\r
987 Target,\r
988 ScsiIoDevice->Lun,\r
989 ExtRequestPacket,\r
990 Event\r
991 );\r
992 } else {\r
993 //\r
994 // If there's no event or the SCSI Device doesn't support NON-BLOCKING,\r
995 // let the 'Event' parameter for PassThru() be NULL.\r
996 //\r
997 Status = ScsiIoDevice->ExtScsiPassThru->PassThru (\r
998 ScsiIoDevice->ExtScsiPassThru,\r
999 Target,\r
1000 ScsiIoDevice->Lun,\r
1001 ExtRequestPacket,\r
1002 NULL\r
1003 );\r
9f840a9e 1004 if ((!EFI_ERROR(Status)) && (Event != NULL)) {\r
0d12e6a0 1005 //\r
9f840a9e
HW
1006 // Signal Event to tell caller to pick up the SCSI IO packet if the\r
1007 // PassThru() succeeds.\r
0d12e6a0
HW
1008 //\r
1009 gBS->SignalEvent (Event);\r
1010 }\r
1011 }\r
70c94b3b 1012 } else {\r
3a10d471 1013\r
9b38ff34 1014 mWorkingBuffer = AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));\r
3a10d471 1015\r
9b38ff34 1016 if (mWorkingBuffer == NULL) {\r
70c94b3b 1017 return EFI_DEVICE_ERROR;\r
1018 }\r
1019\r
1020 //\r
c52fa98c 1021 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.\r
70c94b3b 1022 //\r
9beb888e 1023 Status = ScsiioToPassThruPacket(Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer);\r
70c94b3b 1024 if (EFI_ERROR(Status)) {\r
9beb888e 1025 FreePool(mWorkingBuffer);\r
70c94b3b 1026 return Status;\r
1027 }\r
1028\r
7077edb3 1029 if (((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) {\r
70c94b3b 1030 EventData.Data1 = (VOID*)Packet;\r
1031 EventData.Data2 = Event;\r
1032 //\r
1033 // Create Event\r
1034 //\r
1035 Status = gBS->CreateEvent (\r
1036 EVT_NOTIFY_SIGNAL,\r
6be0af05 1037 TPL_NOTIFY,\r
70c94b3b 1038 NotifyFunction,\r
1039 &EventData,\r
1040 &PacketEvent\r
1041 );\r
1042 if (EFI_ERROR(Status)) {\r
9beb888e 1043 FreePool(mWorkingBuffer);\r
70c94b3b 1044 return Status;\r
1045 }\r
c52fa98c 1046\r
70c94b3b 1047 Status = ScsiIoDevice->ScsiPassThru->PassThru (\r
1048 ScsiIoDevice->ScsiPassThru,\r
1049 ScsiIoDevice->Pun.ScsiId.Scsi,\r
1050 ScsiIoDevice->Lun,\r
9beb888e 1051 mWorkingBuffer,\r
70c94b3b 1052 PacketEvent\r
1053 );\r
1054\r
1055 if (EFI_ERROR(Status)) {\r
9b38ff34 1056 FreePool(mWorkingBuffer);\r
70c94b3b 1057 gBS->CloseEvent(PacketEvent);\r
1058 return Status;\r
1059 }\r
c52fa98c 1060\r
70c94b3b 1061 } else {\r
1062 //\r
1063 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert\r
1064 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.\r
1065 //\r
1066 Status = ScsiIoDevice->ScsiPassThru->PassThru (\r
1067 ScsiIoDevice->ScsiPassThru,\r
1068 ScsiIoDevice->Pun.ScsiId.Scsi,\r
1069 ScsiIoDevice->Lun,\r
9beb888e 1070 mWorkingBuffer,\r
0d12e6a0 1071 NULL\r
70c94b3b 1072 );\r
1073 if (EFI_ERROR(Status)) {\r
9beb888e 1074 FreePool(mWorkingBuffer);\r
70c94b3b 1075 return Status;\r
1076 }\r
1077\r
9beb888e 1078 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer,Packet);\r
70c94b3b 1079 //\r
1080 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,\r
9beb888e 1081 // free mWorkingBuffer.\r
70c94b3b 1082 //\r
9beb888e 1083 FreePool(mWorkingBuffer);\r
0d12e6a0
HW
1084\r
1085 //\r
1086 // Signal Event to tell caller to pick up the SCSI IO Packet.\r
1087 //\r
1088 if (Event != NULL) {\r
1089 gBS->SignalEvent (Event);\r
1090 }\r
70c94b3b 1091 }\r
1092 }\r
3a10d471 1093 return Status;\r
1094}\r
1095\r
3a10d471 1096\r
9beb888e 1097/**\r
70c94b3b 1098 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.\r
3a10d471 1099\r
9beb888e 1100 @param This Protocol instance pointer\r
1101 @param Controller Controller handle\r
1102 @param TargetId Tartget to be scanned\r
1103 @param Lun The Lun of the SCSI device on the SCSI channel.\r
1104 @param ScsiBusDev The pointer of SCSI_BUS_DEVICE\r
3a10d471 1105\r
9beb888e 1106 @retval EFI_SUCCESS Successfully to discover the device and attach\r
1107 ScsiIoProtocol to it.\r
1108 @retval EFI_OUT_OF_RESOURCES Fail to discover the device.\r
3a10d471 1109\r
9beb888e 1110**/\r
1111EFI_STATUS\r
1112EFIAPI\r
1113ScsiScanCreateDevice (\r
1114 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1115 IN EFI_HANDLE Controller,\r
1116 IN SCSI_TARGET_ID *TargetId,\r
1117 IN UINT64 Lun,\r
1118 IN OUT SCSI_BUS_DEVICE *ScsiBusDev\r
1119 )\r
3a10d471 1120{\r
1121 EFI_STATUS Status;\r
1122 SCSI_IO_DEV *ScsiIoDevice;\r
1123 EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath;\r
cbd2a4b3 1124 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1125 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
1126 EFI_HANDLE DeviceHandle;\r
1127\r
1128 DevicePath = NULL;\r
1129 RemainingDevicePath = NULL;\r
1130 ScsiDevicePath = NULL;\r
1131 ScsiIoDevice = NULL;\r
1132\r
1133 //\r
1134 // Build Device Path\r
1135 //\r
1136 if (ScsiBusDev->ExtScsiSupport){\r
1137 Status = ScsiBusDev->ExtScsiInterface->BuildDevicePath (\r
1138 ScsiBusDev->ExtScsiInterface,\r
1139 &TargetId->ScsiId.ExtScsi[0],\r
1140 Lun,\r
1141 &ScsiDevicePath\r
1142 );\r
1143 } else {\r
e7c2a83b 1144 Status = ScsiBusDev->ScsiInterface->BuildDevicePath (\r
1145 ScsiBusDev->ScsiInterface,\r
1146 TargetId->ScsiId.Scsi,\r
1147 Lun,\r
1148 &ScsiDevicePath\r
1149 );\r
cbd2a4b3 1150 }\r
1151\r
1152 if (EFI_ERROR(Status)) {\r
1153 return Status;\r
1154 }\r
1155\r
1156 DevicePath = AppendDevicePathNode (\r
1157 ScsiBusDev->DevicePath,\r
1158 ScsiDevicePath\r
1159 );\r
1160\r
1161 if (DevicePath == NULL) {\r
1162 Status = EFI_OUT_OF_RESOURCES;\r
1163 goto ErrorExit;\r
1164 }\r
1165\r
1166 DeviceHandle = NULL;\r
1167 RemainingDevicePath = DevicePath;\r
1168 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
1169 if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
1170 //\r
1171 // The device has been started, directly return to fast boot.\r
1172 //\r
1173 Status = EFI_ALREADY_STARTED;\r
1174 goto ErrorExit;\r
1175 }\r
3a10d471 1176\r
9beb888e 1177 ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV));\r
1178 if (ScsiIoDevice == NULL) {\r
cbd2a4b3 1179 Status = EFI_OUT_OF_RESOURCES;\r
1180 goto ErrorExit;\r
3a10d471 1181 }\r
1182\r
3a10d471 1183 ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE;\r
37623a5c 1184 ScsiIoDevice->ScsiBusDeviceData = ScsiBusDev;\r
70c94b3b 1185 CopyMem(&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES);\r
3a10d471 1186 ScsiIoDevice->Lun = Lun;\r
1187\r
70c94b3b 1188 if (ScsiBusDev->ExtScsiSupport) {\r
1189 ScsiIoDevice->ExtScsiPassThru = ScsiBusDev->ExtScsiInterface;\r
1190 ScsiIoDevice->ExtScsiSupport = TRUE;\r
1191 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ExtScsiPassThru->Mode->IoAlign;\r
1192\r
1193 } else {\r
1194 ScsiIoDevice->ScsiPassThru = ScsiBusDev->ScsiInterface;\r
1195 ScsiIoDevice->ExtScsiSupport = FALSE;\r
1196 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ScsiPassThru->Mode->IoAlign;\r
1197 }\r
1198\r
3a10d471 1199 ScsiIoDevice->ScsiIo.GetDeviceType = ScsiGetDeviceType;\r
70c94b3b 1200 ScsiIoDevice->ScsiIo.GetDeviceLocation = ScsiGetDeviceLocation;\r
3a10d471 1201 ScsiIoDevice->ScsiIo.ResetBus = ScsiResetBus;\r
1202 ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice;\r
24e734d2 1203 ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand;\r
3a10d471 1204\r
37623a5c 1205 //\r
1206 // Report Status Code here since the new SCSI device will be discovered\r
1207 //\r
1208 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1209 EFI_PROGRESS_CODE,\r
1210 (EFI_IO_BUS_SCSI | EFI_IOB_PC_ENABLE),\r
1211 ScsiBusDev->DevicePath\r
1212 );\r
1213\r
3a10d471 1214 if (!DiscoverScsiDevice (ScsiIoDevice)) {\r
cbd2a4b3 1215 Status = EFI_OUT_OF_RESOURCES;\r
1216 goto ErrorExit;\r
3a10d471 1217 }\r
70c94b3b 1218\r
cbd2a4b3 1219 ScsiIoDevice->DevicePath = DevicePath;\r
c52fa98c 1220\r
3a10d471 1221 Status = gBS->InstallMultipleProtocolInterfaces (\r
1222 &ScsiIoDevice->Handle,\r
1223 &gEfiDevicePathProtocolGuid,\r
1224 ScsiIoDevice->DevicePath,\r
1225 &gEfiScsiIoProtocolGuid,\r
1226 &ScsiIoDevice->ScsiIo,\r
1227 NULL\r
1228 );\r
1229 if (EFI_ERROR (Status)) {\r
cbd2a4b3 1230 goto ErrorExit;\r
3a10d471 1231 } else {\r
70c94b3b 1232 if (ScsiBusDev->ExtScsiSupport) {\r
1233 gBS->OpenProtocol (\r
cbd2a4b3 1234 Controller,\r
1235 &gEfiExtScsiPassThruProtocolGuid,\r
1236 (VOID **) &(ScsiBusDev->ExtScsiInterface),\r
1237 This->DriverBindingHandle,\r
1238 ScsiIoDevice->Handle,\r
1239 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1240 );\r
70c94b3b 1241 } else {\r
1242 gBS->OpenProtocol (\r
cbd2a4b3 1243 Controller,\r
1244 &gEfiScsiPassThruProtocolGuid,\r
1245 (VOID **) &(ScsiBusDev->ScsiInterface),\r
1246 This->DriverBindingHandle,\r
1247 ScsiIoDevice->Handle,\r
1248 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1249 );\r
70c94b3b 1250 }\r
3a10d471 1251 }\r
3a10d471 1252 return EFI_SUCCESS;\r
cbd2a4b3 1253\r
1254ErrorExit:\r
d1102dba 1255\r
cbd2a4b3 1256 //\r
1257 // The memory space for ScsiDevicePath is allocated in\r
1258 // ScsiPassThru->BuildDevicePath() function; It is no longer used\r
1259 // after AppendDevicePathNode,so free the memory it occupies.\r
1260 //\r
1261 FreePool (ScsiDevicePath);\r
1262\r
1263 if (DevicePath != NULL) {\r
1264 FreePool (DevicePath);\r
1265 }\r
1266\r
1267 if (ScsiIoDevice != NULL) {\r
1268 FreePool (ScsiIoDevice);\r
1269 }\r
1270\r
1271 return Status;\r
3a10d471 1272}\r
1273\r
3a10d471 1274\r
9beb888e 1275/**\r
70c94b3b 1276 Discovery SCSI Device\r
3a10d471 1277\r
9beb888e 1278 @param ScsiIoDevice The pointer of SCSI_IO_DEV\r
3a10d471 1279\r
9beb888e 1280 @retval TRUE Find SCSI Device and verify it.\r
1281 @retval FALSE Unable to find SCSI Device.\r
3a10d471 1282\r
9beb888e 1283**/\r
1284BOOLEAN\r
1285DiscoverScsiDevice (\r
1286 IN OUT SCSI_IO_DEV *ScsiIoDevice\r
1287 )\r
3a10d471 1288{\r
1289 EFI_STATUS Status;\r
3a10d471 1290 UINT32 InquiryDataLength;\r
3a10d471 1291 UINT8 SenseDataLength;\r
1292 UINT8 HostAdapterStatus;\r
1293 UINT8 TargetStatus;\r
957fe093 1294 EFI_SCSI_INQUIRY_DATA *InquiryData;\r
ce13d2d8 1295 EFI_SCSI_SENSE_DATA *SenseData;\r
cbd2a4b3 1296 UINT8 MaxRetry;\r
1297 UINT8 Index;\r
957fe093 1298 BOOLEAN ScsiDeviceFound;\r
3a10d471 1299\r
1300 HostAdapterStatus = 0;\r
1301 TargetStatus = 0;\r
ce13d2d8 1302 SenseData = NULL;\r
957fe093
SZ
1303\r
1304 InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA));\r
1305 if (InquiryData == NULL) {\r
1306 ScsiDeviceFound = FALSE;\r
1307 goto Done;\r
1308 }\r
1309\r
ce13d2d8
LE
1310 SenseData = AllocateAlignedBuffer (\r
1311 ScsiIoDevice,\r
1312 sizeof (EFI_SCSI_SENSE_DATA)\r
1313 );\r
1314 if (SenseData == NULL) {\r
1315 ScsiDeviceFound = FALSE;\r
1316 goto Done;\r
1317 }\r
1318\r
3a10d471 1319 //\r
1320 // Using Inquiry command to scan for the device\r
1321 //\r
1322 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
ce13d2d8 1323 SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);\r
957fe093 1324 ZeroMem (InquiryData, InquiryDataLength);\r
ce13d2d8 1325 ZeroMem (SenseData, SenseDataLength);\r
cbd2a4b3 1326\r
1327 MaxRetry = 2;\r
1328 for (Index = 0; Index < MaxRetry; Index++) {\r
1329 Status = ScsiInquiryCommand (\r
1330 &ScsiIoDevice->ScsiIo,\r
3cc033c5 1331 SCSI_BUS_TIMEOUT,\r
ce13d2d8 1332 SenseData,\r
cbd2a4b3 1333 &SenseDataLength,\r
1334 &HostAdapterStatus,\r
1335 &TargetStatus,\r
957fe093 1336 (VOID *) InquiryData,\r
cbd2a4b3 1337 &InquiryDataLength,\r
1338 FALSE\r
1339 );\r
1340 if (!EFI_ERROR (Status)) {\r
ce13d2d8
LE
1341 if ((HostAdapterStatus == EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK) &&\r
1342 (TargetStatus == EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION) &&\r
1343 (SenseData->Error_Code == 0x70) &&\r
1344 (SenseData->Sense_Key == EFI_SCSI_SK_ILLEGAL_REQUEST)) {\r
1345 ScsiDeviceFound = FALSE;\r
1346 goto Done;\r
1347 }\r
cbd2a4b3 1348 break;\r
c09e481b
LE
1349 }\r
1350 if ((Status == EFI_BAD_BUFFER_SIZE) ||\r
1351 (Status == EFI_INVALID_PARAMETER) ||\r
1352 (Status == EFI_UNSUPPORTED)) {\r
957fe093
SZ
1353 ScsiDeviceFound = FALSE;\r
1354 goto Done;\r
cbd2a4b3 1355 }\r
1356 }\r
3a10d471 1357\r
cbd2a4b3 1358 if (Index == MaxRetry) {\r
957fe093
SZ
1359 ScsiDeviceFound = FALSE;\r
1360 goto Done;\r
3a10d471 1361 }\r
d1102dba 1362\r
3a10d471 1363 //\r
1364 // Retrieved inquiry data successfully\r
1365 //\r
897efb97 1366 if (InquiryData->Peripheral_Qualifier != 0) {\r
957fe093
SZ
1367 ScsiDeviceFound = FALSE;\r
1368 goto Done;\r
3a10d471 1369 }\r
1370\r
1ff7ed2c
CZ
1371 if ((InquiryData->Peripheral_Type >= EFI_SCSI_TYPE_RESERVED_LOW) &&\r
1372 (InquiryData->Peripheral_Type <= EFI_SCSI_TYPE_RESERVED_HIGH)) {\r
957fe093
SZ
1373 ScsiDeviceFound = FALSE;\r
1374 goto Done;\r
3a10d471 1375 }\r
c52fa98c 1376\r
3a10d471 1377 //\r
1378 // valid device type and peripheral qualifier combination.\r
1379 //\r
957fe093
SZ
1380 ScsiIoDevice->ScsiDeviceType = InquiryData->Peripheral_Type;\r
1381 ScsiIoDevice->RemovableDevice = InquiryData->Rmb;\r
1382 if (InquiryData->Version == 0) {\r
3a10d471 1383 ScsiIoDevice->ScsiVersion = 0;\r
1384 } else {\r
1385 //\r
1386 // ANSI-approved version\r
1387 //\r
957fe093 1388 ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData->Version & 0x07);\r
3a10d471 1389 }\r
1390\r
957fe093
SZ
1391 ScsiDeviceFound = TRUE;\r
1392\r
1393Done:\r
ce13d2d8 1394 FreeAlignedBuffer (SenseData, sizeof (EFI_SCSI_SENSE_DATA));\r
957fe093
SZ
1395 FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA));\r
1396\r
1397 return ScsiDeviceFound;\r
3a10d471 1398}\r
70c94b3b 1399\r
1400\r
9beb888e 1401/**\r
1402 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.\r
1403\r
1404 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET\r
1405 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
1406\r
1407**/\r
70c94b3b 1408EFI_STATUS\r
1409EFIAPI\r
1410ScsiioToPassThruPacket (\r
1411 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,\r
9beb888e 1412 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket\r
70c94b3b 1413 )\r
70c94b3b 1414{\r
1415 //\r
1416 //EFI 1.10 doesn't support Bi-Direction Command.\r
1417 //\r
1418 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL) {\r
1419 return EFI_UNSUPPORTED;\r
1420 }\r
c52fa98c 1421\r
70c94b3b 1422 ZeroMem (CommandPacket, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));\r
1423\r
1424 CommandPacket->Timeout = Packet->Timeout;\r
1425 CommandPacket->Cdb = Packet->Cdb;\r
1426 CommandPacket->CdbLength = Packet->CdbLength;\r
1427 CommandPacket->DataDirection = Packet->DataDirection;\r
1428 CommandPacket->HostAdapterStatus = Packet->HostAdapterStatus;\r
1429 CommandPacket->TargetStatus = Packet->TargetStatus;\r
1430 CommandPacket->SenseData = Packet->SenseData;\r
1431 CommandPacket->SenseDataLength = Packet->SenseDataLength;\r
1432\r
1433 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {\r
1434 CommandPacket->DataBuffer = Packet->InDataBuffer;\r
1435 CommandPacket->TransferLength = Packet->InTransferLength;\r
1436 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {\r
1437 CommandPacket->DataBuffer = Packet->OutDataBuffer;\r
1438 CommandPacket->TransferLength = Packet->OutTransferLength;\r
1439 }\r
1440 return EFI_SUCCESS;\r
1441}\r
1442\r
1443\r
9beb888e 1444/**\r
1445 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.\r
1446\r
1447 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
1448 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET\r
1449\r
1450**/\r
70c94b3b 1451EFI_STATUS\r
1452EFIAPI\r
1453PassThruToScsiioPacket (\r
1454 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,\r
9beb888e 1455 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet\r
70c94b3b 1456 )\r
70c94b3b 1457{\r
1458 Packet->Timeout = ScsiPacket->Timeout;\r
1459 Packet->Cdb = ScsiPacket->Cdb;\r
1460 Packet->CdbLength = ScsiPacket->CdbLength;\r
1461 Packet->DataDirection = ScsiPacket->DataDirection;\r
1462 Packet->HostAdapterStatus = ScsiPacket->HostAdapterStatus;\r
1463 Packet->TargetStatus = ScsiPacket->TargetStatus;\r
1464 Packet->SenseData = ScsiPacket->SenseData;\r
1465 Packet->SenseDataLength = ScsiPacket->SenseDataLength;\r
1466\r
1467 if (ScsiPacket->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {\r
1468 Packet->InDataBuffer = ScsiPacket->DataBuffer;\r
1469 Packet->InTransferLength = ScsiPacket->TransferLength;\r
1470 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {\r
1471 Packet->OutDataBuffer = ScsiPacket->DataBuffer;\r
1472 Packet->OutTransferLength = ScsiPacket->TransferLength;\r
1473 }\r
c52fa98c 1474\r
70c94b3b 1475 return EFI_SUCCESS;\r
1476}\r
1477\r
9beb888e 1478/**\r
1479 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0\r
1480 SCSI IO Packet.\r
70c94b3b 1481\r
9beb888e 1482 @param Event The instance of EFI_EVENT.\r
1483 @param Context The parameter passed in.\r
70c94b3b 1484\r
9beb888e 1485**/\r
70c94b3b 1486VOID\r
1487EFIAPI\r
1488NotifyFunction (\r
9beb888e 1489 IN EFI_EVENT Event,\r
1490 IN VOID *Context\r
70c94b3b 1491 )\r
70c94b3b 1492{\r
1493 EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet;\r
1494 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket;\r
1495 EFI_EVENT CallerEvent;\r
c52fa98c 1496 SCSI_EVENT_DATA *PassData;\r
70c94b3b 1497\r
1498 PassData = (SCSI_EVENT_DATA*)Context;\r
1499 Packet = (EFI_SCSI_IO_SCSI_REQUEST_PACKET *)PassData->Data1;\r
9beb888e 1500 ScsiPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer;\r
70c94b3b 1501\r
1502 //\r
1503 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.\r
1504 //\r
1505 PassThruToScsiioPacket(ScsiPacket, Packet);\r
c52fa98c 1506\r
70c94b3b 1507 //\r
1508 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,\r
9beb888e 1509 // free mWorkingBuffer.\r
70c94b3b 1510 //\r
9beb888e 1511 gBS->FreePool(mWorkingBuffer);\r
70c94b3b 1512\r
1513 //\r
1514 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.\r
1515 //\r
1516 CallerEvent = PassData->Data2;\r
1517 gBS->CloseEvent(Event);\r
1518 gBS->SignalEvent(CallerEvent);\r
1519}\r
9beb888e 1520\r