vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / bus_managers / scsi / busses.cpp
blob934cf3215eb607e3abf33bed0dcd3c4d1a672ff8
1 /*
2 * Copyright 2002/03, Thomas Kurschel. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
6 /*
7 Part of Open SCSI bus manager
9 Bus node layer.
11 Whenever a controller driver publishes a new controller, a new SCSI bus
12 for public and internal use is registered in turn. After that, this
13 bus is told to rescan for devices. For each device, there is a
14 device registered for peripheral drivers. (see devices.c)
17 #include "scsi_internal.h"
19 #include <string.h>
20 #include <malloc.h>
23 // bus service should hurry up a bit - good controllers don't take much time
24 // but are very happy to be busy; don't make it realtime though as we
25 // don't really need that but would risk to steel processing power of
26 // realtime-demanding threads
27 #define BUS_SERVICE_PRIORITY B_URGENT_DISPLAY_PRIORITY
30 /** implementation of service thread:
31 * it handles DPC and pending requests
34 static void
35 scsi_do_service(scsi_bus_info *bus)
37 while (true) {
38 SHOW_FLOW0( 3, "" );
40 // handle DPCs first as they are more urgent
41 if (scsi_check_exec_dpc(bus))
42 continue;
44 if (scsi_check_exec_service(bus))
45 continue;
47 break;
52 /** main loop of service thread */
54 static int32
55 scsi_service_threadproc(void *arg)
57 scsi_bus_info *bus = (scsi_bus_info *)arg;
58 int32 processed_notifications = 0;
60 SHOW_FLOW(3, "bus = %p", bus);
62 while (true) {
63 // we handle multiple requests in scsi_do_service at once;
64 // to save time, we will acquire all notifications that are sent
65 // up to now at once.
66 // (Sadly, there is no "set semaphore to zero" function, so this
67 // is a poor-man emulation)
68 acquire_sem_etc(bus->start_service, processed_notifications + 1, 0, 0);
70 SHOW_FLOW0( 3, "1" );
72 if (bus->shutting_down)
73 break;
75 // get number of notifications _before_ servicing to make sure no new
76 // notifications are sent after do_service()
77 get_sem_count(bus->start_service, &processed_notifications);
79 scsi_do_service(bus);
82 return 0;
86 static scsi_bus_info *
87 scsi_create_bus(device_node *node, uint8 path_id)
89 scsi_bus_info *bus;
90 int res;
92 SHOW_FLOW0(3, "");
94 bus = (scsi_bus_info *)malloc(sizeof(*bus));
95 if (bus == NULL)
96 return NULL;
98 memset(bus, 0, sizeof(*bus));
100 bus->path_id = path_id;
102 if (pnp->get_attr_uint32(node, SCSI_DEVICE_MAX_TARGET_COUNT, &bus->max_target_count, true) != B_OK)
103 bus->max_target_count = MAX_TARGET_ID + 1;
104 if (pnp->get_attr_uint32(node, SCSI_DEVICE_MAX_LUN_COUNT, &bus->max_lun_count, true) != B_OK)
105 bus->max_lun_count = MAX_LUN_ID + 1;
107 // our scsi_ccb only has a uchar for target_id
108 if (bus->max_target_count > 256)
109 bus->max_target_count = 256;
110 // our scsi_ccb only has a uchar for target_lun
111 if (bus->max_lun_count > 256)
112 bus->max_lun_count = 256;
114 bus->node = node;
115 bus->lock_count = bus->blocked[0] = bus->blocked[1] = 0;
116 bus->sim_overflow = 0;
117 bus->shutting_down = false;
119 bus->waiting_devices = NULL;
120 //bus->resubmitted_req = NULL;
122 bus->dpc_list = NULL;
124 if ((bus->scan_lun_lock = create_sem(1, "scsi_scan_lun_lock")) < 0) {
125 res = bus->scan_lun_lock;
126 goto err6;
129 bus->start_service = create_sem(0, "scsi_start_service");
130 if (bus->start_service < 0) {
131 res = bus->start_service;
132 goto err4;
135 res = INIT_BEN(&bus->mutex, "scsi_bus_mutex");
136 if (res < B_OK)
137 goto err3;
139 spinlock_irq_init(&bus->dpc_lock);
141 res = scsi_init_ccb_alloc(bus);
142 if (res < B_OK)
143 goto err2;
145 bus->service_thread = spawn_kernel_thread(scsi_service_threadproc,
146 "scsi_bus_service", BUS_SERVICE_PRIORITY, bus);
148 if (bus->service_thread < 0) {
149 res = bus->service_thread;
150 goto err1;
153 resume_thread(bus->service_thread);
155 return bus;
157 err1:
158 scsi_uninit_ccb_alloc(bus);
159 err2:
160 DELETE_BEN(&bus->mutex);
161 err3:
162 delete_sem(bus->start_service);
163 err4:
164 delete_sem(bus->scan_lun_lock);
165 err6:
166 free(bus);
167 return NULL;
171 static status_t
172 scsi_destroy_bus(scsi_bus_info *bus)
174 int32 retcode;
176 // noone is using this bus now, time to clean it up
177 bus->shutting_down = true;
178 release_sem(bus->start_service);
180 wait_for_thread(bus->service_thread, &retcode);
182 delete_sem(bus->start_service);
183 DELETE_BEN(&bus->mutex);
184 delete_sem(bus->scan_lun_lock);
186 scsi_uninit_ccb_alloc(bus);
188 return B_OK;
192 static status_t
193 scsi_init_bus(device_node *node, void **cookie)
195 uint8 path_id;
196 scsi_bus_info *bus;
197 status_t res;
199 SHOW_FLOW0( 3, "" );
201 if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, false) != B_OK)
202 return B_ERROR;
204 bus = scsi_create_bus(node, path_id);
205 if (bus == NULL)
206 return B_NO_MEMORY;
208 // extract controller/protocoll restrictions from node
209 if (pnp->get_attr_uint32(node, B_DMA_ALIGNMENT, &bus->dma_params.alignment,
210 true) != B_OK)
211 bus->dma_params.alignment = 0;
212 if (pnp->get_attr_uint32(node, B_DMA_MAX_TRANSFER_BLOCKS,
213 &bus->dma_params.max_blocks, true) != B_OK)
214 bus->dma_params.max_blocks = 0xffffffff;
215 if (pnp->get_attr_uint32(node, B_DMA_BOUNDARY,
216 &bus->dma_params.dma_boundary, true) != B_OK)
217 bus->dma_params.dma_boundary = ~0;
218 if (pnp->get_attr_uint32(node, B_DMA_MAX_SEGMENT_BLOCKS,
219 &bus->dma_params.max_sg_block_size, true) != B_OK)
220 bus->dma_params.max_sg_block_size = 0xffffffff;
221 if (pnp->get_attr_uint32(node, B_DMA_MAX_SEGMENT_COUNT,
222 &bus->dma_params.max_sg_blocks, true) != B_OK)
223 bus->dma_params.max_sg_blocks = ~0;
225 // do some sanity check:
226 bus->dma_params.max_sg_block_size &= ~bus->dma_params.alignment;
228 if (bus->dma_params.alignment > B_PAGE_SIZE) {
229 SHOW_ERROR(0, "Alignment (0x%" B_PRIx32 ") must be less then "
230 "B_PAGE_SIZE", bus->dma_params.alignment);
231 res = B_ERROR;
232 goto err;
235 if (bus->dma_params.max_sg_block_size < 1) {
236 SHOW_ERROR(0, "Max s/g block size (0x%" B_PRIx32 ") is too small",
237 bus->dma_params.max_sg_block_size);
238 res = B_ERROR;
239 goto err;
242 if (bus->dma_params.dma_boundary < B_PAGE_SIZE - 1) {
243 SHOW_ERROR(0, "DMA boundary (0x%" B_PRIx32 ") must be at least "
244 "B_PAGE_SIZE", bus->dma_params.dma_boundary);
245 res = B_ERROR;
246 goto err;
249 if (bus->dma_params.max_blocks < 1 || bus->dma_params.max_sg_blocks < 1) {
250 SHOW_ERROR(0, "Max blocks (%" B_PRIu32 ") and max s/g blocks (%"
251 B_PRIu32 ") must be at least 1", bus->dma_params.max_blocks,
252 bus->dma_params.max_sg_blocks);
253 res = B_ERROR;
254 goto err;
258 device_node *parent = pnp->get_parent_node(node);
259 pnp->get_driver(parent, (driver_module_info **)&bus->interface,
260 (void **)&bus->sim_cookie);
261 pnp->put_node(parent);
263 bus->interface->set_scsi_bus(bus->sim_cookie, bus);
266 // cache inquiry data
267 scsi_inquiry_path(bus, &bus->inquiry_data);
269 // get max. number of commands on bus
270 bus->left_slots = bus->inquiry_data.hba_queue_size;
271 SHOW_FLOW( 3, "Bus has %d slots", bus->left_slots );
273 *cookie = bus;
275 return B_OK;
277 err:
278 scsi_destroy_bus(bus);
279 return res;
283 static void
284 scsi_uninit_bus(scsi_bus_info *bus)
286 scsi_destroy_bus(bus);
290 uchar
291 scsi_inquiry_path(scsi_bus bus, scsi_path_inquiry *inquiry_data)
293 SHOW_FLOW(4, "path_id=%d", bus->path_id);
294 return bus->interface->path_inquiry(bus->sim_cookie, inquiry_data);
298 static uchar
299 scsi_reset_bus(scsi_bus_info *bus)
301 return bus->interface->reset_bus(bus->sim_cookie);
305 static status_t
306 scsi_bus_module_init(void)
308 SHOW_FLOW0(4, "");
309 return init_temp_sg();
313 static status_t
314 scsi_bus_module_uninit(void)
316 SHOW_INFO0(4, "");
318 uninit_temp_sg();
319 return B_OK;
323 static status_t
324 std_ops(int32 op, ...)
326 switch (op) {
327 case B_MODULE_INIT:
328 return scsi_bus_module_init();
329 case B_MODULE_UNINIT:
330 return scsi_bus_module_uninit();
332 default:
333 return B_ERROR;
338 scsi_bus_interface scsi_bus_module = {
341 SCSI_BUS_MODULE_NAME,
343 std_ops
346 NULL, // supported devices
347 NULL, // register node
348 scsi_init_bus,
349 (void (*)(void *))scsi_uninit_bus,
350 (status_t (*)(void *))scsi_scan_bus,
351 (status_t (*)(void *))scsi_scan_bus,
352 NULL
355 scsi_inquiry_path,
356 scsi_reset_bus,