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	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
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	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
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	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
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	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
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	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
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", 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
483err2:
484	if (request->buffered)
485		scsi_release_dma_buffer(request);
486err:
487	release_sem(request->completion_sem);
488	return;
489}
490
491
492/** execute SCSI command synchronously */
493
494void
495scsi_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
520uchar
521scsi_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
529uchar
530scsi_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
586bool
587scsi_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