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
scsi_free_emulation_buffer(scsi_device_info * device)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
scsi_init_emulation_buffer(scsi_device_info * device,size_t buffer_size)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, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
78 0, 0, &virtualRestrictions, &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
scsi_read_write_6(scsi_ccb * request)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
scsi_start_mode_sense_6(scsi_ccb * request)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
171 SHOW_FLOW0(3, "patching MODE SENSE(6) to MODE SENSE(10)");
172
173 request->cdb_length = sizeof(*cdb);
174 memset(cdb, 0, sizeof(*cdb));
175
176 cdb->opcode = SCSI_OP_MODE_SENSE_10;
177 cdb->disable_block_desc = cmd->disable_block_desc;
178 cdb->lun = cmd->lun;
179 cdb->page_code = cmd->page_code;
180 cdb->page_control = cmd->page_control;
181
182 size_t allocationLength = cmd->allocation_length
183 - sizeof(scsi_cmd_mode_sense_6) + sizeof(scsi_cmd_mode_sense_10);
184 cdb->allocation_length = B_HOST_TO_BENDIAN_INT16(allocationLength);
185
186 SHOW_FLOW(3, "allocation_length=%" B_PRIuSIZE, allocationLength);
187
188 cdb->control = cmd->control;
189
190 // data header of 10 byte version is longer, so use internal buffer
191 // and copy it back once the command is finished
192 get_emulation_buffer(request);
193 replace_request_data(request);
194
195 // restrict data buffer len to length specified in cdb
196 request->data_length = allocationLength;
197 return true;
198 }
199
200
201 /*! All ATAPI devices don't like 6 byte MODE SELECT, so we translate
202 that to 10 byte MODE SELECT
203 */
204 static bool
scsi_start_mode_select_6(scsi_ccb * request)205 scsi_start_mode_select_6(scsi_ccb *request)
206 {
207 scsi_device_info *device = request->device;
208 scsi_cmd_mode_select_6 *cmd = (scsi_cmd_mode_select_6 *)request->orig_cdb;
209 scsi_cmd_mode_select_10 *cdb = (scsi_cmd_mode_select_10 *)request->cdb;
210 scsi_mode_param_header_6 header_6;
211 scsi_mode_param_header_10 *header_10 = (scsi_mode_param_header_10 *)device->buffer;
212 size_t param_list_length_6, param_list_length_10;
213
214 SHOW_FLOW0(3, "patching MODE SELECT(6) to MODE SELECT(10)");
215
216 // calculate new data buffer size
217 param_list_length_6 = cmd->param_list_length;
218 param_list_length_10 = param_list_length_6
219 - sizeof(scsi_mode_param_header_6) + sizeof(scsi_mode_param_header_10);
220
221 // we need to replace data header, thus use internal buffer
222 get_emulation_buffer(request);
223
224 // make sure our buffer is large enough
225 if (param_list_length_10 > device->buffer_size)
226 goto err;
227
228 // construct new cdb
229 request->cdb_length = sizeof(*cdb);
230 memset(cdb, 0, sizeof(*cdb));
231
232 cdb->opcode = SCSI_OP_MODE_SELECT_10;
233 cdb->save_pages = cmd->save_pages;
234 cdb->pf = cmd->pf;
235 cdb->lun = cmd->lun;
236 cdb->param_list_length = B_HOST_TO_BENDIAN_INT16(param_list_length_10);
237
238 SHOW_FLOW(3, "param_list_length=%ld", param_list_length_6);
239
240 cdb->control = cmd->control;
241
242 // copy and adapt header
243 if (!copy_sg_data(request, 0, param_list_length_6, &header_6, sizeof(header_6), true))
244 goto err;
245
246 memset(header_10, 0, sizeof(*header_10));
247
248 // mode_data_len is reserved for MODE SELECT
249 header_10->medium_type = header_6.medium_type;
250 header_10->dev_spec_parameter = header_6.dev_spec_parameter;
251 header_10->block_desc_length = B_HOST_TO_BENDIAN_INT16(
252 (uint16)header_6.block_desc_length);
253
254 // append actual mode select data
255 if (!copy_sg_data(request, sizeof(header_6), param_list_length_6, header_10 + 1,
256 param_list_length_10 - sizeof(*header_10), true))
257 goto err;
258
259 replace_request_data(request);
260
261 // restrict buffer size to the one specified in cdb
262 request->data_length = param_list_length_10;
263 return true;
264
265 err:
266 release_emulation_buffer(request);
267
268 set_sense(request, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_PARAM_LIST_FIELD);
269 return false;
270 }
271
272
273 /*! Emulation procedure at start of command
274 returns false if command is to be finished without further execution
275 */
276 bool
scsi_start_emulation(scsi_ccb * request)277 scsi_start_emulation(scsi_ccb *request)
278 {
279 //snooze( 1000000 );
280
281 SHOW_FLOW(3, "command=%x", request->cdb[0]);
282
283 memcpy(request->orig_cdb, request->cdb, SCSI_MAX_CDB_SIZE);
284 request->orig_cdb_length = request->cdb_length;
285
286 switch (request->orig_cdb[0]) {
287 case SCSI_OP_READ_6:
288 case SCSI_OP_WRITE_6:
289 return scsi_read_write_6(request);
290
291 case SCSI_OP_MODE_SENSE_6:
292 return scsi_start_mode_sense_6(request);
293
294 case SCSI_OP_MODE_SELECT_6:
295 return scsi_start_mode_select_6(request);
296 }
297
298 return true;
299 }
300
301
302 /*! Back-translate MODE SENSE 10 to MODE SENSE 6 */
303 static void
scsi_finish_mode_sense_10_6(scsi_ccb * request)304 scsi_finish_mode_sense_10_6(scsi_ccb *request)
305 {
306 scsi_device_info *device = request->device;
307 scsi_mode_param_header_6 header_6;
308 scsi_mode_param_header_10 *header_10 = (scsi_mode_param_header_10 *)device->buffer;
309 int transfer_size_6, transfer_size_10;
310
311 if (request->subsys_status != SCSI_REQ_CMP
312 || request->device_status != SCSI_STATUS_GOOD) {
313 // on error, do nothing
314 restore_request_data(request);
315 release_emulation_buffer(request);
316 return;
317 }
318
319 // check how much data we got from device and thus will copy into
320 // request data
321 transfer_size_10 = request->data_length - request->data_resid;
322 transfer_size_6 = transfer_size_10
323 - sizeof(scsi_mode_param_header_10 *) + sizeof(scsi_mode_param_header_6 *);
324
325 SHOW_FLOW(0, "fixing MODE SENSE(6) (%d bytes)", transfer_size_6);
326
327 restore_request_data(request);
328
329 // adapt header
330
331 // convert total length
332 // (+1 is there because mode_data_len in 10 byte header ignores first
333 // two bytes, whereas in the 6 byte header it ignores only one byte)
334 header_6.mode_data_length = B_BENDIAN_TO_HOST_INT16(header_10->mode_data_length)
335 - sizeof(scsi_mode_param_header_10) + sizeof(scsi_mode_param_header_6)
336 + 1;
337
338 header_6.medium_type = header_10->medium_type;
339 header_6.dev_spec_parameter = header_10->dev_spec_parameter;
340 header_6.block_desc_length = B_BENDIAN_TO_HOST_INT16(header_10->block_desc_length);
341
342 // copy adapted header
343 copy_sg_data(request, 0, transfer_size_6, &header_6, sizeof(header_6), false);
344
345 // copy remaining data
346 copy_sg_data(request, sizeof(header_6), transfer_size_6,
347 header_10 + 1, transfer_size_10 - sizeof(*header_10), false);
348
349 request->data_resid = request->data_length - transfer_size_6;
350
351 release_emulation_buffer(request);
352 }
353
354
355 /*! Back-translate MODE SELECT 10 to MODE SELECT 6 */
356 static void
scsi_finish_mode_select_10_6(scsi_ccb * request)357 scsi_finish_mode_select_10_6(scsi_ccb *request)
358 {
359 SHOW_FLOW0(3, "fixing MODE SELECT(6)");
360
361 // adjust transmission length as we've used the longer
362 // mode select 10 data header
363 request->data_resid += sizeof(scsi_mode_param_header_6)
364 - sizeof(scsi_mode_param_header_10);
365
366 restore_request_data(request);
367 release_emulation_buffer(request);
368 }
369
370
371 /*! Fix inquiry data; some ATAPI devices return wrong version */
372 static void
scsi_finish_inquiry(scsi_ccb * request)373 scsi_finish_inquiry(scsi_ccb *request)
374 {
375 int transferSize;
376 scsi_res_inquiry res;
377
378 SHOW_FLOW0(3, "fixing INQUIRY");
379
380 if (request->subsys_status != SCSI_REQ_CMP
381 || request->device_status != SCSI_STATUS_GOOD)
382 return;
383
384 transferSize = request->data_length - request->data_resid;
385
386 copy_sg_data(request, 0, transferSize, &res, sizeof(res), true);
387
388 SHOW_FLOW(3, "ANSI version: %d, response data format: %d",
389 res.ansi_version, res.response_data_format);
390
391 res.ansi_version = 2;
392 res.response_data_format = 2;
393
394 copy_sg_data(request, 0, transferSize, &res, sizeof(res), false);
395 }
396
397
398 /*! Adjust result of emulated request */
399 void
scsi_finish_emulation(scsi_ccb * request)400 scsi_finish_emulation(scsi_ccb *request)
401 {
402 SHOW_FLOW0(3, "");
403
404 switch ((((int)request->cdb[0]) << 8) | request->orig_cdb[0]) {
405 case (SCSI_OP_MODE_SENSE_10 << 8) | SCSI_OP_MODE_SENSE_6:
406 scsi_finish_mode_sense_10_6(request);
407 break;
408
409 case (SCSI_OP_MODE_SELECT_10 << 8) | SCSI_OP_MODE_SELECT_6:
410 scsi_finish_mode_select_10_6(request);
411 break;
412
413 case (SCSI_OP_INQUIRY << 8) | SCSI_OP_INQUIRY:
414 scsi_finish_inquiry(request);
415 break;
416 }
417
418 // restore cdb
419 memcpy(request->cdb, request->orig_cdb, SCSI_MAX_CDB_SIZE);
420 request->cdb_length = request->orig_cdb_length;
421 }
422
423
424 /*! Set sense of request */
425 static void
set_sense(scsi_ccb * request,int sense_key,int sense_asc)426 set_sense(scsi_ccb *request, int sense_key, int sense_asc)
427 {
428 scsi_sense *sense = (scsi_sense *)request->sense;
429
430 SHOW_FLOW( 3, "sense_key=%d, sense_asc=%d", sense_key, sense_asc );
431
432 request->subsys_status = SCSI_REQ_CMP;
433 request->device_status = SCSI_STATUS_CHECK_CONDITION;
434
435 // TBD: we can only handle requests with autosense
436 // without autosense, we had to manage virtual sense data,
437 // which is probably not worth the hazzle
438 if ((request->flags & SCSI_DIS_AUTOSENSE) != 0)
439 return;
440
441 memset(sense, 0, sizeof(*sense));
442
443 sense->error_code = SCSIS_CURR_ERROR;
444 sense->sense_key = sense_key;
445 sense->add_sense_length = sizeof(*sense) - 7;
446 sense->asc = (sense_asc >> 8) & 0xff;
447 sense->ascq = sense_asc;
448 sense->sense_key_spec.raw.SKSV = 0; // no additional info
449
450 request->subsys_status |= SCSI_AUTOSNS_VALID;
451 }
452
453
454 /*! Copy data between request data and buffer
455 request - request to copy data from/to
456 offset - offset of data in request
457 allocation_length- limit of request's data buffer according to CDB
458 buffer - data to copy data from/to
459 size - number of bytes to copy
460 to_buffer - true: copy from request to buffer
461 false: copy from buffer to request
462 return: true, if data of request was large enough
463 */
464 static bool
copy_sg_data(scsi_ccb * request,uint offset,uint allocation_length,void * buffer,int size,bool to_buffer)465 copy_sg_data(scsi_ccb *request, uint offset, uint allocation_length,
466 void *buffer, int size, bool to_buffer)
467 {
468 const physical_entry *sg_list = request->sg_list;
469 int sg_count = request->sg_count;
470 int req_size;
471
472 SHOW_FLOW(3, "offset=%u, req_size_limit=%d, size=%d, sg_list=%p, sg_count=%d, %s buffer",
473 offset, allocation_length, size, sg_list, sg_count, to_buffer ? "to" : "from");
474
475 // skip unused S/G entries
476 while (sg_count > 0 && offset >= sg_list->size) {
477 offset -= sg_list->size;
478 ++sg_list;
479 --sg_count;
480 }
481
482 if (sg_count == 0)
483 return 0;
484
485 // remaining bytes we are allowed to copy from/to request
486 req_size = min_c(allocation_length, request->data_length) - offset;
487
488 // copy one S/G entry at a time
489 for (; size > 0 && req_size > 0 && sg_count > 0; ++sg_list, --sg_count) {
490 size_t bytes;
491
492 bytes = min_c(size, req_size);
493 bytes = min_c(bytes, sg_list->size);
494
495 SHOW_FLOW(0, "buffer = %p, virt_addr = %#" B_PRIxPHYSADDR ", bytes = %"
496 B_PRIuSIZE ", to_buffer = %d", buffer, sg_list->address + offset,
497 bytes, to_buffer);
498
499 if (to_buffer) {
500 vm_memcpy_from_physical(buffer, sg_list->address + offset, bytes,
501 false);
502 } else {
503 vm_memcpy_to_physical(sg_list->address + offset, buffer, bytes,
504 false);
505 }
506
507 buffer = (char *)buffer + bytes;
508 size -= bytes;
509 offset = 0;
510 }
511
512 return size == 0;
513 }
514
515
516 /*! Allocate emulation buffer */
517 static void
get_emulation_buffer(scsi_ccb * request)518 get_emulation_buffer(scsi_ccb *request)
519 {
520 scsi_device_info *device = request->device;
521
522 SHOW_FLOW0(3, "");
523
524 acquire_sem(device->buffer_sem);
525 }
526
527
528 /*! Replace request data with emulation buffer, saving original pointer;
529 you must have called get_emulation_buffer() first
530 */
531 static void
replace_request_data(scsi_ccb * request)532 replace_request_data(scsi_ccb *request)
533 {
534 scsi_device_info *device = request->device;
535
536 SHOW_FLOW0(3, "");
537
538 request->orig_sg_list = request->sg_list;
539 request->orig_sg_count = request->sg_count;
540 request->orig_data_length = request->data_length;
541
542 request->sg_list = device->buffer_sg_list;
543 request->sg_count = device->buffer_sg_count;
544 request->data_length = device->buffer_size;
545 }
546
547
548 /*! Release emulation buffer */
549 static void
release_emulation_buffer(scsi_ccb * request)550 release_emulation_buffer(scsi_ccb *request)
551 {
552 SHOW_FLOW0(3, "");
553
554 release_sem(request->device->buffer_sem);
555 }
556
557
558 /*! Restore original request data pointers */
559 static void
restore_request_data(scsi_ccb * request)560 restore_request_data(scsi_ccb *request)
561 {
562 SHOW_FLOW0(3, "");
563
564 request->sg_list = request->orig_sg_list;
565 request->sg_count = request->orig_sg_count;
566 request->data_length = request->orig_data_length;
567 }
568