1 /*
2 * Copyright 2004-2007, Haiku, Inc. All RightsReserved.
3 * Copyright 2002-2004, Thomas Kurschel. All rights reserved.
4 *
5 * Distributed under the terms of the MIT License.
6 */
7
8 //! Part of Open SCSI bus manager
9
10
11 #include "scsi_internal.h"
12 #include "queuing.h"
13
14 #include <string.h>
15
16 #include <algorithm>
17
18
19 /** put request back in queue because of device/bus overflow */
20
21 void
scsi_requeue_request(scsi_ccb * request,bool bus_overflow)22 scsi_requeue_request(scsi_ccb *request, bool bus_overflow)
23 {
24 scsi_bus_info *bus = request->bus;
25 scsi_device_info *device = request->device;
26 bool was_servicable, start_retry;
27
28 SHOW_FLOW0(3, "");
29
30 if (request->state != SCSI_STATE_SENT) {
31 panic("Unsent ccb was request to requeue\n");
32 return;
33 }
34
35 request->state = SCSI_STATE_QUEUED;
36
37 mutex_lock(&bus->mutex);
38
39 was_servicable = scsi_can_service_bus(bus);
40
41 if (bus->left_slots++ == 0)
42 scsi_unblock_bus_noresume(bus, false);
43
44 if (device->left_slots++ == 0 || request->ordered)
45 scsi_unblock_device_noresume(device, false);
46
47 // make sure it's the next request for this device
48 scsi_add_req_queue_first(request);
49
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);
69 }
70
71 start_retry = !was_servicable && scsi_can_service_bus(bus);
72
73 mutex_unlock(&bus->mutex);
74
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*/);
78 }
79
80
81 /** restart request ASAP because something went wrong */
82
83 void
scsi_resubmit_request(scsi_ccb * request)84 scsi_resubmit_request(scsi_ccb *request)
85 {
86 scsi_bus_info *bus = request->bus;
87 scsi_device_info *device = request->device;
88 bool was_servicable, start_retry;
89
90 SHOW_FLOW0(3, "");
91
92 if (request->state != SCSI_STATE_SENT) {
93 panic("Unsent ccb was asked to get resubmitted\n");
94 return;
95 }
96
97 request->state = SCSI_STATE_QUEUED;
98
99 mutex_lock(&bus->mutex);
100
101 was_servicable = scsi_can_service_bus(bus);
102
103 if (bus->left_slots++ == 0)
104 scsi_unblock_bus_noresume(bus, false);
105
106 if (device->left_slots++ == 0 || request->ordered)
107 scsi_unblock_device_noresume(device, false);
108
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);
112
113 // we don't want to let anyone overtake this request
114 request->ordered = true;
115
116 // make it the next request submitted to SIM for this device
117 scsi_add_req_queue_first(request);
118
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;
125 }
126
127 start_retry = !was_servicable && scsi_can_service_bus(bus);
128
129 mutex_unlock(&bus->mutex);
130
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*/);
134 }
135
136
137 /** submit autosense for request */
138
139 static void
submit_autosense(scsi_ccb * request)140 submit_autosense(scsi_ccb *request)
141 {
142 scsi_device_info *device = request->device;
143
144 //snooze(1000000);
145
146 SHOW_FLOW0(3, "sending autosense");
147 // we cannot use scsi_scsi_io but must insert it brute-force
148
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!
152
153 // no DMA buffer (we made sure that the data buffer fulfills all
154 // limitations)
155 device->auto_sense_request->buffered = false;
156 // don't let any request bypass us
157 device->auto_sense_request->ordered = true;
158 // request is not emulated
159 device->auto_sense_request->emulated = false;
160
161 device->auto_sense_originator = request;
162
163 // make it next request to process
164 scsi_add_queued_request_first(device->auto_sense_request);
165 }
166
167
168 /** finish special auto-sense request */
169
170 static void
finish_autosense(scsi_device_info * device)171 finish_autosense(scsi_device_info *device)
172 {
173 scsi_ccb *orig_request = device->auto_sense_originator;
174 scsi_ccb *request = device->auto_sense_request;
175
176 SHOW_FLOW0(3, "");
177
178 if (request->subsys_status == SCSI_REQ_CMP) {
179 int sense_len;
180
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);
184
185 SHOW_FLOW(3, "Got sense: %d bytes", sense_len);
186
187 memcpy(orig_request->sense, request->data, sense_len);
188
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;
194 }
195
196 // inform peripheral driver
197 orig_request->completion_cond.NotifyAll();
198 }
199
200
201 /** device refused request because command queue is full */
202
203 static void
scsi_device_queue_overflow(scsi_ccb * request,uint num_requests)204 scsi_device_queue_overflow(scsi_ccb *request, uint num_requests)
205 {
206 scsi_bus_info *bus = request->bus;
207 scsi_device_info *device = request->device;
208 int diff_max_slots;
209
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;
214
215 // at least one request at once must be possible
216 if (num_requests < 1)
217 num_requests = 1;
218
219 SHOW_INFO(2, "Restricting device queue to %d requests", num_requests);
220
221 // update slot count
222 mutex_lock(&bus->mutex);
223
224 diff_max_slots = device->total_slots - num_requests;
225 device->total_slots = num_requests;
226 device->left_slots -= diff_max_slots;
227
228 mutex_unlock(&bus->mutex);
229
230 // requeue request, blocking further device requests
231 scsi_requeue_request(request, false);
232 }
233
234
235 /** finish scsi request */
236
237 void
scsi_request_finished(scsi_ccb * request,uint num_requests)238 scsi_request_finished(scsi_ccb *request, uint num_requests)
239 {
240 scsi_device_info *device = request->device;
241 scsi_bus_info *bus = request->bus;
242 bool was_servicable, start_service, do_autosense;
243
244 SHOW_FLOW(3, "%p", request);
245
246 if (request->state != SCSI_STATE_SENT) {
247 panic("Unsent ccb %p was reported as done\n", request);
248 return;
249 }
250
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;
255 }
256
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;
262 }
263
264 request->state = SCSI_STATE_FINISHED;
265
266 mutex_lock(&bus->mutex);
267
268 was_servicable = scsi_can_service_bus(bus);
269
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;
278
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);
283 }
284
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);
289 }
290
291 if (bus->left_slots++ == 0)
292 scsi_unblock_bus_noresume(bus, false);
293
294 if (device->left_slots++ == 0 || request->ordered)
295 scsi_unblock_device_noresume(device, false);
296
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);
300
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);
305
306 start_service = !was_servicable && scsi_can_service_bus(bus);
307
308 mutex_unlock(&bus->mutex);
309
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*/);
314
315 if (request->emulated)
316 scsi_finish_emulation(request);
317
318 // copy data from buffer and release it
319 if (request->buffered)
320 scsi_release_dma_buffer(request);
321
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 request->completion_cond.NotifyAll();
329 }
330 }
331
332
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
336 */
337
338 static inline bool
scsi_check_enqueue_request(scsi_ccb * request)339 scsi_check_enqueue_request(scsi_ccb *request)
340 {
341 scsi_bus_info *bus = request->bus;
342 scsi_device_info *device = request->device;
343 bool execute;
344
345 mutex_lock(&bus->mutex);
346
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);
360 }
361
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);
366 }
367
368 if (request->sort >= 0) {
369 device->last_sort = request->sort;
370 SHOW_FLOW(1, "%" B_PRId64, device->last_sort);
371 }
372
373 execute = true;
374 }
375
376 mutex_unlock(&bus->mutex);
377
378 return execute;
379 }
380
381
382 // size of SCSI command according to function group
383 int func_group_len[8] = {
384 6, 10, 10, 0, 16, 12, 0, 0
385 };
386
387
388 /** execute scsi command asynchronously */
389
390 void
scsi_async_io(scsi_ccb * request)391 scsi_async_io(scsi_ccb *request)
392 {
393 scsi_bus_info *bus = request->bus;
394
395 //SHOW_FLOW( 0, "path_id=%d", bus->path_id );
396
397 //snooze( 1000000 );
398
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);
403 }
404
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]);
408
409 request->subsys_status = SCSI_REQ_INVALID;
410 goto err;
411 }
412
413 if (!request->device->valid) {
414 SHOW_ERROR0( 3, "device got removed" );
415
416 // device got removed meanwhile
417 request->subsys_status = SCSI_DEV_NOT_THERE;
418 goto err;
419 }
420
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;
427 }
428
429 request->buffered = request->emulated = 0;
430
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" );
437
438 request->subsys_status = SCSI_DATA_RUN_ERR;
439 goto err;
440 }
441 }
442
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;
447
448 if (!scsi_start_emulation(request)) {
449 SHOW_ERROR(3, "cannot emulate SCSI command 0x%02x", request->cdb[0]);
450 goto err2;
451 }
452 }
453
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
459
460 // currently, we always copy LUN into command packet as a safe bet
461 {
462 // abuse TUR to find proper spot in command packet for LUN
463 scsi_cmd_tur *cmd = (scsi_cmd_tur *)request->cdb;
464
465 cmd->lun = request->device->target_lun;
466 }
467
468 request->ordered = (request->flags & SCSI_ORDERED_QTAG) != 0;
469
470 SHOW_FLOW(3, "ordered=%d", request->ordered);
471
472 // make sure device/bus is not blocked
473 if (!scsi_check_enqueue_request(request))
474 return;
475
476 bus = request->bus;
477
478 request->state = SCSI_STATE_SENT;
479 bus->interface->scsi_io(bus->sim_cookie, request);
480 return;
481
482 err2:
483 if (request->buffered)
484 scsi_release_dma_buffer(request);
485 err:
486 request->completion_cond.NotifyAll(B_ERROR);
487 return;
488 }
489
490
491 /** execute SCSI command synchronously */
492
493 void
scsi_sync_io(scsi_ccb * request)494 scsi_sync_io(scsi_ccb *request)
495 {
496 bool tmp_sg = false;
497
498 // create scatter-gather list if required
499 if ((request->flags & SCSI_DIR_MASK) != SCSI_DIR_NONE
500 && request->sg_list == NULL && request->data_length > 0) {
501 tmp_sg = true;
502 if (!create_temp_sg(request)) {
503 SHOW_ERROR0( 3, "data is too much fragmented - you should use s/g list" );
504
505 // ToDo: this means too much (fragmented) data
506 request->subsys_status = SCSI_DATA_RUN_ERR;
507 return;
508 }
509 }
510
511 ConditionVariableEntry entry;
512 request->completion_cond.Add(&entry);
513
514 scsi_async_io(request);
515
516 entry.Wait();
517
518 if (tmp_sg)
519 cleanup_temp_sg(request);
520 }
521
522
523 uchar
scsi_term_io(scsi_ccb * ccb_to_terminate)524 scsi_term_io(scsi_ccb *ccb_to_terminate)
525 {
526 scsi_bus_info *bus = ccb_to_terminate->bus;
527
528 return bus->interface->term_io(bus->sim_cookie, ccb_to_terminate);
529 }
530
531
532 uchar
scsi_abort(scsi_ccb * req_to_abort)533 scsi_abort(scsi_ccb *req_to_abort)
534 {
535 scsi_bus_info *bus = req_to_abort->bus;
536
537 if (bus == NULL) {
538 // checking the validity of the request to abort is a nightmare
539 // this is just a beginning
540 return SCSI_REQ_INVALID;
541 }
542
543 mutex_lock(&bus->mutex);
544
545 switch (req_to_abort->state) {
546 case SCSI_STATE_FINISHED:
547 case SCSI_STATE_SENT:
548 mutex_unlock(&bus->mutex);
549 break;
550
551 case SCSI_STATE_QUEUED: {
552 bool was_servicable, start_retry;
553
554 was_servicable = scsi_can_service_bus(bus);
555
556 // remove request from device queue
557 scsi_remove_queued_request(req_to_abort);
558
559 start_retry = scsi_can_service_bus(bus) && !was_servicable;
560
561 mutex_unlock(&bus->mutex);
562
563 req_to_abort->subsys_status = SCSI_REQ_ABORTED;
564
565 // finish emulation
566 if (req_to_abort->emulated)
567 scsi_finish_emulation(req_to_abort);
568
569 // release DMA buffer
570 if (req_to_abort->buffered)
571 scsi_release_dma_buffer(req_to_abort);
572
573 // tell peripheral driver about
574 req_to_abort->completion_cond.NotifyAll(B_CANCELED);
575
576 if (start_retry)
577 release_sem(bus->start_service);
578
579 break;
580 }
581 }
582
583 return SCSI_REQ_CMP;
584 }
585
586
587 /** submit pending request (at most one!) */
588
589 bool
scsi_check_exec_service(scsi_bus_info * bus)590 scsi_check_exec_service(scsi_bus_info *bus)
591 {
592 SHOW_FLOW0(3, "");
593 mutex_lock(&bus->mutex);
594
595 if (scsi_can_service_bus(bus)) {
596 scsi_ccb *request;
597 scsi_device_info *device;
598
599 SHOW_FLOW0(3, "servicing bus");
600
601 //snooze( 1000000 );
602
603 // handle devices in round-robin-style
604 device = bus->waiting_devices;
605 bus->waiting_devices = bus->waiting_devices->waiting_next;
606
607 request = device->queued_reqs;
608 scsi_remove_queued_request(request);
609
610 // if bus is saturated, block it
611 if (--bus->left_slots == 0) {
612 SHOW_FLOW0(3, "bus is saturated, blocking further requests");
613 scsi_block_bus_nolock(bus, false);
614 }
615
616 // if device saturated or blocking request, block device
617 if (--device->left_slots == 0 || request->ordered) {
618 SHOW_FLOW0(3, "device is saturated/blocked by requests, blocking further requests");
619 scsi_block_device_nolock(device, false);
620 }
621
622 if (request->sort >= 0) {
623 device->last_sort = request->sort;
624 SHOW_FLOW(1, "%" B_PRId64, device->last_sort);
625 }
626
627 mutex_unlock(&bus->mutex);
628
629 request->state = SCSI_STATE_SENT;
630 bus->interface->scsi_io(bus->sim_cookie, request);
631
632 return true;
633 }
634
635 mutex_unlock(&bus->mutex);
636
637 return false;
638 }
639