BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / bus_managers / ide / scsi2ata.c
blob5f6189e100603ce032d1227dcf3c4d8ae193af6d
1 /*
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.
6 */
8 /*
9 Part of Open IDE bus manager
11 Converts SCSI commands to ATA commands.
15 #include "ide_internal.h"
16 #include "ide_sim.h"
17 #include "ide_cmds.h"
19 #include <string.h>
22 /** emulate MODE SENSE 10 command */
24 static void
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 = {
36 _res0_0 : 0,
37 dpo_fua : 0,
38 _res0_6 : 0,
39 write_protected : 0
41 uint32 allocationLength;
43 SHOW_FLOW0(1, "Hi!");
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);
53 return;
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, &param_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));
84 control.RLEC = false;
85 control.DQue = !device->CQ_enabled;
86 control.QErr = false;
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 */
105 static bool
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);
111 return false;
114 // we only support enabling/disabling command queuing
115 enable_CQ(device, !page->DQue);
116 return true;
120 /*! Emulate MODE SELECT 10 command */
121 static void
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;
128 uint32 totalLength;
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);
134 return;
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, &param_header, sizeof(param_header), true))
143 goto err;
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) {
155 uint32 pageLength;
157 // get header to know how long page is
158 if (!copy_sg_data(request, modepageOffset, totalLength,
159 &page_header, sizeof(page_header), true))
160 goto err;
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))
168 goto err;
170 if (!copy_sg_data(request, modepageOffset, totalLength,
171 &modepage_buffer, min(pageLength, sizeof(modepage_buffer)), true))
172 goto err;
174 // modify page;
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))
180 return;
181 break;
183 default:
184 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST,
185 SCSIS_ASC_INV_PARAM_LIST_FIELD);
186 return;
189 modepageOffset += pageLength;
192 if (modepageOffset != totalLength)
193 goto err;
195 request->data_resid = request->data_length - totalLength;
196 return;
198 // if we arrive here, data length was incorrect
199 err:
200 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR);
204 /*! Emulate TEST UNIT READY */
205 static bool
206 ata_test_unit_ready(ide_device_info *device, ide_qrequest *qrequest)
208 SHOW_FLOW0(3, "");
210 if (!device->infoblock.RMSN_supported
211 || device->infoblock._127_RMSN_support != 1)
212 return true;
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))
219 return false;
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,
226 false)) {
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
232 return true;
236 /*! Flush internal device cache */
237 static bool
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)
244 return true;
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))
252 return false;
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
263 static bool
264 ata_load_eject(ide_device_info *device, ide_qrequest *qrequest, bool load)
266 if (load) {
267 // ATA doesn't support loading
268 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_NOT_SUPPORTED);
269 return false;
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))
276 return false;
278 wait_for_sync(device->bus);
280 return check_output(device, true, ide_error_abrt | ide_error_nm, false);
284 /*! Emulate PREVENT ALLOW command */
285 static bool
286 ata_prevent_allow(ide_device_info *device, bool prevent)
288 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_ILL_FUNCTION);
289 return false;
293 /*! Emulate INQUIRY command */
294 static void
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);
305 return;
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;
328 data.linked = false;
330 // these values are free-style
331 data.sync = false;
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 */
354 static void
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;
360 uint32 lastBlock;
362 if (cmd->pmi || cmd->lba) {
363 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD);
364 return;
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 */
379 void
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);
390 return;
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);
401 break;
403 case SCSI_OP_REQUEST_SENSE:
404 ide_request_sense(device, qrequest);
405 return;
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);
413 break;
415 case SCSI_OP_INQUIRY:
416 ata_inquiry(device, qrequest);
417 break;
419 case SCSI_OP_MODE_SELECT_10:
420 ata_mode_select_10(device, qrequest);
421 break;
423 case SCSI_OP_MODE_SENSE_10:
424 ata_mode_sense_10(device, qrequest);
425 break;
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);
431 break;
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);
438 break;
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)
448 if (!cmd->start)
449 // we must always flush cache if start = 0
450 ata_flush_cache(device, qrequest);
452 if (cmd->load_eject)
453 ata_load_eject(device, qrequest, cmd->start);
455 break;
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);
462 break;
465 case SCSI_OP_READ_CAPACITY:
466 read_capacity(device, qrequest);
467 break;
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);
473 break;
475 case SCSI_OP_SYNCHRONIZE_CACHE:
476 // we ignore range and immediate bit, we always immediately flush everything
477 ata_flush_cache(device, qrequest);
478 break;
480 // sadly, there are two possible read/write operation codes;
481 // at least, the third one, read/write(12), is not valid for DAS
482 case SCSI_OP_READ_6:
483 case SCSI_OP_WRITE_6:
485 scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb;
486 uint32 pos;
487 size_t length;
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);
496 return;
499 case SCSI_OP_READ_10:
500 case SCSI_OP_WRITE_10:
502 scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb;
503 uint32 pos;
504 size_t length;
506 pos = B_BENDIAN_TO_HOST_INT32(cmd->lba);
507 length = B_BENDIAN_TO_HOST_INT16(cmd->length);
509 if (length != 0) {
510 ata_send_rw(device, qrequest, pos, length, cmd->opcode == SCSI_OP_WRITE_10);
511 } else {
512 // we cannot transfer zero blocks (apart from LBA48)
513 finish_request(qrequest, false);
515 return;
518 default:
519 set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE);
522 finish_checksense(qrequest);