xref: /haiku/src/add-ons/kernel/bus_managers/scsi/scsi_io.cpp (revision e688bf23d48bfd1216a0cacbdbda5e35a1bcd779)
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 	ACQUIRE_BEN(&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 	RELEASE_BEN(&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 	ACQUIRE_BEN(&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 	RELEASE_BEN(&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 	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;
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 	release_sem_etc(orig_request->completion_sem, 1, 0/*B_DO_NOT_RESCHEDULE*/);
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 	ACQUIRE_BEN(&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 	RELEASE_BEN(&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 	ACQUIRE_BEN(&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=%x, manual_auto_sense=%d",
281 			request->subsys_status, request->device_status, (int)request->flags,
282 			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 	RELEASE_BEN(&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 			release_sem_etc(request->completion_sem, 1, 0/*B_DO_NOT_RESCHEDULE*/);
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 	ACQUIRE_BEN(&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 	RELEASE_BEN(&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", request->state);
402 
403 	if (request->cdb_length < func_group_len[request->cdb[0] >> 5]) {
404 		SHOW_ERROR(3, "invalid command len (%d instead of %d)",
405 			request->cdb_length, func_group_len[request->cdb[0] >> 5]);
406 
407 		request->subsys_status = SCSI_REQ_INVALID;
408 		goto err;
409 	}
410 
411 	if (!request->device->valid) {
412 		SHOW_ERROR0( 3, "device got removed" );
413 
414 		// device got removed meanwhile
415 		request->subsys_status = SCSI_DEV_NOT_THERE;
416 		goto err;
417 	}
418 
419 	if ((request->flags & SCSI_DIR_MASK) != SCSI_DIR_NONE
420 		&& request->sg_list == NULL && request->data_length > 0) {
421 		SHOW_ERROR( 3, "Asynchronous SCSI I/O requires S/G list (data is %d bytes)",
422 			(int)request->data_length );
423 		request->subsys_status = SCSI_DATA_RUN_ERR;
424 		goto err;
425 	}
426 
427 	request->buffered = request->emulated = 0;
428 
429 	// make data DMA safe
430 	// (S/G list must be created first to be able to verify DMA restrictions)
431 	if ((request->flags & SCSI_DMA_SAFE) == 0 && request->data_length > 0) {
432 		request->buffered = true;
433 		if (!scsi_get_dma_buffer(request)) {
434 			SHOW_ERROR0( 3, "cannot create DMA buffer for request - reduce data volume" );
435 
436 			request->subsys_status = SCSI_DATA_RUN_ERR;
437 			goto err;
438 		}
439 	}
440 
441 	// emulate command if not supported
442 	if ((request->device->emulation_map[request->cdb[0] >> 3]
443 		& (1 << (request->cdb[0] & 7))) != 0) {
444 		request->emulated = true;
445 
446 		if (!scsi_start_emulation(request)) {
447 			SHOW_ERROR(3, "cannot emulate SCSI command 0x%02x", request->cdb[0]);
448 			goto err2;
449 		}
450 	}
451 
452 	// SCSI-1 uses 3 bits of command packet for LUN
453 	// SCSI-2 uses identify message, but still needs LUN in command packet
454 	//        (though it won't fit, as LUNs can be 4 bits wide)
455 	// SCSI-3 doesn't use command packet for LUN anymore
456 	// ATAPI uses 3 bits of command packet for LUN
457 
458 	// currently, we always copy LUN into command packet as a safe bet
459 	{
460 		// abuse TUR to find proper spot in command packet for LUN
461 		scsi_cmd_tur *cmd = (scsi_cmd_tur *)request->cdb;
462 
463 		cmd->lun = request->device->target_lun;
464 	}
465 
466 	request->ordered = (request->flags & SCSI_ORDERED_QTAG) != 0;
467 
468 	SHOW_FLOW(3, "ordered=%d", request->ordered);
469 
470 	// give SIM a well-defined first state
471 	request->sim_state = 0;
472 
473 	// make sure device/bus is not blocked
474 	if (!scsi_check_enqueue_request(request))
475 		return;
476 
477 	bus = request->bus;
478 
479 	request->state = SCSI_STATE_SENT;
480 	bus->interface->scsi_io(bus->sim_cookie, request);
481 	return;
482 
483 err2:
484 	if (request->buffered)
485 		scsi_release_dma_buffer(request);
486 err:
487 	release_sem(request->completion_sem);
488 	return;
489 }
490 
491 
492 /** execute SCSI command synchronously */
493 
494 void
495 scsi_sync_io(scsi_ccb *request)
496 {
497 	bool tmp_sg = false;
498 
499 	// create scatter-gather list if required
500 	if ((request->flags & SCSI_DIR_MASK) != SCSI_DIR_NONE
501 		&& request->sg_list == NULL && request->data_length > 0) {
502 		tmp_sg = true;
503 		if (!create_temp_sg(request)) {
504 			SHOW_ERROR0( 3, "data is too much fragmented - you should use s/g list" );
505 
506 			// ToDo: this means too much (fragmented) data
507 			request->subsys_status = SCSI_DATA_RUN_ERR;
508 			return;
509 		}
510 	}
511 
512 	scsi_async_io(request);
513 	acquire_sem(request->completion_sem);
514 
515 	if (tmp_sg)
516 		cleanup_tmp_sg(request);
517 }
518 
519 
520 uchar
521 scsi_term_io(scsi_ccb *ccb_to_terminate)
522 {
523 	scsi_bus_info *bus = ccb_to_terminate->bus;
524 
525 	return bus->interface->term_io(bus->sim_cookie, ccb_to_terminate);
526 }
527 
528 
529 uchar
530 scsi_abort(scsi_ccb *req_to_abort)
531 {
532 	scsi_bus_info *bus = req_to_abort->bus;
533 
534 	if (bus == NULL) {
535 		// checking the validity of the request to abort is a nightmare
536 		// this is just a beginning
537 		return SCSI_REQ_INVALID;
538 	}
539 
540 	ACQUIRE_BEN(&bus->mutex);
541 
542 	switch (req_to_abort->state) {
543 		case SCSI_STATE_FINISHED:
544 		case SCSI_STATE_SENT:
545 			RELEASE_BEN(&bus->mutex);
546 			break;
547 
548 		case SCSI_STATE_QUEUED: {
549 			bool was_servicable, start_retry;
550 
551 			was_servicable = scsi_can_service_bus(bus);
552 
553 			// remove request from device queue
554 			scsi_remove_queued_request(req_to_abort);
555 
556 			start_retry = scsi_can_service_bus(bus) && !was_servicable;
557 
558 			RELEASE_BEN(&bus->mutex);
559 
560 			req_to_abort->subsys_status = SCSI_REQ_ABORTED;
561 
562 			// finish emulation
563 			if (req_to_abort->emulated)
564 				scsi_finish_emulation(req_to_abort);
565 
566 			// release DMA buffer
567 			if (req_to_abort->buffered)
568 				scsi_release_dma_buffer(req_to_abort);
569 
570 			// tell peripheral driver about
571 			release_sem_etc(req_to_abort->completion_sem, 1, 0/*B_DO_NOT_RESCHEDULE*/);
572 
573 			if (start_retry)
574 				release_sem(bus->start_service);
575 
576 			break;
577 		}
578 	}
579 
580 	return SCSI_REQ_CMP;
581 }
582 
583 
584 /** submit pending request (at most one!) */
585 
586 bool
587 scsi_check_exec_service(scsi_bus_info *bus)
588 {
589 	SHOW_FLOW0(3, "");
590 	ACQUIRE_BEN(&bus->mutex);
591 
592 	if (scsi_can_service_bus(bus)) {
593 		scsi_ccb *request;
594 		scsi_device_info *device;
595 
596 		SHOW_FLOW0(3, "servicing bus");
597 
598 		//snooze( 1000000 );
599 
600 		// handle devices in round-robin-style
601 		device = bus->waiting_devices;
602 		bus->waiting_devices = bus->waiting_devices->waiting_next;
603 
604 		request = device->queued_reqs;
605 		scsi_remove_queued_request(request);
606 
607 		// if bus is saturated, block it
608 		if (--bus->left_slots == 0) {
609 			SHOW_FLOW0(3, "bus is saturated, blocking further requests");
610 			scsi_block_bus_nolock(bus, false);
611 		}
612 
613 		// if device saturated or blocking request, block device
614 		if (--device->left_slots == 0 || request->ordered) {
615 			SHOW_FLOW0(3, "device is saturated/blocked by requests, blocking further requests");
616 			scsi_block_device_nolock(device, false);
617 		}
618 
619 		if (request->sort >= 0) {
620 			device->last_sort = request->sort;
621 			SHOW_FLOW(1, "%" B_PRId64, device->last_sort);
622 		}
623 
624 		RELEASE_BEN(&bus->mutex);
625 
626 		request->state = SCSI_STATE_SENT;
627 		bus->interface->scsi_io(bus->sim_cookie, request);
628 
629 		return true;
630 	}
631 
632 	RELEASE_BEN(&bus->mutex);
633 
634 	return false;
635 }
636