1/* 2 * Copyright 2004-2006, Axel D��rfler, axeld@pinc-software.de. All rights reserved. 3 * Copyright 2002/03, Thomas Kurschel. All rights reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8/* 9 Part of Open IDE bus manager 10 11 Interface between ide bus manager and scsi bus manager. 12 13 The IDE bus manager has a bit unusual structure as it 14 consists of a single level only. In fact it is no bus manager 15 in terms of the PnP structure at all but a driver that maps 16 one SCSI bus onto one IDE controller. 17 18 This structure does not allow us to publish IDE devices 19 as they can be accessed via the SCSI bus node only. Therefore 20 we do a full bus scan every time the IDE bus node is loaded. 21 The drawback is that a bus rescan must be done indirectly via a 22 SCSI bus scan. 23*/ 24 25#include "ide_internal.h" 26#include "ide_sim.h" 27 28#include <scsi_cmds.h> 29#include <safemode.h> 30 31#include <string.h> 32#include <malloc.h> 33#include <stdio.h> 34 35scsi_for_sim_interface *scsi; 36 37 38static void disconnect_worker(ide_bus_info *bus, void *arg); 39static void set_check_condition(ide_qrequest *qrequest); 40 41 42/** check whether this request can be within device */ 43 44static inline bool 45is_queuable(ide_device_info *device, scsi_ccb *request) 46{ 47 int opcode = request->cdb[0]; 48 49 // XXX disable queuing 50 if (!device->CQ_enabled) 51 return false; 52 53 // make sure the caller allows queuing 54 if ((request->flags & SCSI_ORDERED_QTAG) != 0) 55 return false; 56 57 // for atapi, all commands could be queued, but all 58 // atapi devices I know don't support queuing anyway 59 return opcode == SCSI_OP_READ_6 || opcode == SCSI_OP_WRITE_6 60 || opcode == SCSI_OP_READ_10 || opcode == SCSI_OP_WRITE_10; 61} 62 63 64static void 65scan_device(ide_bus_info *bus, int device) 66{ 67 SHOW_FLOW0(4, ""); 68 69 // currently, the SCSI bus manager doesn't block the 70 // bus when a bus or device scan is issued, so we 71 // have to use a SPC for that to be sure no one else 72 // is accessing the device or bus concurrently 73 schedule_synced_pc(bus, &bus->scan_bus_syncinfo, (void *)device); 74 75 acquire_sem(bus->scan_device_sem); 76} 77 78 79static uchar 80sim_scan_bus(ide_bus_info *bus) 81{ 82 int i; 83 84 SHOW_FLOW0(4, ""); 85 86 if (bus->disconnected) 87 return SCSI_NO_HBA; 88 89 for (i = 0; i < bus->max_devices; ++i) { 90 scan_device(bus, i); 91 } 92 93 return SCSI_REQ_CMP; 94} 95 96 97static void 98sim_set_scsi_bus(ide_bus_info *bus, scsi_bus scsi) 99{ 100 bus->scsi_cookie = scsi; 101 102 // detect devices 103 sim_scan_bus(bus); 104} 105 106 107static void 108sim_scsi_io(ide_bus_info *bus, scsi_ccb *request) 109{ 110 ide_device_info *device; 111 bool queuable; 112 ide_qrequest *qrequest; 113 114 SHOW_FLOW(3, "%d:%d", request->target_id, request->target_lun); 115 116 if (bus->disconnected) 117 goto err_disconnected; 118 119 // make sure, device is valid 120 // I've read that there are ATAPI devices with more then one LUN, 121 // but it seems that most (all?) devices ignore LUN, so we have 122 // to restrict to LUN 0 to avoid mirror devices 123 if (request->target_id >= 2) 124 goto err_inv_device; 125 126 device = bus->devices[request->target_id]; 127 if (device == NULL) 128 goto err_inv_device; 129 130 if (request->target_lun > device->last_lun) 131 goto err_inv_device; 132 133 queuable = is_queuable(device, request); 134 135 // grab the bus 136 ACQUIRE_BEN(&bus->status_report_ben); 137 IDE_LOCK(bus); 138 139 if (bus->state != ide_state_idle) 140 goto err_bus_busy; 141 142 // bail out if device can't accept further requests 143 if (device->free_qrequests == NULL 144 || (device->num_running_reqs > 0 && !queuable)) 145 goto err_device_busy; 146 147 bus->state = ide_state_accessing; 148 149 IDE_UNLOCK(bus); 150 RELEASE_BEN(&bus->status_report_ben); 151 152 // as we own the bus, noone can bother us 153 qrequest = device->free_qrequests; 154 device->free_qrequests = qrequest->next; 155 156 qrequest->request = request; 157 qrequest->queuable = queuable; 158 qrequest->running = true; 159 qrequest->uses_dma = false; 160 161 ++device->num_running_reqs; 162 ++bus->num_running_reqs; 163 bus->active_qrequest = qrequest; 164 165 device->exec_io(device, qrequest); 166 167 return; 168 169err_inv_device: 170 SHOW_ERROR(3, "Invalid device %d:%d", 171 request->target_id, request->target_lun); 172 173 request->subsys_status = SCSI_SEL_TIMEOUT; 174 scsi->finished(request, 1); 175 return; 176 177err_bus_busy: 178 SHOW_FLOW0(3, "Bus busy"); 179 180 IDE_UNLOCK(bus); 181 scsi->requeue(request, true); 182 RELEASE_BEN(&bus->status_report_ben); 183 return; 184 185err_device_busy: 186 SHOW_FLOW0(3, "Device busy"); 187 188 IDE_UNLOCK(bus); 189 scsi->requeue(request, false); 190 RELEASE_BEN(&bus->status_report_ben); 191 return; 192 193err_disconnected: 194 SHOW_ERROR0(3, "No controller anymore"); 195 request->subsys_status = SCSI_NO_HBA; 196 scsi->finished(request, 1); 197 return; 198} 199 200 201static uchar 202sim_path_inquiry(ide_bus_info *bus, scsi_path_inquiry *info) 203{ 204 const char *controller_name; 205 206 SHOW_FLOW0(4, ""); 207 208 if (bus->disconnected) 209 return SCSI_NO_HBA; 210 211 info->hba_inquiry = SCSI_PI_TAG_ABLE | SCSI_PI_WIDE_16; 212 213 info->hba_misc = 0; 214 215 memset(info->vuhba_flags, 0, sizeof(info->vuhba_flags)); 216 // we don't need any of the private data 217 info->sim_priv = 0; 218 219 // there is no initiator for IDE, but SCSI needs it for scanning 220 info->initiator_id = 2; 221 // there's no controller limit, so set it higher then the maximum 222 // number of queued requests, which is 32 per device * 2 devices 223 info->hba_queue_size = 65; 224 225 strncpy(info->sim_vid, "Haiku", SCSI_SIM_ID); 226 227 if (pnp->get_attr_string(bus->node, SCSI_DESCRIPTION_CONTROLLER_NAME, 228 &controller_name, true) == B_OK) { 229 strlcpy(info->hba_vid, controller_name, SCSI_HBA_ID); 230 } else 231 strlcpy(info->hba_vid, "", SCSI_HBA_ID); 232 233 strlcpy(info->controller_family, "IDE", SCSI_FAM_ID); 234 strlcpy(info->controller_type, "IDE", SCSI_TYPE_ID); 235 236 SHOW_FLOW0(4, "done"); 237 238 return SCSI_REQ_CMP; 239} 240 241 242static uchar 243sim_abort(ide_bus_info *bus, scsi_ccb *ccb_to_abort) 244{ 245 // we cannot abort specific commands, so just ignore 246 if (bus->disconnected) 247 return SCSI_NO_HBA; 248 249 return SCSI_REQ_CMP; 250} 251 252 253static uchar 254sim_term_io(ide_bus_info *bus, scsi_ccb *ccb_to_abort) 255{ 256 // we cannot terminate commands, so just ignore 257 if (bus->disconnected) 258 return SCSI_NO_HBA; 259 260 return SCSI_REQ_CMP; 261} 262 263 264static uchar 265sim_reset_bus(ide_bus_info *bus) 266{ 267 // no, we don't do that 268 if (bus->disconnected) 269 return SCSI_NO_HBA; 270 271 return SCSI_REQ_INVALID; 272} 273 274 275static uchar 276sim_reset_device(ide_bus_info *bus, uchar target_id, uchar target_lun) 277{ 278 // xxx to do 279 if (bus->disconnected) 280 return SCSI_NO_HBA; 281 282 return SCSI_REQ_INVALID; 283} 284 285 286/** fill sense buffer according to device sense */ 287 288void 289create_sense(ide_device_info *device, scsi_sense *sense) 290{ 291 memset(sense, 0, sizeof(*sense)); 292 293 sense->error_code = SCSIS_CURR_ERROR; 294 sense->sense_key = decode_sense_key(device->combined_sense); 295 sense->add_sense_length = sizeof(*sense) - 7; 296 sense->asc = decode_sense_asc(device->combined_sense); 297 sense->ascq = decode_sense_ascq(device->combined_sense); 298 sense->sense_key_spec.raw.SKSV = 0; // no additional info 299} 300 301 302/** finish command, updating sense of device and request, and release bus */ 303 304void 305finish_checksense(ide_qrequest *qrequest) 306{ 307 SHOW_FLOW(3, "%p, subsys_status=%d, sense=%x", 308 qrequest->request, 309 qrequest->request->subsys_status, 310 (int)qrequest->device->new_combined_sense); 311 312 qrequest->request->subsys_status = qrequest->device->subsys_status; 313 314 if (qrequest->request->subsys_status == SCSI_REQ_CMP) { 315 // device or emulation code completed command 316 qrequest->device->combined_sense = qrequest->device->new_combined_sense; 317 318 // if emulation code detected error, set CHECK CONDITION 319 if (qrequest->device->combined_sense) 320 set_check_condition(qrequest); 321 } 322 323 finish_request(qrequest, false); 324} 325 326 327/** finish request and release bus 328 * resubmit - true, if request should be resubmitted by XPT 329 */ 330 331void 332finish_request(ide_qrequest *qrequest, bool resubmit) 333{ 334 ide_device_info *device = qrequest->device; 335 ide_bus_info *bus = device->bus; 336 scsi_ccb *request; 337 uint num_running; 338 339 SHOW_FLOW0(3, ""); 340 341 // save request first, as qrequest can be reused as soon as 342 // access_finished is called! 343 request = qrequest->request; 344 345 qrequest->running = false; 346 qrequest->next = device->free_qrequests; 347 device->free_qrequests = qrequest; 348 349 // num_running is not really correct as the XPT is interested 350 // in the number of concurrent requests when it was *started* ! 351 num_running = device->num_running_reqs--; 352 --bus->num_running_reqs; 353 354 // paranoia 355 bus->active_qrequest = NULL; 356 357 // release bus, handling service requests; 358 // TBD: 359 // if we really handle a service request, the finished command 360 // is delayed unnecessarily, but if we tell the XPT about the finished 361 // command first, it will instantly try to pass us another 362 // request to handle, which we will refuse as the bus is still 363 // locked; this really has to be improved 364 access_finished(bus, device); 365 366 ACQUIRE_BEN(&bus->status_report_ben); 367 368 if (resubmit) 369 scsi->resubmit(request); 370 else 371 scsi->finished(request, num_running); 372 373 RELEASE_BEN(&bus->status_report_ben); 374} 375 376 377/** set CHECK CONDITION of device and perform auto-sense if requested. 378 * (don't move it before finish_request - we don't want to inline 379 * it as it's on the rarely used error path) 380 */ 381 382static void 383set_check_condition(ide_qrequest *qrequest) 384{ 385 scsi_ccb *request = qrequest->request; 386 ide_device_info *device = qrequest->device; 387 388 SHOW_FLOW0(3, ""); 389 390 request->subsys_status = SCSI_REQ_CMP_ERR; 391 request->device_status = SCSI_STATUS_CHECK_CONDITION; 392 393 // copy sense only if caller requested it 394 if ((request->flags & SCSI_DIS_AUTOSENSE) == 0) { 395 scsi_sense sense; 396 int sense_len; 397 398 SHOW_FLOW0(3, "autosense"); 399 400 // we cannot copy sense directly as sense buffer may be too small 401 create_sense(device, &sense); 402 403 sense_len = min(SCSI_MAX_SENSE_SIZE, sizeof(sense)); 404 405 memcpy(request->sense, &sense, sense_len); 406 request->sense_resid = SCSI_MAX_SENSE_SIZE - sense_len; 407 request->subsys_status |= SCSI_AUTOSNS_VALID; 408 409 // device sense gets reset once it's read 410 device->combined_sense = 0; 411 } 412} 413 414 415void 416finish_retry(ide_qrequest *qrequest) 417{ 418 qrequest->device->combined_sense = 0; 419 finish_request(qrequest, true); 420} 421 422 423/** finish request and abort pending requests of the device 424 * (to be called when the request failed and thus messed up the queue) 425 */ 426 427void 428finish_reset_queue(ide_qrequest *qrequest) 429{ 430 ide_bus_info *bus = qrequest->device->bus; 431 432 // don't remove block_bus!!! 433 // during finish_checksense, the bus is released, so 434 // the SCSI bus manager could send us further commands 435 scsi->block_bus(bus->scsi_cookie); 436 437 finish_checksense(qrequest); 438 send_abort_queue(qrequest->device); 439 440 scsi->unblock_bus(bus->scsi_cookie); 441} 442 443 444/** finish request, but don't release bus 445 * if resubmit is true, the request will be resubmitted 446 */ 447 448static void 449finish_norelease(ide_qrequest *qrequest, bool resubmit) 450{ 451 ide_device_info *device = qrequest->device; 452 ide_bus_info *bus = device->bus; 453 uint num_requests; 454 455 qrequest->running = false; 456 qrequest->next = device->free_qrequests; 457 device->free_qrequests = qrequest; 458 459 num_requests = device->num_running_reqs++; 460 --bus->num_running_reqs; 461 462 if (bus->active_qrequest == qrequest) 463 bus->active_qrequest = NULL; 464 465 ACQUIRE_BEN(&bus->status_report_ben); 466 467 if (resubmit) 468 scsi->resubmit(qrequest->request); 469 else 470 scsi->finished(qrequest->request, num_requests); 471 472 RELEASE_BEN(&bus->status_report_ben); 473} 474 475 476/** finish all queued requests but <ignore> of the device; 477 * set resubmit, if requests are to be resubmitted by xpt 478 */ 479 480void 481finish_all_requests(ide_device_info *device, ide_qrequest *ignore, 482 int subsys_status, bool resubmit) 483{ 484 int i; 485 486 if (device == NULL) 487 return; 488 489 // we only have to block the device, but for CD changers we 490 // have to block all LUNS of the device (and we neither know 491 // their device handle nor which exist at all), so block 492 // the entire bus instead (it won't take that long anyway) 493 scsi->block_bus(device->bus->scsi_cookie); 494 495 for (i = 0; i < device->queue_depth; ++i) { 496 ide_qrequest *qrequest = &device->qreq_array[i]; 497 498 if (qrequest->running && qrequest != ignore) { 499 qrequest->request->subsys_status = subsys_status; 500 finish_norelease(qrequest, resubmit); 501 } 502 } 503 504 scsi->unblock_bus(device->bus->scsi_cookie); 505} 506 507 508static status_t 509ide_sim_init_bus(device_node *node, void **cookie) 510{ 511 ide_bus_info *bus; 512 bool dmaDisabled = false; 513 status_t status; 514 515 SHOW_FLOW0(3, ""); 516 517 // first prepare the info structure 518 bus = (ide_bus_info *)malloc(sizeof(*bus)); 519 if (bus == NULL) 520 return B_NO_MEMORY; 521 522 memset(bus, 0, sizeof(*bus)); 523 bus->node = node; 524 B_INITIALIZE_SPINLOCK(&bus->lock); 525 bus->num_running_reqs = 0; 526 bus->active_qrequest = NULL; 527 bus->disconnected = false; 528 529 { 530 int32 channel_id = -1; 531 532 pnp->get_attr_uint32(node, IDE_CHANNEL_ID_ITEM, (uint32 *)&channel_id, true); 533 534 sprintf(bus->name, "ide_bus %d", (int)channel_id); 535 } 536 537 init_synced_pc(&bus->scan_bus_syncinfo, scan_device_worker); 538 init_synced_pc(&bus->disconnect_syncinfo, disconnect_worker); 539 540 bus->state = ide_state_idle; 541 bus->timer.bus = bus; 542 bus->synced_pc_list = NULL; 543 544 if ((status = scsi->alloc_dpc(&bus->irq_dpc)) < B_OK) 545 goto err1; 546 547 bus->active_device = NULL; 548 bus->sync_wait_sem = create_sem(0, "ide_sync_wait"); 549 if (bus->sync_wait_sem < 0) { 550 status = bus->sync_wait_sem; 551 goto err2; 552 } 553 554 bus->devices[0] = bus->devices[1] = NULL; 555 556 bus->scan_device_sem = create_sem(0, "ide_scan_finished"); 557 if (bus->scan_device_sem < 0) { 558 status = bus->scan_device_sem; 559 goto err3; 560 } 561 562 status = INIT_BEN(&bus->status_report_ben, "ide_status_report"); 563 if (status < B_OK) 564 goto err4; 565 566 { 567 // check if safemode settings disable DMA 568 void *settings = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS); 569 if (settings != NULL) { 570 dmaDisabled = get_driver_boolean_parameter(settings, B_SAFEMODE_DISABLE_IDE_DMA, 571 false, false); 572 unload_driver_settings(settings); 573 } 574 } 575 576 bus->first_device = NULL; 577 578 // read restrictions of controller 579 580 if (pnp->get_attr_uint8(node, IDE_CONTROLLER_MAX_DEVICES_ITEM, 581 &bus->max_devices, true) != B_OK) { 582 // per default, 2 devices are supported per node 583 bus->max_devices = 2; 584 } 585 586 bus->max_devices = min(bus->max_devices, 2); 587 588 if (dmaDisabled 589 || pnp->get_attr_uint8(node, IDE_CONTROLLER_CAN_DMA_ITEM, &bus->can_DMA, true) != B_OK) { 590 // per default, no dma support 591 bus->can_DMA = false; 592 } 593 594 SHOW_FLOW(2, "can_dma: %d", bus->can_DMA); 595 596 if (bus->can_DMA) { 597 if (pnp->get_attr_uint8(node, IDE_CONTROLLER_CAN_CQ_ITEM, &bus->can_CQ, true) != B_OK) { 598 // per default, command queuing is supported unless the driver 599 // reports problems (queuing should be transparent to 600 // controller, but for sure there is some buggy, over-optimizing 601 // controller out there) 602 bus->can_CQ = true; 603 } 604 } else { 605 // I am not sure if it's a problem of the driver or the drive (probably the 606 // former), but we're generally disabling command queueing in case of PIO 607 // transfers. Since those should be rare on a real system (as is CQ support 608 // in the drive), it's not really worth investigating, though. 609 bus->can_CQ = false; 610 } 611 612 { 613 device_node *parent = pnp->get_parent_node(node); 614 pnp->get_driver(parent, (driver_module_info **)&bus->controller, 615 (void **)&bus->channel_cookie); 616 617 bus->controller->set_channel(bus->channel_cookie, bus); 618 pnp->put_node(parent); 619 } 620 621 *cookie = bus; 622 return B_OK; 623 624err4: 625 delete_sem(bus->scan_device_sem); 626err3: 627 delete_sem(bus->sync_wait_sem); 628err2: 629 scsi->free_dpc(bus->irq_dpc); 630err1: 631 uninit_synced_pc(&bus->scan_bus_syncinfo); 632 uninit_synced_pc(&bus->disconnect_syncinfo); 633 free(bus); 634 635 return status; 636} 637 638 639static status_t 640ide_sim_uninit_bus(ide_bus_info *bus) 641{ 642 DELETE_BEN(&bus->status_report_ben); 643 delete_sem(bus->scan_device_sem); 644 delete_sem(bus->sync_wait_sem); 645 scsi->free_dpc(bus->irq_dpc); 646 uninit_synced_pc(&bus->scan_bus_syncinfo); 647 uninit_synced_pc(&bus->disconnect_syncinfo); 648 649 free(bus); 650 651 return B_OK; 652} 653 654 655// abort all running requests with SCSI_NO_HBA; finally, unblock bus 656static void 657disconnect_worker(ide_bus_info *bus, void *arg) 658{ 659 int i; 660 661 for (i = 0; i < bus->max_devices; ++i) { 662 if (bus->devices[i]) 663 // is this the proper error code? 664 finish_all_requests(bus->devices[i], NULL, SCSI_NO_HBA, false); 665 } 666 667 scsi->unblock_bus(bus->scsi_cookie); 668} 669 670 671static void 672ide_sim_bus_removed(ide_bus_info *bus) 673{ 674 // XPT must not issue further commands 675 scsi->block_bus(bus->scsi_cookie); 676 // make sure, we refuse all new commands 677 bus->disconnected = true; 678 // abort all running commands with SCSI_NO_HBA 679 // (the scheduled function also unblocks the bus when finished) 680 schedule_synced_pc(bus, &bus->disconnect_syncinfo, NULL); 681} 682 683 684static void 685ide_sim_get_restrictions(ide_bus_info *bus, uchar target_id, 686 bool *is_atapi, bool *no_autosense, uint32 *max_blocks) 687{ 688 ide_device_info *device = bus->devices[target_id]; 689 690 // we declare even ATA devices as ATAPI so we have to emulate fewer 691 // commands 692 *is_atapi = true; 693 694 // we emulate autosense for ATA devices 695 *no_autosense = false; 696 697 if (device != NULL && device->is_atapi) { 698 // we don't support native autosense for ATAPI devices 699 *no_autosense = true; 700 } 701 702 *max_blocks = 255; 703 704 if (device->is_atapi) { 705 if (strncmp(device->infoblock.model_number, "IOMEGA ZIP 100 ATAPI", 706 strlen("IOMEGA ZIP 100 ATAPI")) == 0 707 || strncmp( device->infoblock.model_number, "IOMEGA Clik!", 708 strlen( "IOMEGA Clik!")) == 0) { 709 SHOW_ERROR0(2, "Found buggy ZIP/Clik! drive - restricting transmission size"); 710 *max_blocks = 64; 711 } 712 } 713} 714 715 716static status_t 717ide_sim_ioctl(ide_bus_info *bus, uint8 targetID, uint32 op, void *buffer, size_t length) 718{ 719 ide_device_info *device = bus->devices[targetID]; 720 721 // We currently only support IDE_GET_INFO_BLOCK 722 switch (op) { 723 case IDE_GET_INFO_BLOCK: 724 // we already have the info block, just copy it 725 memcpy(buffer, &device->infoblock, 726 min(sizeof(device->infoblock), length)); 727 return B_OK; 728 729 case IDE_GET_STATUS: 730 { 731 // TODO: have our own structure and fill it with some useful stuff 732 ide_status status; 733 if (device->DMA_enabled) 734 status.dma_status = 1; 735 else if (device->DMA_supported) { 736 if (device->DMA_failures > 0) 737 status.dma_status = 6; 738 else if (device->bus->can_DMA) 739 status.dma_status = 2; 740 else 741 status.dma_status = 4; 742 } else 743 status.dma_status = 2; 744 745 status.pio_mode = 0; 746 status.dma_mode = get_device_dma_mode(device); 747 748 memcpy(buffer, &status, min(sizeof(status), length)); 749 return B_OK; 750 } 751 } 752 753 return B_DEV_INVALID_IOCTL; 754} 755 756 757static status_t 758std_ops(int32 op, ...) 759{ 760 switch (op) { 761 case B_MODULE_INIT: 762 case B_MODULE_UNINIT: 763 return B_OK; 764 765 default: 766 return B_ERROR; 767 } 768} 769 770 771module_dependency module_dependencies[] = { 772 { SCSI_FOR_SIM_MODULE_NAME, (module_info **)&scsi }, 773 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, 774 {} 775}; 776 777 778scsi_sim_interface ide_sim_module = { 779 { 780 { 781 IDE_SIM_MODULE_NAME, 782 0, 783 std_ops, 784 }, 785 786 NULL, // supported devices 787 NULL, // register node 788 (status_t (*)(device_node *, void **)) ide_sim_init_bus, 789 (void (*)(void *)) ide_sim_uninit_bus, 790 NULL, // register child devices 791 NULL, // rescan 792 (void (*)(void *)) ide_sim_bus_removed, 793 NULL, // suspend 794 NULL // resume 795 }, 796 797 (void (*)(scsi_sim_cookie, scsi_bus)) sim_set_scsi_bus, 798 (void (*)(scsi_sim_cookie, scsi_ccb *)) sim_scsi_io, 799 (uchar (*)(scsi_sim_cookie, scsi_ccb *)) sim_abort, 800 (uchar (*)(scsi_sim_cookie, uchar, uchar)) sim_reset_device, 801 (uchar (*)(scsi_sim_cookie, scsi_ccb *)) sim_term_io, 802 803 (uchar (*)(scsi_sim_cookie, scsi_path_inquiry *))sim_path_inquiry, 804 (uchar (*)(scsi_sim_cookie)) sim_scan_bus, 805 (uchar (*)(scsi_sim_cookie)) sim_reset_bus, 806 807 (void (*)(scsi_sim_cookie, uchar, 808 bool*, bool *, uint32 *)) ide_sim_get_restrictions, 809 810 (status_t (*)(scsi_sim_cookie, uint8, uint32, void *, size_t))ide_sim_ioctl, 811}; 812