1 /* 2 ** Copyright 2002/03, Thomas Kurschel. All rights reserved. 3 ** Distributed under the terms of the OpenBeOS License. 4 */ 5 6 /* 7 Part of Open SCSI bus manager 8 9 Handling of bus/device blocking. Inline functions defined 10 here don't wake service thread if required and don't lock bus, so 11 everyone using them must take care of that himself. 12 */ 13 14 #ifndef __BLOCKING_H__ 15 #define __BLOCKING_H__ 16 17 #include "dl_list.h" 18 19 void scsi_add_queued_request( scsi_ccb *request ); 20 void scsi_add_queued_request_first( scsi_ccb *request ); 21 void scsi_remove_queued_request( scsi_ccb *request ); 22 23 24 static inline void scsi_add_req_queue_first( scsi_ccb *request ) 25 { 26 scsi_device_info *device = request->device; 27 28 SHOW_FLOW( 3, "request=%p", request ); 29 30 ADD_CDL_LIST_HEAD( request, scsi_ccb, device->queued_reqs, ); 31 } 32 33 static inline void scsi_add_req_queue_last( scsi_ccb *request ) 34 { 35 scsi_device_info *device = request->device; 36 37 SHOW_FLOW( 3, "request=%p", request ); 38 39 ADD_CDL_LIST_TAIL( request, scsi_ccb, device->queued_reqs, ); 40 } 41 42 static inline void scsi_remove_req_queue( scsi_ccb *request ) 43 { 44 scsi_device_info *device = request->device; 45 46 SHOW_FLOW( 3, "request=%p", request ); 47 48 REMOVE_CDL_LIST( request, device->queued_reqs, ); 49 } 50 51 // ignored, if device is already queued 52 static inline void scsi_add_device_queue_first( scsi_device_info *device ) 53 { 54 SHOW_FLOW0( 3, "" ); 55 56 if( DEVICE_IN_WAIT_QUEUE( device )) 57 return; 58 59 SHOW_FLOW0( 3, "was not in wait queue - adding" ); 60 61 ADD_CDL_LIST_HEAD( device, scsi_device_info, device->bus->waiting_devices, waiting_ ); 62 } 63 64 // ignored, if device is already queued 65 static inline void scsi_add_device_queue_last( scsi_device_info *device ) 66 { 67 SHOW_FLOW0( 3, "" ); 68 69 if( DEVICE_IN_WAIT_QUEUE( device )) 70 return; 71 72 SHOW_FLOW0( 3, "was not in wait queue - adding" ); 73 74 ADD_CDL_LIST_TAIL( device, scsi_device_info, device->bus->waiting_devices, waiting_ ); 75 } 76 77 // ignored, if device is not in queue 78 static inline void scsi_remove_device_queue( scsi_device_info *device ) 79 { 80 SHOW_FLOW0( 3, "" ); 81 82 if( !DEVICE_IN_WAIT_QUEUE( device )) 83 return; 84 85 SHOW_FLOW0( 3, "was in wait queue - removing from it" ); 86 87 REMOVE_CDL_LIST( device, device->bus->waiting_devices, waiting_ ); 88 89 // reset next link so we can see that it's not in device queue 90 device->waiting_next = NULL; 91 } 92 93 // set overflow bit of device; this will not remove device from bus queue! 94 // (multiple calls are ignored gracefully) 95 static inline void scsi_set_device_overflow( scsi_device_info *device ) 96 { 97 device->lock_count += device->sim_overflow ^ 1; 98 device->sim_overflow = 1; 99 } 100 101 // set overflow bit of bus 102 // (multiple calls are ignored gracefully) 103 static inline void scsi_set_bus_overflow( scsi_bus_info *bus ) 104 { 105 bus->lock_count += bus->sim_overflow ^ 1; 106 bus->sim_overflow = 1; 107 } 108 109 // clear overflow bit of device; this will not add device to bus queue! 110 // (multiple calls are ignored gracefully) 111 static inline void scsi_clear_device_overflow( scsi_device_info *device ) 112 { 113 device->lock_count -= device->sim_overflow; 114 device->sim_overflow = 0; 115 } 116 117 // clear overflow bit of bus 118 // (multiple calls are ignored gracefully) 119 static inline void scsi_clear_bus_overflow( scsi_bus_info *bus ) 120 { 121 bus->lock_count -= bus->sim_overflow; 122 bus->sim_overflow = 0; 123 } 124 125 // check whether bus has some pending requests it can process now 126 static inline bool scsi_can_service_bus( scsi_bus_info *bus ) 127 { 128 // bus must not be blocked and requests pending 129 return (bus->lock_count == 0) & (bus->waiting_devices != NULL); 130 } 131 132 // unblock bus 133 // lock must be hold; service thread is not informed 134 static inline void scsi_unblock_bus_noresume( scsi_bus_info *bus, bool by_SIM ) 135 { 136 if( bus->blocked[by_SIM] > 0 ) { 137 --bus->blocked[by_SIM]; 138 --bus->lock_count; 139 } else { 140 panic( "Tried to unblock bus %d which wasn't blocked", 141 bus->path_id ); 142 } 143 } 144 145 146 // unblock device 147 // lock must be hold; device is not added to queue and service thread is not informed 148 static inline void scsi_unblock_device_noresume( scsi_device_info *device, bool by_SIM ) 149 { 150 if( device->blocked[by_SIM] > 0 ) { 151 --device->blocked[by_SIM]; 152 --device->lock_count; 153 } else { 154 panic( "Tried to unblock device %d/%d/%d which wasn't blocked", 155 device->bus->path_id, device->target_id, device->target_lun ); 156 } 157 } 158 159 160 // block bus 161 // lock must be hold 162 static inline void scsi_block_bus_nolock( scsi_bus_info *bus, bool by_SIM ) 163 { 164 ++bus->blocked[by_SIM]; 165 ++bus->lock_count; 166 } 167 168 169 // block device 170 // lock must be hold 171 static inline void scsi_block_device_nolock( scsi_device_info *device, bool by_SIM ) 172 { 173 ++device->blocked[by_SIM]; 174 ++device->lock_count; 175 176 // remove device from bus queue as it cannot be processed anymore 177 scsi_remove_device_queue( device ); 178 } 179 180 181 void scsi_block_bus( scsi_bus_info *bus ); 182 void scsi_unblock_bus( scsi_bus_info *bus ); 183 void scsi_block_device( scsi_device_info *device ); 184 void scsi_unblock_device( scsi_device_info *device ); 185 186 void scsi_cont_send_bus( scsi_bus_info *bus ); 187 void scsi_cont_send_device( scsi_device_info *device ); 188 189 #endif 190