14535495dSIngo Weinhold /* 24535495dSIngo Weinhold * Copyright 2004-2006, Haiku, Inc. All RightsReserved. 34535495dSIngo Weinhold * Copyright 2002/03, Thomas Kurschel. All rights reserved. 44535495dSIngo Weinhold * 54535495dSIngo Weinhold * Distributed under the terms of the MIT License. 64535495dSIngo Weinhold */ 74535495dSIngo Weinhold 84535495dSIngo Weinhold /* 94535495dSIngo Weinhold Device node layer. 104535495dSIngo Weinhold 114535495dSIngo Weinhold When a SCSI bus is registered, this layer scans for SCSI devices 124535495dSIngo Weinhold and registers a node for each of them. Peripheral drivers are on 134535495dSIngo Weinhold top of these nodes. 144535495dSIngo Weinhold */ 154535495dSIngo Weinhold 164535495dSIngo Weinhold #include "scsi_internal.h" 174535495dSIngo Weinhold 184535495dSIngo Weinhold #include <string.h> 194535495dSIngo Weinhold #include <stdlib.h> 204535495dSIngo Weinhold #include <stdio.h> 214535495dSIngo Weinhold 224535495dSIngo Weinhold #include <algorithm> 234535495dSIngo Weinhold 244535495dSIngo Weinhold 254535495dSIngo Weinhold /** free autosense request of device */ 264535495dSIngo Weinhold 274535495dSIngo Weinhold static void 284535495dSIngo Weinhold scsi_free_autosense_request(scsi_device_info *device) 294535495dSIngo Weinhold { 304535495dSIngo Weinhold SHOW_FLOW0( 3, "" ); 314535495dSIngo Weinhold 324535495dSIngo Weinhold if (device->auto_sense_request != NULL) { 334535495dSIngo Weinhold scsi_free_ccb(device->auto_sense_request); 344535495dSIngo Weinhold device->auto_sense_request = NULL; 354535495dSIngo Weinhold } 364535495dSIngo Weinhold 374535495dSIngo Weinhold if (device->auto_sense_area > 0) { 384535495dSIngo Weinhold delete_area(device->auto_sense_area); 394535495dSIngo Weinhold device->auto_sense_area = 0; 404535495dSIngo Weinhold } 414535495dSIngo Weinhold } 424535495dSIngo Weinhold 434535495dSIngo Weinhold 444535495dSIngo Weinhold /** free all data of device */ 454535495dSIngo Weinhold 464535495dSIngo Weinhold static void 474535495dSIngo Weinhold scsi_free_device(scsi_device_info *device) 484535495dSIngo Weinhold { 494535495dSIngo Weinhold SHOW_FLOW0( 3, "" ); 504535495dSIngo Weinhold 514535495dSIngo Weinhold scsi_free_emulation_buffer(device); 524535495dSIngo Weinhold scsi_free_autosense_request(device); 534535495dSIngo Weinhold 544535495dSIngo Weinhold unregister_kernel_daemon(scsi_dma_buffer_daemon, device); 554535495dSIngo Weinhold 564535495dSIngo Weinhold scsi_dma_buffer_free(&device->dma_buffer); 574535495dSIngo Weinhold 584535495dSIngo Weinhold DELETE_BEN(&device->dma_buffer_lock); 594535495dSIngo Weinhold delete_sem(device->dma_buffer_owner); 604535495dSIngo Weinhold 614535495dSIngo Weinhold free(device); 624535495dSIngo Weinhold } 634535495dSIngo Weinhold 644535495dSIngo Weinhold 654535495dSIngo Weinhold /** copy string src without trailing zero to dst and remove trailing 664535495dSIngo Weinhold * spaces size of dst is dst_size, size of src is dst_size-1 674535495dSIngo Weinhold */ 684535495dSIngo Weinhold 694535495dSIngo Weinhold static void 704535495dSIngo Weinhold beautify_string(char *dst, char *src, int dst_size) 714535495dSIngo Weinhold { 724535495dSIngo Weinhold int i; 734535495dSIngo Weinhold 744535495dSIngo Weinhold memcpy(dst, src, dst_size - 1); 754535495dSIngo Weinhold 764535495dSIngo Weinhold for (i = dst_size - 2; i >= 0; --i) { 774535495dSIngo Weinhold if (dst[i] != ' ') 784535495dSIngo Weinhold break; 794535495dSIngo Weinhold } 804535495dSIngo Weinhold 814535495dSIngo Weinhold dst[i + 1] = 0; 824535495dSIngo Weinhold } 834535495dSIngo Weinhold 844535495dSIngo Weinhold 854535495dSIngo Weinhold /** register new device */ 864535495dSIngo Weinhold 874535495dSIngo Weinhold status_t 884535495dSIngo Weinhold scsi_register_device(scsi_bus_info *bus, uchar target_id, 894535495dSIngo Weinhold uchar target_lun, scsi_res_inquiry *inquiry_data) 904535495dSIngo Weinhold { 914535495dSIngo Weinhold bool is_atapi, manual_autosense; 924535495dSIngo Weinhold uint32 orig_max_blocks, max_blocks; 934535495dSIngo Weinhold 944535495dSIngo Weinhold SHOW_FLOW0( 3, "" ); 954535495dSIngo Weinhold 964535495dSIngo Weinhold // ask for restrictions 974535495dSIngo Weinhold bus->interface->get_restrictions(bus->sim_cookie, 984535495dSIngo Weinhold target_id, &is_atapi, &manual_autosense, &max_blocks); 994535495dSIngo Weinhold if (target_lun != 0) 1004535495dSIngo Weinhold dprintf("WARNING: SCSI target %d lun %d getting restrictions without lun\n", 1014535495dSIngo Weinhold target_id, target_lun); 1024535495dSIngo Weinhold 1034535495dSIngo Weinhold // find maximum transfer blocks 1044535495dSIngo Weinhold // set default value to max (need something like ULONG_MAX here) 1054535495dSIngo Weinhold orig_max_blocks = ~0; 1064535495dSIngo Weinhold pnp->get_attr_uint32(bus->node, B_DMA_MAX_TRANSFER_BLOCKS, &orig_max_blocks, 1074535495dSIngo Weinhold true); 1084535495dSIngo Weinhold 1094535495dSIngo Weinhold max_blocks = std::min(max_blocks, orig_max_blocks); 1104535495dSIngo Weinhold 1114535495dSIngo Weinhold { 1124535495dSIngo Weinhold char vendor_ident[sizeof( inquiry_data->vendor_ident ) + 1]; 1134535495dSIngo Weinhold char product_ident[sizeof( inquiry_data->product_ident ) + 1]; 1144535495dSIngo Weinhold char product_rev[sizeof( inquiry_data->product_rev ) + 1]; 1154535495dSIngo Weinhold device_attr attrs[] = { 1164535495dSIngo Weinhold // connection 1174535495dSIngo Weinhold { SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }}, 1184535495dSIngo Weinhold { SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }}, 1194535495dSIngo Weinhold 1204535495dSIngo Weinhold // inquiry data (used for both identification and information) 1214535495dSIngo Weinhold { SCSI_DEVICE_INQUIRY_ITEM, B_RAW_TYPE, 1224535495dSIngo Weinhold { raw: { inquiry_data, sizeof( *inquiry_data ) }}}, 1234535495dSIngo Weinhold 1244535495dSIngo Weinhold // some more info for driver loading 1254535495dSIngo Weinhold { SCSI_DEVICE_TYPE_ITEM, B_UINT8_TYPE, { ui8: inquiry_data->device_type }}, 1264535495dSIngo Weinhold { SCSI_DEVICE_VENDOR_ITEM, B_STRING_TYPE, { string: vendor_ident }}, 1274535495dSIngo Weinhold { SCSI_DEVICE_PRODUCT_ITEM, B_STRING_TYPE, { string: product_ident }}, 1284535495dSIngo Weinhold { SCSI_DEVICE_REVISION_ITEM, B_STRING_TYPE, { string: product_rev }}, 1294535495dSIngo Weinhold 1304535495dSIngo Weinhold // description of peripheral drivers 1314535495dSIngo Weinhold { B_DEVICE_BUS, B_STRING_TYPE, { string: "scsi" }}, 1324535495dSIngo Weinhold 1334535495dSIngo Weinhold // extra restriction of maximum number of blocks per transfer 1344535495dSIngo Weinhold { B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, { ui32: max_blocks }}, 1354535495dSIngo Weinhold 1364535495dSIngo Weinhold // atapi emulation 1374535495dSIngo Weinhold { SCSI_DEVICE_IS_ATAPI_ITEM, B_UINT8_TYPE, { ui8: is_atapi }}, 1384535495dSIngo Weinhold // manual autosense 1394535495dSIngo Weinhold { SCSI_DEVICE_MANUAL_AUTOSENSE_ITEM, B_UINT8_TYPE, { ui8: manual_autosense }}, 1404535495dSIngo Weinhold { NULL } 1414535495dSIngo Weinhold }; 1424535495dSIngo Weinhold 1434535495dSIngo Weinhold beautify_string(vendor_ident, inquiry_data->vendor_ident, sizeof(vendor_ident)); 1444535495dSIngo Weinhold beautify_string(product_ident, inquiry_data->product_ident, sizeof(product_ident)); 1454535495dSIngo Weinhold beautify_string(product_rev, inquiry_data->product_rev, sizeof(product_rev)); 1464535495dSIngo Weinhold 1474535495dSIngo Weinhold return pnp->register_node(bus->node, SCSI_DEVICE_MODULE_NAME, attrs, 1484535495dSIngo Weinhold NULL, NULL); 1494535495dSIngo Weinhold } 1504535495dSIngo Weinhold 1514535495dSIngo Weinhold return B_OK; 1524535495dSIngo Weinhold } 1534535495dSIngo Weinhold 1544535495dSIngo Weinhold 1554535495dSIngo Weinhold // create data structure for a device 1564535495dSIngo Weinhold static scsi_device_info * 1574535495dSIngo Weinhold scsi_create_device(device_node *node, scsi_bus_info *bus, 1584535495dSIngo Weinhold int target_id, int target_lun) 1594535495dSIngo Weinhold { 1604535495dSIngo Weinhold scsi_device_info *device; 1614535495dSIngo Weinhold 1624535495dSIngo Weinhold SHOW_FLOW0( 3, "" ); 1634535495dSIngo Weinhold 1644535495dSIngo Weinhold device = (scsi_device_info *)malloc(sizeof(*device)); 1654535495dSIngo Weinhold if (device == NULL) 1664535495dSIngo Weinhold return NULL; 1674535495dSIngo Weinhold 1684535495dSIngo Weinhold memset(device, 0, sizeof(*device)); 1694535495dSIngo Weinhold 1704535495dSIngo Weinhold device->lock_count = device->blocked[0] = device->blocked[1] = 0; 1714535495dSIngo Weinhold device->sim_overflow = 0; 1724535495dSIngo Weinhold device->queued_reqs = NULL; 1734535495dSIngo Weinhold device->bus = bus; 1744535495dSIngo Weinhold device->target_id = target_id; 1754535495dSIngo Weinhold device->target_lun = target_lun; 1764535495dSIngo Weinhold device->valid = true; 1774535495dSIngo Weinhold device->node = node; 1784535495dSIngo Weinhold 1794535495dSIngo Weinhold scsi_dma_buffer_init(&device->dma_buffer); 1804535495dSIngo Weinhold 1814535495dSIngo Weinhold if (INIT_BEN(&device->dma_buffer_lock, "dma_buffer") < 0) 1824535495dSIngo Weinhold goto err; 1834535495dSIngo Weinhold 1844535495dSIngo Weinhold device->dma_buffer_owner = create_sem(1, "dma_buffer"); 1854535495dSIngo Weinhold if (device->dma_buffer_owner < 0) 1864535495dSIngo Weinhold goto err2; 1874535495dSIngo Weinhold 1884535495dSIngo Weinhold register_kernel_daemon(scsi_dma_buffer_daemon, device, 5 * 10); 1894535495dSIngo Weinhold 1904535495dSIngo Weinhold return device; 1914535495dSIngo Weinhold 1924535495dSIngo Weinhold err2: 1934535495dSIngo Weinhold DELETE_BEN(&device->dma_buffer_lock); 1944535495dSIngo Weinhold err: 1954535495dSIngo Weinhold free(device); 1964535495dSIngo Weinhold return NULL; 1974535495dSIngo Weinhold } 1984535495dSIngo Weinhold 1994535495dSIngo Weinhold 2004535495dSIngo Weinhold /** prepare autosense request. 2014535495dSIngo Weinhold * this cannot be done on demand but during init as we may 2024535495dSIngo Weinhold * have run out of ccbs when we need it 2034535495dSIngo Weinhold */ 2044535495dSIngo Weinhold 2054535495dSIngo Weinhold static status_t 2064535495dSIngo Weinhold scsi_create_autosense_request(scsi_device_info *device) 2074535495dSIngo Weinhold { 2084535495dSIngo Weinhold scsi_ccb *request; 2094535495dSIngo Weinhold unsigned char *buffer; 2104535495dSIngo Weinhold scsi_cmd_request_sense *cmd; 2114535495dSIngo Weinhold size_t total_size; 2124535495dSIngo Weinhold 2134535495dSIngo Weinhold SHOW_FLOW0( 3, "" ); 2144535495dSIngo Weinhold 2154535495dSIngo Weinhold device->auto_sense_request = request = scsi_alloc_ccb(device); 2164535495dSIngo Weinhold if (device->auto_sense_request == NULL) 2174535495dSIngo Weinhold return B_NO_MEMORY; 2184535495dSIngo Weinhold 2194535495dSIngo Weinhold total_size = SCSI_MAX_SENSE_SIZE + sizeof(physical_entry); 2204535495dSIngo Weinhold total_size = (total_size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 2214535495dSIngo Weinhold 2224535495dSIngo Weinhold // allocate buffer for space sense data and S/G list 2234535495dSIngo Weinhold device->auto_sense_area = create_area("auto_sense", (void**)&buffer, 2244535495dSIngo Weinhold B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_32_BIT_FULL_LOCK, 0); 2254535495dSIngo Weinhold // TODO: Use B_FULL_LOCK, if addresses >= 4 GB are supported! 2264535495dSIngo Weinhold if (device->auto_sense_area < 0) 2274535495dSIngo Weinhold goto err; 2284535495dSIngo Weinhold 2294535495dSIngo Weinhold request->data = buffer; 2304535495dSIngo Weinhold request->data_length = SCSI_MAX_SENSE_SIZE; 2314535495dSIngo Weinhold request->sg_list = (physical_entry *)(buffer + SCSI_MAX_SENSE_SIZE); 2324535495dSIngo Weinhold request->sg_count = 1; 2334535495dSIngo Weinhold 2344535495dSIngo Weinhold get_memory_map(buffer, SCSI_MAX_SENSE_SIZE, 2354535495dSIngo Weinhold (physical_entry *)request->sg_list, 1); 2364535495dSIngo Weinhold 2374535495dSIngo Weinhold // disable auto-autosense, just in case; 2384535495dSIngo Weinhold // make sure no other request overtakes sense request; 2394535495dSIngo Weinhold // buffer is/must be DMA safe as we cannot risk trouble with 2404535495dSIngo Weinhold // dynamically allocated DMA buffer 2414535495dSIngo Weinhold request->flags = SCSI_DIR_IN | SCSI_DIS_AUTOSENSE | 2424535495dSIngo Weinhold SCSI_ORDERED_QTAG | SCSI_DMA_SAFE; 2434535495dSIngo Weinhold 2444535495dSIngo Weinhold cmd = (scsi_cmd_request_sense *)request->cdb; 2454535495dSIngo Weinhold request->cdb_length = sizeof(*cmd); 2464535495dSIngo Weinhold 2474535495dSIngo Weinhold memset(cmd, 0, sizeof(*cmd)); 2484535495dSIngo Weinhold cmd->opcode = SCSI_OP_REQUEST_SENSE; 2494535495dSIngo Weinhold cmd->lun = device->target_lun; 2504535495dSIngo Weinhold cmd->allocation_length = SCSI_MAX_SENSE_SIZE; 2514535495dSIngo Weinhold 2524535495dSIngo Weinhold return B_OK; 2534535495dSIngo Weinhold 2544535495dSIngo Weinhold err: 2554535495dSIngo Weinhold scsi_free_ccb(request); 2564535495dSIngo Weinhold return B_NO_MEMORY; 2574535495dSIngo Weinhold } 2584535495dSIngo Weinhold 2594535495dSIngo Weinhold 2604535495dSIngo Weinhold #define SET_BIT(field, bit) field[(bit) >> 3] |= 1 << ((bit) & 7) 2614535495dSIngo Weinhold 2624535495dSIngo Weinhold static status_t 2634535495dSIngo Weinhold scsi_init_device(device_node *node, void **cookie) 2644535495dSIngo Weinhold { 2654535495dSIngo Weinhold const scsi_res_inquiry *inquiry_data = NULL; 2664535495dSIngo Weinhold uint8 target_id, target_lun, path_id; 2674535495dSIngo Weinhold scsi_bus_info *bus; 2684535495dSIngo Weinhold scsi_device_info *device; 2694535495dSIngo Weinhold status_t res; 2704535495dSIngo Weinhold size_t inquiry_data_len; 2714535495dSIngo Weinhold uint8 is_atapi, manual_autosense; 2724535495dSIngo Weinhold 2734535495dSIngo Weinhold SHOW_FLOW0(3, ""); 2744535495dSIngo Weinhold 2754535495dSIngo Weinhold if (pnp->get_attr_uint8( node, SCSI_DEVICE_TARGET_ID_ITEM, &target_id, false) != B_OK 2764535495dSIngo Weinhold || pnp->get_attr_uint8( node, SCSI_DEVICE_TARGET_LUN_ITEM, &target_lun, false) != B_OK 2774535495dSIngo Weinhold || pnp->get_attr_uint8( node, SCSI_DEVICE_IS_ATAPI_ITEM, &is_atapi, false) != B_OK 2784535495dSIngo Weinhold || pnp->get_attr_uint8( node, SCSI_DEVICE_MANUAL_AUTOSENSE_ITEM, &manual_autosense, false) != B_OK 2794535495dSIngo Weinhold || pnp->get_attr_raw( node, SCSI_DEVICE_INQUIRY_ITEM, 2804535495dSIngo Weinhold (const void **)&inquiry_data, &inquiry_data_len, false) != B_OK 2814535495dSIngo Weinhold || inquiry_data_len != sizeof(*inquiry_data)) { 2824535495dSIngo Weinhold return B_ERROR; 2834535495dSIngo Weinhold } 2844535495dSIngo Weinhold 2854535495dSIngo Weinhold { 2864535495dSIngo Weinhold device_node *parent = pnp->get_parent_node(node); 2874535495dSIngo Weinhold pnp->get_driver(parent, NULL, (void **)&bus); 2884535495dSIngo Weinhold pnp->put_node(parent); 2894535495dSIngo Weinhold } 2904535495dSIngo Weinhold 2914535495dSIngo Weinhold device = scsi_create_device(node, bus, target_id, target_lun); 2924535495dSIngo Weinhold if (device == NULL) 2934535495dSIngo Weinhold return B_NO_MEMORY; 2944535495dSIngo Weinhold 2954535495dSIngo Weinhold // never mind if there is no path - it might be an emulated controller 2964535495dSIngo Weinhold path_id = (uint8)-1; 2974535495dSIngo Weinhold 2984535495dSIngo Weinhold pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, true); 2994535495dSIngo Weinhold 3004535495dSIngo Weinhold device->inquiry_data = *inquiry_data; 3014535495dSIngo Weinhold 3024535495dSIngo Weinhold // save restrictions 3034535495dSIngo Weinhold device->is_atapi = is_atapi; 3044535495dSIngo Weinhold device->manual_autosense = manual_autosense; 3054535495dSIngo Weinhold 3064535495dSIngo Weinhold // size of device queue must be detected by trial and error, so 3074535495dSIngo Weinhold // we start with a really high number and see when the device chokes 3084535495dSIngo Weinhold device->total_slots = 4096; 3094535495dSIngo Weinhold 3104535495dSIngo Weinhold // disable queuing if bus doesn't support it 3114535495dSIngo Weinhold if ((bus->inquiry_data.hba_inquiry & SCSI_PI_TAG_ABLE) == 0) 3124535495dSIngo Weinhold device->total_slots = 1; 3134535495dSIngo Weinhold 3144535495dSIngo Weinhold // if there is no autosense, disable queuing to make sure autosense is 3154535495dSIngo Weinhold // not overtaken by other requests 3164535495dSIngo Weinhold if (device->manual_autosense) 3174535495dSIngo Weinhold device->total_slots = 1; 3184535495dSIngo Weinhold 3194535495dSIngo Weinhold device->left_slots = device->total_slots; 3204535495dSIngo Weinhold 3214535495dSIngo Weinhold // get autosense request if required 3224535495dSIngo Weinhold if (device->manual_autosense) { 3234535495dSIngo Weinhold if (scsi_create_autosense_request(device) != B_OK) { 3244535495dSIngo Weinhold res = B_NO_MEMORY; 3254535495dSIngo Weinhold goto err; 3264535495dSIngo Weinhold } 3274535495dSIngo Weinhold } 3284535495dSIngo Weinhold 3294535495dSIngo Weinhold // if this is an ATAPI device, we need an emulation buffer 3304535495dSIngo Weinhold if (scsi_init_emulation_buffer(device, SCSI_ATAPI_BUFFER_SIZE) != B_OK) { 3314535495dSIngo Weinhold res = B_NO_MEMORY; 3324535495dSIngo Weinhold goto err; 3334535495dSIngo Weinhold } 3344535495dSIngo Weinhold 3354535495dSIngo Weinhold memset(device->emulation_map, 0, sizeof(device->emulation_map)); 3364535495dSIngo Weinhold 3374535495dSIngo Weinhold if (device->is_atapi) { 3384535495dSIngo Weinhold SET_BIT(device->emulation_map, SCSI_OP_READ_6); 3394535495dSIngo Weinhold SET_BIT(device->emulation_map, SCSI_OP_WRITE_6); 3404535495dSIngo Weinhold SET_BIT(device->emulation_map, SCSI_OP_MODE_SENSE_6); 3414535495dSIngo Weinhold SET_BIT(device->emulation_map, SCSI_OP_MODE_SELECT_6); 3424535495dSIngo Weinhold SET_BIT(device->emulation_map, SCSI_OP_INQUIRY); 3434535495dSIngo Weinhold } 3444535495dSIngo Weinhold 3454535495dSIngo Weinhold *cookie = device; 3464535495dSIngo Weinhold return B_OK; 3474535495dSIngo Weinhold 3484535495dSIngo Weinhold err: 3494535495dSIngo Weinhold scsi_free_device(device); 3504535495dSIngo Weinhold return res; 3514535495dSIngo Weinhold } 3524535495dSIngo Weinhold 3534535495dSIngo Weinhold 3544535495dSIngo Weinhold static void 3554535495dSIngo Weinhold scsi_uninit_device(scsi_device_info *device) 3564535495dSIngo Weinhold { 3574535495dSIngo Weinhold SHOW_FLOW0(3, ""); 3584535495dSIngo Weinhold 3594535495dSIngo Weinhold scsi_free_device(device); 3604535495dSIngo Weinhold } 3614535495dSIngo Weinhold 3624535495dSIngo Weinhold 3634535495dSIngo Weinhold static void 3644535495dSIngo Weinhold scsi_device_removed(scsi_device_info *device) 3654535495dSIngo Weinhold { 3664535495dSIngo Weinhold SHOW_FLOW0(3, ""); 3674535495dSIngo Weinhold 3684535495dSIngo Weinhold if (device == NULL) 3694535495dSIngo Weinhold return; 3704535495dSIngo Weinhold 3714535495dSIngo Weinhold // this must be atomic as no lock is used 3724535495dSIngo Weinhold device->valid = false; 3734535495dSIngo Weinhold } 3744535495dSIngo Weinhold 3754535495dSIngo Weinhold 3764535495dSIngo Weinhold /** get device info; create a temporary one if it's not registered 3774535495dSIngo Weinhold * (used during detection) 3784535495dSIngo Weinhold * on success, scan_lun_lock of bus is hold 3794535495dSIngo Weinhold */ 3804535495dSIngo Weinhold 3814535495dSIngo Weinhold status_t 3824535495dSIngo Weinhold scsi_force_get_device(scsi_bus_info *bus, uchar target_id, 3834535495dSIngo Weinhold uchar target_lun, scsi_device_info **res_device) 3844535495dSIngo Weinhold { 3854535495dSIngo Weinhold device_attr attrs[] = { 3864535495dSIngo Weinhold { SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }}, 3874535495dSIngo Weinhold { SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }}, 3884535495dSIngo Weinhold { NULL } 3894535495dSIngo Weinhold }; 3904535495dSIngo Weinhold device_node *node; 3914535495dSIngo Weinhold status_t res; 3924535495dSIngo Weinhold driver_module_info *driver_interface; 3934535495dSIngo Weinhold scsi_device device; 3944535495dSIngo Weinhold 3954535495dSIngo Weinhold SHOW_FLOW0(3, ""); 3964535495dSIngo Weinhold 3974535495dSIngo Weinhold // very important: only one can use a forced device to avoid double detection 3984535495dSIngo Weinhold acquire_sem(bus->scan_lun_lock); 3994535495dSIngo Weinhold 4004535495dSIngo Weinhold // check whether device registered already 4014535495dSIngo Weinhold node = NULL; 4024535495dSIngo Weinhold pnp->get_next_child_node(bus->node, attrs, &node); 4034535495dSIngo Weinhold 4044535495dSIngo Weinhold SHOW_FLOW(3, "%p", node); 4054535495dSIngo Weinhold 4064535495dSIngo Weinhold if (node != NULL) { 4074535495dSIngo Weinhold // TODO: have a second look a this one! 4084535495dSIngo Weinhold // there is one - get it 4094535495dSIngo Weinhold res = pnp->get_driver(node, &driver_interface, (void **)&device); 4104535495dSIngo Weinhold if (res != B_OK) 4114535495dSIngo Weinhold pnp->put_node(node); 4124535495dSIngo Weinhold } else { 4134535495dSIngo Weinhold // device doesn't exist yet - create a temporary one 4144535495dSIngo Weinhold device = scsi_create_device(NULL, bus, target_id, target_lun); 4154535495dSIngo Weinhold if (device == NULL) 4164535495dSIngo Weinhold res = B_NO_MEMORY; 4174535495dSIngo Weinhold else 4184535495dSIngo Weinhold res = B_OK; 4194535495dSIngo Weinhold } 4204535495dSIngo Weinhold 4214535495dSIngo Weinhold *res_device = device; 4224535495dSIngo Weinhold 4234535495dSIngo Weinhold if (res != B_OK) 4244535495dSIngo Weinhold release_sem(bus->scan_lun_lock); 4254535495dSIngo Weinhold 4264535495dSIngo Weinhold return res; 4274535495dSIngo Weinhold } 4284535495dSIngo Weinhold 4294535495dSIngo Weinhold 4304535495dSIngo Weinhold /** cleanup device received from scsi_force_get_device 4314535495dSIngo Weinhold * on return, scan_lun_lock of bus is released 4324535495dSIngo Weinhold */ 4334535495dSIngo Weinhold 4344535495dSIngo Weinhold void 4354535495dSIngo Weinhold scsi_put_forced_device(scsi_device_info *device) 4364535495dSIngo Weinhold { 4374535495dSIngo Weinhold scsi_bus_info *bus = device->bus; 4384535495dSIngo Weinhold 4394535495dSIngo Weinhold SHOW_FLOW0(3, ""); 4404535495dSIngo Weinhold 4414535495dSIngo Weinhold if (device->node != NULL) { 4424535495dSIngo Weinhold // device is registered 4434535495dSIngo Weinhold pnp->put_node(device->node); 4444535495dSIngo Weinhold } else { 4454535495dSIngo Weinhold // device is temporary 4464535495dSIngo Weinhold scsi_free_device(device); 4474535495dSIngo Weinhold } 4484535495dSIngo Weinhold 4494535495dSIngo Weinhold release_sem(bus->scan_lun_lock); 4504535495dSIngo Weinhold } 4514535495dSIngo Weinhold 4524535495dSIngo Weinhold 4534535495dSIngo Weinhold static uchar 4544535495dSIngo Weinhold scsi_reset_device(scsi_device_info *device) 4554535495dSIngo Weinhold { 4564535495dSIngo Weinhold SHOW_FLOW0(3, ""); 4574535495dSIngo Weinhold 4584535495dSIngo Weinhold if (device->node == NULL) 4594535495dSIngo Weinhold return SCSI_DEV_NOT_THERE; 4604535495dSIngo Weinhold 4614535495dSIngo Weinhold return device->bus->interface->reset_device(device->bus->sim_cookie, 4624535495dSIngo Weinhold device->target_id, device->target_lun); 4634535495dSIngo Weinhold } 4644535495dSIngo Weinhold 4654535495dSIngo Weinhold 4664535495dSIngo Weinhold static status_t 4674535495dSIngo Weinhold scsi_ioctl(scsi_device_info *device, uint32 op, void *buffer, size_t length) 4684535495dSIngo Weinhold { 4694535495dSIngo Weinhold if (device->bus->interface->ioctl != NULL) { 4704535495dSIngo Weinhold return device->bus->interface->ioctl(device->bus->sim_cookie, 4714535495dSIngo Weinhold device->target_id, op, buffer, length); 4724535495dSIngo Weinhold } 4734535495dSIngo Weinhold 474*e523d3cfSJérôme Duval return B_DEV_INVALID_IOCTL; 4754535495dSIngo Weinhold } 4764535495dSIngo Weinhold 4774535495dSIngo Weinhold 4784535495dSIngo Weinhold static status_t 4794535495dSIngo Weinhold std_ops(int32 op, ...) 4804535495dSIngo Weinhold { 4814535495dSIngo Weinhold switch (op) { 4824535495dSIngo Weinhold case B_MODULE_INIT: 4834535495dSIngo Weinhold { 4844535495dSIngo Weinhold // Link to SCSI bus. 4854535495dSIngo Weinhold // SCSI device driver must have SCSI bus loaded, but it calls its functions 4864535495dSIngo Weinhold // directly instead via official interface, so this pointer is never read. 4874535495dSIngo Weinhold module_info *dummy; 4884535495dSIngo Weinhold return get_module(SCSI_BUS_MODULE_NAME, &dummy); 4894535495dSIngo Weinhold } 4904535495dSIngo Weinhold case B_MODULE_UNINIT: 4914535495dSIngo Weinhold return put_module(SCSI_BUS_MODULE_NAME); 4924535495dSIngo Weinhold 4934535495dSIngo Weinhold default: 4944535495dSIngo Weinhold return B_ERROR; 4954535495dSIngo Weinhold } 4964535495dSIngo Weinhold } 4974535495dSIngo Weinhold 4984535495dSIngo Weinhold 4994535495dSIngo Weinhold scsi_device_interface scsi_device_module = { 5004535495dSIngo Weinhold { 5014535495dSIngo Weinhold { 5024535495dSIngo Weinhold SCSI_DEVICE_MODULE_NAME, 5034535495dSIngo Weinhold 0, 5044535495dSIngo Weinhold std_ops 5054535495dSIngo Weinhold }, 5064535495dSIngo Weinhold 5074535495dSIngo Weinhold NULL, // supported devices 5084535495dSIngo Weinhold NULL, // register node 5094535495dSIngo Weinhold scsi_init_device, 5104535495dSIngo Weinhold (void (*)(void *)) scsi_uninit_device, 5114535495dSIngo Weinhold NULL, // register child devices 5124535495dSIngo Weinhold NULL, // rescan 5134535495dSIngo Weinhold (void (*)(void *)) scsi_device_removed 5144535495dSIngo Weinhold }, 5154535495dSIngo Weinhold 5164535495dSIngo Weinhold scsi_alloc_ccb, 5174535495dSIngo Weinhold scsi_free_ccb, 5184535495dSIngo Weinhold 5194535495dSIngo Weinhold scsi_async_io, 5204535495dSIngo Weinhold scsi_sync_io, 5214535495dSIngo Weinhold scsi_abort, 5224535495dSIngo Weinhold scsi_reset_device, 5234535495dSIngo Weinhold scsi_term_io, 5244535495dSIngo Weinhold scsi_ioctl, 5254535495dSIngo Weinhold }; 526