1*4535495dSIngo Weinhold /* 2*4535495dSIngo Weinhold * Copyright 2004-2006, Haiku, Inc. All RightsReserved. 3*4535495dSIngo Weinhold * Copyright 2002/03, Thomas Kurschel. All rights reserved. 4*4535495dSIngo Weinhold * 5*4535495dSIngo Weinhold * Distributed under the terms of the MIT License. 6*4535495dSIngo Weinhold */ 7*4535495dSIngo Weinhold 8*4535495dSIngo Weinhold /* 9*4535495dSIngo Weinhold Device node layer. 10*4535495dSIngo Weinhold 11*4535495dSIngo Weinhold When a SCSI bus is registered, this layer scans for SCSI devices 12*4535495dSIngo Weinhold and registers a node for each of them. Peripheral drivers are on 13*4535495dSIngo Weinhold top of these nodes. 14*4535495dSIngo Weinhold */ 15*4535495dSIngo Weinhold 16*4535495dSIngo Weinhold #include "scsi_internal.h" 17*4535495dSIngo Weinhold 18*4535495dSIngo Weinhold #include <string.h> 19*4535495dSIngo Weinhold #include <stdlib.h> 20*4535495dSIngo Weinhold #include <stdio.h> 21*4535495dSIngo Weinhold 22*4535495dSIngo Weinhold #include <algorithm> 23*4535495dSIngo Weinhold 24*4535495dSIngo Weinhold 25*4535495dSIngo Weinhold /** free autosense request of device */ 26*4535495dSIngo Weinhold 27*4535495dSIngo Weinhold static void 28*4535495dSIngo Weinhold scsi_free_autosense_request(scsi_device_info *device) 29*4535495dSIngo Weinhold { 30*4535495dSIngo Weinhold SHOW_FLOW0( 3, "" ); 31*4535495dSIngo Weinhold 32*4535495dSIngo Weinhold if (device->auto_sense_request != NULL) { 33*4535495dSIngo Weinhold scsi_free_ccb(device->auto_sense_request); 34*4535495dSIngo Weinhold device->auto_sense_request = NULL; 35*4535495dSIngo Weinhold } 36*4535495dSIngo Weinhold 37*4535495dSIngo Weinhold if (device->auto_sense_area > 0) { 38*4535495dSIngo Weinhold delete_area(device->auto_sense_area); 39*4535495dSIngo Weinhold device->auto_sense_area = 0; 40*4535495dSIngo Weinhold } 41*4535495dSIngo Weinhold } 42*4535495dSIngo Weinhold 43*4535495dSIngo Weinhold 44*4535495dSIngo Weinhold /** free all data of device */ 45*4535495dSIngo Weinhold 46*4535495dSIngo Weinhold static void 47*4535495dSIngo Weinhold scsi_free_device(scsi_device_info *device) 48*4535495dSIngo Weinhold { 49*4535495dSIngo Weinhold SHOW_FLOW0( 3, "" ); 50*4535495dSIngo Weinhold 51*4535495dSIngo Weinhold scsi_free_emulation_buffer(device); 52*4535495dSIngo Weinhold scsi_free_autosense_request(device); 53*4535495dSIngo Weinhold 54*4535495dSIngo Weinhold unregister_kernel_daemon(scsi_dma_buffer_daemon, device); 55*4535495dSIngo Weinhold 56*4535495dSIngo Weinhold scsi_dma_buffer_free(&device->dma_buffer); 57*4535495dSIngo Weinhold 58*4535495dSIngo Weinhold DELETE_BEN(&device->dma_buffer_lock); 59*4535495dSIngo Weinhold delete_sem(device->dma_buffer_owner); 60*4535495dSIngo Weinhold 61*4535495dSIngo Weinhold free(device); 62*4535495dSIngo Weinhold } 63*4535495dSIngo Weinhold 64*4535495dSIngo Weinhold 65*4535495dSIngo Weinhold /** copy string src without trailing zero to dst and remove trailing 66*4535495dSIngo Weinhold * spaces size of dst is dst_size, size of src is dst_size-1 67*4535495dSIngo Weinhold */ 68*4535495dSIngo Weinhold 69*4535495dSIngo Weinhold static void 70*4535495dSIngo Weinhold beautify_string(char *dst, char *src, int dst_size) 71*4535495dSIngo Weinhold { 72*4535495dSIngo Weinhold int i; 73*4535495dSIngo Weinhold 74*4535495dSIngo Weinhold memcpy(dst, src, dst_size - 1); 75*4535495dSIngo Weinhold 76*4535495dSIngo Weinhold for (i = dst_size - 2; i >= 0; --i) { 77*4535495dSIngo Weinhold if (dst[i] != ' ') 78*4535495dSIngo Weinhold break; 79*4535495dSIngo Weinhold } 80*4535495dSIngo Weinhold 81*4535495dSIngo Weinhold dst[i + 1] = 0; 82*4535495dSIngo Weinhold } 83*4535495dSIngo Weinhold 84*4535495dSIngo Weinhold 85*4535495dSIngo Weinhold /** register new device */ 86*4535495dSIngo Weinhold 87*4535495dSIngo Weinhold status_t 88*4535495dSIngo Weinhold scsi_register_device(scsi_bus_info *bus, uchar target_id, 89*4535495dSIngo Weinhold uchar target_lun, scsi_res_inquiry *inquiry_data) 90*4535495dSIngo Weinhold { 91*4535495dSIngo Weinhold bool is_atapi, manual_autosense; 92*4535495dSIngo Weinhold uint32 orig_max_blocks, max_blocks; 93*4535495dSIngo Weinhold 94*4535495dSIngo Weinhold SHOW_FLOW0( 3, "" ); 95*4535495dSIngo Weinhold 96*4535495dSIngo Weinhold // ask for restrictions 97*4535495dSIngo Weinhold bus->interface->get_restrictions(bus->sim_cookie, 98*4535495dSIngo Weinhold target_id, &is_atapi, &manual_autosense, &max_blocks); 99*4535495dSIngo Weinhold if (target_lun != 0) 100*4535495dSIngo Weinhold dprintf("WARNING: SCSI target %d lun %d getting restrictions without lun\n", 101*4535495dSIngo Weinhold target_id, target_lun); 102*4535495dSIngo Weinhold 103*4535495dSIngo Weinhold // find maximum transfer blocks 104*4535495dSIngo Weinhold // set default value to max (need something like ULONG_MAX here) 105*4535495dSIngo Weinhold orig_max_blocks = ~0; 106*4535495dSIngo Weinhold pnp->get_attr_uint32(bus->node, B_DMA_MAX_TRANSFER_BLOCKS, &orig_max_blocks, 107*4535495dSIngo Weinhold true); 108*4535495dSIngo Weinhold 109*4535495dSIngo Weinhold max_blocks = std::min(max_blocks, orig_max_blocks); 110*4535495dSIngo Weinhold 111*4535495dSIngo Weinhold { 112*4535495dSIngo Weinhold char vendor_ident[sizeof( inquiry_data->vendor_ident ) + 1]; 113*4535495dSIngo Weinhold char product_ident[sizeof( inquiry_data->product_ident ) + 1]; 114*4535495dSIngo Weinhold char product_rev[sizeof( inquiry_data->product_rev ) + 1]; 115*4535495dSIngo Weinhold device_attr attrs[] = { 116*4535495dSIngo Weinhold // connection 117*4535495dSIngo Weinhold { SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }}, 118*4535495dSIngo Weinhold { SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }}, 119*4535495dSIngo Weinhold 120*4535495dSIngo Weinhold // inquiry data (used for both identification and information) 121*4535495dSIngo Weinhold { SCSI_DEVICE_INQUIRY_ITEM, B_RAW_TYPE, 122*4535495dSIngo Weinhold { raw: { inquiry_data, sizeof( *inquiry_data ) }}}, 123*4535495dSIngo Weinhold 124*4535495dSIngo Weinhold // some more info for driver loading 125*4535495dSIngo Weinhold { SCSI_DEVICE_TYPE_ITEM, B_UINT8_TYPE, { ui8: inquiry_data->device_type }}, 126*4535495dSIngo Weinhold { SCSI_DEVICE_VENDOR_ITEM, B_STRING_TYPE, { string: vendor_ident }}, 127*4535495dSIngo Weinhold { SCSI_DEVICE_PRODUCT_ITEM, B_STRING_TYPE, { string: product_ident }}, 128*4535495dSIngo Weinhold { SCSI_DEVICE_REVISION_ITEM, B_STRING_TYPE, { string: product_rev }}, 129*4535495dSIngo Weinhold 130*4535495dSIngo Weinhold // description of peripheral drivers 131*4535495dSIngo Weinhold { B_DEVICE_BUS, B_STRING_TYPE, { string: "scsi" }}, 132*4535495dSIngo Weinhold 133*4535495dSIngo Weinhold // extra restriction of maximum number of blocks per transfer 134*4535495dSIngo Weinhold { B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, { ui32: max_blocks }}, 135*4535495dSIngo Weinhold 136*4535495dSIngo Weinhold // atapi emulation 137*4535495dSIngo Weinhold { SCSI_DEVICE_IS_ATAPI_ITEM, B_UINT8_TYPE, { ui8: is_atapi }}, 138*4535495dSIngo Weinhold // manual autosense 139*4535495dSIngo Weinhold { SCSI_DEVICE_MANUAL_AUTOSENSE_ITEM, B_UINT8_TYPE, { ui8: manual_autosense }}, 140*4535495dSIngo Weinhold { NULL } 141*4535495dSIngo Weinhold }; 142*4535495dSIngo Weinhold 143*4535495dSIngo Weinhold beautify_string(vendor_ident, inquiry_data->vendor_ident, sizeof(vendor_ident)); 144*4535495dSIngo Weinhold beautify_string(product_ident, inquiry_data->product_ident, sizeof(product_ident)); 145*4535495dSIngo Weinhold beautify_string(product_rev, inquiry_data->product_rev, sizeof(product_rev)); 146*4535495dSIngo Weinhold 147*4535495dSIngo Weinhold return pnp->register_node(bus->node, SCSI_DEVICE_MODULE_NAME, attrs, 148*4535495dSIngo Weinhold NULL, NULL); 149*4535495dSIngo Weinhold } 150*4535495dSIngo Weinhold 151*4535495dSIngo Weinhold return B_OK; 152*4535495dSIngo Weinhold } 153*4535495dSIngo Weinhold 154*4535495dSIngo Weinhold 155*4535495dSIngo Weinhold // create data structure for a device 156*4535495dSIngo Weinhold static scsi_device_info * 157*4535495dSIngo Weinhold scsi_create_device(device_node *node, scsi_bus_info *bus, 158*4535495dSIngo Weinhold int target_id, int target_lun) 159*4535495dSIngo Weinhold { 160*4535495dSIngo Weinhold scsi_device_info *device; 161*4535495dSIngo Weinhold 162*4535495dSIngo Weinhold SHOW_FLOW0( 3, "" ); 163*4535495dSIngo Weinhold 164*4535495dSIngo Weinhold device = (scsi_device_info *)malloc(sizeof(*device)); 165*4535495dSIngo Weinhold if (device == NULL) 166*4535495dSIngo Weinhold return NULL; 167*4535495dSIngo Weinhold 168*4535495dSIngo Weinhold memset(device, 0, sizeof(*device)); 169*4535495dSIngo Weinhold 170*4535495dSIngo Weinhold device->lock_count = device->blocked[0] = device->blocked[1] = 0; 171*4535495dSIngo Weinhold device->sim_overflow = 0; 172*4535495dSIngo Weinhold device->queued_reqs = NULL; 173*4535495dSIngo Weinhold device->bus = bus; 174*4535495dSIngo Weinhold device->target_id = target_id; 175*4535495dSIngo Weinhold device->target_lun = target_lun; 176*4535495dSIngo Weinhold device->valid = true; 177*4535495dSIngo Weinhold device->node = node; 178*4535495dSIngo Weinhold 179*4535495dSIngo Weinhold scsi_dma_buffer_init(&device->dma_buffer); 180*4535495dSIngo Weinhold 181*4535495dSIngo Weinhold if (INIT_BEN(&device->dma_buffer_lock, "dma_buffer") < 0) 182*4535495dSIngo Weinhold goto err; 183*4535495dSIngo Weinhold 184*4535495dSIngo Weinhold device->dma_buffer_owner = create_sem(1, "dma_buffer"); 185*4535495dSIngo Weinhold if (device->dma_buffer_owner < 0) 186*4535495dSIngo Weinhold goto err2; 187*4535495dSIngo Weinhold 188*4535495dSIngo Weinhold register_kernel_daemon(scsi_dma_buffer_daemon, device, 5 * 10); 189*4535495dSIngo Weinhold 190*4535495dSIngo Weinhold return device; 191*4535495dSIngo Weinhold 192*4535495dSIngo Weinhold err2: 193*4535495dSIngo Weinhold DELETE_BEN(&device->dma_buffer_lock); 194*4535495dSIngo Weinhold err: 195*4535495dSIngo Weinhold free(device); 196*4535495dSIngo Weinhold return NULL; 197*4535495dSIngo Weinhold } 198*4535495dSIngo Weinhold 199*4535495dSIngo Weinhold 200*4535495dSIngo Weinhold /** prepare autosense request. 201*4535495dSIngo Weinhold * this cannot be done on demand but during init as we may 202*4535495dSIngo Weinhold * have run out of ccbs when we need it 203*4535495dSIngo Weinhold */ 204*4535495dSIngo Weinhold 205*4535495dSIngo Weinhold static status_t 206*4535495dSIngo Weinhold scsi_create_autosense_request(scsi_device_info *device) 207*4535495dSIngo Weinhold { 208*4535495dSIngo Weinhold scsi_ccb *request; 209*4535495dSIngo Weinhold unsigned char *buffer; 210*4535495dSIngo Weinhold scsi_cmd_request_sense *cmd; 211*4535495dSIngo Weinhold size_t total_size; 212*4535495dSIngo Weinhold 213*4535495dSIngo Weinhold SHOW_FLOW0( 3, "" ); 214*4535495dSIngo Weinhold 215*4535495dSIngo Weinhold device->auto_sense_request = request = scsi_alloc_ccb(device); 216*4535495dSIngo Weinhold if (device->auto_sense_request == NULL) 217*4535495dSIngo Weinhold return B_NO_MEMORY; 218*4535495dSIngo Weinhold 219*4535495dSIngo Weinhold total_size = SCSI_MAX_SENSE_SIZE + sizeof(physical_entry); 220*4535495dSIngo Weinhold total_size = (total_size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 221*4535495dSIngo Weinhold 222*4535495dSIngo Weinhold // allocate buffer for space sense data and S/G list 223*4535495dSIngo Weinhold device->auto_sense_area = create_area("auto_sense", (void**)&buffer, 224*4535495dSIngo Weinhold B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_32_BIT_FULL_LOCK, 0); 225*4535495dSIngo Weinhold // TODO: Use B_FULL_LOCK, if addresses >= 4 GB are supported! 226*4535495dSIngo Weinhold if (device->auto_sense_area < 0) 227*4535495dSIngo Weinhold goto err; 228*4535495dSIngo Weinhold 229*4535495dSIngo Weinhold request->data = buffer; 230*4535495dSIngo Weinhold request->data_length = SCSI_MAX_SENSE_SIZE; 231*4535495dSIngo Weinhold request->sg_list = (physical_entry *)(buffer + SCSI_MAX_SENSE_SIZE); 232*4535495dSIngo Weinhold request->sg_count = 1; 233*4535495dSIngo Weinhold 234*4535495dSIngo Weinhold get_memory_map(buffer, SCSI_MAX_SENSE_SIZE, 235*4535495dSIngo Weinhold (physical_entry *)request->sg_list, 1); 236*4535495dSIngo Weinhold 237*4535495dSIngo Weinhold // disable auto-autosense, just in case; 238*4535495dSIngo Weinhold // make sure no other request overtakes sense request; 239*4535495dSIngo Weinhold // buffer is/must be DMA safe as we cannot risk trouble with 240*4535495dSIngo Weinhold // dynamically allocated DMA buffer 241*4535495dSIngo Weinhold request->flags = SCSI_DIR_IN | SCSI_DIS_AUTOSENSE | 242*4535495dSIngo Weinhold SCSI_ORDERED_QTAG | SCSI_DMA_SAFE; 243*4535495dSIngo Weinhold 244*4535495dSIngo Weinhold cmd = (scsi_cmd_request_sense *)request->cdb; 245*4535495dSIngo Weinhold request->cdb_length = sizeof(*cmd); 246*4535495dSIngo Weinhold 247*4535495dSIngo Weinhold memset(cmd, 0, sizeof(*cmd)); 248*4535495dSIngo Weinhold cmd->opcode = SCSI_OP_REQUEST_SENSE; 249*4535495dSIngo Weinhold cmd->lun = device->target_lun; 250*4535495dSIngo Weinhold cmd->allocation_length = SCSI_MAX_SENSE_SIZE; 251*4535495dSIngo Weinhold 252*4535495dSIngo Weinhold return B_OK; 253*4535495dSIngo Weinhold 254*4535495dSIngo Weinhold err: 255*4535495dSIngo Weinhold scsi_free_ccb(request); 256*4535495dSIngo Weinhold return B_NO_MEMORY; 257*4535495dSIngo Weinhold } 258*4535495dSIngo Weinhold 259*4535495dSIngo Weinhold 260*4535495dSIngo Weinhold #define SET_BIT(field, bit) field[(bit) >> 3] |= 1 << ((bit) & 7) 261*4535495dSIngo Weinhold 262*4535495dSIngo Weinhold static status_t 263*4535495dSIngo Weinhold scsi_init_device(device_node *node, void **cookie) 264*4535495dSIngo Weinhold { 265*4535495dSIngo Weinhold const scsi_res_inquiry *inquiry_data = NULL; 266*4535495dSIngo Weinhold uint8 target_id, target_lun, path_id; 267*4535495dSIngo Weinhold scsi_bus_info *bus; 268*4535495dSIngo Weinhold scsi_device_info *device; 269*4535495dSIngo Weinhold status_t res; 270*4535495dSIngo Weinhold size_t inquiry_data_len; 271*4535495dSIngo Weinhold uint8 is_atapi, manual_autosense; 272*4535495dSIngo Weinhold 273*4535495dSIngo Weinhold SHOW_FLOW0(3, ""); 274*4535495dSIngo Weinhold 275*4535495dSIngo Weinhold if (pnp->get_attr_uint8( node, SCSI_DEVICE_TARGET_ID_ITEM, &target_id, false) != B_OK 276*4535495dSIngo Weinhold || pnp->get_attr_uint8( node, SCSI_DEVICE_TARGET_LUN_ITEM, &target_lun, false) != B_OK 277*4535495dSIngo Weinhold || pnp->get_attr_uint8( node, SCSI_DEVICE_IS_ATAPI_ITEM, &is_atapi, false) != B_OK 278*4535495dSIngo Weinhold || pnp->get_attr_uint8( node, SCSI_DEVICE_MANUAL_AUTOSENSE_ITEM, &manual_autosense, false) != B_OK 279*4535495dSIngo Weinhold || pnp->get_attr_raw( node, SCSI_DEVICE_INQUIRY_ITEM, 280*4535495dSIngo Weinhold (const void **)&inquiry_data, &inquiry_data_len, false) != B_OK 281*4535495dSIngo Weinhold || inquiry_data_len != sizeof(*inquiry_data)) { 282*4535495dSIngo Weinhold return B_ERROR; 283*4535495dSIngo Weinhold } 284*4535495dSIngo Weinhold 285*4535495dSIngo Weinhold { 286*4535495dSIngo Weinhold device_node *parent = pnp->get_parent_node(node); 287*4535495dSIngo Weinhold pnp->get_driver(parent, NULL, (void **)&bus); 288*4535495dSIngo Weinhold pnp->put_node(parent); 289*4535495dSIngo Weinhold } 290*4535495dSIngo Weinhold 291*4535495dSIngo Weinhold device = scsi_create_device(node, bus, target_id, target_lun); 292*4535495dSIngo Weinhold if (device == NULL) 293*4535495dSIngo Weinhold return B_NO_MEMORY; 294*4535495dSIngo Weinhold 295*4535495dSIngo Weinhold // never mind if there is no path - it might be an emulated controller 296*4535495dSIngo Weinhold path_id = (uint8)-1; 297*4535495dSIngo Weinhold 298*4535495dSIngo Weinhold pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, true); 299*4535495dSIngo Weinhold 300*4535495dSIngo Weinhold device->inquiry_data = *inquiry_data; 301*4535495dSIngo Weinhold 302*4535495dSIngo Weinhold // save restrictions 303*4535495dSIngo Weinhold device->is_atapi = is_atapi; 304*4535495dSIngo Weinhold device->manual_autosense = manual_autosense; 305*4535495dSIngo Weinhold 306*4535495dSIngo Weinhold // size of device queue must be detected by trial and error, so 307*4535495dSIngo Weinhold // we start with a really high number and see when the device chokes 308*4535495dSIngo Weinhold device->total_slots = 4096; 309*4535495dSIngo Weinhold 310*4535495dSIngo Weinhold // disable queuing if bus doesn't support it 311*4535495dSIngo Weinhold if ((bus->inquiry_data.hba_inquiry & SCSI_PI_TAG_ABLE) == 0) 312*4535495dSIngo Weinhold device->total_slots = 1; 313*4535495dSIngo Weinhold 314*4535495dSIngo Weinhold // if there is no autosense, disable queuing to make sure autosense is 315*4535495dSIngo Weinhold // not overtaken by other requests 316*4535495dSIngo Weinhold if (device->manual_autosense) 317*4535495dSIngo Weinhold device->total_slots = 1; 318*4535495dSIngo Weinhold 319*4535495dSIngo Weinhold device->left_slots = device->total_slots; 320*4535495dSIngo Weinhold 321*4535495dSIngo Weinhold // get autosense request if required 322*4535495dSIngo Weinhold if (device->manual_autosense) { 323*4535495dSIngo Weinhold if (scsi_create_autosense_request(device) != B_OK) { 324*4535495dSIngo Weinhold res = B_NO_MEMORY; 325*4535495dSIngo Weinhold goto err; 326*4535495dSIngo Weinhold } 327*4535495dSIngo Weinhold } 328*4535495dSIngo Weinhold 329*4535495dSIngo Weinhold // if this is an ATAPI device, we need an emulation buffer 330*4535495dSIngo Weinhold if (scsi_init_emulation_buffer(device, SCSI_ATAPI_BUFFER_SIZE) != B_OK) { 331*4535495dSIngo Weinhold res = B_NO_MEMORY; 332*4535495dSIngo Weinhold goto err; 333*4535495dSIngo Weinhold } 334*4535495dSIngo Weinhold 335*4535495dSIngo Weinhold memset(device->emulation_map, 0, sizeof(device->emulation_map)); 336*4535495dSIngo Weinhold 337*4535495dSIngo Weinhold if (device->is_atapi) { 338*4535495dSIngo Weinhold SET_BIT(device->emulation_map, SCSI_OP_READ_6); 339*4535495dSIngo Weinhold SET_BIT(device->emulation_map, SCSI_OP_WRITE_6); 340*4535495dSIngo Weinhold SET_BIT(device->emulation_map, SCSI_OP_MODE_SENSE_6); 341*4535495dSIngo Weinhold SET_BIT(device->emulation_map, SCSI_OP_MODE_SELECT_6); 342*4535495dSIngo Weinhold SET_BIT(device->emulation_map, SCSI_OP_INQUIRY); 343*4535495dSIngo Weinhold } 344*4535495dSIngo Weinhold 345*4535495dSIngo Weinhold *cookie = device; 346*4535495dSIngo Weinhold return B_OK; 347*4535495dSIngo Weinhold 348*4535495dSIngo Weinhold err: 349*4535495dSIngo Weinhold scsi_free_device(device); 350*4535495dSIngo Weinhold return res; 351*4535495dSIngo Weinhold } 352*4535495dSIngo Weinhold 353*4535495dSIngo Weinhold 354*4535495dSIngo Weinhold static void 355*4535495dSIngo Weinhold scsi_uninit_device(scsi_device_info *device) 356*4535495dSIngo Weinhold { 357*4535495dSIngo Weinhold SHOW_FLOW0(3, ""); 358*4535495dSIngo Weinhold 359*4535495dSIngo Weinhold scsi_free_device(device); 360*4535495dSIngo Weinhold } 361*4535495dSIngo Weinhold 362*4535495dSIngo Weinhold 363*4535495dSIngo Weinhold static void 364*4535495dSIngo Weinhold scsi_device_removed(scsi_device_info *device) 365*4535495dSIngo Weinhold { 366*4535495dSIngo Weinhold SHOW_FLOW0(3, ""); 367*4535495dSIngo Weinhold 368*4535495dSIngo Weinhold if (device == NULL) 369*4535495dSIngo Weinhold return; 370*4535495dSIngo Weinhold 371*4535495dSIngo Weinhold // this must be atomic as no lock is used 372*4535495dSIngo Weinhold device->valid = false; 373*4535495dSIngo Weinhold } 374*4535495dSIngo Weinhold 375*4535495dSIngo Weinhold 376*4535495dSIngo Weinhold /** get device info; create a temporary one if it's not registered 377*4535495dSIngo Weinhold * (used during detection) 378*4535495dSIngo Weinhold * on success, scan_lun_lock of bus is hold 379*4535495dSIngo Weinhold */ 380*4535495dSIngo Weinhold 381*4535495dSIngo Weinhold status_t 382*4535495dSIngo Weinhold scsi_force_get_device(scsi_bus_info *bus, uchar target_id, 383*4535495dSIngo Weinhold uchar target_lun, scsi_device_info **res_device) 384*4535495dSIngo Weinhold { 385*4535495dSIngo Weinhold device_attr attrs[] = { 386*4535495dSIngo Weinhold { SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }}, 387*4535495dSIngo Weinhold { SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }}, 388*4535495dSIngo Weinhold { NULL } 389*4535495dSIngo Weinhold }; 390*4535495dSIngo Weinhold device_node *node; 391*4535495dSIngo Weinhold status_t res; 392*4535495dSIngo Weinhold driver_module_info *driver_interface; 393*4535495dSIngo Weinhold scsi_device device; 394*4535495dSIngo Weinhold 395*4535495dSIngo Weinhold SHOW_FLOW0(3, ""); 396*4535495dSIngo Weinhold 397*4535495dSIngo Weinhold // very important: only one can use a forced device to avoid double detection 398*4535495dSIngo Weinhold acquire_sem(bus->scan_lun_lock); 399*4535495dSIngo Weinhold 400*4535495dSIngo Weinhold // check whether device registered already 401*4535495dSIngo Weinhold node = NULL; 402*4535495dSIngo Weinhold pnp->get_next_child_node(bus->node, attrs, &node); 403*4535495dSIngo Weinhold 404*4535495dSIngo Weinhold SHOW_FLOW(3, "%p", node); 405*4535495dSIngo Weinhold 406*4535495dSIngo Weinhold if (node != NULL) { 407*4535495dSIngo Weinhold // TODO: have a second look a this one! 408*4535495dSIngo Weinhold // there is one - get it 409*4535495dSIngo Weinhold res = pnp->get_driver(node, &driver_interface, (void **)&device); 410*4535495dSIngo Weinhold if (res != B_OK) 411*4535495dSIngo Weinhold pnp->put_node(node); 412*4535495dSIngo Weinhold } else { 413*4535495dSIngo Weinhold // device doesn't exist yet - create a temporary one 414*4535495dSIngo Weinhold device = scsi_create_device(NULL, bus, target_id, target_lun); 415*4535495dSIngo Weinhold if (device == NULL) 416*4535495dSIngo Weinhold res = B_NO_MEMORY; 417*4535495dSIngo Weinhold else 418*4535495dSIngo Weinhold res = B_OK; 419*4535495dSIngo Weinhold } 420*4535495dSIngo Weinhold 421*4535495dSIngo Weinhold *res_device = device; 422*4535495dSIngo Weinhold 423*4535495dSIngo Weinhold if (res != B_OK) 424*4535495dSIngo Weinhold release_sem(bus->scan_lun_lock); 425*4535495dSIngo Weinhold 426*4535495dSIngo Weinhold return res; 427*4535495dSIngo Weinhold } 428*4535495dSIngo Weinhold 429*4535495dSIngo Weinhold 430*4535495dSIngo Weinhold /** cleanup device received from scsi_force_get_device 431*4535495dSIngo Weinhold * on return, scan_lun_lock of bus is released 432*4535495dSIngo Weinhold */ 433*4535495dSIngo Weinhold 434*4535495dSIngo Weinhold void 435*4535495dSIngo Weinhold scsi_put_forced_device(scsi_device_info *device) 436*4535495dSIngo Weinhold { 437*4535495dSIngo Weinhold scsi_bus_info *bus = device->bus; 438*4535495dSIngo Weinhold 439*4535495dSIngo Weinhold SHOW_FLOW0(3, ""); 440*4535495dSIngo Weinhold 441*4535495dSIngo Weinhold if (device->node != NULL) { 442*4535495dSIngo Weinhold // device is registered 443*4535495dSIngo Weinhold pnp->put_node(device->node); 444*4535495dSIngo Weinhold } else { 445*4535495dSIngo Weinhold // device is temporary 446*4535495dSIngo Weinhold scsi_free_device(device); 447*4535495dSIngo Weinhold } 448*4535495dSIngo Weinhold 449*4535495dSIngo Weinhold release_sem(bus->scan_lun_lock); 450*4535495dSIngo Weinhold } 451*4535495dSIngo Weinhold 452*4535495dSIngo Weinhold 453*4535495dSIngo Weinhold static uchar 454*4535495dSIngo Weinhold scsi_reset_device(scsi_device_info *device) 455*4535495dSIngo Weinhold { 456*4535495dSIngo Weinhold SHOW_FLOW0(3, ""); 457*4535495dSIngo Weinhold 458*4535495dSIngo Weinhold if (device->node == NULL) 459*4535495dSIngo Weinhold return SCSI_DEV_NOT_THERE; 460*4535495dSIngo Weinhold 461*4535495dSIngo Weinhold return device->bus->interface->reset_device(device->bus->sim_cookie, 462*4535495dSIngo Weinhold device->target_id, device->target_lun); 463*4535495dSIngo Weinhold } 464*4535495dSIngo Weinhold 465*4535495dSIngo Weinhold 466*4535495dSIngo Weinhold static status_t 467*4535495dSIngo Weinhold scsi_ioctl(scsi_device_info *device, uint32 op, void *buffer, size_t length) 468*4535495dSIngo Weinhold { 469*4535495dSIngo Weinhold if (device->bus->interface->ioctl != NULL) { 470*4535495dSIngo Weinhold return device->bus->interface->ioctl(device->bus->sim_cookie, 471*4535495dSIngo Weinhold device->target_id, op, buffer, length); 472*4535495dSIngo Weinhold } 473*4535495dSIngo Weinhold 474*4535495dSIngo Weinhold return B_BAD_VALUE; 475*4535495dSIngo Weinhold } 476*4535495dSIngo Weinhold 477*4535495dSIngo Weinhold 478*4535495dSIngo Weinhold static status_t 479*4535495dSIngo Weinhold std_ops(int32 op, ...) 480*4535495dSIngo Weinhold { 481*4535495dSIngo Weinhold switch (op) { 482*4535495dSIngo Weinhold case B_MODULE_INIT: 483*4535495dSIngo Weinhold { 484*4535495dSIngo Weinhold // Link to SCSI bus. 485*4535495dSIngo Weinhold // SCSI device driver must have SCSI bus loaded, but it calls its functions 486*4535495dSIngo Weinhold // directly instead via official interface, so this pointer is never read. 487*4535495dSIngo Weinhold module_info *dummy; 488*4535495dSIngo Weinhold return get_module(SCSI_BUS_MODULE_NAME, &dummy); 489*4535495dSIngo Weinhold } 490*4535495dSIngo Weinhold case B_MODULE_UNINIT: 491*4535495dSIngo Weinhold return put_module(SCSI_BUS_MODULE_NAME); 492*4535495dSIngo Weinhold 493*4535495dSIngo Weinhold default: 494*4535495dSIngo Weinhold return B_ERROR; 495*4535495dSIngo Weinhold } 496*4535495dSIngo Weinhold } 497*4535495dSIngo Weinhold 498*4535495dSIngo Weinhold 499*4535495dSIngo Weinhold scsi_device_interface scsi_device_module = { 500*4535495dSIngo Weinhold { 501*4535495dSIngo Weinhold { 502*4535495dSIngo Weinhold SCSI_DEVICE_MODULE_NAME, 503*4535495dSIngo Weinhold 0, 504*4535495dSIngo Weinhold std_ops 505*4535495dSIngo Weinhold }, 506*4535495dSIngo Weinhold 507*4535495dSIngo Weinhold NULL, // supported devices 508*4535495dSIngo Weinhold NULL, // register node 509*4535495dSIngo Weinhold scsi_init_device, 510*4535495dSIngo Weinhold (void (*)(void *)) scsi_uninit_device, 511*4535495dSIngo Weinhold NULL, // register child devices 512*4535495dSIngo Weinhold NULL, // rescan 513*4535495dSIngo Weinhold (void (*)(void *)) scsi_device_removed 514*4535495dSIngo Weinhold }, 515*4535495dSIngo Weinhold 516*4535495dSIngo Weinhold scsi_alloc_ccb, 517*4535495dSIngo Weinhold scsi_free_ccb, 518*4535495dSIngo Weinhold 519*4535495dSIngo Weinhold scsi_async_io, 520*4535495dSIngo Weinhold scsi_sync_io, 521*4535495dSIngo Weinhold scsi_abort, 522*4535495dSIngo Weinhold scsi_reset_device, 523*4535495dSIngo Weinhold scsi_term_io, 524*4535495dSIngo Weinhold scsi_ioctl, 525*4535495dSIngo Weinhold }; 526