2 Copyright © 2019, The AROS Development Team. All rights reserved.
6 #include <aros/debug.h>
8 #include <proto/exec.h>
10 /* We want all other bases obtained from our base */
13 #include <proto/oop.h>
14 #include <proto/utility.h>
16 #include <hidd/storage.h>
18 #include <hidd/scsi.h>
20 #include <utility/tagitem.h>
28 static void Hidd_SCSIBus_HandleIRQ(UBYTE status
, struct scsi_Bus
*bus
)
30 struct scsi_Unit
*unit
= bus
->sb_SelectedUnit
;
33 * don't waste your time on checking other devices.
34 * pass irq ONLY if task is expecting one;
36 if (unit
&& bus
->sb_HandleIRQ
)
38 /* ok, we have a routine to handle any form of transmission etc. */
39 DIRQ(bug("[SCSI%02d] IRQ: Calling dedicated handler 0x%p... \n",
40 unit
->su_UnitNum
, bus
->sb_HandleIRQ
));
41 bus
->sb_HandleIRQ(unit
, status
);
48 * if we got *here* then device is most likely not expected to have an irq.
50 bug("[SCSI%02d] Spurious IRQ\n", unit
? unit
->su_UnitNum
: -1);
52 if (0 == (ATAF_BUSY
& status
))
54 bug("[SCSI ] STATUS: %02lx\n" , status
);
55 bug("[SCSI ] ALT STATUS: %02lx\n" , PIO_InAlt(bus
, scsi_AltStatus
));
56 bug("[SCSI ] ERROR: %02lx\n" , PIO_In(bus
, scsi_Error
));
57 bug("[SCSI ] IRQ: REASON: %02lx\n", PIO_In(bus
, atapi_Reason
));
62 static AROS_INTH1(ataBus_Reset
, struct scsi_Bus
*, bus
)
66 struct scsiBase
*SCSIBase
= bus
->sb_Base
;
67 OOP_Object
*obj
= (void *)bus
- SCSIBase
->busClass
->InstOffset
;
69 D(bug("[SCSI:Bus] %s()\n", __func__
));
71 HIDD_SCSIBus_Shutdown(obj
);
78 /*****************************************************************************************
87 This class serves as a base class for implementing IDE (ATA) bus drivers.
88 One particularity of this class is that IDE bus is very speed-critical.
89 At the other hand, the driver implements very lowlevel operations which
90 are called quite often. OOP_DoMethod() call is not fast enough, and in
91 order to circumvent this limitation, additionally to normal OOP API
92 IDE bus drivers offer two additional non-standard interfaces. Internally
93 they are implemented as library-alike function table plus driver-specific
94 data. For the purpose of some performance optimizations the function
95 table is private to ata.device and managed entirely by the base class.
96 Driver classes have access only to data portion.
98 These interfaces are documented below.
100 *****************************************************************************************/
101 /*****************************************************************************************
110 PIO interface is responsible for accessing I/O registers on the IDE
111 bus, as well as performing PIO-mode 16- and 32-bit data transfers.
112 This interface is mandatory and must be implemented by the driver,
113 however some functions are optional. They can be either omitted
114 entirely from the function table, or set to NULL pointers.
116 Control functions table for the interface consists of the following
117 functions (listed in their order in the array):
119 VOID scsi_out(void *obj, UBYTE val, UWORD offset)
120 - Write byte into primary register bank with the given offset.
122 UBYTE scsi_in(void *obj, UWORD offset)
123 - Read byte from primary register bank with the given offset.
125 VOID scsi_out_alt(void *obj, UBYTE val, UWORD offset)
126 - Write byte into alternate register bank with the given offset.
127 This function is optional.
129 UBYTE scsi_in_alt(void *obj, UWORD offset)
130 - Read byte from alternate register bank with the given offset.
131 This function is optional.
133 Transfer functions table for the interface consists of the following
134 functions (listed in their order in the array):
136 VOID scsi_outsw(void *obj, APTR address, ULONG count)
137 - Perform 16-bit PIO data write operation from the given memory
138 region of the given size.
140 VOID scsi_insw(void *obj, APTR address, ULONG count)
141 - Perform 16-bit PIO data read operation into the given memory
142 region of the given size.
144 VOID scsi_outsl(void *obj, APTR address, ULONG count)
145 - Perform 32-bit PIO data write operation from the given memory
146 region of the given size. This function is optional.
148 UBYTE scsi_insl(void *obj, APTR address, ULONG count)
149 - Perform 32-bit PIO data read operation into the given memory
150 region of the given size. This function is optional.
152 *****************************************************************************************/
153 /*****************************************************************************************
162 DMA interface is optional, and is needed in order to support DMA data
165 Function table for the interface consists of the following functions:
167 BOOL dma_Setup(void *obj, APTR buffer, IPTR size, BOOL read)
168 - Prepare the controller to DMA data transfer. The last argument is
169 TRUE for read operation and FALSE for write. The function should
170 return TRUE for success or FALSE for failure.
172 VOID dma_Start(void *obj)
173 - Start DMA transfer.
175 VOID dma_End(void *obj, APTR buffer, IPTR size, BOOL read)
176 - End DMA transfer and perform post-transfer cleanup of the given region.
178 ULONG dma_Result(void *obj)
179 - Get resulting status of the operation. The function should return 0
180 for successful completion or error code to be passed up to ata.device
181 caller in io_Result field of the IORequest.
183 *****************************************************************************************/
184 /*****************************************************************************************
187 aoHidd_SCSIBus_Use80Wire
196 Tells whether the bus currently uses 80-conductor cable.
199 This attribute actually makes difference only for DMA modes. If
200 your bus driver returns FALSE, ata.device will not use modes
201 higher than UDMA2 on the bus.
211 *****************************************************************************************/
212 /*****************************************************************************************
215 aoHidd_SCSIBus_Use32Bit
224 When queried, tells whether the bus supports 32-bit PIO data transfers.
225 When set, enables or disables 32-bit mode for PIO data transfers.
237 *****************************************************************************************/
238 /*****************************************************************************************
241 aoHidd_SCSIBus_UseDMA
250 Tells whether the bus supports DMA transfers.
261 Default implementation in base class returns value depending on whether
262 the subclass provided DMA interface function table during object creation.
264 *****************************************************************************************/
265 /*****************************************************************************************
268 aoHidd_SCSIBus_PIODataSize
277 Specifies size of PIO interface data structure.
289 *****************************************************************************************/
290 /*****************************************************************************************
293 aoHidd_SCSIBus_DMADataSize
302 Specifies size of DMA interface data structure.
314 *****************************************************************************************/
315 /*****************************************************************************************
318 aoHidd_SCSIBus_BusVectors
327 Specifies control functions table for building PIO interface object.
328 The function table is an array of function pointers terminated
329 by -1 value. The terminator must be present for purpose of
330 binary compatibility with future extensions.
333 This function table is mandatory to be implemented by the driver.
343 *****************************************************************************************/
344 /*****************************************************************************************
347 aoHidd_SCSIBus_PIOVectors
356 Specifies transfers function table for building PIO interface object.
357 The function table is an array of function pointers terminated
358 by -1 value. The terminator must be present for purpose of
359 binary compatibility with future extensions.
362 This function table is mandatory to be implemented by the driver.
372 *****************************************************************************************/
373 /*****************************************************************************************
376 aoHidd_SCSIBus_DMAVectors
385 Specifies function table for building DMA interface object. If not supplied,
386 the bus is considered not DMA-capable.
395 aoHidd_SCSIBus_PIOVectors
399 *****************************************************************************************/
400 /*****************************************************************************************
403 aoHidd_SCSIBus_UseIOAlt
412 Tells whether the bus supports alternate registers bank
413 (scsi_AltControl and scsi_AltStatus).
424 Default implementation in base class returns value depending on whether
425 the subclass provided respective I/O functions in bus interface vector
426 table during object creation.
428 *****************************************************************************************/
429 /*****************************************************************************************
432 aoHidd_SCSIBus_Master
441 Returns a pointer to OOP object of private unit class, representing
442 a master drive on the bus, or NULL if there's no master device.
455 *****************************************************************************************/
456 /*****************************************************************************************
468 Returns a pointer to OOP object of private unit class, representing
469 a slave drive on the bus, or NULL if there's no master device.
478 aoHidd_SCSIBus_Master
482 *****************************************************************************************/
483 /*****************************************************************************************
486 aoHidd_SCSIBus_CanSetXferMode
495 Tells whether the bus driver implements moHidd_SCSIBus_SetXferMode method.
502 Current version of ata.device does not use this attribute, and it is
506 moHidd_SCSIBus_SetXferMode
510 *****************************************************************************************/
512 OOP_Object
*SCSIBus__Root__New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
514 struct scsiBase
*SCSIBase
= cl
->UserData
;
515 D(bug("[SCSI:Bus] %s()\n", __func__
));
517 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, &msg
->mID
);
520 struct scsi_Bus
*data
= OOP_INST_DATA(cl
, o
);
521 struct TagItem
*tstate
= msg
->attrList
;
525 bug("[SCSI:Bus] %s: instance @ 0x%p\n", __func__
, o
);
526 bug("[SCSI:Bus] %s: scsi_Bus @ 0x%p\n", __func__
, data
);
530 data
->keepEmpty
= TRUE
;
532 while ((tag
= NextTagItem(&tstate
)))
536 Hidd_SCSIBus_Switch(tag
->ti_Tag
, idx
)
538 case aoHidd_SCSIBus_PIODataSize
:
539 data
->pioDataSize
= tag
->ti_Data
;
540 D(bug("[SCSI:Bus] %s: PIODataSize = %d\n", __func__
, data
->pioDataSize
);)
543 case aoHidd_SCSIBus_DMADataSize
:
544 data
->dmaDataSize
= tag
->ti_Data
;
545 DATTR(bug("[SCSI:Bus] %s: DMADataSize = %d\n", __func__
, data
->dmaDataSize
);)
548 case aoHidd_SCSIBus_BusVectors
:
549 data
->busVectors
= (struct SCSI_BusInterface
*)tag
->ti_Data
;
550 DATTR(bug("[SCSI:Bus] %s: BusVectors @ 0x%p\n", __func__
, data
->busVectors
);)
553 case aoHidd_SCSIBus_PIOVectors
:
554 data
->pioVectors
= (struct SCSI_PIOInterface
*)tag
->ti_Data
;
555 DATTR(bug("[SCSI:Bus] %s: PIOVectors @ 0x%p\n", __func__
, data
->pioVectors
);)
558 case aoHidd_SCSIBus_DMAVectors
:
559 data
->dmaVectors
= (APTR
*)tag
->ti_Data
;
560 DATTR(bug("[SCSI:Bus] %s: DMAVectors @ 0x%p\n", __func__
, data
->dmaVectors
);)
563 Hidd_Bus_Switch(tag
->ti_Tag
, idx
)
565 case aoHidd_Bus_KeepEmpty
:
566 data
->keepEmpty
= tag
->ti_Data
;
571 /* Cache device base pointer. Useful. */
572 data
->sb_Base
= SCSIBase
;
574 /* Install reset callback */
575 data
->sb_ResetInt
.is_Node
.ln_Name
= SCSIBase
->scsi_Device
.dd_Library
.lib_Node
.ln_Name
;
576 data
->sb_ResetInt
.is_Code
= (VOID_FUNC
)ataBus_Reset
;
577 data
->sb_ResetInt
.is_Data
= data
;
578 AddResetCallback(&data
->sb_ResetInt
);
583 void SCSIBus__Root__Dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
585 struct scsi_Bus
*data
= OOP_INST_DATA(cl
, o
);
587 RemResetCallback(&data
->sb_ResetInt
);
589 if (data
->dmaInterface
)
591 void *ptr
= data
->dmaInterface
- sizeof(struct SCSI_DMAInterface
);
593 FreeMem(ptr
, sizeof(struct SCSI_DMAInterface
) + data
->dmaDataSize
);
595 if (data
->pioInterface
)
597 void *ptr
= data
->pioInterface
- sizeof(struct SCSI_BusInterface
);
599 FreeMem(ptr
, sizeof(struct SCSI_BusInterface
) + data
->pioDataSize
);
602 OOP_DoSuperMethod(cl
, o
, msg
);
606 * Here we take into account that the table can be either
607 * terminated early, or have NULL entries.
609 #define HAVE_VECTOR(x) (x && (x != (APTR)-1))
611 void SCSIBus__Root__Get(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_Get
*msg
)
613 struct scsiBase
*SCSIBase
= cl
->UserData
;
614 struct scsi_Bus
*data
= OOP_INST_DATA(cl
, o
);
617 Hidd_Bus_Switch (msg
->attrID
, idx
)
619 case aoHidd_Bus_MaxUnits
:
620 *msg
->storage
= MAX_BUSUNITS
;
624 Hidd_SCSIBus_Switch (msg
->attrID
, idx
)
626 case aoHidd_SCSIBus_Use80Wire
:
627 *msg
->storage
= FALSE
;
630 case aoHidd_SCSIBus_Use32Bit
:
631 *msg
->storage
= (HAVE_VECTOR(data
->pioVectors
->scsi_outsl
) &&
632 HAVE_VECTOR(data
->pioVectors
->scsi_insl
)) ?
636 case aoHidd_SCSIBus_UseDMA
:
637 *msg
->storage
= data
->dmaVectors
? TRUE
: FALSE
;
640 case aoHidd_SCSIBus_UseIOAlt
:
641 *msg
->storage
= (HAVE_VECTOR(data
->busVectors
->scsi_out_alt
) &&
642 HAVE_VECTOR(data
->busVectors
->scsi_in_alt
)) ?
646 case aoHidd_SCSIBus_CanSetXferMode
:
647 *msg
->storage
= FALSE
;
651 OOP_DoSuperMethod(cl
, o
, &msg
->mID
);
654 void SCSIBus__Hidd_StorageBus__EnumUnits(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_StorageBus_EnumUnits
*msg
)
656 struct scsi_Bus
*data
= OOP_INST_DATA(cl
, o
);
659 D(bug ("[SCSI:Bus] Hidd_StorageBus__EnumUnits()\n");)
661 if (data
->sb_Units
[0])
662 stop
= CALLHOOKPKT(msg
->callback
, data
->sb_Units
[0], msg
->hookMsg
);
663 if ((!stop
) && (data
->sb_Units
[1]))
664 stop
= CALLHOOKPKT(msg
->callback
, data
->sb_Units
[1], msg
->hookMsg
);
667 /* Default scsi_out_alt does nothing */
668 static void default_out_alt(void *obj
, UBYTE val
, UWORD offset
)
673 /* Default scsi_in_alt wraps AltStatus to status */
674 static UBYTE
default_in_alt(void *obj
, UWORD offset
)
676 struct SCSI_BusInterface
*vec
= obj
- sizeof(struct SCSI_BusInterface
);
678 return vec
->scsi_in(obj
, scsi_Status
);
681 static void CopyVectors(APTR
*dest
, APTR
*src
, unsigned int num
)
685 for (i
= 0; i
< num
; i
++)
687 if (src
[i
] == (APTR
*)-1)
694 /*****************************************************************************************
697 moHidd_SCSIBus_GetPIOInterface
700 APTR OOP_DoMethod(OOP_Object *obj, struct pHidd_SCSIBus_GetPIOInterface *Msg);
702 APTR HIDD_SCSIBus_GetPIOInterface(void);
708 Instantiates encapsulated PIO interface object and returns its
715 A pointer to opaque PIO interface object or NULL in case of failure.
718 This method should be overloaded by driver subclasses in order to
719 initialize data portion of the interface object.
726 moHidd_SCSIBus_GetDMAInterface
729 Interface objects contain not only driver-specific data, but also
730 a private vector table. Because of this you cannot just AllocMem()
731 the necessary structure in your driver. Always call OOP_DoSuperMethod()
732 in order for the base class to instantiate the interface correctly.
734 *****************************************************************************************/
736 APTR
SCSIBus__Hidd_SCSIBus__GetPIOInterface(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
738 struct scsi_Bus
*data
= OOP_INST_DATA(cl
, o
);
739 struct SCSI_BusInterface
*vec
;
742 bug("[SCSI:Bus] %s()\n", __func__
);
743 bug("[SCSI:Bus] %s: scsi_Bus @ 0x%p\n", __func__
, data
);
746 vec
= AllocMem(sizeof(struct SCSI_BusInterface
) + data
->pioDataSize
,
747 MEMF_PUBLIC
|MEMF_CLEAR
);
750 D(bug("[SCSI:Bus] %s: SCSI_BusInterface @ 0x%p (%d bytes + %d)\n", __func__
, vec
, sizeof(struct SCSI_BusInterface
), data
->pioDataSize
);)
752 /* Some default vectors for simplicity */
753 vec
->scsi_out_alt
= default_out_alt
;
754 vec
->scsi_in_alt
= default_in_alt
;
756 CopyVectors((APTR
*)vec
, (APTR
*)data
->busVectors
,
757 sizeof(struct SCSI_BusInterface
) / sizeof(APTR
));
759 data
->pioInterface
= &vec
[1];
760 return data
->pioInterface
;
766 /*****************************************************************************************
769 moHidd_SCSIBus_GetDMAInterface
772 APTR OOP_DoMethod(OOP_Object *obj, struct pHidd_SCSIBus_GetDMAInterface *Msg);
774 APTR HIDD_SCSIBus_GetDMAInterface(void);
780 Instantiates encapsulated DMA interface object and returns its
787 A pointer to opaque DMA interface object or NULL upon failure or
788 if DMA is not supported by this bus.
791 This method should be overloaded by driver subclasses in order to
792 initialize data portion of the interface object.
799 moHidd_SCSIBus_GetPIOInterface
802 Interface objects contain not only driver-specific data, but also
803 a private vector table. Because of this you cannot just AllocMem()
804 the necessary structure in your driver. Always call OOP_DoSuperMethod()
805 in order for the base class to instantiate the interface correctly.
807 *****************************************************************************************/
809 APTR
SCSIBus__Hidd_SCSIBus__GetDMAInterface(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
811 struct scsi_Bus
*data
= OOP_INST_DATA(cl
, o
);
812 struct SCSI_DMAInterface
*vec
;
814 D(bug("[SCSI:Bus] %s()\n", __func__
));
816 if (!data
->dmaVectors
)
819 vec
= AllocMem(sizeof(struct SCSI_DMAInterface
) + data
->dmaDataSize
,
820 MEMF_PUBLIC
|MEMF_CLEAR
);
823 CopyVectors((APTR
*)vec
, data
->dmaVectors
,
824 sizeof(struct SCSI_DMAInterface
) / sizeof(APTR
));
826 data
->dmaInterface
= &vec
[1];
827 return data
->dmaInterface
;
833 /*****************************************************************************************
836 moHidd_SCSIBus_SetXferMode
839 APTR OOP_DoMethod(OOP_Object *obj, struct pHidd_SCSIBus_SetXferMode *Msg);
841 APTR HIDD_SCSIBus_SetXferMode(UBYTE unit, scsi_XferMode mode);
847 Sets the desired transfer mode for the given drive on the bus controller.
850 unit - drive number (0 for master and 1 for slave)
851 mode - Mode number (see hidd/ata.h)
854 TRUE if successful or FALSE if the desired mode is not supported
858 The default implementation is provided for drivers not supporting
859 DMA and always returns FALSE if the caller attempts to set any of
865 Current version of ata.device does not use this method, and it is
869 aoHidd_SCSIBus_CanSetXferMode
873 *****************************************************************************************/
875 BOOL
SCSIBus__Hidd_SCSIBus__SetXferMode(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_SCSIBus_SetXferMode
*msg
)
877 D(bug("[SCSI:Bus] %s()\n", __func__
));
879 if ((msg
->mode
>= AB_XFER_MDMA0
) && (msg
->mode
<= AB_XFER_UDMA6
))
881 /* DMA is not supported, we cannot set DMA modes */
888 /*****************************************************************************************
891 moHidd_SCSIBus_Shutdown
894 APTR OOP_DoMethod(OOP_Object *obj, struct pHidd_SCSIBus_Shutdown *Msg);
896 APTR HIDD_SCSIBus_Shutdown(void);
902 Instantly shutdown all activity on the bus.
911 This method is called by ata.device during system reset handler execution.
920 Default implementation disables interrupt using AltControl register.
922 *****************************************************************************************/
924 void SCSIBus__Hidd_SCSIBus__Shutdown(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg
*msg
)
926 struct scsi_Bus
*data
= OOP_INST_DATA(cl
, o
);
928 D(bug("[SCSI:Bus] %s()\n", __func__
));
930 if (data
->pioInterface
)
932 struct SCSI_BusInterface
*vec
= data
->pioInterface
- sizeof(struct SCSI_BusInterface
);
934 vec
->scsi_out_alt(data
->pioInterface
, SCSICTLF_INT_DISABLE
, scsi_AltControl
);
938 /***************** Private nonvirtual methods follow *****************/
940 BOOL
Hidd_SCSIBus_Start(OOP_Object
*o
, struct scsiBase
*SCSIBase
)
942 struct scsi_Bus
*sb
= OOP_INST_DATA(SCSIBase
->busClass
, o
);
944 D(bug("[SCSI:Bus] %s()\n", __func__
));
946 /* Attach IRQ handler */
947 OOP_SetAttrsTags(o
, aHidd_Bus_IRQHandler
, Hidd_SCSIBus_HandleIRQ
,
948 aHidd_Bus_IRQData
, sb
,
951 /* scan bus - try to locate all devices (disables irq) */
954 if ((sb
->sb_Dev
[0] == DEV_NONE
) && (sb
->sb_Dev
[1] == DEV_NONE
) &&
958 * If there are no devices, and KeepEmpty is not set
959 * the bus will be thrown away.
967 * 1. This does not take into account possibility to
968 * unload drivers. In this case existing units will disappear,
969 * freeing up their numbers. These numbers should be reused.
970 * 2. We REALLY need modify-and-fetch atomics.
973 sb
->sb_BusNum
= SCSIBase
->scsi__buscount
++;
976 if ((sb
->sb_Dev
[0] < DEV_ATA
) && (sb
->sb_Dev
[1] < DEV_ATA
))
978 /* Do not start up task if there are no usable devices. */
983 * This small trick is based on the fact that shared semaphores
984 * have no specific owner. You can obtain and release them from
985 * within any task. It will block only on attempt to re-lock it
987 * So instead of complex handshake we obtain the semaphore before
988 * starting bus task. It will release the semaphore when done.
990 ObtainSemaphoreShared(&SCSIBase
->DetectionSem
);
993 * Start up bus task. It will perform scanning asynchronously, and
994 * then, if successful, insert units. This allows to keep things parallel.
996 D(bug("[SCSI>>] Start: Bus %u: Unit 0 - %d, Unit 1 - %d\n", sb
->sb_BusNum
, sb
->sb_Dev
[0], sb
->sb_Dev
[1]));
997 return NewCreateTask(TASKTAG_PC
, BusTaskCode
,
998 TASKTAG_NAME
, "ATA[PI] Subsystem",
999 TASKTAG_STACKSIZE
, STACK_SIZE
,
1000 TASKTAG_PRI
, TASK_PRI
,
1001 TASKTAG_TASKMSGPORT
, &sb
->sb_MsgPort
,
1003 TASKTAG_ARG2
, SCSIBase
,
1004 TAG_DONE
) ? TRUE
: FALSE
;
1007 AROS_UFH3(BOOL
, Hidd_SCSIBus_Open
,
1008 AROS_UFHA(struct Hook
*, h
, A0
),
1009 AROS_UFHA(OOP_Object
*, obj
, A2
),
1010 AROS_UFHA(IPTR
, reqUnit
, A1
))
1014 struct IORequest
*req
= h
->h_Data
;
1015 struct scsiBase
*SCSIBase
= (struct scsiBase
*)req
->io_Device
;
1016 struct scsi_Bus
*sb
= (struct scsi_Bus
*)OOP_INST_DATA(SCSIBase
->busClass
, obj
);
1017 ULONG bus
= reqUnit
>> 1;
1018 UBYTE dev
= reqUnit
& 1;
1020 D(bug("[SCSI:Bus] %s()\n", __func__
));
1021 D(bug("[SCSI%02ld] Checking bus %u dev %u\n", reqUnit
, bus
, dev
));
1023 if ((sb
->sb_BusNum
== bus
) && sb
->sb_Units
[dev
])
1025 struct scsi_Unit
*unit
= (struct scsi_Unit
*)OOP_INST_DATA(SCSIBase
->unitClass
, sb
->sb_Units
[dev
]);
1028 req
->io_Unit
= &unit
->su_Unit
;
1031 unit
->su_Unit
.unit_OpenCnt
++;