Updated MSA by putting Specification element at the end of the header section
[mirror_edk2.git] / EdkModulePkg / Bus / Scsi / ScsiBus / Dxe / ScsiBus.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 scsibus.c\r
15 \r
16Abstract: \r
17 \r
18\r
19Revision History\r
20--*/\r
21\r
f0ec738d 22#include "ScsiBus.h"\r
878ddf1f 23\r
24EFI_STATUS\r
25EFIAPI\r
26SCSIBusDriverBindingSupported (\r
27 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
28 IN EFI_HANDLE Controller,\r
29 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
30 );\r
31\r
32EFI_STATUS\r
33EFIAPI\r
34SCSIBusDriverBindingStart (\r
35 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
36 IN EFI_HANDLE Controller,\r
37 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
38 );\r
39\r
40EFI_STATUS\r
41EFIAPI\r
42SCSIBusDriverBindingStop (\r
43 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
44 IN EFI_HANDLE Controller,\r
45 IN UINTN NumberOfChildren,\r
46 IN EFI_HANDLE *ChildHandleBuffer\r
47 );\r
48\r
49EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = {\r
50 SCSIBusDriverBindingSupported,\r
51 SCSIBusDriverBindingStart,\r
52 SCSIBusDriverBindingStop,\r
53 0x10,\r
54 NULL,\r
55 NULL\r
56};\r
57\r
58EFI_STATUS\r
59EFIAPI\r
60SCSIBusDriverBindingSupported (\r
61 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
62 IN EFI_HANDLE Controller,\r
63 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
64 )\r
65/*++\r
66 \r
67 Routine Description:\r
68 \r
69 Arguments:\r
70 \r
71 Returns:\r
72 \r
73--*/\r
74// TODO: This - add argument and description to function comment\r
75// TODO: Controller - add argument and description to function comment\r
76// TODO: RemainingDevicePath - add argument and description to function comment\r
77// TODO: EFI_UNSUPPORTED - add return value to function comment\r
78// TODO: EFI_UNSUPPORTED - add return value to function comment\r
79// TODO: EFI_SUCCESS - add return value to function comment\r
80{\r
81 EFI_STATUS Status;\r
82\r
83 //\r
84 // If RemainingDevicePath is not NULL, it should verify that the first device\r
85 // path node in RemainingDevicePath is an ATAPI Device path node.\r
86 //\r
87 if (RemainingDevicePath != NULL) {\r
88 if ((RemainingDevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
89 (RemainingDevicePath->SubType != MSG_ATAPI_DP) ||\r
90 (DevicePathNodeLength (RemainingDevicePath) != sizeof(ATAPI_DEVICE_PATH))) {\r
91 return EFI_UNSUPPORTED;\r
92 }\r
93 }\r
94 //\r
95 // check for the existence of SCSI Pass Thru Protocol\r
96 //\r
97 Status = gBS->OpenProtocol (\r
98 Controller,\r
99 &gEfiScsiPassThruProtocolGuid,\r
100 NULL,\r
101 This->DriverBindingHandle,\r
102 Controller,\r
103 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
104 );\r
105 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
106 return EFI_UNSUPPORTED;\r
107 }\r
108\r
109 return EFI_SUCCESS;\r
110}\r
111\r
112EFI_STATUS\r
113EFIAPI\r
114SCSIBusDriverBindingStart (\r
115 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
116 IN EFI_HANDLE Controller,\r
117 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
118 )\r
119/*++\r
120 \r
121 Routine Description:\r
122 \r
123 Arguments:\r
124 \r
125 Returns:\r
126 \r
127--*/\r
128// TODO: This - add argument and description to function comment\r
129// TODO: Controller - add argument and description to function comment\r
130// TODO: RemainingDevicePath - add argument and description to function comment\r
131{\r
132 EFI_STATUS Status;\r
133 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
134 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;\r
135 UINT32 StartPun;\r
136 UINT64 StartLun;\r
137 UINT32 Pun;\r
138 UINT64 Lun;\r
139 BOOLEAN ScanOtherPuns;\r
140\r
141 StartPun = 0;\r
142 StartLun = 0;\r
143 Status = gBS->OpenProtocol (\r
144 Controller,\r
145 &gEfiDevicePathProtocolGuid,\r
146 (VOID **) &ParentDevicePath,\r
147 This->DriverBindingHandle,\r
148 Controller,\r
149 EFI_OPEN_PROTOCOL_BY_DRIVER\r
150 );\r
151 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
152 return Status;\r
153 }\r
154\r
155 //\r
156 // Consume SCSI Pass Thru protocol.\r
157 //\r
158 Status = gBS->OpenProtocol (\r
159 Controller,\r
160 &gEfiScsiPassThruProtocolGuid,\r
161 (VOID **) &ScsiPassThru,\r
162 This->DriverBindingHandle,\r
163 Controller,\r
164 EFI_OPEN_PROTOCOL_BY_DRIVER\r
165 );\r
166 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
167 gBS->CloseProtocol (\r
168 Controller,\r
169 &gEfiDevicePathProtocolGuid,\r
170 This->DriverBindingHandle,\r
171 Controller\r
172 );\r
173 return Status;\r
174 }\r
175\r
176 if (RemainingDevicePath == NULL) {\r
177 StartPun = 0xFFFFFFFF;\r
178 StartLun = 0;\r
179 } else {\r
180 ScsiPassThru->GetTargetLun (ScsiPassThru, RemainingDevicePath, &StartPun, &StartLun);\r
181 }\r
182\r
183 for (Pun = StartPun, ScanOtherPuns = TRUE; ScanOtherPuns;) {\r
184\r
185 if (StartPun == 0xFFFFFFFF) {\r
186 //\r
187 // Remaining Device Path is NULL, scan all the possible Puns in the\r
188 // SCSI Channel.\r
189 //\r
190 Status = ScsiPassThru->GetNextDevice (ScsiPassThru, &Pun, &Lun);\r
191 if (EFI_ERROR (Status)) {\r
192 //\r
193 // no legal Pun and Lun found any more\r
194 //\r
195 break;\r
196 }\r
197 } else {\r
198 //\r
199 // Remaining Device Path is not NULL, only scan the specified Pun.\r
200 //\r
201 Pun = StartPun;\r
202 Lun = StartLun;\r
203 ScanOtherPuns = FALSE;\r
204 }\r
205 \r
206 //\r
207 // Avoid creating handle for the host adapter.\r
208 //\r
209 if (Pun == ScsiPassThru->Mode->AdapterId) {\r
210 continue;\r
211 }\r
212 \r
213 //\r
214 // Scan for the scsi device, if it attaches to the scsi bus,\r
215 // then create handle and install scsi i/o protocol.\r
216 //\r
217 Status = ScsiScanCreateDevice (This, Controller, Pun, Lun, ScsiPassThru, ParentDevicePath);\r
218 }\r
219\r
220 return Status;\r
221}\r
222\r
223EFI_STATUS\r
224EFIAPI\r
225SCSIBusDriverBindingStop (\r
226 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
227 IN EFI_HANDLE Controller,\r
228 IN UINTN NumberOfChildren,\r
229 IN EFI_HANDLE *ChildHandleBuffer\r
230 )\r
231/*++\r
232 \r
233 Routine Description:\r
234 \r
235 Arguments:\r
236 \r
237 Returns:\r
238 \r
239--*/\r
240// TODO: This - add argument and description to function comment\r
241// TODO: Controller - add argument and description to function comment\r
242// TODO: NumberOfChildren - add argument and description to function comment\r
243// TODO: ChildHandleBuffer - add argument and description to function comment\r
244// TODO: EFI_SUCCESS - add return value to function comment\r
245// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
246// TODO: EFI_SUCCESS - add return value to function comment\r
247{\r
248 EFI_STATUS Status;\r
249 BOOLEAN AllChildrenStopped;\r
250 UINTN Index;\r
251 EFI_SCSI_IO_PROTOCOL *ScsiIo;\r
252 SCSI_IO_DEV *ScsiIoDevice;\r
253 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;\r
254\r
255 if (NumberOfChildren == 0) {\r
256 //\r
257 // Close the bus driver\r
258 //\r
259 gBS->CloseProtocol (\r
260 Controller,\r
261 &gEfiScsiPassThruProtocolGuid,\r
262 This->DriverBindingHandle,\r
263 Controller\r
264 );\r
265 gBS->CloseProtocol (\r
266 Controller,\r
267 &gEfiDevicePathProtocolGuid,\r
268 This->DriverBindingHandle,\r
269 Controller\r
270 );\r
271\r
272 return EFI_SUCCESS;\r
273 }\r
274\r
275 AllChildrenStopped = TRUE;\r
276\r
277 for (Index = 0; Index < NumberOfChildren; Index++) {\r
278\r
279 Status = gBS->OpenProtocol (\r
280 ChildHandleBuffer[Index],\r
281 &gEfiScsiIoProtocolGuid,\r
282 (VOID **) &ScsiIo,\r
283 This->DriverBindingHandle,\r
284 Controller,\r
285 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
286 );\r
287 if (EFI_ERROR (Status)) {\r
288 AllChildrenStopped = FALSE;\r
289 continue;\r
290 }\r
291\r
292 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (ScsiIo);\r
293 //\r
294 // Close the child handle\r
295 //\r
296 Status = gBS->CloseProtocol (\r
297 Controller,\r
298 &gEfiScsiPassThruProtocolGuid,\r
299 This->DriverBindingHandle,\r
300 ChildHandleBuffer[Index]\r
301 );\r
302\r
303 Status = gBS->UninstallMultipleProtocolInterfaces (\r
304 ChildHandleBuffer[Index],\r
305 &gEfiDevicePathProtocolGuid,\r
306 ScsiIoDevice->DevicePath,\r
307 &gEfiScsiIoProtocolGuid,\r
308 &ScsiIoDevice->ScsiIo,\r
309 NULL\r
310 );\r
311 if (EFI_ERROR (Status)) {\r
312 AllChildrenStopped = FALSE;\r
313 gBS->OpenProtocol (\r
314 Controller,\r
315 &gEfiScsiPassThruProtocolGuid,\r
316 (VOID **) &ScsiPassThru,\r
317 This->DriverBindingHandle,\r
318 ChildHandleBuffer[Index],\r
319 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
320 );\r
321 } else {\r
322 gBS->FreePool (ScsiIoDevice);\r
323 }\r
324 }\r
325\r
326 if (!AllChildrenStopped) {\r
327 return EFI_DEVICE_ERROR;\r
328 }\r
329\r
330 return EFI_SUCCESS;\r
331}\r
332\r
333EFI_STATUS\r
334EFIAPI\r
335ScsiGetDeviceType (\r
336 IN EFI_SCSI_IO_PROTOCOL *This,\r
337 OUT UINT8 *DeviceType\r
338 )\r
339/*++\r
340\r
341 Routine Description:\r
342 Retrieves the device type information of the SCSI Controller.\r
343 \r
344 Arguments:\r
345 This - Protocol instance pointer.\r
346 DeviceType - A pointer to the device type information\r
347 retrieved from the SCSI Controller. \r
348\r
349 Returns:\r
350 EFI_SUCCESS - Retrieves the device type information successfully.\r
351 EFI_INVALID_PARAMETER - The DeviceType is NULL.\r
352--*/\r
353{\r
354 SCSI_IO_DEV *ScsiIoDevice;\r
355\r
356 if (DeviceType == NULL) {\r
357 return EFI_INVALID_PARAMETER;\r
358 }\r
359\r
360 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
361 *DeviceType = ScsiIoDevice->ScsiDeviceType;\r
362 return EFI_SUCCESS;\r
363}\r
364\r
365EFI_STATUS\r
366EFIAPI\r
367ScsiGetDeviceLocation (\r
368 IN EFI_SCSI_IO_PROTOCOL *This,\r
369 OUT UINT8 **Target,\r
370 OUT UINT64 *Lun\r
371 )\r
372/*++\r
373 Routine Description:\r
374 Retrieves the device location in the SCSI channel.\r
375 \r
376 Arguments:\r
377 This - Protocol instance pointer.\r
378 Target - A pointer to the Target ID of a SCSI device \r
379 on the SCSI channel. \r
380 Lun - A pointer to the LUN of the SCSI device on \r
381 the SCSI channel.\r
382\r
383 Returns:\r
384 EFI_SUCCESS - Retrieves the device location successfully.\r
385 EFI_INVALID_PARAMETER - The Target or Lun is NULL.\r
386--*/\r
387{\r
388 SCSI_IO_DEV *ScsiIoDevice;\r
389\r
390 if (Target == NULL || Lun == NULL) {\r
391 return EFI_INVALID_PARAMETER;\r
392 }\r
393\r
394 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
395\r
396 *Target = (UINT8 *) (UINTN) ScsiIoDevice->Pun;\r
397 *Lun = ScsiIoDevice->Lun;\r
398\r
399 return EFI_SUCCESS;\r
400}\r
401\r
402EFI_STATUS\r
403EFIAPI\r
404ScsiResetBus (\r
405 IN EFI_SCSI_IO_PROTOCOL *This\r
406 )\r
407/*++\r
408\r
409 Routine Description:\r
410 Resets the SCSI Bus that the SCSI Controller is attached to.\r
411 \r
412 Arguments:\r
413 This - Protocol instance pointer.\r
414\r
415 Returns:\r
416 EFI_SUCCESS - The SCSI bus is reset successfully.\r
417 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.\r
418 EFI_UNSUPPORTED - The bus reset operation is not supported by the\r
419 SCSI Host Controller.\r
420 EFI_TIMEOUT - A timeout occurred while attempting to reset \r
421 the SCSI bus.\r
422--*/\r
423{\r
424 SCSI_IO_DEV *ScsiIoDevice;\r
425\r
426 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
427\r
428 return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru);\r
429\r
430}\r
431\r
432EFI_STATUS\r
433EFIAPI\r
434ScsiResetDevice (\r
435 IN EFI_SCSI_IO_PROTOCOL *This\r
436 )\r
437/*++\r
438\r
439 Routine Description:\r
440 Resets the SCSI Controller that the device handle specifies.\r
441 \r
442 Arguments:\r
443 This - Protocol instance pointer.\r
444 \r
445\r
446 Returns:\r
447 EFI_SUCCESS - Reset the SCSI controller successfully.\r
448 EFI_DEVICE_ERROR - Errors are encountered when resetting the\r
449 SCSI Controller.\r
450 EFI_UNSUPPORTED - The SCSI bus does not support a device \r
451 reset operation.\r
452 EFI_TIMEOUT - A timeout occurred while attempting to \r
453 reset the SCSI Controller.\r
454--*/\r
455{\r
456 SCSI_IO_DEV *ScsiIoDevice;\r
457\r
458 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
459\r
460 return ScsiIoDevice->ScsiPassThru->ResetTarget (\r
461 ScsiIoDevice->ScsiPassThru,\r
462 ScsiIoDevice->Pun,\r
463 ScsiIoDevice->Lun\r
464 );\r
465}\r
466\r
467EFI_STATUS\r
468EFIAPI\r
469ScsiExecuteSCSICommand (\r
470 IN EFI_SCSI_IO_PROTOCOL *This,\r
471 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,\r
472 IN EFI_EVENT Event OPTIONAL\r
473 )\r
474/*++\r
475\r
476 Routine Description:\r
477 Sends a SCSI Request Packet to the SCSI Controller for execution.\r
478 \r
479 Arguments:\r
480 This - Protocol instance pointer.\r
481 Packet - The SCSI request packet to send to the SCSI \r
482 Controller specified by the device handle.\r
483 Event - If the SCSI bus where the SCSI device is attached\r
484 does not support non-blocking I/O, then Event is \r
485 ignored, and blocking I/O is performed. \r
486 If Event is NULL, then blocking I/O is performed.\r
487 If Event is not NULL and non-blocking I/O is \r
488 supported, then non-blocking I/O is performed,\r
489 and Event will be signaled when the SCSI Request\r
490 Packet completes.\r
491 Returns:\r
492 EFI_SUCCESS - The SCSI Request Packet was sent by the host \r
493 successfully, and TransferLength bytes were \r
494 transferred to/from DataBuffer.See \r
495 HostAdapterStatus, TargetStatus, \r
496 SenseDataLength, and SenseData in that order\r
497 for additional status information.\r
498 EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed, \r
499 but the entire DataBuffer could not be transferred.\r
500 The actual number of bytes transferred is returned\r
501 in TransferLength. See HostAdapterStatus, \r
502 TargetStatus, SenseDataLength, and SenseData in \r
503 that order for additional status information.\r
504 EFI_NOT_READY - The SCSI Request Packet could not be sent because \r
505 there are too many SCSI Command Packets already \r
506 queued.The caller may retry again later.\r
507 EFI_DEVICE_ERROR - A device error occurred while attempting to send \r
508 the SCSI Request Packet. See HostAdapterStatus, \r
509 TargetStatus, SenseDataLength, and SenseData in \r
510 that order for additional status information.\r
511 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid. \r
512 The SCSI Request Packet was not sent, so no \r
513 additional status information is available.\r
514 EFI_UNSUPPORTED - The command described by the SCSI Request Packet\r
515 is not supported by the SCSI initiator(i.e., SCSI \r
516 Host Controller). The SCSI Request Packet was not\r
517 sent, so no additional status information is \r
518 available.\r
519 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI \r
520 Request Packet to execute. See HostAdapterStatus,\r
521 TargetStatus, SenseDataLength, and SenseData in \r
522 that order for additional status information.\r
523--*/\r
524{\r
525 SCSI_IO_DEV *ScsiIoDevice;\r
526 EFI_STATUS Status;\r
527\r
528 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *RequestPacket;\r
529\r
530 if (Packet == NULL) {\r
531 return EFI_INVALID_PARAMETER;\r
532 }\r
533\r
534 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
535\r
536 RequestPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;\r
537\r
538 Status = ScsiIoDevice->ScsiPassThru->PassThru (\r
539 ScsiIoDevice->ScsiPassThru,\r
540 ScsiIoDevice->Pun,\r
541 ScsiIoDevice->Lun,\r
542 RequestPacket,\r
543 Event\r
544 );\r
545 return Status;\r
546}\r
547\r
548EFI_STATUS\r
549ScsiScanCreateDevice (\r
550 EFI_DRIVER_BINDING_PROTOCOL *This,\r
551 EFI_HANDLE Controller,\r
552 UINT32 Pun,\r
553 UINT64 Lun,\r
554 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru,\r
555 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath\r
556 )\r
557/*++\r
558\r
559Routine Description:\r
560\r
561 TODO: Add function description\r
562\r
563Arguments:\r
564\r
565 This - TODO: add argument description\r
566 Controller - TODO: add argument description\r
567 Pun - TODO: add argument description\r
568 Lun - TODO: add argument description\r
569 ScsiPassThru - TODO: add argument description\r
570 ParentDevicePath - TODO: add argument description\r
571\r
572Returns:\r
573\r
574 EFI_SUCCESS - TODO: Add description for return value\r
575 EFI_OUT_OF_RESOURCES - TODO: Add description for return value\r
576 EFI_SUCCESS - TODO: Add description for return value\r
577\r
578--*/\r
579{\r
580 EFI_STATUS Status;\r
581 SCSI_IO_DEV *ScsiIoDevice;\r
582 EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath;\r
583\r
584 Status = gBS->AllocatePool (\r
585 EfiBootServicesData,\r
586 sizeof (SCSI_IO_DEV),\r
587 (VOID **) &ScsiIoDevice\r
588 );\r
589 if (EFI_ERROR (Status)) {\r
590 return Status;\r
591 }\r
592\r
593 ZeroMem (ScsiIoDevice, sizeof (SCSI_IO_DEV));\r
594\r
595 ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE;\r
596 ScsiIoDevice->ScsiPassThru = ScsiPassThru;\r
597 ScsiIoDevice->Pun = Pun;\r
598 ScsiIoDevice->Lun = Lun;\r
599\r
600 ScsiIoDevice->ScsiIo.GetDeviceType = ScsiGetDeviceType;\r
601 ScsiIoDevice->ScsiIo.GetDeviceLocation = ScsiGetDeviceLocation;\r
602 ScsiIoDevice->ScsiIo.ResetBus = ScsiResetBus;\r
603 ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice;\r
604 ScsiIoDevice->ScsiIo.ExecuteSCSICommand = ScsiExecuteSCSICommand;\r
605\r
606 if (!DiscoverScsiDevice (ScsiIoDevice)) {\r
607 gBS->FreePool (ScsiIoDevice);\r
608 return EFI_SUCCESS;\r
609 }\r
610 \r
611 //\r
612 // Set Device Path\r
613 //\r
614 Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath (\r
615 ScsiIoDevice->ScsiPassThru,\r
616 ScsiIoDevice->Pun,\r
617 ScsiIoDevice->Lun,\r
618 &ScsiDevicePath\r
619 );\r
620 if (Status == EFI_OUT_OF_RESOURCES) {\r
621 gBS->FreePool (ScsiIoDevice);\r
622 return Status;\r
623 }\r
624\r
625 ScsiIoDevice->DevicePath = AppendDevicePathNode (\r
626 ParentDevicePath,\r
627 ScsiDevicePath\r
628 );\r
629 //\r
630 // The memory space for ScsiDevicePath is allocated in\r
631 // ScsiPassThru->BuildDevicePath() function; It is no longer used\r
632 // after EfiAppendDevicePathNode,so free the memory it occupies.\r
633 //\r
634 gBS->FreePool (ScsiDevicePath);\r
635\r
636 if (ScsiIoDevice->DevicePath == NULL) {\r
637 gBS->FreePool (ScsiIoDevice);\r
638 return EFI_OUT_OF_RESOURCES;\r
639 }\r
640\r
641 Status = gBS->InstallMultipleProtocolInterfaces (\r
642 &ScsiIoDevice->Handle,\r
643 &gEfiDevicePathProtocolGuid,\r
644 ScsiIoDevice->DevicePath,\r
645 &gEfiScsiIoProtocolGuid,\r
646 &ScsiIoDevice->ScsiIo,\r
647 NULL\r
648 );\r
649 if (EFI_ERROR (Status)) {\r
650 gBS->FreePool (ScsiIoDevice);\r
651 } else {\r
652 gBS->OpenProtocol (\r
653 Controller,\r
654 &gEfiScsiPassThruProtocolGuid,\r
655 (VOID **) &ScsiPassThru,\r
656 This->DriverBindingHandle,\r
657 ScsiIoDevice->Handle,\r
658 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
659 );\r
660 }\r
661\r
662 return EFI_SUCCESS;\r
663}\r
664\r
665BOOLEAN\r
666DiscoverScsiDevice (\r
667 SCSI_IO_DEV *ScsiIoDevice\r
668 )\r
669/*++\r
670\r
671Routine Description:\r
672\r
673 TODO: Add function description\r
674\r
675Arguments:\r
676\r
677 ScsiIoDevice - TODO: add argument description\r
678\r
679Returns:\r
680\r
681 TODO: add return values\r
682\r
683--*/\r
684{\r
685 EFI_STATUS Status;\r
686 EFI_SCSI_INQUIRY_DATA InquiryData;\r
687 UINT32 InquiryDataLength;\r
688 EFI_SCSI_SENSE_DATA SenseData;\r
689 UINT8 SenseDataLength;\r
690 UINT8 HostAdapterStatus;\r
691 UINT8 TargetStatus;\r
692\r
693 HostAdapterStatus = 0;\r
694 TargetStatus = 0;\r
695 //\r
696 // Using Inquiry command to scan for the device\r
697 //\r
698 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
699 SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);\r
700\r
701 Status = SubmitInquiryCommand (\r
702 &ScsiIoDevice->ScsiIo,\r
703 EfiScsiStallSeconds (1),\r
704 (VOID *) &SenseData,\r
705 &SenseDataLength,\r
706 &HostAdapterStatus,\r
707 &TargetStatus,\r
708 (VOID *) &InquiryData,\r
709 &InquiryDataLength,\r
710 FALSE\r
711 );\r
712 if (EFI_ERROR (Status)) {\r
713 //\r
714 // ParseSenseData (&SenseData,SenseDataLength);\r
715 //\r
716 return FALSE;\r
717 }\r
718 //\r
719 // Retrieved inquiry data successfully\r
720 //\r
721 if ((InquiryData.Peripheral_Qualifier != 0) &&\r
722 (InquiryData.Peripheral_Qualifier != 3)) {\r
723 return FALSE;\r
724 }\r
725\r
726 if (InquiryData.Peripheral_Qualifier == 3) {\r
727 if (InquiryData.Peripheral_Type != 0x1f) {\r
728 return FALSE;\r
729 }\r
730 }\r
731\r
732 if ((0x1e >= InquiryData.Peripheral_Type) && (InquiryData.Peripheral_Type >= 0xa)) {\r
733 return FALSE;\r
734 }\r
735 \r
736 //\r
737 // valid device type and peripheral qualifier combination.\r
738 //\r
739 ScsiIoDevice->ScsiDeviceType = InquiryData.Peripheral_Type;\r
740 ScsiIoDevice->RemovableDevice = InquiryData.RMB;\r
741 if (InquiryData.Version == 0) {\r
742 ScsiIoDevice->ScsiVersion = 0;\r
743 } else {\r
744 //\r
745 // ANSI-approved version\r
746 //\r
747 ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData.Version & 0x03);\r
748 }\r
749\r
750 return TRUE;\r
751}\r