Пример #1
0
/*
 * This function is called by the interrupt handler when we
 * actually have a command that is complete.  Change the
 * flags to indicate that we have a result.
 */
static void sg_command_done(Scsi_Cmnd * SCpnt)
{
    int dev = MINOR(SCpnt->request.rq_dev);
    struct scsi_generic *device = &scsi_generics[dev];
    if (!device->pending)
    {
        printk("unexpected done for sg %d\n",dev);
        scsi_release_command(SCpnt);
        SCpnt = NULL;
        return;
    }

    /*
     * See if the command completed normally, or whether something went
     * wrong.
     */
    memcpy(device->header.sense_buffer, SCpnt->sense_buffer,
           sizeof(SCpnt->sense_buffer));
    switch (host_byte(SCpnt->result)) {
    case DID_OK:
        device->header.result = 0;
        break;
    case DID_NO_CONNECT:
    case DID_BUS_BUSY:
    case DID_TIME_OUT:
        device->header.result = EBUSY;
        break;
    case DID_BAD_TARGET:
    case DID_ABORT:
    case DID_PARITY:
    case DID_RESET:
    case DID_BAD_INTR:
        device->header.result = EIO;
        break;
    case DID_ERROR:
        /*
         * There really should be DID_UNDERRUN and DID_OVERRUN error values,
         * and a means for callers of scsi_do_cmd to indicate whether an
         * underrun or overrun should signal an error.  Until that can be
         * implemented, this kludge allows for returning useful error values
         * except in cases that return DID_ERROR that might be due to an
         * underrun.
         */
        if (SCpnt->sense_buffer[0] == 0 &&
                status_byte(SCpnt->result) == GOOD)
            device->header.result = 0;
        else device->header.result = EIO;
        break;
    }

    /*
     * Now wake up the process that is waiting for the
     * result.
     */
    device->complete=1;
    scsi_release_command(SCpnt);
    SCpnt = NULL;
    wake_up(&scsi_generics[dev].read_wait);
}
Пример #2
0
/*
 * This interface is depreciated - users should use the scsi generics
 * interface instead, as this is a more flexible approach to performing
 * generic SCSI commands on a device.
 */
int scsi_ioctl_send_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
{
    unsigned long flags;
    char * buf;
    unsigned char cmd[12]; 
    char * cmd_in;
    Scsi_Cmnd * SCpnt;
    Scsi_Device * SDpnt;
    unsigned char opcode;
    int inlen, outlen, cmdlen;
    int needed, buf_needed;
    int timeout, retries, result;
    
    if (!sic)
	return -EINVAL;
    

    /*
     * Verify that we can read at least this much.
     */
    result = verify_area(VERIFY_READ, sic, sizeof (Scsi_Ioctl_Command));
    if (result) return result;

    /*
     * The structure that we are passed should look like:
     *
     * struct sdata {
     *	unsigned int inlen;
     *	unsigned int outlen;
     *	unsigned char  cmd[];  # However many bytes are used for cmd.
     *	unsigned char  data[];
     * };
     */
    get_user(inlen, &sic->inlen);
    get_user(outlen, &sic->outlen);
    
    /*
     * We do not transfer more than MAX_BUF with this interface.
     * If the user needs to transfer more data than this, they
     * should use scsi_generics instead.
     */
    if( inlen > MAX_BUF ) return -EINVAL;
    if( outlen > MAX_BUF ) return -EINVAL;

    cmd_in = sic->data;
    get_user(opcode, cmd_in); 
    
    needed = buf_needed = (inlen > outlen ? inlen : outlen);
    if(buf_needed){
	buf_needed = (buf_needed + 511) & ~511;
	if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
        spin_lock_irqsave(&io_request_lock, flags);
	buf = (char *) scsi_malloc(buf_needed);
        spin_unlock_irqrestore(&io_request_lock, flags);
	if (!buf) return -ENOMEM;
	memset(buf, 0, buf_needed);
    } else
	buf = NULL;
    
    /*
     * Obtain the command from the user's address space.
     */
    cmdlen = COMMAND_SIZE(opcode);

    result = verify_area(VERIFY_READ, cmd_in, 
                         cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen);
    if (result) return result;

    copy_from_user ((void *) cmd,  cmd_in,  cmdlen);
    
    /*
     * Obtain the data to be sent to the device (if any).
     */
    copy_from_user ((void *) buf,  
                   (void *) (cmd_in + cmdlen), 
                   inlen);
    
    /*
     * Set the lun field to the correct value.
     */
    cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
    
    switch (opcode)
      {
      case FORMAT_UNIT:
 	timeout = FORMAT_UNIT_TIMEOUT;
	retries = 1;
	break;
      case START_STOP:
 	timeout = START_STOP_TIMEOUT;
 	retries = NORMAL_RETRIES;
	break;
      case MOVE_MEDIUM:
 	timeout = MOVE_MEDIUM_TIMEOUT;
 	retries = NORMAL_RETRIES;
 	break;
      case READ_ELEMENT_STATUS:
 	timeout = READ_ELEMENT_STATUS_TIMEOUT;
 	retries = NORMAL_RETRIES;
	break;
      default:
 	timeout = NORMAL_TIMEOUT;
 	retries = NORMAL_RETRIES;
	break;
      }

#ifndef DEBUG_NO_CMD

    spin_lock_irqsave(&io_request_lock, flags);
    
    SCpnt = scsi_allocate_device(NULL, dev, 1);

    {
	struct semaphore sem = MUTEX_LOCKED;
	SCpnt->request.sem = &sem;
	scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,
		    timeout, retries);
	spin_unlock_irqrestore(&io_request_lock, flags);
	down(&sem);
        SCpnt->request.sem = NULL;
    }
    
    /* 
     * If there was an error condition, pass the info back to the user. 
     */
    if(SCpnt->result) {
        result = verify_area(VERIFY_WRITE, 
                             cmd_in, 
                             sizeof(SCpnt->sense_buffer));
        if (result) return result;
        copy_to_user((void *) cmd_in,  
                    SCpnt->sense_buffer, 
                    sizeof(SCpnt->sense_buffer));
    } else {
        result = verify_area(VERIFY_WRITE, cmd_in, outlen);
        if (result) return result;
        copy_to_user ((void *) cmd_in,  buf,  outlen);
    }
    result = SCpnt->result;

    spin_lock_irqsave(&io_request_lock, flags);

    wake_up(&SCpnt->device->device_wait);
    SDpnt = SCpnt->device;
    scsi_release_command(SCpnt);
    SCpnt = NULL;

    if (buf) scsi_free(buf, buf_needed);
    
    if(SDpnt->scsi_request_fn)
	(*SDpnt->scsi_request_fn)();
    
    spin_unlock_irqrestore(&io_request_lock, flags);
    return result;
#else
    {
	int i;
	printk("scsi_ioctl : device %d.  command = ", dev->id);
	for (i = 0; i < 12; ++i)
	    printk("%02x ", cmd[i]);
	printk("\nbuffer =");
	for (i = 0; i < 20; ++i)
	    printk("%02x ", buf[i]);
	printk("\n");
	printk("inlen = %d, outlen = %d, cmdlen = %d\n",
	       inlen, outlen, cmdlen);
	printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
    }
    return 0;
#endif
}
Пример #3
0
static int ioctl_internal_command(Scsi_Device *dev, char * cmd,
				  int timeout, int retries)
{
    unsigned long flags;
    int result;
    Scsi_Cmnd * SCpnt;
    Scsi_Device * SDpnt;

    spin_lock_irqsave(&io_request_lock, flags);

    SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0]));
    SCpnt = scsi_allocate_device(NULL, dev, 1);
    {
	struct semaphore sem = MUTEX_LOCKED;
	SCpnt->request.sem = &sem;
	scsi_do_cmd(SCpnt,  cmd, NULL,  0, scsi_ioctl_done,  timeout, retries);
	spin_unlock_irqrestore(&io_request_lock, flags);
	down(&sem);
        spin_lock_irqsave(&io_request_lock, flags);
        SCpnt->request.sem = NULL;
    }
    
    SCSI_LOG_IOCTL(2, printk("Ioctl returned  0x%x\n", SCpnt->result));

    if(driver_byte(SCpnt->result) != 0)
	switch(SCpnt->sense_buffer[2] & 0xf) {
	case ILLEGAL_REQUEST:
	    if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
	    else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
	    break;
	case NOT_READY: /* This happens if there is no disc in drive */
	    if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
		printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
		break;
	    }
	case UNIT_ATTENTION:
	    if (dev->removable){
		dev->changed = 1;
		SCpnt->result = 0; /* This is no longer considered an error */
		/* gag this error, VFS will log it anyway /axboe */
		/* printk(KERN_INFO "Disc change detected.\n"); */
		break;
	    };
	default: /* Fall through for non-removable media */
	    printk("SCSI error: host %d id %d lun %d return code = %x\n",
		   dev->host->host_no,
		   dev->id,
		   dev->lun,
		   SCpnt->result);
	    printk("\tSense class %x, sense error %x, extended sense %x\n",
		   sense_class(SCpnt->sense_buffer[0]),
		   sense_error(SCpnt->sense_buffer[0]),
		   SCpnt->sense_buffer[2] & 0xf);
	    
	};
    
    result = SCpnt->result;

    SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n"));
    SDpnt = SCpnt->device;
    scsi_release_command(SCpnt);
    SCpnt = NULL;

    if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
	(*SDpnt->scsi_request_fn)();

    wake_up(&SDpnt->device_wait);
    spin_unlock_irqrestore(&io_request_lock, flags);
    return result;
}