xref: /haiku/src/add-ons/kernel/bus_managers/scsi/scsi_io.cpp (revision 344ded80d400028c8f561b4b876257b94c12db4a)
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
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
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
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
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
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
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
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
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
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
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
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
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