xref: /haiku/src/add-ons/kernel/bus_managers/scsi/emulation.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
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
24 static void set_sense(scsi_ccb *request, int sense_key, int sense_asc);
25 static bool copy_sg_data(scsi_ccb *request, uint offset, uint allocation_length,
26 	void *buffer, int size, bool to_buffer);
27 static void get_emulation_buffer(scsi_ccb *request);
28 static void replace_request_data(scsi_ccb *request);
29 static void release_emulation_buffer(scsi_ccb *request);
30 static void restore_request_data(scsi_ccb *request);
31 
32 
33 /*! Free emulation buffer */
34 void
35 scsi_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 */
53 status_t
54 scsi_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, &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 */
112 static bool
113 scsi_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 */
165 static bool
166 scsi_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 */
205 static bool
206 scsi_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 
266 err:
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 */
277 bool
278 scsi_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 */
304 static void
305 scsi_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 */
357 static void
358 scsi_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 */
373 static void
374 scsi_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 */
400 void
401 scsi_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 */
426 static void
427 set_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 */
465 static bool
466 copy_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 */
518 static void
519 get_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 */
532 static void
533 replace_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 */
550 static void
551 release_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 */
560 static void
561 restore_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