xref: /haiku/src/add-ons/kernel/bus_managers/scsi/queuing.h (revision b55a57da7173b9af0432bd3e148d03f06161d036)
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