BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / bus_managers / scsi / scsi_io.cpp
blob80acf4f20a4b369f7daf4f36ebe2899caf48b78b
1 /*
2 * Copyright 2004-2007, Haiku, Inc. All RightsReserved.
3 * Copyright 2002-2004, Thomas Kurschel. All rights reserved.
5 * Distributed under the terms of the MIT License.
6 */
8 //! Part of Open SCSI bus manager
11 #include "scsi_internal.h"
12 #include "queuing.h"
14 #include <string.h>
16 #include <algorithm>
19 /** put request back in queue because of device/bus overflow */
21 void
22 scsi_requeue_request(scsi_ccb *request, bool bus_overflow)
24 scsi_bus_info *bus = request->bus;
25 scsi_device_info *device = request->device;
26 bool was_servicable, start_retry;
28 SHOW_FLOW0(3, "");
30 if (request->state != SCSI_STATE_SENT) {
31 panic("Unsent ccb was request to requeue\n");
32 return;
35 request->state = SCSI_STATE_QUEUED;
37 ACQUIRE_BEN(&bus->mutex);
39 was_servicable = scsi_can_service_bus(bus);
41 if (bus->left_slots++ == 0)
42 scsi_unblock_bus_noresume(bus, false);
44 if (device->left_slots++ == 0 || request->ordered)
45 scsi_unblock_device_noresume(device, false);
47 // make sure it's the next request for this device
48 scsi_add_req_queue_first(request);
50 if (bus_overflow) {
51 // bus has overflown
52 scsi_set_bus_overflow(bus);
53 // add device to queue as last - other devices may be waiting already
54 scsi_add_device_queue_last(device);
55 // don't change device overflow condition as the device has never seen
56 // this request
57 } else {
58 // device has overflown
59 scsi_set_device_overflow(device);
60 scsi_remove_device_queue(device);
61 // either, the device has refused the request, i.e. it was transmitted
62 // over the bus - in this case, the bus cannot be overloaded anymore;
63 // or, the driver detected that the device can not be able to process
64 // further requests, because the driver knows its maximum queue depth
65 // or something - in this case, the bus state hasn't changed, but the
66 // driver will tell us about any overflow when we submit the next
67 // request, so the overflow state will be fixed automatically
68 scsi_clear_bus_overflow(bus);
71 start_retry = !was_servicable && scsi_can_service_bus(bus);
73 RELEASE_BEN(&bus->mutex);
75 // submit requests to other devices in case bus was overloaded
76 if (start_retry)
77 release_sem_etc(bus->start_service, 1, 0/*B_DO_NOT_RESCHEDULE*/);
81 /** restart request ASAP because something went wrong */
83 void
84 scsi_resubmit_request(scsi_ccb *request)
86 scsi_bus_info *bus = request->bus;
87 scsi_device_info *device = request->device;
88 bool was_servicable, start_retry;
90 SHOW_FLOW0(3, "");
92 if (request->state != SCSI_STATE_SENT) {
93 panic("Unsent ccb was asked to get resubmitted\n");
94 return;
97 request->state = SCSI_STATE_QUEUED;
99 ACQUIRE_BEN(&bus->mutex);
101 was_servicable = scsi_can_service_bus(bus);
103 if (bus->left_slots++ == 0)
104 scsi_unblock_bus_noresume(bus, false);
106 if (device->left_slots++ == 0 || request->ordered)
107 scsi_unblock_device_noresume(device, false);
109 // if SIM reported overflow of device/bus, this should (hopefully) be over now
110 scsi_clear_device_overflow(device);
111 scsi_clear_bus_overflow(bus);
113 // we don't want to let anyone overtake this request
114 request->ordered = true;
116 // make it the next request submitted to SIM for this device
117 scsi_add_req_queue_first(request);
119 // if device is not blocked (anymore) add it to waiting list of bus
120 if (device->lock_count == 0) {
121 scsi_add_device_queue_first(device);
122 // as previous line does nothing if already queued, we force device
123 // to be the next one to get handled
124 bus->waiting_devices = device;
127 start_retry = !was_servicable && scsi_can_service_bus(bus);
129 RELEASE_BEN(&bus->mutex);
131 // let the service thread do the resubmit
132 if (start_retry)
133 release_sem_etc(bus->start_service, 1, 0/*B_DO_NOT_RESCHEDULE*/);
137 /** submit autosense for request */
139 static void
140 submit_autosense(scsi_ccb *request)
142 scsi_device_info *device = request->device;
144 //snooze(1000000);
146 SHOW_FLOW0(3, "sending autosense");
147 // we cannot use scsi_scsi_io but must insert it brute-force
149 // give SIM a well-defined first state
150 // WARNING: this is a short version of scsi_async_io, so if
151 // you change something there, do it here as well!
153 // no DMA buffer (we made sure that the data buffer fulfills all
154 // limitations)
155 request->buffered = false;
156 // don't let any request bypass us
157 request->ordered = true;
158 // initial SIM state for this request
159 request->sim_state = 0;
161 device->auto_sense_originator = request;
163 // make it next request to process
164 scsi_add_queued_request_first(device->auto_sense_request);
168 /** finish special auto-sense request */
170 static void
171 finish_autosense(scsi_device_info *device)
173 scsi_ccb *orig_request = device->auto_sense_originator;
174 scsi_ccb *request = device->auto_sense_request;
176 SHOW_FLOW0(3, "");
178 if (request->subsys_status == SCSI_REQ_CMP) {
179 int sense_len;
181 // we got sense data -> copy it to sense buffer
182 sense_len = std::min((uint32)SCSI_MAX_SENSE_SIZE,
183 request->data_length - request->data_resid);
185 SHOW_FLOW(3, "Got sense: %d bytes", sense_len);
187 memcpy(orig_request->sense, request->data, sense_len);
189 orig_request->sense_resid = SCSI_MAX_SENSE_SIZE - sense_len;
190 orig_request->subsys_status |= SCSI_AUTOSNS_VALID;
191 } else {
192 // failed to get sense
193 orig_request->subsys_status = SCSI_AUTOSENSE_FAIL;
196 // inform peripheral driver
197 release_sem_etc(orig_request->completion_sem, 1, 0/*B_DO_NOT_RESCHEDULE*/);
201 /** device refused request because command queue is full */
203 static void
204 scsi_device_queue_overflow(scsi_ccb *request, uint num_requests)
206 scsi_bus_info *bus = request->bus;
207 scsi_device_info *device = request->device;
208 int diff_max_slots;
210 // set maximum number of concurrent requests to number of
211 // requests running when QUEUE FULL condition occurred - 1
212 // (the "1" is the refused request)
213 --num_requests;
215 // at least one request at once must be possible
216 if (num_requests < 1)
217 num_requests = 1;
219 SHOW_INFO(2, "Restricting device queue to %d requests", num_requests);
221 // update slot count
222 ACQUIRE_BEN(&bus->mutex);
224 diff_max_slots = device->total_slots - num_requests;
225 device->total_slots = num_requests;
226 device->left_slots -= diff_max_slots;
228 RELEASE_BEN(&bus->mutex);
230 // requeue request, blocking further device requests
231 scsi_requeue_request(request, false);
235 /** finish scsi request */
237 void
238 scsi_request_finished(scsi_ccb *request, uint num_requests)
240 scsi_device_info *device = request->device;
241 scsi_bus_info *bus = request->bus;
242 bool was_servicable, start_service, do_autosense;
244 SHOW_FLOW(3, "%p", request);
246 if (request->state != SCSI_STATE_SENT) {
247 panic("Unsent ccb %p was reported as done\n", request);
248 return;
251 if (request->subsys_status == SCSI_REQ_INPROG) {
252 panic("ccb %p with status \"Request in Progress\" was reported as done\n",
253 request);
254 return;
257 // check for queue overflow reported by device
258 if (request->subsys_status == SCSI_REQ_CMP_ERR
259 && request->device_status == SCSI_STATUS_QUEUE_FULL) {
260 scsi_device_queue_overflow(request, num_requests);
261 return;
264 request->state = SCSI_STATE_FINISHED;
266 ACQUIRE_BEN(&bus->mutex);
268 was_servicable = scsi_can_service_bus(bus);
270 // do pseudo-autosense if device doesn't support it and
271 // device reported a check condition state and auto-sense haven't
272 // been retrieved by SIM
273 // (last test is implicit as SIM adds SCSI_AUTOSNS_VALID to subsys_status)
274 do_autosense = device->manual_autosense
275 && (request->flags & SCSI_DIS_AUTOSENSE) == 0
276 && request->subsys_status == SCSI_REQ_CMP_ERR
277 && request->device_status == SCSI_STATUS_CHECK_CONDITION;
279 if (request->subsys_status != SCSI_REQ_CMP) {
280 SHOW_FLOW(3, "subsys=%x, device=%x, flags=%" B_PRIx32
281 ", manual_auto_sense=%d", request->subsys_status,
282 request->device_status, request->flags, device->manual_autosense);
285 if (do_autosense) {
286 // queue auto-sense request after checking was_servicable but before
287 // releasing locks so no other request overtakes auto-sense
288 submit_autosense(request);
291 if (bus->left_slots++ == 0)
292 scsi_unblock_bus_noresume(bus, false);
294 if (device->left_slots++ == 0 || request->ordered)
295 scsi_unblock_device_noresume(device, false);
297 // if SIM reported overflow of device/bus, this should (hopefully) be over now
298 scsi_clear_device_overflow(device);
299 scsi_clear_bus_overflow(bus);
301 // if device is not blocked (anymore) and has pending requests,
302 // add it to waiting list of bus
303 if (device->lock_count == 0 && device->queued_reqs != NULL)
304 scsi_add_device_queue_last(device);
306 start_service = !was_servicable && scsi_can_service_bus(bus);
308 RELEASE_BEN(&bus->mutex);
310 // tell service thread to submit new requests to SIM
311 // (do this ASAP to keep bus/device busy)
312 if (start_service)
313 release_sem_etc(bus->start_service, 1, 0/*B_DO_NOT_RESCHEDULE*/);
315 if (request->emulated)
316 scsi_finish_emulation(request);
318 // copy data from buffer and release it
319 if (request->buffered)
320 scsi_release_dma_buffer(request);
322 // special treatment for finished auto-sense
323 if (request == device->auto_sense_request)
324 finish_autosense(device);
325 else {
326 // tell peripheral driver about completion
327 if (!do_autosense)
328 release_sem_etc(request->completion_sem, 1, 0/*B_DO_NOT_RESCHEDULE*/);
333 /** check whether request can be executed right now, enqueuing it if not,
334 * return: true if request can be executed
335 * side effect: updates device->last_sort
338 static inline bool
339 scsi_check_enqueue_request(scsi_ccb *request)
341 scsi_bus_info *bus = request->bus;
342 scsi_device_info *device = request->device;
343 bool execute;
345 ACQUIRE_BEN(&bus->mutex);
347 // if device/bus is locked, or there are waiting requests
348 // or waiting devices (last condition makes sure we don't overtake
349 // requests that got queued because bus was full)
350 if (device->lock_count > 0 || device->queued_reqs != NULL
351 || bus->lock_count > 0 || bus->waiting_devices != NULL) {
352 SHOW_FLOW0(3, "bus/device is currently locked");
353 scsi_add_queued_request(request);
354 execute = false;
355 } else {
356 // if bus is saturated, block it
357 if (--bus->left_slots == 0) {
358 SHOW_FLOW0(3, "bus is saturated, blocking further requests");
359 scsi_block_bus_nolock(bus, false);
362 // if device saturated or blocking request, block device
363 if (--device->left_slots == 0 || request->ordered) {
364 SHOW_FLOW0( 3, "device is saturated/blocked by requests, blocking further requests" );
365 scsi_block_device_nolock(device, false);
368 if (request->sort >= 0) {
369 device->last_sort = request->sort;
370 SHOW_FLOW(1, "%" B_PRId64, device->last_sort);
373 execute = true;
376 RELEASE_BEN(&bus->mutex);
378 return execute;
382 // size of SCSI command according to function group
383 int func_group_len[8] = {
384 6, 10, 10, 0, 16, 12, 0, 0
388 /** execute scsi command asynchronously */
390 void
391 scsi_async_io(scsi_ccb *request)
393 scsi_bus_info *bus = request->bus;
395 //SHOW_FLOW( 0, "path_id=%d", bus->path_id );
397 //snooze( 1000000 );
399 // do some sanity tests first
400 if (request->state != SCSI_STATE_FINISHED) {
401 panic("Passed ccb to scsi_action that isn't ready (state = %d)\n",
402 request->state);
405 if (request->cdb_length < func_group_len[request->cdb[0] >> 5]) {
406 SHOW_ERROR(3, "invalid command len (%d instead of %d)",
407 request->cdb_length, func_group_len[request->cdb[0] >> 5]);
409 request->subsys_status = SCSI_REQ_INVALID;
410 goto err;
413 if (!request->device->valid) {
414 SHOW_ERROR0( 3, "device got removed" );
416 // device got removed meanwhile
417 request->subsys_status = SCSI_DEV_NOT_THERE;
418 goto err;
421 if ((request->flags & SCSI_DIR_MASK) != SCSI_DIR_NONE
422 && request->sg_list == NULL && request->data_length > 0) {
423 SHOW_ERROR( 3, "Asynchronous SCSI I/O requires S/G list (data is %"
424 B_PRIu32 " bytes)", request->data_length );
425 request->subsys_status = SCSI_DATA_RUN_ERR;
426 goto err;
429 request->buffered = request->emulated = 0;
431 // make data DMA safe
432 // (S/G list must be created first to be able to verify DMA restrictions)
433 if ((request->flags & SCSI_DMA_SAFE) == 0 && request->data_length > 0) {
434 request->buffered = true;
435 if (!scsi_get_dma_buffer(request)) {
436 SHOW_ERROR0( 3, "cannot create DMA buffer for request - reduce data volume" );
438 request->subsys_status = SCSI_DATA_RUN_ERR;
439 goto err;
443 // emulate command if not supported
444 if ((request->device->emulation_map[request->cdb[0] >> 3]
445 & (1 << (request->cdb[0] & 7))) != 0) {
446 request->emulated = true;
448 if (!scsi_start_emulation(request)) {
449 SHOW_ERROR(3, "cannot emulate SCSI command 0x%02x", request->cdb[0]);
450 goto err2;
454 // SCSI-1 uses 3 bits of command packet for LUN
455 // SCSI-2 uses identify message, but still needs LUN in command packet
456 // (though it won't fit, as LUNs can be 4 bits wide)
457 // SCSI-3 doesn't use command packet for LUN anymore
458 // ATAPI uses 3 bits of command packet for LUN
460 // currently, we always copy LUN into command packet as a safe bet
462 // abuse TUR to find proper spot in command packet for LUN
463 scsi_cmd_tur *cmd = (scsi_cmd_tur *)request->cdb;
465 cmd->lun = request->device->target_lun;
468 request->ordered = (request->flags & SCSI_ORDERED_QTAG) != 0;
470 SHOW_FLOW(3, "ordered=%d", request->ordered);
472 // give SIM a well-defined first state
473 request->sim_state = 0;
475 // make sure device/bus is not blocked
476 if (!scsi_check_enqueue_request(request))
477 return;
479 bus = request->bus;
481 request->state = SCSI_STATE_SENT;
482 bus->interface->scsi_io(bus->sim_cookie, request);
483 return;
485 err2:
486 if (request->buffered)
487 scsi_release_dma_buffer(request);
488 err:
489 release_sem(request->completion_sem);
490 return;
494 /** execute SCSI command synchronously */
496 void
497 scsi_sync_io(scsi_ccb *request)
499 bool tmp_sg = false;
501 // create scatter-gather list if required
502 if ((request->flags & SCSI_DIR_MASK) != SCSI_DIR_NONE
503 && request->sg_list == NULL && request->data_length > 0) {
504 tmp_sg = true;
505 if (!create_temp_sg(request)) {
506 SHOW_ERROR0( 3, "data is too much fragmented - you should use s/g list" );
508 // ToDo: this means too much (fragmented) data
509 request->subsys_status = SCSI_DATA_RUN_ERR;
510 return;
514 scsi_async_io(request);
515 acquire_sem(request->completion_sem);
517 if (tmp_sg)
518 cleanup_tmp_sg(request);
522 uchar
523 scsi_term_io(scsi_ccb *ccb_to_terminate)
525 scsi_bus_info *bus = ccb_to_terminate->bus;
527 return bus->interface->term_io(bus->sim_cookie, ccb_to_terminate);
531 uchar
532 scsi_abort(scsi_ccb *req_to_abort)
534 scsi_bus_info *bus = req_to_abort->bus;
536 if (bus == NULL) {
537 // checking the validity of the request to abort is a nightmare
538 // this is just a beginning
539 return SCSI_REQ_INVALID;
542 ACQUIRE_BEN(&bus->mutex);
544 switch (req_to_abort->state) {
545 case SCSI_STATE_FINISHED:
546 case SCSI_STATE_SENT:
547 RELEASE_BEN(&bus->mutex);
548 break;
550 case SCSI_STATE_QUEUED: {
551 bool was_servicable, start_retry;
553 was_servicable = scsi_can_service_bus(bus);
555 // remove request from device queue
556 scsi_remove_queued_request(req_to_abort);
558 start_retry = scsi_can_service_bus(bus) && !was_servicable;
560 RELEASE_BEN(&bus->mutex);
562 req_to_abort->subsys_status = SCSI_REQ_ABORTED;
564 // finish emulation
565 if (req_to_abort->emulated)
566 scsi_finish_emulation(req_to_abort);
568 // release DMA buffer
569 if (req_to_abort->buffered)
570 scsi_release_dma_buffer(req_to_abort);
572 // tell peripheral driver about
573 release_sem_etc(req_to_abort->completion_sem, 1, 0/*B_DO_NOT_RESCHEDULE*/);
575 if (start_retry)
576 release_sem(bus->start_service);
578 break;
582 return SCSI_REQ_CMP;
586 /** submit pending request (at most one!) */
588 bool
589 scsi_check_exec_service(scsi_bus_info *bus)
591 SHOW_FLOW0(3, "");
592 ACQUIRE_BEN(&bus->mutex);
594 if (scsi_can_service_bus(bus)) {
595 scsi_ccb *request;
596 scsi_device_info *device;
598 SHOW_FLOW0(3, "servicing bus");
600 //snooze( 1000000 );
602 // handle devices in round-robin-style
603 device = bus->waiting_devices;
604 bus->waiting_devices = bus->waiting_devices->waiting_next;
606 request = device->queued_reqs;
607 scsi_remove_queued_request(request);
609 // if bus is saturated, block it
610 if (--bus->left_slots == 0) {
611 SHOW_FLOW0(3, "bus is saturated, blocking further requests");
612 scsi_block_bus_nolock(bus, false);
615 // if device saturated or blocking request, block device
616 if (--device->left_slots == 0 || request->ordered) {
617 SHOW_FLOW0(3, "device is saturated/blocked by requests, blocking further requests");
618 scsi_block_device_nolock(device, false);
621 if (request->sort >= 0) {
622 device->last_sort = request->sort;
623 SHOW_FLOW(1, "%" B_PRId64, device->last_sort);
626 RELEASE_BEN(&bus->mutex);
628 request->state = SCSI_STATE_SENT;
629 bus->interface->scsi_io(bus->sim_cookie, request);
631 return true;
634 RELEASE_BEN(&bus->mutex);
636 return false;