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
21void
22scsi_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
83void
84scsi_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
139static void
140submit_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
170static void
171finish_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
203static void
204scsi_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
237void
238scsi_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			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
338static inline bool
339scsi_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
383int func_group_len[8] = {
384	6, 10, 10, 0, 16, 12, 0, 0
385};
386
387
388/** execute scsi command asynchronously */
389
390void
391scsi_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	// give SIM a well-defined first state
473	request->sim_state = 0;
474
475	// make sure device/bus is not blocked
476	if (!scsi_check_enqueue_request(request))
477		return;
478
479	bus = request->bus;
480
481	request->state = SCSI_STATE_SENT;
482	bus->interface->scsi_io(bus->sim_cookie, request);
483	return;
484
485err2:
486	if (request->buffered)
487		scsi_release_dma_buffer(request);
488err:
489	release_sem(request->completion_sem);
490	return;
491}
492
493
494/** execute SCSI command synchronously */
495
496void
497scsi_sync_io(scsi_ccb *request)
498{
499	bool tmp_sg = false;
500
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" );
507
508			// ToDo: this means too much (fragmented) data
509			request->subsys_status = SCSI_DATA_RUN_ERR;
510			return;
511		}
512	}
513
514	scsi_async_io(request);
515	acquire_sem(request->completion_sem);
516
517	if (tmp_sg)
518		cleanup_tmp_sg(request);
519}
520
521
522uchar
523scsi_term_io(scsi_ccb *ccb_to_terminate)
524{
525	scsi_bus_info *bus = ccb_to_terminate->bus;
526
527	return bus->interface->term_io(bus->sim_cookie, ccb_to_terminate);
528}
529
530
531uchar
532scsi_abort(scsi_ccb *req_to_abort)
533{
534	scsi_bus_info *bus = req_to_abort->bus;
535
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;
540	}
541
542	mutex_lock(&bus->mutex);
543
544	switch (req_to_abort->state) {
545		case SCSI_STATE_FINISHED:
546		case SCSI_STATE_SENT:
547			mutex_unlock(&bus->mutex);
548			break;
549
550		case SCSI_STATE_QUEUED: {
551			bool was_servicable, start_retry;
552
553			was_servicable = scsi_can_service_bus(bus);
554
555			// remove request from device queue
556			scsi_remove_queued_request(req_to_abort);
557
558			start_retry = scsi_can_service_bus(bus) && !was_servicable;
559
560			mutex_unlock(&bus->mutex);
561
562			req_to_abort->subsys_status = SCSI_REQ_ABORTED;
563
564			// finish emulation
565			if (req_to_abort->emulated)
566				scsi_finish_emulation(req_to_abort);
567
568			// release DMA buffer
569			if (req_to_abort->buffered)
570				scsi_release_dma_buffer(req_to_abort);
571
572			// tell peripheral driver about
573			release_sem_etc(req_to_abort->completion_sem, 1, 0/*B_DO_NOT_RESCHEDULE*/);
574
575			if (start_retry)
576				release_sem(bus->start_service);
577
578			break;
579		}
580	}
581
582	return SCSI_REQ_CMP;
583}
584
585
586/** submit pending request (at most one!) */
587
588bool
589scsi_check_exec_service(scsi_bus_info *bus)
590{
591	SHOW_FLOW0(3, "");
592	mutex_lock(&bus->mutex);
593
594	if (scsi_can_service_bus(bus)) {
595		scsi_ccb *request;
596		scsi_device_info *device;
597
598		SHOW_FLOW0(3, "servicing bus");
599
600		//snooze( 1000000 );
601
602		// handle devices in round-robin-style
603		device = bus->waiting_devices;
604		bus->waiting_devices = bus->waiting_devices->waiting_next;
605
606		request = device->queued_reqs;
607		scsi_remove_queued_request(request);
608
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);
613		}
614
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);
619		}
620
621		if (request->sort >= 0) {
622			device->last_sort = request->sort;
623			SHOW_FLOW(1, "%" B_PRId64, device->last_sort);
624		}
625
626		mutex_unlock(&bus->mutex);
627
628		request->state = SCSI_STATE_SENT;
629		bus->interface->scsi_io(bus->sim_cookie, request);
630
631		return true;
632	}
633
634	mutex_unlock(&bus->mutex);
635
636	return false;
637}
638