1/* 2** Copyright 2002/03, Thomas Kurschel. All rights reserved. 3** Distributed under the terms of the MIT 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 19void scsi_add_queued_request( scsi_ccb *request ); 20void scsi_add_queued_request_first( scsi_ccb *request ); 21void scsi_remove_queued_request( scsi_ccb *request ); 22 23 24static 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 33static 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 42static 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 52static 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 65static 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 78static 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) 95static 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) 103static 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) 111static 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) 119static 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 126static 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 134static 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 148static 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 162static 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 171static 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 181void scsi_block_bus( scsi_bus_info *bus ); 182void scsi_unblock_bus( scsi_bus_info *bus ); 183void scsi_block_device( scsi_device_info *device ); 184void scsi_unblock_device( scsi_device_info *device ); 185 186void scsi_cont_send_bus( scsi_bus_info *bus ); 187void scsi_cont_send_device( scsi_device_info *device ); 188 189#endif 190