1/*
2 * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2002/03, Thomas Kurschel. All rights reserved.
4 *
5 * Distributed under the terms of the MIT License.
6 */
7
8/*!	Emulation of SCSI commands that a device cannot handle.
9
10	Some SCSI devices don't support all SCSI commands, especially
11	those connected via ATAPI, USB or FireWire. These commands are
12	emulated here.
13*/
14
15
16#include "scsi_internal.h"
17
18#include <vm/vm.h>
19
20#include <string.h>
21
22
23// move some function to end of file to avoid inlining
24static void set_sense(scsi_ccb *request, int sense_key, int sense_asc);
25static bool copy_sg_data(scsi_ccb *request, uint offset, uint allocation_length,
26	void *buffer, int size, bool to_buffer);
27static void get_emulation_buffer(scsi_ccb *request);
28static void replace_request_data(scsi_ccb *request);
29static void release_emulation_buffer(scsi_ccb *request);
30static void restore_request_data(scsi_ccb *request);
31
32
33/*! Free emulation buffer */
34void
35scsi_free_emulation_buffer(scsi_device_info *device)
36{
37	if (device->buffer_area)
38		delete_area(device->buffer_area);
39
40	device->buffer_area = 0;
41	device->buffer = NULL;
42	device->buffer_sg_list = NULL;
43	device->buffer_size = 0;
44
45	if (device->buffer_sem > 0)
46		delete_sem(device->buffer_sem);
47}
48
49
50/*!	Setup buffer used to emulate unsupported SCSI commands
51	buffer_size must be power of two
52*/
53status_t
54scsi_init_emulation_buffer(scsi_device_info *device, size_t buffer_size)
55{
56	physical_entry map[1];
57	size_t total_size;
58
59	SHOW_FLOW0(3, "");
60
61	device->buffer_sem = create_sem(1, "SCSI emulation buffer");
62	if (device->buffer_sem < 0) {
63		SHOW_ERROR(1, "cannot create DMA buffer semaphore (%s)", strerror(device->buffer_sem));
64		return device->buffer_sem;
65	}
66
67	// we append S/G list to buffer as it must be locked as well
68	total_size = (buffer_size + sizeof(physical_entry) + B_PAGE_SIZE - 1)
69		& ~(B_PAGE_SIZE - 1);
70
71	void* address;
72	virtual_address_restrictions virtualRestrictions = {};
73	virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
74	physical_address_restrictions physicalRestrictions = {};
75	physicalRestrictions.alignment = buffer_size;
76	device->buffer_area = create_area_etc(B_SYSTEM_TEAM, "ATAPI buffer",
77		total_size, B_32_BIT_CONTIGUOUS, 0, 0, 0, &virtualRestrictions,
78		&physicalRestrictions, &address);
79		// TODO: Use B_CONTIGUOUS, if possible!
80
81	if (device->buffer_area < 0) {
82		SHOW_ERROR( 1, "cannot create DMA buffer (%s)", strerror(device->buffer_area));
83
84		delete_sem(device->buffer_sem);
85		return device->buffer_area;
86	}
87
88	get_memory_map(address, B_PAGE_SIZE, map, 1);
89
90	// get aligned part
91	phys_addr_t physicalAddress = map[0].address;
92
93	SHOW_FLOW(3, "physical = %#" B_PRIxPHYSADDR ", address = %p",
94		physicalAddress, address);
95
96	device->buffer = (char*)address;
97	device->buffer_size = buffer_size;
98	// s/g list is directly after buffer
99	device->buffer_sg_list = (physical_entry*)((char*)address + buffer_size);
100	device->buffer_sg_list[0].address = physicalAddress;
101	device->buffer_sg_list[0].size = buffer_size;
102	device->buffer_sg_count = 1;
103
104	return B_OK;
105}
106
107
108/*!	Some ATAPI devices don't like 6 byte read/write commands, so
109	we translate them to their 10 byte counterparts;
110	USB devices usually don't like 10 bytes either
111*/
112static bool
113scsi_read_write_6(scsi_ccb *request)
114{
115	scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->orig_cdb;
116	scsi_cmd_rw_10 *cdb = (scsi_cmd_rw_10 *)request->cdb;
117
118	SHOW_FLOW0(3, "patching READ/WRITE(6) to READ/WRITE(10)");
119
120	request->cdb_length = sizeof(*cdb);
121	memset(cdb, 0, sizeof(*cdb));
122
123	cdb->opcode = cmd->opcode + (SCSI_OP_READ_10 - SCSI_OP_READ_6);
124	cdb->lun = cmd->lun;
125	cdb->lba = B_HOST_TO_BENDIAN_INT32((uint32)cmd->low_lba
126		| ((uint32)cmd->mid_lba << 8) | ((uint32)cmd->high_lba << 16));
127	if (cmd->length == 0)
128		cdb->length = B_HOST_TO_BENDIAN_INT16(256);
129	else
130		cdb->length = B_HOST_TO_BENDIAN_INT16((uint16)cmd->length);
131	cdb->control = cmd->control;
132
133#if 0
134	{
135		static uint32 lastLBA = 0;
136		static uint16 lastLength = 0;
137		static uint32 contigCount = 0;
138		static uint64 totalContig = 0;
139
140		uint32 currentLBA = B_BENDIAN_TO_HOST_INT32(cdb->lba);
141		uint16 currentLength = B_BENDIAN_TO_HOST_INT16(cdb->length);
142
143		if (lastLBA + lastLength == currentLBA) {
144			contigCount++;
145			totalContig++;
146		} else
147			contigCount = 0;
148
149		lastLBA = currentLBA;
150		lastLength = currentLength;
151
152		dprintf("scsi_read_write_6: %lld lba %ld; length: %d\n", totalContig,
153			B_BENDIAN_TO_HOST_INT32(cdb->lba),
154			B_BENDIAN_TO_HOST_INT16(cdb->length));
155	}
156#endif
157
158	return true;
159}
160
161
162/*!	All ATAPI devices don't like 6 byte MODE SENSE, so we translate
163	that to 10 byte MODE SENSE
164*/
165static bool
166scsi_start_mode_sense_6(scsi_ccb *request)
167{
168	scsi_cmd_mode_sense_6 *cmd = (scsi_cmd_mode_sense_6 *)request->orig_cdb;
169	scsi_cmd_mode_sense_10 *cdb = (scsi_cmd_mode_sense_10 *)request->cdb;
170	size_t allocationLength;
171
172	SHOW_FLOW0(3, "patching MODE SENSE(6) to MODE SENSE(10)");
173
174	request->cdb_length = sizeof(*cdb);
175	memset(cdb, 0, sizeof(*cdb));
176
177	cdb->opcode = SCSI_OP_MODE_SENSE_10;
178	cdb->disable_block_desc = cmd->disable_block_desc;
179	cdb->lun = cmd->lun;
180	cdb->page_code = cmd->page_code;
181	cdb->page_control = cmd->page_control;
182
183	allocationLength = cmd->allocation_length
184		- sizeof(scsi_cmd_mode_sense_6) + sizeof(scsi_cmd_mode_sense_10);
185	cdb->allocation_length = B_HOST_TO_BENDIAN_INT16(allocationLength);
186
187	SHOW_FLOW(3, "allocation_length=%ld", allocationLength);
188
189	cdb->control = cmd->control;
190
191	// data header of 10 byte version is longer, so use internal buffer
192	// and copy it back once the command is finished
193	get_emulation_buffer(request);
194	replace_request_data(request);
195
196	// restrict data buffer len to length specified in cdb
197	request->data_length = allocationLength;
198	return true;
199}
200
201
202/*!	All ATAPI devices don't like 6 byte MODE SELECT, so we translate
203	that to 10 byte MODE SELECT
204*/
205static bool
206scsi_start_mode_select_6(scsi_ccb *request)
207{
208	scsi_device_info *device = request->device;
209	scsi_cmd_mode_select_6 *cmd = (scsi_cmd_mode_select_6 *)request->orig_cdb;
210	scsi_cmd_mode_select_10 *cdb = (scsi_cmd_mode_select_10 *)request->cdb;
211	scsi_mode_param_header_6 header_6;
212	scsi_mode_param_header_10 *header_10 = (scsi_mode_param_header_10 *)device->buffer;
213	size_t param_list_length_6, param_list_length_10;
214
215	SHOW_FLOW0(3, "patching MODE SELECT(6) to MODE SELECT(10)");
216
217	// calculate new data buffer size
218	param_list_length_6 = cmd->param_list_length;
219	param_list_length_10 = param_list_length_6
220		- sizeof(scsi_mode_param_header_6) + sizeof(scsi_mode_param_header_10);
221
222	// we need to replace data header, thus use internal buffer
223	get_emulation_buffer(request);
224
225	// make sure our buffer is large enough
226	if (param_list_length_10 > device->buffer_size)
227		goto err;
228
229	// construct new cdb
230	request->cdb_length = sizeof(*cdb);
231	memset(cdb, 0, sizeof(*cdb));
232
233	cdb->opcode = SCSI_OP_MODE_SELECT_10;
234	cdb->save_pages = cmd->save_pages;
235	cdb->pf = cmd->pf;
236	cdb->lun = cmd->lun;
237	cdb->param_list_length = B_HOST_TO_BENDIAN_INT16(param_list_length_10);
238
239	SHOW_FLOW(3, "param_list_length=%ld", param_list_length_6);
240
241	cdb->control = cmd->control;
242
243	// copy and adapt header
244	if (!copy_sg_data(request, 0, param_list_length_6, &header_6, sizeof(header_6), true))
245		goto err;
246
247	memset(header_10, 0, sizeof(*header_10));
248
249	// mode_data_len is reserved for MODE SELECT
250	header_10->medium_type = header_6.medium_type;
251	header_10->dev_spec_parameter = header_6.dev_spec_parameter;
252	header_10->block_desc_length = B_HOST_TO_BENDIAN_INT16(
253		(uint16)header_6.block_desc_length);
254
255	// append actual mode select data
256	if (!copy_sg_data(request, sizeof(header_6), param_list_length_6, header_10 + 1,
257			param_list_length_10 - sizeof(*header_10), true))
258		goto err;
259
260	replace_request_data(request);
261
262	// restrict buffer size to the one specified in cdb
263	request->data_length = param_list_length_10;
264	return true;
265
266err:
267	release_emulation_buffer(request);
268
269	set_sense(request, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_PARAM_LIST_FIELD);
270	return false;
271}
272
273
274/*!	Emulation procedure at start of command
275	returns false if command is to be finished without further execution
276*/
277bool
278scsi_start_emulation(scsi_ccb *request)
279{
280	//snooze( 1000000 );
281
282	SHOW_FLOW(3, "command=%x", request->cdb[0]);
283
284	memcpy(request->orig_cdb, request->cdb, SCSI_MAX_CDB_SIZE);
285	request->orig_cdb_length = request->cdb_length;
286
287	switch (request->orig_cdb[0]) {
288		case SCSI_OP_READ_6:
289		case SCSI_OP_WRITE_6:
290			return scsi_read_write_6(request);
291
292		case SCSI_OP_MODE_SENSE_6:
293			return scsi_start_mode_sense_6(request);
294
295		case SCSI_OP_MODE_SELECT_6:
296			return scsi_start_mode_select_6(request);
297	}
298
299	return true;
300}
301
302
303/*! Back-translate MODE SENSE 10 to MODE SENSE 6 */
304static void
305scsi_finish_mode_sense_10_6(scsi_ccb *request)
306{
307	scsi_device_info *device = request->device;
308	scsi_mode_param_header_6 header_6;
309	scsi_mode_param_header_10 *header_10 = (scsi_mode_param_header_10 *)device->buffer;
310	int transfer_size_6, transfer_size_10;
311
312	if (request->subsys_status != SCSI_REQ_CMP
313		|| request->device_status != SCSI_STATUS_GOOD) {
314		// on error, do nothing
315		restore_request_data(request);
316		release_emulation_buffer(request);
317		return;
318	}
319
320	// check how much data we got from device and thus will copy into
321	// request data
322	transfer_size_10 = request->data_length - request->data_resid;
323	transfer_size_6 = transfer_size_10
324		- sizeof(scsi_mode_param_header_10 *) + sizeof(scsi_mode_param_header_6 *);
325
326	SHOW_FLOW(0, "fixing MODE SENSE(6) (%d bytes)", transfer_size_6);
327
328	restore_request_data(request);
329
330	// adapt header
331
332	// convert total length
333	// (+1 is there because mode_data_len in 10 byte header ignores first
334	// two bytes, whereas in the 6 byte header it ignores only one byte)
335	header_6.mode_data_length = B_BENDIAN_TO_HOST_INT16(header_10->mode_data_length)
336		- sizeof(scsi_mode_param_header_10) + sizeof(scsi_mode_param_header_6)
337		+ 1;
338
339	header_6.medium_type = header_10->medium_type;
340	header_6.dev_spec_parameter = header_10->dev_spec_parameter;
341	header_6.block_desc_length = B_BENDIAN_TO_HOST_INT16(header_10->block_desc_length);
342
343	// copy adapted header
344	copy_sg_data(request, 0, transfer_size_6, &header_6, sizeof(header_6), false);
345
346	// copy remaining data
347	copy_sg_data(request, sizeof(header_6), transfer_size_6,
348		header_10 + 1, transfer_size_10 - sizeof(*header_10), false);
349
350	request->data_resid = request->data_length - transfer_size_6;
351
352	release_emulation_buffer(request);
353}
354
355
356/*! Back-translate MODE SELECT 10 to MODE SELECT 6 */
357static void
358scsi_finish_mode_select_10_6(scsi_ccb *request)
359{
360	SHOW_FLOW0(3, "fixing MODE SELECT(6)");
361
362	// adjust transmission length as we've used the longer
363	// mode select 10 data header
364	request->data_resid += sizeof(scsi_mode_param_header_6)
365		- sizeof(scsi_mode_param_header_10);
366
367	restore_request_data(request);
368	release_emulation_buffer(request);
369}
370
371
372/*! Fix inquiry data; some ATAPI devices return wrong version */
373static void
374scsi_finish_inquiry(scsi_ccb *request)
375{
376	int transferSize;
377	scsi_res_inquiry res;
378
379	SHOW_FLOW0(3, "fixing INQUIRY");
380
381	if (request->subsys_status != SCSI_REQ_CMP
382		|| request->device_status != SCSI_STATUS_GOOD)
383		return;
384
385	transferSize = request->data_length - request->data_resid;
386
387	copy_sg_data(request, 0, transferSize, &res, sizeof(res), true);
388
389	SHOW_FLOW(3, "ANSI version: %d, response data format: %d",
390		res.ansi_version, res.response_data_format);
391
392	res.ansi_version = 2;
393	res.response_data_format = 2;
394
395	copy_sg_data(request, 0, transferSize, &res, sizeof(res), false);
396}
397
398
399/*! Adjust result of emulated request */
400void
401scsi_finish_emulation(scsi_ccb *request)
402{
403	SHOW_FLOW0(3, "");
404
405	switch ((((int)request->cdb[0]) << 8) | request->orig_cdb[0]) {
406		case (SCSI_OP_MODE_SENSE_10 << 8) | SCSI_OP_MODE_SENSE_6:
407			scsi_finish_mode_sense_10_6(request);
408			break;
409
410		case (SCSI_OP_MODE_SELECT_10 << 8) | SCSI_OP_MODE_SELECT_6:
411			scsi_finish_mode_select_10_6(request);
412			break;
413
414		case (SCSI_OP_INQUIRY << 8) | SCSI_OP_INQUIRY:
415			scsi_finish_inquiry(request);
416			break;
417	}
418
419	// restore cdb
420	memcpy(request->cdb, request->orig_cdb, SCSI_MAX_CDB_SIZE);
421	request->cdb_length = request->orig_cdb_length;
422}
423
424
425/*! Set sense of request */
426static void
427set_sense(scsi_ccb *request, int sense_key, int sense_asc)
428{
429	scsi_sense *sense = (scsi_sense *)request->sense;
430
431	SHOW_FLOW( 3, "sense_key=%d, sense_asc=%d", sense_key, sense_asc );
432
433	request->subsys_status = SCSI_REQ_CMP;
434	request->device_status = SCSI_STATUS_CHECK_CONDITION;
435
436	// TBD: we can only handle requests with autosense
437	// 		without autosense, we had to manage virtual sense data,
438	//		which is probably not worth the hazzle
439	if ((request->flags & SCSI_DIS_AUTOSENSE) != 0)
440		return;
441
442	memset(sense, 0, sizeof(*sense));
443
444	sense->error_code = SCSIS_CURR_ERROR;
445	sense->sense_key = sense_key;
446	sense->add_sense_length = sizeof(*sense) - 7;
447	sense->asc = (sense_asc >> 8) & 0xff;
448	sense->ascq = sense_asc;
449	sense->sense_key_spec.raw.SKSV = 0;	// no additional info
450
451	request->subsys_status |= SCSI_AUTOSNS_VALID;
452}
453
454
455/*!	Copy data between request data and buffer
456	request			- request to copy data from/to
457	offset			- offset of data in request
458	allocation_length- limit of request's data buffer according to CDB
459	buffer			- data to copy data from/to
460	size			- number of bytes to copy
461	to_buffer		- true: copy from request to buffer
462					  false: copy from buffer to request
463	return: true, if data of request was large enough
464*/
465static bool
466copy_sg_data(scsi_ccb *request, uint offset, uint allocation_length,
467	void *buffer, int size, bool to_buffer)
468{
469	const physical_entry *sg_list = request->sg_list;
470	int sg_count = request->sg_count;
471	int req_size;
472
473	SHOW_FLOW(3, "offset=%u, req_size_limit=%d, size=%d, sg_list=%p, sg_count=%d, %s buffer",
474		offset, allocation_length, size, sg_list, sg_count, to_buffer ? "to" : "from");
475
476	// skip unused S/G entries
477	while (sg_count > 0 && offset >= sg_list->size) {
478		offset -= sg_list->size;
479		++sg_list;
480		--sg_count;
481	}
482
483	if (sg_count == 0)
484		return 0;
485
486	// remaining bytes we are allowed to copy from/to request
487	req_size = min_c(allocation_length, request->data_length) - offset;
488
489	// copy one S/G entry at a time
490	for (; size > 0 && req_size > 0 && sg_count > 0; ++sg_list, --sg_count) {
491		size_t bytes;
492
493		bytes = min_c(size, req_size);
494		bytes = min_c(bytes, sg_list->size);
495
496		SHOW_FLOW(0, "buffer = %p, virt_addr = %#" B_PRIxPHYSADDR ", bytes = %"
497			B_PRIuSIZE ", to_buffer = %d", buffer, sg_list->address + offset,
498			bytes, to_buffer);
499
500		if (to_buffer) {
501			vm_memcpy_from_physical(buffer, sg_list->address + offset, bytes,
502				false);
503		} else {
504			vm_memcpy_to_physical(sg_list->address + offset, buffer, bytes,
505				false);
506		}
507
508		buffer = (char *)buffer + bytes;
509		size -= bytes;
510		offset = 0;
511	}
512
513	return size == 0;
514}
515
516
517/*! Allocate emulation buffer */
518static void
519get_emulation_buffer(scsi_ccb *request)
520{
521	scsi_device_info *device = request->device;
522
523	SHOW_FLOW0(3, "");
524
525	acquire_sem(device->buffer_sem);
526}
527
528
529/*!	Replace request data with emulation buffer, saving original pointer;
530	you must have called get_emulation_buffer() first
531*/
532static void
533replace_request_data(scsi_ccb *request)
534{
535	scsi_device_info *device = request->device;
536
537	SHOW_FLOW0(3, "");
538
539	request->orig_sg_list = request->sg_list;
540	request->orig_sg_count = request->sg_count;
541	request->orig_data_length = request->data_length;
542
543	request->sg_list = device->buffer_sg_list;
544	request->sg_count = device->buffer_sg_count;
545	request->data_length = device->buffer_size;
546}
547
548
549/*! Release emulation buffer */
550static void
551release_emulation_buffer(scsi_ccb *request)
552{
553	SHOW_FLOW0(3, "");
554
555	release_sem(request->device->buffer_sem);
556}
557
558
559/*! Restore original request data pointers */
560static void
561restore_request_data(scsi_ccb *request)
562{
563	SHOW_FLOW0(3, "");
564
565	request->sg_list = request->orig_sg_list;
566	request->sg_count = request->orig_sg_count;
567	request->data_length = request->orig_data_length;
568}
569