Exemplo n.º 1
0
/*
 * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
 * @sdev: sdev the command should be sent to
 */
static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
{
	struct request *rq;
	int err = SCSI_DH_RES_TEMP_UNAVAIL;

	rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
	if (!rq)
		goto done;

	/* Prepare the command. */
	rq->cmd[0] = MAINTENANCE_IN;
	rq->cmd[1] = MI_REPORT_TARGET_PGS;
	rq->cmd[6] = (h->bufflen >> 24) & 0xff;
	rq->cmd[7] = (h->bufflen >> 16) & 0xff;
	rq->cmd[8] = (h->bufflen >>  8) & 0xff;
	rq->cmd[9] = h->bufflen & 0xff;
	rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);

	rq->sense = h->sense;
	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
	rq->sense_len = h->senselen = 0;

	err = blk_execute_rq(rq->q, NULL, rq, 1);
	if (err == -EIO) {
		sdev_printk(KERN_INFO, sdev,
			    "%s: rtpg failed with %x\n",
			    ALUA_DH_NAME, rq->errors);
		h->senselen = rq->sense_len;
		err = SCSI_DH_IO;
	}
	blk_put_request(rq);
done:
	return err;
}
Exemplo n.º 2
0
/*
 * submit_stpg - Issue a SET TARGET GROUP STATES command
 *
 * Currently we're only setting the current target port group state
 * to 'active/optimized' and let the array firmware figure out
 * the states of the remaining groups.
 */
static unsigned submit_stpg(struct alua_dh_data *h)
{
	struct request *rq;
	int stpg_len = 8;
	struct scsi_device *sdev = h->sdev;

	/* Prepare the data buffer */
	memset(h->buff, 0, stpg_len);
	h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
	put_unaligned_be16(h->group_id, &h->buff[6]);

	rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
	if (!rq)
		return SCSI_DH_RES_TEMP_UNAVAIL;

	/* Prepare the command. */
	rq->cmd[0] = MAINTENANCE_OUT;
	rq->cmd[1] = MO_SET_TARGET_PGS;
	put_unaligned_be32(stpg_len, &rq->cmd[6]);
	rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);

	rq->sense = h->sense;
	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
	rq->sense_len = 0;
	rq->end_io_data = h;

	blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
	return SCSI_DH_OK;
}
Exemplo n.º 3
0
/*
 * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command
 * @sdev: sdev the command should be sent to
 */
static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
{
	struct request *rq;
	int err = SCSI_DH_RES_TEMP_UNAVAIL;

	rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
	if (!rq)
		goto done;

	/* Prepare the command. */
	rq->cmd[0] = INQUIRY;
	rq->cmd[1] = 1;
	rq->cmd[2] = 0x83;
	rq->cmd[4] = h->bufflen;
	rq->cmd_len = COMMAND_SIZE(INQUIRY);

	rq->sense = h->sense;
	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
	rq->sense_len = h->senselen = 0;

	err = blk_execute_rq(rq->q, NULL, rq, 1);
	if (err == -EIO) {
		sdev_printk(KERN_INFO, sdev,
			    "%s: evpd inquiry failed with %x\n",
			    ALUA_DH_NAME, rq->errors);
		h->senselen = rq->sense_len;
		err = SCSI_DH_IO;
	}
	blk_put_request(rq);
done:
	return err;
}
Exemplo n.º 4
0
/*
 * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
 * @sdev: sdev the command should be sent to
 */
static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
{
	struct request *rq;
	int err = 0;

	rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
	if (!rq) {
		err = DRIVER_BUSY << 24;
		goto done;
	}

	/* Prepare the command. */
	rq->cmd[0] = MAINTENANCE_IN;
	if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP))
		rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
	else
		rq->cmd[1] = MI_REPORT_TARGET_PGS;
	put_unaligned_be32(h->bufflen, &rq->cmd[6]);
	rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);

	rq->sense = h->sense;
	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
	rq->sense_len = 0;

	blk_execute_rq(rq->q, NULL, rq, 1);
	if (rq->errors)
		err = rq->errors;
	blk_put_request(rq);
done:
	return err;
}
Exemplo n.º 5
0
/*
 * hp_sw_get_request - Allocate an HP specific path activation request
 * @path: path on which request will be sent (needed for request queue)
 *
 * The START command is used for path activation request.
 * These arrays are controller-based failover, not LUN based.
 * One START command issued to a single path will fail over all
 * LUNs for the same controller.
 *
 * Possible optimizations
 * 1. Make timeout configurable
 * 2. Preallocate request
 */
static struct request *hp_sw_get_request(struct dm_path *path)
{
    struct request *req;
    struct block_device *bdev = path->dev->bdev;
    struct request_queue *q = bdev_get_queue(bdev);
    struct hp_sw_context *h = path->hwhcontext;

    req = blk_get_request(q, WRITE, GFP_NOIO);
    if (!req)
        goto out;

    req->timeout = 60 * HZ;

    req->errors = 0;
    req->cmd_type = REQ_TYPE_BLOCK_PC;
    req->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
    req->end_io_data = path;
    req->sense = h->sense;
    memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);

    req->cmd[0] = START_STOP;
    req->cmd[4] = 1;
    req->cmd_len = COMMAND_SIZE(req->cmd[0]);

out:
    return req;
}
Exemplo n.º 6
0
void print_command (unsigned char *command) {
  int i,s;
  print_opcode(command[0]);
  for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) 
  	printk("%02x ", command[i]);
  printk("\n");
}
Exemplo n.º 7
0
static void print_commandk (unsigned char *command)
{
	int i,s;
	printk(KERN_DEBUG);
	print_opcodek(command[0]);
	/*printk(KERN_DEBUG __FUNCTION__ " ");*/
	for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) {
		printk("%02x ", command[i]);
	}
	switch (COMMAND_SIZE(command[0])) {
	case 6:
		printk("LBA=%d len=%d",
		       (((unsigned int)command[1] & 0x0f) << 16) |
		       ( (unsigned int)command[2]         <<  8) |
		       ( (unsigned int)command[3]              ),
		       (unsigned int)command[4]
			);
		break;
	case 10:
		printk("LBA=%d len=%d",
		       ((unsigned int)command[2] << 24) |
		       ((unsigned int)command[3] << 16) |
		       ((unsigned int)command[4] <<  8) |
		       ((unsigned int)command[5]      ),
		       ((unsigned int)command[7] <<  8) |
		       ((unsigned int)command[8]      )
		       );
		break;
	case 12:
		printk("LBA=%d len=%d",
		       ((unsigned int)command[2] << 24) |
		       ((unsigned int)command[3] << 16) |
		       ((unsigned int)command[4] <<  8) |
		       ((unsigned int)command[5]      ),
		       ((unsigned int)command[6] << 24) |
		       ((unsigned int)command[7] << 16) |
		       ((unsigned int)command[8] <<  8) |
		       ((unsigned int)command[9]      )
		       );
		break;
	default:
		break;
	}
	printk("\n");
}
Exemplo n.º 8
0
static struct request *emc_trespass_get(struct emc_handler *h,
					struct path *path)
{
	struct bio *bio;
	struct request *rq;
	unsigned char *page22;
	unsigned char long_trespass_pg[] = {
		0, 0, 0, 0,
		TRESPASS_PAGE,        /* Page code */
		0x09,                 /* Page length - 2 */
		h->hr ? 0x01 : 0x81,  /* Trespass code + Honor reservation bit */
		0xff, 0xff,           /* Trespass target */
		0, 0, 0, 0, 0, 0      /* Reserved bytes / unknown */
		};
	unsigned char short_trespass_pg[] = {
		0, 0, 0, 0,
		TRESPASS_PAGE,        /* Page code */
		0x02,                 /* Page length - 2 */
		h->hr ? 0x01 : 0x81,  /* Trespass code + Honor reservation bit */
		0xff,                 /* Trespass target */
		};
	unsigned data_size = h->short_trespass ? sizeof(short_trespass_pg) :
				sizeof(long_trespass_pg);

	/* get bio backing */
	if (data_size > PAGE_SIZE)
		/* this should never happen */
		return NULL;

	bio = get_failover_bio(path, data_size);
	if (!bio) {
		DMERR("dm-emc: emc_trespass_get: no bio");
		return NULL;
	}

	page22 = (unsigned char *)bio_data(bio);
	memset(page22, 0, data_size);

	memcpy(page22, h->short_trespass ?
		short_trespass_pg : long_trespass_pg, data_size);

	/* get request for block layer packet command */
	rq = get_failover_req(h, bio, path);
	if (!rq) {
		DMERR("dm-emc: emc_trespass_get: no rq");
		free_bio(bio);
		return NULL;
	}

	/* Prepare the command. */
	rq->cmd[0] = MODE_SELECT;
	rq->cmd[1] = 0x10;
	rq->cmd[4] = data_size;
	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);

	return rq;
}
Exemplo n.º 9
0
/*
 * Get block request for REQ_BLOCK_PC command issued to path.  Currently
 * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
 *
 * Uses data and sense buffers in hardware handler context structure and
 * assumes serial servicing of commands, both issuance and completion.
 */
static struct request *get_req(struct scsi_device *sdev, int cmd,
				unsigned char *buffer)
{
	struct request *rq;
	int len = 0;

	rq = blk_get_request(sdev->request_queue,
			(cmd != INQUIRY) ? WRITE : READ, GFP_NOIO);
	if (IS_ERR(rq)) {
		sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
		return NULL;
	}

	blk_rq_set_block_pc(rq);
	rq->cmd_len = COMMAND_SIZE(cmd);
	rq->cmd[0] = cmd;

	switch (cmd) {
	case MODE_SELECT:
		len = sizeof(short_trespass);
		rq->cmd[1] = 0x10;
		rq->cmd[4] = len;
		break;
	case MODE_SELECT_10:
		len = sizeof(long_trespass);
		rq->cmd[1] = 0x10;
		rq->cmd[8] = len;
		break;
	case INQUIRY:
		len = CLARIION_BUFFER_SIZE;
		rq->cmd[4] = len;
		memset(buffer, 0, len);
		break;
	default:
		BUG_ON(1);
		break;
	}

	rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
			 REQ_FAILFAST_DRIVER;
	rq->timeout = CLARIION_TIMEOUT;
	rq->retries = CLARIION_RETRIES;

	if (blk_rq_map_kern(rq->q, rq, buffer, len, GFP_NOIO)) {
		blk_put_request(rq);
		return NULL;
	}

	return rq;
}
Exemplo n.º 10
0
void __scsi_print_command(unsigned char *command)
{
	int k, len;

	print_opcode_name(command, 0, 1);
	if (VARIABLE_LENGTH_CMD == command[0])
		len = command[7] + 8;
	else
		len = COMMAND_SIZE(command[0]);
	/* print out all bytes in cdb */
	for (k = 0; k < len; ++k) 
		printk(" %02x", command[k]);
	printk("\n");
}
Exemplo n.º 11
0
/*
 * hp_sw_tur - Send TEST UNIT READY
 * @sdev: sdev command should be sent to
 *
 * Use the TEST UNIT READY command to determine
 * the path state.
 */
static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
{
	struct request *req;
	int ret;

retry:
	req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
	if (IS_ERR(req))
		return SCSI_DH_RES_TEMP_UNAVAIL;

	blk_rq_set_block_pc(req);
	req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
			  REQ_FAILFAST_DRIVER;
	req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
	req->cmd[0] = TEST_UNIT_READY;
	req->timeout = HP_SW_TIMEOUT;
	req->sense = h->sense;
	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
	req->sense_len = 0;

	ret = blk_execute_rq(req->q, NULL, req, 1);
	if (ret == -EIO) {
		if (req->sense_len > 0) {
			ret = tur_done(sdev, h->sense);
		} else {
			sdev_printk(KERN_WARNING, sdev,
				    "%s: sending tur failed with %x\n",
				    HP_SW_NAME, req->errors);
			ret = SCSI_DH_IO;
		}
	} else {
		h->path_state = HP_SW_PATH_ACTIVE;
		ret = SCSI_DH_OK;
	}
	if (ret == SCSI_DH_IMM_RETRY) {
		blk_put_request(req);
		goto retry;
	}
	if (ret == SCSI_DH_DEV_OFFLINED) {
		h->path_state = HP_SW_PATH_PASSIVE;
		ret = SCSI_DH_OK;
	}

	blk_put_request(req);

	return ret;
}
Exemplo n.º 12
0
/*
 * Common code to make Scsi_Cmnd
 */
static void init_scsi_command(Scsi_Device *sdev, Scsi_Cmnd *scmd, void *buf, int len, unsigned char direction, int set_lun)
{
	struct Scsi_Host *host	= scmd->host;

	scmd->sc_magic	= SCSI_CMND_MAGIC;
	scmd->owner	= SCSI_OWNER_MIDLEVEL;
	scmd->device	= sdev;
	scmd->host	= sdev->host;
	scmd->target	= sdev->id;
	scmd->lun	= sdev->lun;
	scmd->channel	= sdev->channel;
	scmd->buffer	= scmd->request_buffer = buf;
	scmd->bufflen	= scmd->request_bufflen = len;


	scmd->sc_data_direction = direction;

	memcpy(scmd->data_cmnd, scmd->cmnd, sizeof(scmd->cmnd));
	scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
	scmd->old_cmd_len = scmd->cmd_len;


	if (set_lun)
		scmd->cmnd[1] |= (sdev->scsi_level <= SCSI_2) ?
				  ((scmd->lun << 5) & 0xe0) : 0;

	scmd->transfersize = sdev->sector_size;
	if (direction == SCSI_DATA_WRITE)
		scmd->underflow = len;

	scmd->allowed = MAX_RETRIES;
	scmd->timeout_per_command = SD_TIMEOUT;

	/*
	 * This is the completion routine we use.  This is matched in terms
	 * of capability to this function.
	 */
	scmd->done = rw_intr;

	/*
	 * Some low driver put eh_timeout into the timer list.
	 */
	init_timer(&scmd->eh_timeout);
	scmd->eh_timeout.data		= (unsigned long)scmd;
	scmd->eh_timeout.function	= eh_timeout;
}
Exemplo n.º 13
0
/**
 * usb_stor_prep_cmd  - Save a scsi command info as part of error recovery
 * @scmd:       SCSI command structure to hijack
 * @ses:        structure to save restore information
 * @sensebuf:   a buffer to store sense data
 *
 * This function is used to save a scsi command information before re-execution
 * as part of the error recovery process.  This functions sets up a REQUEST_SENSE 
 * command and cmnd buffers to read sense data into @sensebuf.
 **/
static void usb_stor_prep_cmd(struct scsi_cmnd *scmd,
	 struct scsi_eh_save *ses, unsigned char *sensebuf)
{
	struct scsi_device *sdev = scmd->device;

	/*
	 * We need saved copies of a number of fields - this is because
	 * error handling may need to overwrite these with different values
	 * to run different commands, and once error handling is complete,
	 * we will need to restore these values prior to running the actual
	 * command.
	 */

	ses->cmd_len = scmd->cmd_len;
	memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd));
	ses->data_direction = scmd->sc_data_direction;
	ses->bufflen = scmd->request_bufflen;
	ses->buffer = scmd->request_buffer;
	ses->use_sg = scmd->use_sg;
	ses->resid = scmd->resid;
	ses->result = scmd->result;

	scmd->request_bufflen = min_t(unsigned, 
				sizeof(scmd->sense_buffer), US_SENSE_SIZE);
	scmd->request_buffer = sensebuf;
	scmd->sc_data_direction = DMA_FROM_DEVICE;
	scmd->use_sg = 0;
	memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
	scmd->cmnd[0] = REQUEST_SENSE;
	scmd->cmnd[4] = scmd->request_bufflen;
	scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
	scmd->underflow = 0;

	if (sdev->scsi_level <= SCSI_2 && sdev->scsi_level != SCSI_UNKNOWN)
		scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
			(sdev->lun << 5 & 0xe0);

	/*
	 * Zero the sense buffer.  The scsi spec mandates that any
	 * untransferred sense data should be interpreted as being zero.
	 */
	memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
}
Exemplo n.º 14
0
/*
 * Function:    scsi_init_cmd_errh()
 *
 * Purpose:     Initialize SCpnt fields related to error handling.
 *
 * Arguments:   SCpnt   - command that is ready to be queued.
 *
 * Returns:     Nothing
 *
 * Notes:       This function has the job of initializing a number of
 *              fields related to error handling.   Typically this will
 *              be called once for each command, as required.
 */
int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt)
{
	ASSERT_LOCK(&io_request_lock, 0);

	SCpnt->owner = SCSI_OWNER_MIDLEVEL;
	SCpnt->reset_chain = NULL;
	SCpnt->serial_number = 0;
	SCpnt->serial_number_at_timeout = 0;
	SCpnt->flags = 0;
	SCpnt->retries = 0;

	SCpnt->abort_reason = 0;

	memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);

	if (SCpnt->cmd_len == 0)
		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);

	/*
	 * We need saved copies of a number of fields - this is because
	 * error handling may need to overwrite these with different values
	 * to run different commands, and once error handling is complete,
	 * we will need to restore these values prior to running the actual
	 * command.
	 */
	SCpnt->old_use_sg = SCpnt->use_sg;
	SCpnt->old_cmd_len = SCpnt->cmd_len;
	SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
	SCpnt->old_underflow = SCpnt->underflow;
	memcpy((void *) SCpnt->data_cmnd,
	       (const void *) SCpnt->cmnd, sizeof(SCpnt->cmnd));
	SCpnt->buffer = SCpnt->request_buffer;
	SCpnt->bufflen = SCpnt->request_bufflen;

	SCpnt->reset_chain = NULL;

	SCpnt->internal_timeout = NORMAL_TIMEOUT;
	SCpnt->abort_reason = 0;

	return 1;
}
Exemplo n.º 15
0
/*
 * hp_sw_start_stop - Send START STOP UNIT command
 * @sdev: sdev command should be sent to
 *
 * Sending START STOP UNIT activates the SP.
 */
static int hp_sw_start_stop(struct hp_sw_dh_data *h)
{
	struct request *req;

	req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC);
	if (IS_ERR(req))
		return SCSI_DH_RES_TEMP_UNAVAIL;

	blk_rq_set_block_pc(req);
	req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
			  REQ_FAILFAST_DRIVER;
	req->cmd_len = COMMAND_SIZE(START_STOP);
	req->cmd[0] = START_STOP;
	req->cmd[4] = 1;	/* Start spin cycle */
	req->timeout = HP_SW_TIMEOUT;
	req->sense = h->sense;
	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
	req->sense_len = 0;
	req->end_io_data = h;

	blk_execute_rq_nowait(req->q, NULL, req, 1, start_stop_endio);
	return SCSI_DH_OK;
}
Exemplo n.º 16
0
static int sg_scsi_ioctl(struct file *file, request_queue_t *q,
                         struct gendisk *bd_disk, Scsi_Ioctl_Command __user *sic)
{
    struct request *rq;
    int err, in_len, out_len, bytes, opcode, cmdlen;
    char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE];

    /*
     * get in an out lengths, verify they don't exceed a page worth of data
     */
    if (get_user(in_len, &sic->inlen))
        return -EFAULT;
    if (get_user(out_len, &sic->outlen))
        return -EFAULT;
    if (in_len > PAGE_SIZE || out_len > PAGE_SIZE)
        return -EINVAL;
    if (get_user(opcode, sic->data))
        return -EFAULT;

    bytes = max(in_len, out_len);
    if (bytes) {
        buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER);
        if (!buffer)
            return -ENOMEM;

        memset(buffer, 0, bytes);
    }

    rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);

    cmdlen = COMMAND_SIZE(opcode);

    /*
     * get command and data to send to device, if any
     */
    err = -EFAULT;
    rq->cmd_len = cmdlen;
    if (copy_from_user(rq->cmd, sic->data, cmdlen))
        goto error;

    if (copy_from_user(buffer, sic->data + cmdlen, in_len))
        goto error;

    err = verify_command(file, rq->cmd);
    if (err)
        goto error;

    switch (opcode) {
    case SEND_DIAGNOSTIC:
    case FORMAT_UNIT:
        rq->timeout = FORMAT_UNIT_TIMEOUT;
        break;
    case START_STOP:
        rq->timeout = START_STOP_TIMEOUT;
        break;
    case MOVE_MEDIUM:
        rq->timeout = MOVE_MEDIUM_TIMEOUT;
        break;
    case READ_ELEMENT_STATUS:
        rq->timeout = READ_ELEMENT_STATUS_TIMEOUT;
        break;
    case READ_DEFECT_DATA:
        rq->timeout = READ_DEFECT_DATA_TIMEOUT;
        break;
    default:
        rq->timeout = BLK_DEFAULT_TIMEOUT;
        break;
    }

    memset(sense, 0, sizeof(sense));
    rq->sense = sense;
    rq->sense_len = 0;

    rq->data = buffer;
    rq->data_len = bytes;
    rq->flags |= REQ_BLOCK_PC;

    blk_execute_rq(q, bd_disk, rq);
    err = rq->errors & 0xff;	/* only 8 bit SCSI status */
    if (err) {
        if (rq->sense_len && rq->sense) {
            bytes = (OMAX_SB_LEN > rq->sense_len) ?
                    rq->sense_len : OMAX_SB_LEN;
            if (copy_to_user(sic->data, rq->sense, bytes))
                err = -EFAULT;
        }
    } else {
        if (copy_to_user(sic->data, buffer, out_len))
            err = -EFAULT;
    }

error:
    kfree(buffer);
    blk_put_request(rq);
    return err;
}
Exemplo n.º 17
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
}
Exemplo n.º 18
0
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
}
Exemplo n.º 19
0
/*
* Get block request for REQ_BLOCK_PC command issued to path.  Currently
* limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
*
* Uses data and sense buffers in hardware handler context structure and
* assumes serial servicing of commands, both issuance and completion.
*/
static struct request *get_req(struct scsi_device *sdev, int cmd)
{
	struct clariion_dh_data *csdev = get_clariion_data(sdev);
	struct request *rq;
	unsigned char *page22;
	int len = 0;

	rq = blk_get_request(sdev->request_queue,
			(cmd == MODE_SELECT) ? WRITE : READ, GFP_ATOMIC);
	if (!rq) {
		sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
		return NULL;
	}

	memset(&rq->cmd, 0, BLK_MAX_CDB);
	rq->cmd[0] = cmd;
	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);

	switch (cmd) {
	case MODE_SELECT:
		if (csdev->short_trespass) {
			page22 = csdev->hr ? short_trespass_hr : short_trespass;
			len = sizeof(short_trespass);
		} else {
			page22 = csdev->hr ? long_trespass_hr : long_trespass;
			len = sizeof(long_trespass);
		}
		/*
		 * Can't DMA from kernel BSS -- must copy selected trespass
		 * command mode page contents to context buffer which is
		 * allocated by kmalloc.
		 */
		BUG_ON((len > CLARIION_BUFFER_SIZE));
		memcpy(csdev->buffer, page22, len);
		rq->cmd_flags |= REQ_RW;
		rq->cmd[1] = 0x10;
		break;
	case INQUIRY:
		rq->cmd[1] = 0x1;
		rq->cmd[2] = 0xC0;
		len = CLARIION_BUFFER_SIZE;
		memset(csdev->buffer, 0, CLARIION_BUFFER_SIZE);
		break;
	default:
		BUG_ON(1);
		break;
	}

	rq->cmd[4] = len;
	rq->cmd_type = REQ_TYPE_BLOCK_PC;
	rq->cmd_flags |= REQ_FAILFAST;
	rq->timeout = CLARIION_TIMEOUT;
	rq->retries = CLARIION_RETRIES;

	rq->sense = csdev->sense;
	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
	rq->sense_len = 0;

	if (blk_rq_map_kern(sdev->request_queue, rq, csdev->buffer,
							len, GFP_ATOMIC)) {
		__blk_put_request(rq->q, rq);
		return NULL;
	}

	return rq;
}
Exemplo n.º 20
0
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, gfp_mask = GFP_KERNEL;

	if (!sic)
		return -EINVAL;

	if (dev->host->unchecked_isa_dma)
		gfp_mask |= GFP_DMA;

	/*
	 * 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 *) kmalloc(buf_needed, gfp_mask);
		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 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)
		kfree(buf);


	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
}
Exemplo n.º 21
0
/**
 * sg_scsi_ioctl  --  handle deprecated SCSI_IOCTL_SEND_COMMAND ioctl
 * @q:		request queue to send scsi commands down
 * @disk:	gendisk to operate on (option)
 * @mode:	mode used to open the file through which the ioctl has been
 *		submitted
 * @sic:	userspace structure describing the command to perform
 *
 * Send down the scsi command described by @sic to the device below
 * the request queue @q.  If @file is non-NULL it's used to perform
 * fine-grained permission checks that allow users to send down
 * non-destructive SCSI commands.  If the caller has a struct gendisk
 * available it should be passed in as @disk to allow the low level
 * driver to use the information contained in it.  A non-NULL @disk
 * is only allowed if the caller knows that the low level driver doesn't
 * need it (e.g. in the scsi subsystem).
 *
 * Notes:
 *   -  This interface is deprecated - users should use the SG_IO
 *      interface instead, as this is a more flexible approach to
 *      performing SCSI commands on a device.
 *   -  The SCSI command length is determined by examining the 1st byte
 *      of the given command. There is no way to override this.
 *   -  Data transfers are limited to PAGE_SIZE
 *   -  The length (x + y) must be at least OMAX_SB_LEN bytes long to
 *      accommodate the sense buffer when an error occurs.
 *      The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that
 *      old code will not be surprised.
 *   -  If a Unix error occurs (e.g. ENOMEM) then the user will receive
 *      a negative return and the Unix error code in 'errno'.
 *      If the SCSI command succeeds then 0 is returned.
 *      Positive numbers returned are the compacted SCSI error codes (4
 *      bytes in one int) where the lowest byte is the SCSI status.
 */
int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
		struct scsi_ioctl_command __user *sic)
{
	enum { OMAX_SB_LEN = 16 };	/* For backward compatibility */
	struct request *rq;
	struct scsi_request *req;
	int err;
	unsigned int in_len, out_len, bytes, opcode, cmdlen;
	char *buffer = NULL;

	if (!sic)
		return -EINVAL;

	/*
	 * get in an out lengths, verify they don't exceed a page worth of data
	 */
	if (get_user(in_len, &sic->inlen))
		return -EFAULT;
	if (get_user(out_len, &sic->outlen))
		return -EFAULT;
	if (in_len > PAGE_SIZE || out_len > PAGE_SIZE)
		return -EINVAL;
	if (get_user(opcode, sic->data))
		return -EFAULT;

	bytes = max(in_len, out_len);
	if (bytes) {
		buffer = kzalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN);
		if (!buffer)
			return -ENOMEM;

	}

	rq = blk_get_request(q, in_len ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0);
	if (IS_ERR(rq)) {
		err = PTR_ERR(rq);
		goto error_free_buffer;
	}
	req = scsi_req(rq);

	cmdlen = COMMAND_SIZE(opcode);

	/*
	 * get command and data to send to device, if any
	 */
	err = -EFAULT;
	req->cmd_len = cmdlen;
	if (copy_from_user(req->cmd, sic->data, cmdlen))
		goto error;

	if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
		goto error;

	err = blk_verify_command(req->cmd, mode);
	if (err)
		goto error;

	/* default.  possible overriden later */
	req->retries = 5;

	switch (opcode) {
	case SEND_DIAGNOSTIC:
	case FORMAT_UNIT:
		rq->timeout = FORMAT_UNIT_TIMEOUT;
		req->retries = 1;
		break;
	case START_STOP:
		rq->timeout = START_STOP_TIMEOUT;
		break;
	case MOVE_MEDIUM:
		rq->timeout = MOVE_MEDIUM_TIMEOUT;
		break;
	case READ_ELEMENT_STATUS:
		rq->timeout = READ_ELEMENT_STATUS_TIMEOUT;
		break;
	case READ_DEFECT_DATA:
		rq->timeout = READ_DEFECT_DATA_TIMEOUT;
		req->retries = 1;
		break;
	default:
		rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
		break;
	}

	if (bytes && blk_rq_map_kern(q, rq, buffer, bytes, GFP_NOIO)) {
		err = DRIVER_ERROR << 24;
		goto error;
	}

	blk_execute_rq(q, disk, rq, 0);

	err = req->result & 0xff;	/* only 8 bit SCSI status */
	if (err) {
		if (req->sense_len && req->sense) {
			bytes = (OMAX_SB_LEN > req->sense_len) ?
				req->sense_len : OMAX_SB_LEN;
			if (copy_to_user(sic->data, req->sense, bytes))
				err = -EFAULT;
		}
	} else {
		if (copy_to_user(sic->data, buffer, out_len))
			err = -EFAULT;
	}
	
error:
	blk_put_request(rq);

error_free_buffer:
	kfree(buffer);

	return err;
}
Exemplo n.º 22
0
int scsi_ioctl_send_command(struct scsi_device *sdev,
			    struct scsi_ioctl_command __user *sic)
{
	char *buf;
	unsigned char cmd[MAX_COMMAND_SIZE];
	char __user *cmd_in;
	struct scsi_request *sreq;
	unsigned char opcode;
	unsigned int inlen, outlen, cmdlen;
	unsigned int needed, buf_needed;
	int timeout, retries, result;
	int data_direction, gfp_mask = GFP_KERNEL;

	if (!sic)
		return -EINVAL;

	if (sdev->host->unchecked_isa_dma)
		gfp_mask |= GFP_DMA;

	/*
	 * Verify that we can read at least this much.
	 */
	if (!access_ok(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 = kmalloc(buf_needed, gfp_mask);
		if (!buf)
			return -ENOMEM;
		memset(buf, 0, buf_needed);
		if (inlen == 0) {
			data_direction = DMA_FROM_DEVICE;
		} else if (outlen == 0 ) {
			data_direction = DMA_TO_DEVICE;
		} else {
			/*
			 * Can this ever happen?
			 */
			data_direction = DMA_BIDIRECTIONAL;
		}

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

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

	if (!access_ok(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;

	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;
	}

	sreq = scsi_allocate_request(sdev, GFP_KERNEL);
        if (!sreq) {
                result = -EINTR;
                goto error;
        }

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

	/* 
	 * If there was an error condition, pass the info back to the user. 
	 */
	result = sreq->sr_result;
	if (result) {
		int sb_len = sizeof(sreq->sr_sense_buffer);

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

	scsi_release_request(sreq);
error:
	kfree(buf);
	return result;
}
Exemplo n.º 23
0
/* Detect all SSAs attached to the machine.
   To be fast, do it on all online FC channels at the same time. */
__initfunc(int pluto_detect(Scsi_Host_Template *tpnt))
{
	int i, retry, nplutos;
	fc_channel *fc;
	Scsi_Device dev;

	tpnt->proc_dir = &proc_scsi_pluto;
	fcscount = 0;
	for_each_online_fc_channel(fc)
		fcscount++;
	PLND(("%d channels online\n", fcscount))
	if (!fcscount) {
#if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KMOD)
		request_module("soc");
		
		for_each_online_fc_channel(fc)
			fcscount++;
		if (!fcscount)
#endif
			return 0;
	}
	fcs = (struct ctrl_inquiry *) scsi_init_malloc (sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA);
	if (!fcs) {
		printk ("PLUTO: Not enough memory to probe\n");
		return 0;
	}
	
	memset (fcs, 0, sizeof (struct ctrl_inquiry) * fcscount);
	memset (&dev, 0, sizeof(dev));
	atomic_set (&fcss, fcscount);
	fc_timer.function = pluto_detect_timeout;
	
	i = 0;
	for_each_online_fc_channel(fc) {
		Scsi_Cmnd *SCpnt;
		struct Scsi_Host *host;
		struct pluto *pluto;
		
		if (i == fcscount) break;
		
		PLD(("trying to find SSA\n"))

		/* If this is already registered to some other SCSI host, then it cannot be pluto */
		if (fc->scsi_name[0]) continue;
		memcpy (fc->scsi_name, "SSA", 4);
		
		fcs[i].fc = fc;
		
		fc->can_queue = PLUTO_CAN_QUEUE;
		fc->rsp_size = 64;
		fc->encode_addr = pluto_encode_addr;
		
		fc->fcp_register(fc, TYPE_SCSI_FCP, 0);
	
		SCpnt = &(fcs[i].cmd);
		host = &(fcs[i].host);
		pluto = (struct pluto *)host->hostdata;
		
		pluto->fc = fc;
	
		SCpnt->host = host;
		SCpnt->cmnd[0] = INQUIRY;
		SCpnt->cmnd[4] = 255;
		
		/* FC layer requires this, so that SCpnt->device->tagged_supported is initially 0 */
		SCpnt->device = &dev;
		
		SCpnt->cmd_len = COMMAND_SIZE(INQUIRY);
	
		SCpnt->request.rq_status = RQ_SCSI_BUSY;
		
		SCpnt->done = pluto_detect_done;
		SCpnt->bufflen = 256;
		SCpnt->buffer = fcs[i].inquiry;
		SCpnt->request_bufflen = 256;
		SCpnt->request_buffer = fcs[i].inquiry;
		PLD(("set up %d %08lx\n", i, (long)SCpnt))
		i++;
	}
	
	for (retry = 0; retry < 5; retry++) {
		for (i = 0; i < fcscount; i++) {
			if (!fcs[i].fc) break;
			if (fcs[i].cmd.request.rq_status != RQ_SCSI_DONE) {
				disable_irq(fcs[i].fc->irq);
				PLND(("queuecommand %d %d\n", retry, i))
				fcp_scsi_queuecommand (&(fcs[i].cmd), 
					pluto_detect_scsi_done);
				enable_irq(fcs[i].fc->irq);
			}
		}
	    
		fc_timer.expires = jiffies + 10 * HZ;
		add_timer(&fc_timer);
		
		down(&fc_sem);
		PLND(("Woken up\n"))
		if (!atomic_read(&fcss))
			break; /* All fc channels have answered us */
	}
	del_timer(&fc_timer);

	PLND(("Finished search\n"))
	for (i = 0, nplutos = 0; i < fcscount; i++) {
		Scsi_Cmnd *SCpnt;
		
		if (!(fc = fcs[i].fc)) break;
	
		SCpnt = &(fcs[i].cmd);
		
		/* Let FC mid-level free allocated resources */
		SCpnt->done (SCpnt);
		
		if (!SCpnt->result) {
			struct pluto_inquiry *inq;
			struct pluto *pluto;
			struct Scsi_Host *host;
			
			inq = (struct pluto_inquiry *)fcs[i].inquiry;

			if ((inq->dtype & 0x1f) == TYPE_PROCESSOR &&
			    !strncmp (inq->vendor_id, "SUN", 3) &&
			    !strncmp (inq->product_id, "SSA", 3)) {
				char *p;
				long *ages;
				
				ages = kmalloc (((inq->channels + 1) * inq->targets) * sizeof(long), GFP_KERNEL);
				if (!ages) continue;
				
				host = scsi_register (tpnt, sizeof (struct pluto));
				if (!host) panic ("Cannot register PLUTO host\n");
				
				nplutos++;
				
				if (fc->module) __MOD_INC_USE_COUNT(fc->module);
				
				pluto = (struct pluto *)host->hostdata;
				
				host->max_id = inq->targets;
				host->max_channel = inq->channels;
				host->irq = fc->irq;
				
				host->select_queue_depths = pluto_select_queue_depths;
				
				fc->channels = inq->channels + 1;
				fc->targets = inq->targets;
				fc->ages = ages;
				memset (ages, 0, ((inq->channels + 1) * inq->targets) * sizeof(long));
				
				pluto->fc = fc;
				memcpy (pluto->rev_str, inq->revision, 4);
				pluto->rev_str[4] = 0;
				p = strchr (pluto->rev_str, ' ');
				if (p) *p = 0;
				memcpy (pluto->fw_rev_str, inq->fw_revision, 4);
				pluto->fw_rev_str[4] = 0;
				p = strchr (pluto->fw_rev_str, ' ');
				if (p) *p = 0;
				memcpy (pluto->serial_str, inq->serial, 12);
				pluto->serial_str[12] = 0;
				p = strchr (pluto->serial_str, ' ');
				if (p) *p = 0;
				
				PLD(("Found SSA rev %s fw rev %s serial %s %dx%d\n", pluto->rev_str, pluto->fw_rev_str, pluto->serial_str, host->max_channel, host->max_id))
			} else
				fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
		} else
Exemplo n.º 24
0
int get_scsi_command_size(unsigned char op)
{
	return COMMAND_SIZE(op);
}
Exemplo n.º 25
0
/* Do the scsi command. Waits until command performed if do_wait is true.
   Otherwise osst_write_behind_check() is used to check that the command
   has finished. */
static	struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct osst_tape *STp, 
	unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
{
	unsigned char *bp;
	unsigned short use_sg;
#ifdef OSST_INJECT_ERRORS
	static   int   inject = 0;
	static   int   repeat = 0;
#endif
	struct completion *waiting;

	/* if async, make sure there's no command outstanding */
	if (!do_wait && ((STp->buffer)->last_SRpnt)) {
		printk(KERN_ERR "%s: Async command already active.\n",
		       tape_name(STp));
		if (signal_pending(current))
			(STp->buffer)->syscall_result = (-EINTR);
		else
			(STp->buffer)->syscall_result = (-EBUSY);
		return NULL;
	}

	if (SRpnt == NULL) {
		SRpnt = osst_allocate_request();
		if (SRpnt == NULL) {
			printk(KERN_ERR "%s: Can't allocate SCSI request.\n",
				     tape_name(STp));
			if (signal_pending(current))
				(STp->buffer)->syscall_result = (-EINTR);
			else
				(STp->buffer)->syscall_result = (-EBUSY);
			return NULL;
		}
		SRpnt->stp = STp;
	}

	/* If async IO, set last_SRpnt. This ptr tells write_behind_check
	   which IO is outstanding. It's nulled out when the IO completes. */
	if (!do_wait)
		(STp->buffer)->last_SRpnt = SRpnt;

	waiting = &STp->wait;
	init_completion(waiting);
	SRpnt->waiting = waiting;

	use_sg = (bytes > STp->buffer->sg[0].length) ? STp->buffer->use_sg : 0;
	if (use_sg) {
		bp = (char *)&(STp->buffer->sg[0]);
		if (STp->buffer->sg_segs < use_sg)
			use_sg = STp->buffer->sg_segs;
	}
	else
		bp = (STp->buffer)->b_data;

	memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));
	STp->buffer->cmdstat.have_sense = 0;
	STp->buffer->syscall_result = 0;

	if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes,
			 use_sg, timeout, retries))
		/* could not allocate the buffer or request was too large */
		(STp->buffer)->syscall_result = (-EBUSY);
	else if (do_wait) {
		wait_for_completion(waiting);
		SRpnt->waiting = NULL;
		STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
#ifdef OSST_INJECT_ERRORS
		if (STp->buffer->syscall_result == 0 &&
		    cmd[0] == READ_6 &&
		    cmd[4] && 
		    ( (++ inject % 83) == 29  ||
		      (STp->first_frame_position == 240 
			         /* or STp->read_error_frame to fail again on the block calculated above */ &&
				 ++repeat < 3))) {
			printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp));
			STp->buffer->last_result_fatal = 1;
		}
#endif
	}
	return SRpnt;
}
/**
 * sg_scsi_ioctl  --  handle deprecated SCSI_IOCTL_SEND_COMMAND ioctl
 * @file:	file this ioctl operates on (optional)
 * @q:		request queue to send scsi commands down
 * @disk:	gendisk to operate on (option)
 * @sic:	userspace structure describing the command to perform
 *
 * Send down the scsi command described by @sic to the device below
 * the request queue @q.  If @file is non-NULL it's used to perform
 * fine-grained permission checks that allow users to send down
 * non-destructive SCSI commands.  If the caller has a struct gendisk
 * available it should be passed in as @disk to allow the low level
 * driver to use the information contained in it.  A non-NULL @disk
 * is only allowed if the caller knows that the low level driver doesn't
 * need it (e.g. in the scsi subsystem).
 *
 * Notes:
 *   -  This interface is deprecated - users should use the SG_IO
 *      interface instead, as this is a more flexible approach to
 *      performing SCSI commands on a device.
 *   -  The SCSI command length is determined by examining the 1st byte
 *      of the given command. There is no way to override this.
 *   -  Data transfers are limited to PAGE_SIZE
 *   -  The length (x + y) must be at least OMAX_SB_LEN bytes long to
 *      accommodate the sense buffer when an error occurs.
 *      The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that
 *      old code will not be surprised.
 *   -  If a Unix error occurs (e.g. ENOMEM) then the user will receive
 *      a negative return and the Unix error code in 'errno'.
 *      If the SCSI command succeeds then 0 is returned.
 *      Positive numbers returned are the compacted SCSI error codes (4
 *      bytes in one int) where the lowest byte is the SCSI status.
 */
#define OMAX_SB_LEN 16          /* For backward compatibility */
int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
		struct scsi_ioctl_command __user *sic)
{
	struct request *rq;
	int err;
	unsigned int in_len, out_len, bytes, opcode, cmdlen;
	char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE];

	if (!sic)
		return -EINVAL;

	/*
	 * get in an out lengths, verify they don't exceed a page worth of data
	 */
	if (get_user(in_len, &sic->inlen))
		return -EFAULT;
	if (get_user(out_len, &sic->outlen))
		return -EFAULT;
	if (in_len > PAGE_SIZE || out_len > PAGE_SIZE)
		return -EINVAL;
	if (get_user(opcode, sic->data))
		return -EFAULT;

	bytes = max(in_len, out_len);
	if (bytes) {
		buffer = kzalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN);
		if (!buffer)
			return -ENOMEM;

	}

	rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);

	cmdlen = COMMAND_SIZE(opcode);

	/*
	 * get command and data to send to device, if any
	 */
	err = -EFAULT;
	rq->cmd_len = cmdlen;
	if (copy_from_user(rq->cmd, sic->data, cmdlen))
		goto error;

	if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
		goto error;

	err = blk_verify_command(rq->cmd, mode & FMODE_WRITE);
	if (err)
		goto error;

	/* default.  possible overriden later */
	rq->retries = 5;

	switch (opcode) {
	case SEND_DIAGNOSTIC:
	case FORMAT_UNIT:
		rq->timeout = FORMAT_UNIT_TIMEOUT;
		rq->retries = 1;
		break;
	case START_STOP:
		rq->timeout = START_STOP_TIMEOUT;
		break;
	case MOVE_MEDIUM:
		rq->timeout = MOVE_MEDIUM_TIMEOUT;
		break;
	case READ_ELEMENT_STATUS:
		rq->timeout = READ_ELEMENT_STATUS_TIMEOUT;
		break;
	case READ_DEFECT_DATA:
		rq->timeout = READ_DEFECT_DATA_TIMEOUT;
		rq->retries = 1;
		break;
	default:
		rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
		break;
	}

	if (bytes && blk_rq_map_kern(q, rq, buffer, bytes, __GFP_WAIT)) {
		err = DRIVER_ERROR << 24;
		goto out;
	}

	memset(sense, 0, sizeof(sense));
	rq->sense = sense;
	rq->sense_len = 0;
	rq->cmd_type = REQ_TYPE_BLOCK_PC;

	blk_execute_rq(q, disk, rq, 0);

out:
	err = rq->errors & 0xff;	/* only 8 bit SCSI status */
	if (err) {
		if (rq->sense_len && rq->sense) {
			bytes = (OMAX_SB_LEN > rq->sense_len) ?
				rq->sense_len : OMAX_SB_LEN;
			if (copy_to_user(sic->data, rq->sense, bytes))
				err = -EFAULT;
		}
	} else {
		if (copy_to_user(sic->data, buffer, out_len))
			err = -EFAULT;
	}
	
error:
	kfree(buffer);
	blk_put_request(rq);
	return err;
}
Exemplo n.º 27
0
static ssize_t sg_write(struct file *filp, const char *buf,
                        size_t count, loff_t *ppos)
{
    unsigned long	  flags;
    struct inode         *inode = filp->f_dentry->d_inode;
    int			  bsize,size,amt,i;
    unsigned char	  cmnd[MAX_COMMAND_SIZE];
    kdev_t		  devt = inode->i_rdev;
    int			  dev = MINOR(devt);
    struct scsi_generic   * device=&scsi_generics[dev];
    int			  input_size;
    unsigned char	  opcode;
    Scsi_Cmnd		* SCpnt;

    /*
     * If we are in the middle of error recovery, don't let anyone
     * else try and use this device.  Also, if error recovery fails, it
     * may try and take the device offline, in which case all further
     * access to the device is prohibited.
     */
    if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
    {
        return -ENXIO;
    }

    if (ppos != &filp->f_pos) {
        /* FIXME: Hmm.  Seek to the right place, or fail?  */
    }

    if ((i=verify_area(VERIFY_READ,buf,count)))
        return i;
    /*
     * The minimum scsi command length is 6 bytes.  If we get anything
     * less than this, it is clearly bogus.
     */
    if (count<(sizeof(struct sg_header) + 6))
        return -EIO;

    /*
     * If we still have a result pending from a previous command,
     * wait until the result has been read by the user before sending
     * another command.
     */
    while(device->pending)
    {
        if (filp->f_flags & O_NONBLOCK)
            return -EAGAIN;
#ifdef DEBUG
        printk("sg_write: sleeping on pending request\n");
#endif
        interruptible_sleep_on(&device->write_wait);
        if (signal_pending(current))
            return -ERESTARTSYS;
    }

    /*
     * Mark the device flags for the new state.
     */
    device->pending=1;
    device->complete=0;
    copy_from_user(&device->header,buf,sizeof(struct sg_header));

    device->header.pack_len=count;
    buf+=sizeof(struct sg_header);

    /*
     * Now we need to grab the command itself from the user's buffer.
     */
    get_user(opcode, buf);
    size=COMMAND_SIZE(opcode);
    if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;

    /*
     * Determine buffer size.
     */
    input_size = device->header.pack_len - size;
    if( input_size > device->header.reply_len)
    {
        bsize = input_size;
    } else {
        bsize = device->header.reply_len;
    }

    /*
     * Don't include the command header itself in the size.
     */
    bsize-=sizeof(struct sg_header);
    input_size-=sizeof(struct sg_header);

    /*
     * Verify that the user has actually passed enough bytes for this command.
     */
    if( input_size < 0 )
    {
        device->pending=0;
        wake_up( &device->write_wait );
        return -EIO;
    }

    /*
     * Allocate a buffer that is large enough to hold the data
     * that has been requested.  Round up to an even number of sectors,
     * since scsi_malloc allocates in chunks of 512 bytes.
     */
    amt=bsize;
    if (!bsize)
        bsize++;
    bsize=(bsize+511) & ~511;

    /*
     * If we cannot allocate the buffer, report an error.
     */
    if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize)))
    {
        device->pending=0;
        wake_up(&device->write_wait);
        return -ENOMEM;
    }

#ifdef DEBUG
    printk("allocating device\n");
#endif

    /*
     * Grab a device pointer for the device we want to talk to.  If we
     * don't want to block, just return with the appropriate message.
     */
    if (!(SCpnt=scsi_allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
    {
        device->pending=0;
        wake_up(&device->write_wait);
        sg_free(device->buff,device->buff_len);
        device->buff = NULL;
        return -EAGAIN;
    }
#ifdef DEBUG
    printk("device allocated\n");
#endif

    SCpnt->request.rq_dev = devt;
    SCpnt->request.rq_status = RQ_ACTIVE;
    SCpnt->sense_buffer[0]=0;
    SCpnt->cmd_len = size;

    /*
     * Now copy the SCSI command from the user's address space.
     */
    copy_from_user(cmnd,buf,size);
    buf+=size;

    /*
     * If we are writing data, copy the data we are writing.  The pack_len
     * field also includes the length of the header and the command,
     * so we need to subtract these off.
     */
    if (input_size > 0) copy_from_user(device->buff, buf, input_size);

    /*
     * Set the LUN field in the command structure.
     */
    cmnd[1]= (cmnd[1] & 0x1f) | (device->device->lun<<5);

#ifdef DEBUG
    printk("do cmd\n");
#endif

    /*
     * Now pass the actual command down to the low-level driver.  We
     * do not do any more here - when the interrupt arrives, we will
     * then do the post-processing.
     */
    spin_lock_irqsave(&io_request_lock, flags);
    scsi_do_cmd (SCpnt,(void *) cmnd,
                 (void *) device->buff,amt,
                 sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
    spin_unlock_irqrestore(&io_request_lock, flags);

#ifdef DEBUG
    printk("done cmd\n");
#endif

    return count;
}