/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
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"); }
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"); }
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; }
/* * 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; }
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"); }
/* * 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; }
/* * 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; }
/** * 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)); }
/* * 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; }
/* * 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; }
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; }
/* * 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 }
/* * 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; }
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 }
/** * 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; }
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; }
/* 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
int get_scsi_command_size(unsigned char op) { return COMMAND_SIZE(op); }
/* 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; }
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; }