2 * Copyright 2004-2007, Haiku, Inc. All RightsReserved.
3 * Copyright 2002/03, Thomas Kurschel. All rights reserved.
5 * Distributed under the terms of the MIT License.
9 Part of Open IDE bus manager
11 Converts SCSI commands to ATA commands.
15 #include "ide_internal.h"
22 /** emulate MODE SENSE 10 command */
25 ata_mode_sense_10(ide_device_info
*device
, ide_qrequest
*qrequest
)
27 scsi_ccb
*request
= qrequest
->request
;
28 scsi_cmd_mode_sense_10
*cmd
= (scsi_cmd_mode_sense_10
*)request
->cdb
;
29 scsi_mode_param_header_10 param_header
;
30 scsi_modepage_control control
;
31 scsi_mode_param_block_desc block_desc
;
32 size_t totalLength
= sizeof(scsi_mode_param_header_10
)
33 + sizeof(scsi_mode_param_block_desc
)
34 + sizeof(scsi_modepage_control
);
35 scsi_mode_param_dev_spec_da devspec
= {
41 uint32 allocationLength
;
45 allocationLength
= B_BENDIAN_TO_HOST_INT16(cmd
->allocation_length
);
47 // we answer control page requests and "all pages" requests
48 // (as the latter are the same as the first)
49 if ((cmd
->page_code
!= SCSI_MODEPAGE_CONTROL
&& cmd
->page_code
!= SCSI_MODEPAGE_ALL
)
50 || (cmd
->page_control
!= SCSI_MODE_SENSE_PC_CURRENT
51 && cmd
->page_control
!= SCSI_MODE_SENSE_PC_SAVED
)) {
52 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_INV_CDB_FIELD
);
56 //param_header = (scsi_mode_param_header_10 *)request->data;
57 param_header
.mode_data_length
= B_HOST_TO_BENDIAN_INT16(totalLength
- 1);
58 param_header
.medium_type
= 0; // XXX standard is a bit vague here
59 param_header
.dev_spec_parameter
= *(uint8
*)&devspec
;
60 param_header
.block_desc_length
61 = B_HOST_TO_BENDIAN_INT16(sizeof(scsi_mode_param_block_desc
));
63 copy_sg_data(request
, 0, allocationLength
, ¶m_header
,
64 sizeof(param_header
), false);
66 /*block_desc = (scsi_mode_param_block_desc *)(request->data
67 + sizeof(*param_header));*/
68 memset(&block_desc
, 0, sizeof(block_desc
));
69 // density is reserved (0), descriptor apply to entire medium (num_blocks=0)
70 // remains the blocklen to be set
71 block_desc
.high_blocklen
= 0;
72 block_desc
.med_blocklen
= 512 >> 8;
73 block_desc
.low_blocklen
= 512 & 0xff;
75 copy_sg_data(request
, sizeof(param_header
), allocationLength
,
76 &block_desc
, sizeof(block_desc
), false);
78 /*contr = (scsi_modepage_contr *)(request->data
79 + sizeof(*param_header)
80 + ((uint16)param_header->high_block_desc_len << 8)
81 + param_header->low_block_desc_len);*/
83 memset(&control
, 0, sizeof(control
));
85 control
.DQue
= !device
->CQ_enabled
;
87 // when a command fails we requeue all
88 // lost commands automagically
89 control
.QAM
= SCSI_QAM_UNRESTRICTED
;
91 copy_sg_data(request
, sizeof(param_header
)
92 + B_BENDIAN_TO_HOST_INT16(param_header
.block_desc_length
),
93 allocationLength
, &control
, sizeof(control
), false);
95 // the number of bytes that were transferred to buffer is
96 // restricted by allocation length and by request data buffer size
97 totalLength
= min(totalLength
, allocationLength
);
98 totalLength
= min(totalLength
, request
->data_length
);
100 request
->data_resid
= request
->data_length
- totalLength
;
104 /*! Emulate modifying control page */
106 ata_mode_select_control_page(ide_device_info
*device
, ide_qrequest
*qrequest
,
107 scsi_modepage_control
*page
)
109 if (page
->header
.page_length
!= sizeof(*page
) - sizeof(page
->header
)) {
110 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_PARAM_LIST_LENGTH_ERR
);
114 // we only support enabling/disabling command queuing
115 enable_CQ(device
, !page
->DQue
);
120 /*! Emulate MODE SELECT 10 command */
122 ata_mode_select_10(ide_device_info
*device
, ide_qrequest
*qrequest
)
124 scsi_ccb
*request
= qrequest
->request
;
125 scsi_cmd_mode_select_10
*cmd
= (scsi_cmd_mode_select_10
*)request
->cdb
;
126 scsi_mode_param_header_10 param_header
;
127 scsi_modepage_header page_header
;
129 uint32 modepageOffset
;
130 char modepage_buffer
[64]; // !!! enlarge this to support longer mode pages
132 if (cmd
->save_pages
|| cmd
->pf
!= 1) {
133 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_INV_CDB_FIELD
);
137 totalLength
= min(request
->data_length
,
138 B_BENDIAN_TO_HOST_INT16(cmd
->param_list_length
));
140 // first, retrieve page header to get size of different chunks
141 //param_header = (scsi_mode_param_header_10 *)request->data;
142 if (!copy_sg_data(request
, 0, totalLength
, ¶m_header
, sizeof(param_header
), true))
145 totalLength
= min(totalLength
,
146 B_BENDIAN_TO_HOST_INT16(param_header
.mode_data_length
) + 1UL);
148 // this is the start of the first mode page;
149 // we ignore the block descriptor silently
150 modepageOffset
= sizeof(param_header
)
151 + B_BENDIAN_TO_HOST_INT16(param_header
.block_desc_length
);
153 // go through list of pages
154 while (modepageOffset
< totalLength
) {
157 // get header to know how long page is
158 if (!copy_sg_data(request
, modepageOffset
, totalLength
,
159 &page_header
, sizeof(page_header
), true))
162 // get size of one page and copy it to buffer
163 pageLength
= page_header
.page_length
+ sizeof(scsi_modepage_header
);
165 // the buffer has a maximum size - this is really standard compliant but
166 // sufficient for our needs
167 if (pageLength
> sizeof(modepage_buffer
))
170 if (!copy_sg_data(request
, modepageOffset
, totalLength
,
171 &modepage_buffer
, min(pageLength
, sizeof(modepage_buffer
)), true))
175 // currently, we only support the control mode page
176 switch (page_header
.page_code
) {
177 case SCSI_MODEPAGE_CONTROL
:
178 if (!ata_mode_select_control_page(device
, qrequest
,
179 (scsi_modepage_control
*)modepage_buffer
))
184 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
,
185 SCSIS_ASC_INV_PARAM_LIST_FIELD
);
189 modepageOffset
+= pageLength
;
192 if (modepageOffset
!= totalLength
)
195 request
->data_resid
= request
->data_length
- totalLength
;
198 // if we arrive here, data length was incorrect
200 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_PARAM_LIST_LENGTH_ERR
);
204 /*! Emulate TEST UNIT READY */
206 ata_test_unit_ready(ide_device_info
*device
, ide_qrequest
*qrequest
)
210 if (!device
->infoblock
.RMSN_supported
211 || device
->infoblock
._127_RMSN_support
!= 1)
214 // ask device about status
215 device
->tf_param_mask
= 0;
216 device
->tf
.write
.command
= IDE_CMD_GET_MEDIA_STATUS
;
218 if (!send_command(device
, qrequest
, true, 15, ide_state_sync_waiting
))
221 // bits ide_error_mcr | ide_error_mc | ide_error_wp are also valid
222 // but not requested by TUR; ide_error_wp can safely be ignored, but
223 // we don't want to loose media change (request) reports
224 if (!check_output(device
, true,
225 ide_error_nm
| ide_error_abrt
| ide_error_mcr
| ide_error_mc
,
227 // SCSI spec is unclear here: we shouldn't report "media change (request)"
228 // but what to do if there is one? anyway - we report them
236 /*! Flush internal device cache */
238 ata_flush_cache(ide_device_info
*device
, ide_qrequest
*qrequest
)
240 // we should also ask for FLUSH CACHE support, but everyone denies it
241 // (looks like they cheat to gain some performance advantage, but
242 // that's pretty useless: everyone does it...)
243 if (!device
->infoblock
.write_cache_supported
)
246 device
->tf_param_mask
= 0;
247 device
->tf
.lba
.command
= device
->use_48bits
? IDE_CMD_FLUSH_CACHE_EXT
248 : IDE_CMD_FLUSH_CACHE
;
250 // spec says that this may take more then 30s, how much more?
251 if (!send_command(device
, qrequest
, true, 60, ide_state_sync_waiting
))
254 wait_for_sync(device
->bus
);
256 return check_output(device
, true, ide_error_abrt
, false);
260 /*! Load or eject medium
261 load = true - load medium
264 ata_load_eject(ide_device_info
*device
, ide_qrequest
*qrequest
, bool load
)
267 // ATA doesn't support loading
268 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_PARAM_NOT_SUPPORTED
);
272 device
->tf_param_mask
= 0;
273 device
->tf
.lba
.command
= IDE_CMD_MEDIA_EJECT
;
275 if (!send_command(device
, qrequest
, true, 15, ide_state_sync_waiting
))
278 wait_for_sync(device
->bus
);
280 return check_output(device
, true, ide_error_abrt
| ide_error_nm
, false);
284 /*! Emulate PREVENT ALLOW command */
286 ata_prevent_allow(ide_device_info
*device
, bool prevent
)
288 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_ILL_FUNCTION
);
293 /*! Emulate INQUIRY command */
295 ata_inquiry(ide_device_info
*device
, ide_qrequest
*qrequest
)
297 scsi_ccb
*request
= qrequest
->request
;
298 scsi_res_inquiry data
;
299 scsi_cmd_inquiry
*cmd
= (scsi_cmd_inquiry
*)request
->cdb
;
300 uint32 allocation_length
= cmd
->allocation_length
;
301 uint32 transfer_size
;
303 if (cmd
->evpd
|| cmd
->page_code
) {
304 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_INV_CDB_FIELD
);
308 memset(&data
, 0, sizeof(data
));
310 data
.device_type
= scsi_dev_direct_access
;
311 data
.device_qualifier
= scsi_periph_qual_connected
;
313 data
.device_type_modifier
= 0;
314 data
.removable_medium
= false;
316 data
.ansi_version
= 2;
317 data
.ecma_version
= 0;
318 data
.iso_version
= 0;
320 data
.response_data_format
= 2;
321 data
.term_iop
= false;
322 // to be changed if we support TERM I/O
324 data
.additional_length
= sizeof(scsi_res_inquiry
) - 4;
326 data
.soft_reset
= false;
327 data
.cmd_queue
= device
->queue_depth
> 1;
330 // these values are free-style
332 data
.write_bus16
= true;
333 data
.write_bus32
= false;
335 data
.relative_address
= false;
337 // the following fields are *much* to small, sigh...
338 memcpy(data
.vendor_ident
, device
->infoblock
.model_number
,
339 sizeof(data
.vendor_ident
));
340 memcpy(data
.product_ident
, device
->infoblock
.model_number
+ 8,
341 sizeof(data
.product_ident
));
342 memcpy(data
.product_rev
, " ", sizeof(data
.product_rev
));
344 copy_sg_data(request
, 0, allocation_length
, &data
, sizeof(data
), false);
346 transfer_size
= min(sizeof(data
), allocation_length
);
347 transfer_size
= min(transfer_size
, request
->data_length
);
349 request
->data_resid
= request
->data_length
- transfer_size
;
353 /*! Emulate READ CAPACITY command */
355 read_capacity(ide_device_info
*device
, ide_qrequest
*qrequest
)
357 scsi_ccb
*request
= qrequest
->request
;
358 scsi_res_read_capacity data
;
359 scsi_cmd_read_capacity
*cmd
= (scsi_cmd_read_capacity
*)request
->cdb
;
362 if (cmd
->pmi
|| cmd
->lba
) {
363 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_INV_CDB_FIELD
);
367 // TODO: 512 bytes fixed block size?
368 data
.block_size
= B_HOST_TO_BENDIAN_INT32(512);
370 lastBlock
= device
->total_sectors
- 1;
371 data
.lba
= B_HOST_TO_BENDIAN_INT32(lastBlock
);
373 copy_sg_data(request
, 0, request
->data_length
, &data
, sizeof(data
), false);
374 request
->data_resid
= max(request
->data_length
- sizeof(data
), 0);
378 /*! Execute SCSI command */
380 ata_exec_io(ide_device_info
*device
, ide_qrequest
*qrequest
)
382 scsi_ccb
*request
= qrequest
->request
;
384 SHOW_FLOW(3, "command=%x", request
->cdb
[0]);
386 // ATA devices have one LUN only
387 if (request
->target_lun
!= 0) {
388 request
->subsys_status
= SCSI_SEL_TIMEOUT
;
389 finish_request(qrequest
, false);
393 // starting a request means deleting sense, so don't do it if
394 // the command wants to read it
395 if (request
->cdb
[0] != SCSI_OP_REQUEST_SENSE
)
396 start_request(device
, qrequest
);
398 switch (request
->cdb
[0]) {
399 case SCSI_OP_TEST_UNIT_READY
:
400 ata_test_unit_ready(device
, qrequest
);
403 case SCSI_OP_REQUEST_SENSE
:
404 ide_request_sense(device
, qrequest
);
407 case SCSI_OP_FORMAT
: /* FORMAT UNIT */
408 // we could forward request to disk, but modern disks cannot
409 // be formatted anyway, so we just refuse request
410 // (exceptions are removable media devices, but to my knowledge
411 // they don't have to be formatted as well)
412 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_INV_OPCODE
);
415 case SCSI_OP_INQUIRY
:
416 ata_inquiry(device
, qrequest
);
419 case SCSI_OP_MODE_SELECT_10
:
420 ata_mode_select_10(device
, qrequest
);
423 case SCSI_OP_MODE_SENSE_10
:
424 ata_mode_sense_10(device
, qrequest
);
427 case SCSI_OP_MODE_SELECT_6
:
428 case SCSI_OP_MODE_SENSE_6
:
429 // we've told SCSI bus manager to emulates these commands
430 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_INV_OPCODE
);
433 case SCSI_OP_RESERVE
:
434 case SCSI_OP_RELEASE
:
435 // though mandatory, this doesn't make much sense in a
436 // single initiator environment; so what
437 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_INV_OPCODE
);
440 case SCSI_OP_START_STOP
: {
441 scsi_cmd_ssu
*cmd
= (scsi_cmd_ssu
*)request
->cdb
;
443 // with no LoEj bit set, we should only allow/deny further access
444 // we ignore that (unsupported for ATA)
445 // with LoEj bit set, we should additionally either load or eject the medium
446 // (start = 0 - eject; start = 1 - load)
449 // we must always flush cache if start = 0
450 ata_flush_cache(device
, qrequest
);
453 ata_load_eject(device
, qrequest
, cmd
->start
);
458 case SCSI_OP_PREVENT_ALLOW
: {
459 scsi_cmd_prevent_allow
*cmd
= (scsi_cmd_prevent_allow
*)request
->cdb
;
461 ata_prevent_allow(device
, cmd
->prevent
);
465 case SCSI_OP_READ_CAPACITY
:
466 read_capacity(device
, qrequest
);
469 case SCSI_OP_VERIFY_6
:
470 // does anyone uses this function?
471 // effectly, it does a read-and-compare, which IDE doesn't support
472 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_INV_OPCODE
);
475 case SCSI_OP_SYNCHRONIZE_CACHE
:
476 // we ignore range and immediate bit, we always immediately flush everything
477 ata_flush_cache(device
, qrequest
);
480 // sadly, there are two possible read/write operation codes;
481 // at least, the third one, read/write(12), is not valid for DAS
483 case SCSI_OP_WRITE_6
:
485 scsi_cmd_rw_6
*cmd
= (scsi_cmd_rw_6
*)request
->cdb
;
489 pos
= ((uint32
)cmd
->high_lba
<< 16) | ((uint32
)cmd
->mid_lba
<< 8)
490 | (uint32
)cmd
->low_lba
;
491 length
= cmd
->length
!= 0 ? cmd
->length
: 256;
493 SHOW_FLOW(3, "READ6/WRITE6 pos=%lx, length=%lx", pos
, length
);
495 ata_send_rw(device
, qrequest
, pos
, length
, cmd
->opcode
== SCSI_OP_WRITE_6
);
499 case SCSI_OP_READ_10
:
500 case SCSI_OP_WRITE_10
:
502 scsi_cmd_rw_10
*cmd
= (scsi_cmd_rw_10
*)request
->cdb
;
506 pos
= B_BENDIAN_TO_HOST_INT32(cmd
->lba
);
507 length
= B_BENDIAN_TO_HOST_INT16(cmd
->length
);
510 ata_send_rw(device
, qrequest
, pos
, length
, cmd
->opcode
== SCSI_OP_WRITE_10
);
512 // we cannot transfer zero blocks (apart from LBA48)
513 finish_request(qrequest
, false);
519 set_sense(device
, SCSIS_KEY_ILLEGAL_REQUEST
, SCSIS_ASC_INV_OPCODE
);
522 finish_checksense(qrequest
);