Example #1
0
static char *sg_malloc(int size)
{
    if (size<=4096)
        return (char *) scsi_malloc(size);
#ifdef SG_BIG_BUFF
    if (size<=SG_BIG_BUFF)
    {
        while(big_inuse)
        {
            interruptible_sleep_on(&big_wait);
            if (signal_pending(current))
                return NULL;
        }
        big_inuse=1;
        return big_buff;
    }
#endif
    return NULL;
}
Example #2
0
static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
{
    unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
    unsigned long addr = VTOP(cmd->SCp.ptr);

    /*
     * if the physical address has the wrong alignment, or if
     * physical address is bad, or if it is a write and at the
     * end of a physical memory chunk, then allocate a bounce
     * buffer
     */
    if (addr & A3000_XFER_MASK ||
	(!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
    {
	HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
	    & ~0x1ff;
	HDATA(a3000_host)->dma_bounce_buffer =
	    scsi_malloc (HDATA(a3000_host)->dma_bounce_len);
	
	/* can't allocate memory; use PIO */
	if (!HDATA(a3000_host)->dma_bounce_buffer) {
	    HDATA(a3000_host)->dma_bounce_len = 0;
	    return 1;
	}

	if (!dir_in) {
	    /* copy to bounce buffer for a write */
	    if (cmd->use_sg) {
		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
			cmd->SCp.ptr, cmd->SCp.this_residual);
	    } else
		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
			cmd->request_buffer, cmd->request_bufflen);
	}

	addr = VTOP(HDATA(a3000_host)->dma_bounce_buffer);
    }

    /* setup dma direction */
    if (!dir_in)
	cntr |= CNTR_DDIR;

    /* remember direction */
    HDATA(a3000_host)->dma_dir = dir_in;

    DMA(a3000_host)->CNTR = cntr;

    /* setup DMA *physical* address */
    DMA(a3000_host)->ACR = addr;

    if (dir_in)
  	/* invalidate any cache */
	cache_clear (addr, cmd->SCp.this_residual);
    else
	/* push any dirty cache */
	cache_push (addr, cmd->SCp.this_residual);

    /* start DMA */
    DMA(a3000_host)->ST_DMA = 1;

    /* return success */
    return 0;
}
Example #3
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
}
static int ioctl_command(Scsi_Device *dev, void *buffer)
{
	char * buf;
	char cmd[12];
	char * cmd_in;
	Scsi_Cmnd * SCpnt;
	unsigned char opcode;
	int inlen, outlen, cmdlen;
	int needed;
	int result;

	if (!buffer)
		return -EINVAL;
	
	inlen = get_fs_long((unsigned long *) buffer);
	outlen = get_fs_long( ((unsigned long *) buffer) + 1);

	cmd_in = (char *) ( ((int *)buffer) + 2);
	opcode = get_fs_byte(cmd_in); 

	needed = (inlen > outlen ? inlen : outlen);
	if(needed){
	  needed = (needed + 511) & ~511;
	  if (needed > MAX_BUF) needed = MAX_BUF;
	  buf = (char *) scsi_malloc(needed);
	  if (!buf) return -ENOMEM;
	} else
	  buf = NULL;

	memcpy_fromfs ((void *) cmd,  cmd_in,  cmdlen = COMMAND_SIZE (opcode));
	memcpy_fromfs ((void *) buf,  (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen);

	cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);

#ifndef DEBUG_NO_CMD
	
	SCpnt = allocate_device(NULL, dev->index, 1);

	scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,  MAX_TIMEOUT, 
			MAX_RETRIES);

	if (SCpnt->request.dev != 0xfffe){
	  SCpnt->request.waiting = current;
	  current->state = TASK_UNINTERRUPTIBLE;
	  while (SCpnt->request.dev != 0xfffe) schedule();
	};


	/* 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;
	  memcpy_tofs((void *) cmd_in,  SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
	} else {

	  result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF  : outlen);
	  if (result)
	    return result;
	  memcpy_tofs ((void *) cmd_in,  buf,  (outlen > MAX_BUF) ? MAX_BUF  : outlen);
	};
	result = SCpnt->result;
	SCpnt->request.dev = -1;  /* Mark as not busy */
	if (buf) scsi_free(buf, needed);
	wake_up(&scsi_devices[SCpnt->index].device_wait);
	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
}
int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
{
	char *buf;
	unsigned char cmd[MAX_COMMAND_SIZE];
	char *cmd_in;
	Scsi_Request *SRpnt;
	Scsi_Device *SDpnt;
	unsigned char opcode;
	unsigned int inlen, outlen, cmdlen;
	unsigned int needed, buf_needed;
	int timeout, retries, result;
	int data_direction;

	if (!sic)
		return -EINVAL;
	/*
	 * Verify that we can read at least this much.
	 */
	if (verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command)))
		return -EFAULT;

	if(__get_user(inlen, &sic->inlen))
		return -EFAULT;
		
	if(__get_user(outlen, &sic->outlen))
		return -EFAULT;

	/*
	 * 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 (sg) instead.
	 */
	if (inlen > MAX_BUF)
		return -EINVAL;
	if (outlen > MAX_BUF)
		return -EINVAL;

	cmd_in = sic->data;
	if(get_user(opcode, cmd_in))
		return -EFAULT;

	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;
		buf = (char *) scsi_malloc(buf_needed);
		if (!buf)
			return -ENOMEM;
		memset(buf, 0, buf_needed);
		if( inlen == 0 ) {
			data_direction = SCSI_DATA_READ;
		} else if (outlen == 0 ) {
			data_direction = SCSI_DATA_WRITE;
		} else {
			/*
			 * Can this ever happen?
			 */
			data_direction = SCSI_DATA_UNKNOWN;
		}

	} else {
		buf = NULL;
		data_direction = SCSI_DATA_NONE;
	}

	/*
	 * Obtain the command from the user's address space.
	 */
	cmdlen = COMMAND_SIZE(opcode);
	
	result = -EFAULT;

	if (verify_area(VERIFY_READ, cmd_in, cmdlen + inlen))
		goto error;

	if(__copy_from_user(cmd, cmd_in, cmdlen))
		goto error;

	/*
	 * Obtain the data to be sent to the device (if any).
	 */

	if(copy_from_user(buf, cmd_in + cmdlen, inlen))
		goto error;

	/*
	 * Set the lun field to the correct value.
	 */
	if (dev->scsi_level <= SCSI_2)
		cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5);

	switch (opcode) {
	case SEND_DIAGNOSTIC:
	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;
	case READ_DEFECT_DATA:
		timeout = READ_DEFECT_DATA_TIMEOUT;
		retries = 1;
		break;
	default:
		timeout = IOCTL_NORMAL_TIMEOUT;
		retries = NORMAL_RETRIES;
		break;
	}

#ifndef DEBUG_NO_CMD


	SRpnt = scsi_allocate_request(dev);
        if( SRpnt == NULL )
        {
                result = -EINTR;
                goto error;
        }

	SRpnt->sr_data_direction = data_direction;
        scsi_wait_req(SRpnt, cmd, buf, needed, timeout, retries);

	/* 
	 * If there was an error condition, pass the info back to the user. 
	 */

	result = SRpnt->sr_result;

	if (SRpnt->sr_result) {
		int sb_len = sizeof(SRpnt->sr_sense_buffer);

		sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len;
		if (copy_to_user(cmd_in, SRpnt->sr_sense_buffer, sb_len))
			result = -EFAULT;
	} else {
		if (copy_to_user(cmd_in, buf, outlen))
			result = -EFAULT;
	}	

	SDpnt = SRpnt->sr_device;
	scsi_release_request(SRpnt);
	SRpnt = NULL;

error:
	if (buf)
		scsi_free(buf, buf_needed);


	return result;
#else
	{
		int i;
		printk("scsi_ioctl : device %d.  command = ", dev->id);
		for (i = 0; i < cmdlen; ++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
}