Ejemplo n.º 1
0
unsigned int scsi_init()
{
    static int called = 0;
    int i, pcount;
    Scsi_Host_Template * tpnt;
    struct Scsi_Host * shpnt;
    const char * name;
    
    if(called) return 0;
    
    called = 1;
    for (tpnt = &builtin_scsi_hosts[0], i = 0; i < MAX_SCSI_HOSTS; ++i, tpnt++)
    {
	/*
	 * Initialize our semaphores.  -1 is interpreted to mean
	 * "inactive" - where as 0 will indicate a time out condition.
	 */
	
	pcount = next_scsi_host;
	if ((tpnt->detect) &&
	    (tpnt->present =
	     tpnt->detect(tpnt)))
	{
	    /* The only time this should come up is when people use
	     * some kind of patched driver of some kind or another. */
	    if(pcount == next_scsi_host) {
		if(tpnt->present > 1)
		    panic("Failure to register low-level scsi driver");
		/* The low-level driver failed to register a driver.  We
		 * can do this now. */
		scsi_register(tpnt,0);
	    }
	    tpnt->next = scsi_hosts;
	    scsi_hosts = tpnt;

            /* Add the driver to /proc/scsi */
#if CONFIG_PROC_FS 
            build_proc_dir_entries(tpnt);    
#endif
	}
    }
        
    for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
    {
	if(shpnt->hostt->info)
	    name = shpnt->hostt->info(shpnt);
	else
	    name = shpnt->hostt->name;
	printk ("scsi%d : %s\n", /* And print a little message */
		shpnt->host_no, name);
    }
    
    printk ("scsi : %d host%s.\n", next_scsi_host,
	    (next_scsi_host == 1) ? "" : "s");
    
    scsi_make_blocked_list();
    
    /* Now attach the high level drivers */
#ifdef CONFIG_BLK_DEV_SD
    scsi_register_device(&sd_template);
#endif
#ifdef CONFIG_BLK_DEV_SR
    scsi_register_device(&sr_template);
#endif
#ifdef CONFIG_CHR_DEV_ST
    scsi_register_device(&st_template);
#endif
#ifdef CONFIG_CHR_DEV_SG
    scsi_register_device(&sg_template);
#endif
    
#if 0      
    max_scsi_hosts = next_scsi_host;
#endif
    return 0;
}
Ejemplo n.º 2
0
status_t
scsi_scan_lun(scsi_bus_info *bus, uchar target_id, uchar target_lun)
{
	scsi_ccb *worker_req;
	scsi_res_inquiry new_inquiry_data;
	status_t res;
	scsi_device_info *device;
	bool found;

	//snooze(1000000);

	SHOW_FLOW(3, "%d:%d:%d", bus->path_id, target_id, target_lun);

	res = scsi_force_get_device(bus, target_id, target_lun, &device);
	if (res != B_OK)
		goto err;

	//SHOW_FLOW(3, "temp_device: %d", (int)temp_device);

	worker_req = scsi_alloc_ccb(device);
	if (worker_req == NULL) {
		// there is no out-of-mem code
		res = B_NO_MEMORY;
		goto err2;
	}

	SHOW_FLOW0(3, "2");

	worker_req->flags = SCSI_DIR_IN;

	// to give controller a chance to transfer speed negotiation, we
	// send a TUR first; unfortunatily, some devices don't like TURing
	// invalid luns apart from lun 0...
	if (device->target_lun == 0) {
		if (!scsi_scan_send_tur(worker_req)) {
			// TBD: need better error code like "device not found"
			res = B_NAME_NOT_FOUND;
			goto err3;
		}
	}

	// get inquiry data to be used as identification
	// and to check whether there is a device at all
	found = scsi_scan_get_inquiry(worker_req, &new_inquiry_data)
		&& new_inquiry_data.device_qualifier == scsi_periph_qual_connected;

	// get rid of temporary device - as soon as the device is
	// registered, it can be loaded, and we don't want two data
	// structures for one device (the temporary and the official one)
	scsi_free_ccb(worker_req);
	scsi_put_forced_device(device);

	if (!found) {
		// TBD: better error code, s.a.
		return B_NAME_NOT_FOUND;
	}

	// !danger!
	// if a new device is detected on the same connection, all connections
	// to the old device are disabled;
	// scenario: you plug in a device, scan the bus, replace the device and then
	// open it; in this case, the connection seems to be to the old device, but really
	// is to the new one; if you scan the bus now, the opened connection is disabled
	// - bad luck -
	// solution 1: scan device during each scsi_init_device
	// disadvantage: it takes time and we had to submit commands during the load
	//   sequence, which could lead to deadlocks
	// solution 2: device drivers must scan devices before first use
	// disadvantage: it takes time and driver must perform a task that
	//   the bus_manager should really take care of
	res = scsi_register_device(bus, target_id, target_lun, &new_inquiry_data);
	if (res == B_NAME_IN_USE) {
		SHOW_FLOW0(3, "name in use");
		if (scsi_force_get_device(bus, target_id, target_lun, &device) != B_OK)
			return B_OK;
		// the device was already registered, let's tell our child to rescan it
		device_node *childNode = NULL;
		const device_attr attrs[] = { { NULL } };
		if (pnp->get_next_child_node(bus->node, attrs, &childNode) == B_OK) {
			pnp->rescan_node(childNode);
			pnp->put_node(childNode);
		}
		scsi_put_forced_device(device);
	}
	return B_OK;

err3:
	scsi_free_ccb(worker_req);
err2:
	scsi_put_forced_device(device);
err:
	return res;
}