2 * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2002/03, Thomas Kurschel. All rights reserved.
5 * Distributed under the terms of the MIT License.
8 /*! Emulation of SCSI commands that a device cannot handle.
10 Some SCSI devices don't support all SCSI commands, especially
11 those connected via ATAPI, USB or FireWire. These commands are
16 #include "scsi_internal.h"
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
);
33 /*! Free emulation buffer */
35 scsi_free_emulation_buffer(scsi_device_info
*device
)
37 if (device
->buffer_area
)
38 delete_area(device
->buffer_area
);
40 device
->buffer_area
= 0;
41 device
->buffer
= NULL
;
42 device
->buffer_sg_list
= NULL
;
43 device
->buffer_size
= 0;
45 if (device
->buffer_sem
> 0)
46 delete_sem(device
->buffer_sem
);
50 /*! Setup buffer used to emulate unsupported SCSI commands
51 buffer_size must be power of two
54 scsi_init_emulation_buffer(scsi_device_info
*device
, size_t buffer_size
)
56 physical_entry map
[1];
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
;
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)
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!
81 if (device
->buffer_area
< 0) {
82 SHOW_ERROR( 1, "cannot create DMA buffer (%s)", strerror(device
->buffer_area
));
84 delete_sem(device
->buffer_sem
);
85 return device
->buffer_area
;
88 get_memory_map(address
, B_PAGE_SIZE
, map
, 1);
91 phys_addr_t physicalAddress
= map
[0].address
;
93 SHOW_FLOW(3, "physical = %#" B_PRIxPHYSADDR
", address = %p",
94 physicalAddress
, address
);
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;
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
113 scsi_read_write_6(scsi_ccb
*request
)
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
;
118 SHOW_FLOW0(3, "patching READ/WRITE(6) to READ/WRITE(10)");
120 request
->cdb_length
= sizeof(*cdb
);
121 memset(cdb
, 0, sizeof(*cdb
));
123 cdb
->opcode
= cmd
->opcode
+ (SCSI_OP_READ_10
- SCSI_OP_READ_6
);
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);
130 cdb
->length
= B_HOST_TO_BENDIAN_INT16((uint16
)cmd
->length
);
131 cdb
->control
= cmd
->control
;
135 static uint32 lastLBA
= 0;
136 static uint16 lastLength
= 0;
137 static uint32 contigCount
= 0;
138 static uint64 totalContig
= 0;
140 uint32 currentLBA
= B_BENDIAN_TO_HOST_INT32(cdb
->lba
);
141 uint16 currentLength
= B_BENDIAN_TO_HOST_INT16(cdb
->length
);
143 if (lastLBA
+ lastLength
== currentLBA
) {
149 lastLBA
= currentLBA
;
150 lastLength
= currentLength
;
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
));
162 /*! All ATAPI devices don't like 6 byte MODE SENSE, so we translate
163 that to 10 byte MODE SENSE
166 scsi_start_mode_sense_6(scsi_ccb
*request
)
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
;
171 SHOW_FLOW0(3, "patching MODE SENSE(6) to MODE SENSE(10)");
173 request
->cdb_length
= sizeof(*cdb
);
174 memset(cdb
, 0, sizeof(*cdb
));
176 cdb
->opcode
= SCSI_OP_MODE_SENSE_10
;
177 cdb
->disable_block_desc
= cmd
->disable_block_desc
;
179 cdb
->page_code
= cmd
->page_code
;
180 cdb
->page_control
= cmd
->page_control
;
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
);
186 SHOW_FLOW(3, "allocation_length=%" B_PRIuSIZE
, allocationLength
);
188 cdb
->control
= cmd
->control
;
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
);
195 // restrict data buffer len to length specified in cdb
196 request
->data_length
= allocationLength
;
201 /*! All ATAPI devices don't like 6 byte MODE SELECT, so we translate
202 that to 10 byte MODE SELECT
205 scsi_start_mode_select_6(scsi_ccb
*request
)
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
;
214 SHOW_FLOW0(3, "patching MODE SELECT(6) to MODE SELECT(10)");
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
);
221 // we need to replace data header, thus use internal buffer
222 get_emulation_buffer(request
);
224 // make sure our buffer is large enough
225 if (param_list_length_10
> device
->buffer_size
)
229 request
->cdb_length
= sizeof(*cdb
);
230 memset(cdb
, 0, sizeof(*cdb
));
232 cdb
->opcode
= SCSI_OP_MODE_SELECT_10
;
233 cdb
->save_pages
= cmd
->save_pages
;
236 cdb
->param_list_length
= B_HOST_TO_BENDIAN_INT16(param_list_length_10
);
238 SHOW_FLOW(3, "param_list_length=%ld", param_list_length_6
);
240 cdb
->control
= cmd
->control
;
242 // copy and adapt header
243 if (!copy_sg_data(request
, 0, param_list_length_6
, &header_6
, sizeof(header_6
), true))
246 memset(header_10
, 0, sizeof(*header_10
));
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
);
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))
259 replace_request_data(request
);
261 // restrict buffer size to the one specified in cdb
262 request
->data_length
= param_list_length_10
;
266 release_emulation_buffer(request
);
268 set_sense(request
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_INV_PARAM_LIST_FIELD
);
273 /*! Emulation procedure at start of command
274 returns false if command is to be finished without further execution
277 scsi_start_emulation(scsi_ccb
*request
)
281 SHOW_FLOW(3, "command=%x", request
->cdb
[0]);
283 memcpy(request
->orig_cdb
, request
->cdb
, SCSI_MAX_CDB_SIZE
);
284 request
->orig_cdb_length
= request
->cdb_length
;
286 switch (request
->orig_cdb
[0]) {
288 case SCSI_OP_WRITE_6
:
289 return scsi_read_write_6(request
);
291 case SCSI_OP_MODE_SENSE_6
:
292 return scsi_start_mode_sense_6(request
);
294 case SCSI_OP_MODE_SELECT_6
:
295 return scsi_start_mode_select_6(request
);
302 /*! Back-translate MODE SENSE 10 to MODE SENSE 6 */
304 scsi_finish_mode_sense_10_6(scsi_ccb
*request
)
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
;
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
);
319 // check how much data we got from device and thus will copy into
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
*);
325 SHOW_FLOW(0, "fixing MODE SENSE(6) (%d bytes)", transfer_size_6
);
327 restore_request_data(request
);
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
)
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
);
342 // copy adapted header
343 copy_sg_data(request
, 0, transfer_size_6
, &header_6
, sizeof(header_6
), false);
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);
349 request
->data_resid
= request
->data_length
- transfer_size_6
;
351 release_emulation_buffer(request
);
355 /*! Back-translate MODE SELECT 10 to MODE SELECT 6 */
357 scsi_finish_mode_select_10_6(scsi_ccb
*request
)
359 SHOW_FLOW0(3, "fixing MODE SELECT(6)");
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
);
366 restore_request_data(request
);
367 release_emulation_buffer(request
);
371 /*! Fix inquiry data; some ATAPI devices return wrong version */
373 scsi_finish_inquiry(scsi_ccb
*request
)
376 scsi_res_inquiry res
;
378 SHOW_FLOW0(3, "fixing INQUIRY");
380 if (request
->subsys_status
!= SCSI_REQ_CMP
381 || request
->device_status
!= SCSI_STATUS_GOOD
)
384 transferSize
= request
->data_length
- request
->data_resid
;
386 copy_sg_data(request
, 0, transferSize
, &res
, sizeof(res
), true);
388 SHOW_FLOW(3, "ANSI version: %d, response data format: %d",
389 res
.ansi_version
, res
.response_data_format
);
391 res
.ansi_version
= 2;
392 res
.response_data_format
= 2;
394 copy_sg_data(request
, 0, transferSize
, &res
, sizeof(res
), false);
398 /*! Adjust result of emulated request */
400 scsi_finish_emulation(scsi_ccb
*request
)
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
);
409 case (SCSI_OP_MODE_SELECT_10
<< 8) | SCSI_OP_MODE_SELECT_6
:
410 scsi_finish_mode_select_10_6(request
);
413 case (SCSI_OP_INQUIRY
<< 8) | SCSI_OP_INQUIRY
:
414 scsi_finish_inquiry(request
);
419 memcpy(request
->cdb
, request
->orig_cdb
, SCSI_MAX_CDB_SIZE
);
420 request
->cdb_length
= request
->orig_cdb_length
;
424 /*! Set sense of request */
426 set_sense(scsi_ccb
*request
, int sense_key
, int sense_asc
)
428 scsi_sense
*sense
= (scsi_sense
*)request
->sense
;
430 SHOW_FLOW( 3, "sense_key=%d, sense_asc=%d", sense_key
, sense_asc
);
432 request
->subsys_status
= SCSI_REQ_CMP
;
433 request
->device_status
= SCSI_STATUS_CHECK_CONDITION
;
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)
441 memset(sense
, 0, sizeof(*sense
));
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
450 request
->subsys_status
|= SCSI_AUTOSNS_VALID
;
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
465 copy_sg_data(scsi_ccb
*request
, uint offset
, uint allocation_length
,
466 void *buffer
, int size
, bool to_buffer
)
468 const physical_entry
*sg_list
= request
->sg_list
;
469 int sg_count
= request
->sg_count
;
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");
475 // skip unused S/G entries
476 while (sg_count
> 0 && offset
>= sg_list
->size
) {
477 offset
-= sg_list
->size
;
485 // remaining bytes we are allowed to copy from/to request
486 req_size
= min_c(allocation_length
, request
->data_length
) - offset
;
488 // copy one S/G entry at a time
489 for (; size
> 0 && req_size
> 0 && sg_count
> 0; ++sg_list
, --sg_count
) {
492 bytes
= min_c(size
, req_size
);
493 bytes
= min_c(bytes
, sg_list
->size
);
495 SHOW_FLOW(0, "buffer = %p, virt_addr = %#" B_PRIxPHYSADDR
", bytes = %"
496 B_PRIuSIZE
", to_buffer = %d", buffer
, sg_list
->address
+ offset
,
500 vm_memcpy_from_physical(buffer
, sg_list
->address
+ offset
, bytes
,
503 vm_memcpy_to_physical(sg_list
->address
+ offset
, buffer
, bytes
,
507 buffer
= (char *)buffer
+ bytes
;
516 /*! Allocate emulation buffer */
518 get_emulation_buffer(scsi_ccb
*request
)
520 scsi_device_info
*device
= request
->device
;
524 acquire_sem(device
->buffer_sem
);
528 /*! Replace request data with emulation buffer, saving original pointer;
529 you must have called get_emulation_buffer() first
532 replace_request_data(scsi_ccb
*request
)
534 scsi_device_info
*device
= request
->device
;
538 request
->orig_sg_list
= request
->sg_list
;
539 request
->orig_sg_count
= request
->sg_count
;
540 request
->orig_data_length
= request
->data_length
;
542 request
->sg_list
= device
->buffer_sg_list
;
543 request
->sg_count
= device
->buffer_sg_count
;
544 request
->data_length
= device
->buffer_size
;
548 /*! Release emulation buffer */
550 release_emulation_buffer(scsi_ccb
*request
)
554 release_sem(request
->device
->buffer_sem
);
558 /*! Restore original request data pointers */
560 restore_request_data(scsi_ccb
*request
)
564 request
->sg_list
= request
->orig_sg_list
;
565 request
->sg_count
= request
->orig_sg_count
;
566 request
->data_length
= request
->orig_data_length
;