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