/* * 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 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; }
static int ioctl_internal_command(Scsi_Device *dev, char * cmd, int timeout, int retries) { unsigned long flags; int result; Scsi_Cmnd * SCpnt; Scsi_Device * SDpnt; spin_lock_irqsave(&io_request_lock, flags); SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0])); SCpnt = scsi_allocate_device(NULL, dev, 1); { struct semaphore sem = MUTEX_LOCKED; SCpnt->request.sem = &sem; scsi_do_cmd(SCpnt, cmd, NULL, 0, scsi_ioctl_done, timeout, retries); spin_unlock_irqrestore(&io_request_lock, flags); down(&sem); spin_lock_irqsave(&io_request_lock, flags); SCpnt->request.sem = NULL; } SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", SCpnt->result)); if(driver_byte(SCpnt->result) != 0) switch(SCpnt->sense_buffer[2] & 0xf) { case ILLEGAL_REQUEST: if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0; else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); break; case NOT_READY: /* This happens if there is no disc in drive */ if(dev->removable && (cmd[0] != TEST_UNIT_READY)){ printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); break; } case UNIT_ATTENTION: if (dev->removable){ dev->changed = 1; SCpnt->result = 0; /* This is no longer considered an error */ /* gag this error, VFS will log it anyway /axboe */ /* printk(KERN_INFO "Disc change detected.\n"); */ break; }; default: /* Fall through for non-removable media */ printk("SCSI error: host %d id %d lun %d return code = %x\n", dev->host->host_no, dev->id, dev->lun, SCpnt->result); printk("\tSense class %x, sense error %x, extended sense %x\n", sense_class(SCpnt->sense_buffer[0]), sense_error(SCpnt->sense_buffer[0]), SCpnt->sense_buffer[2] & 0xf); }; result = SCpnt->result; SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); SDpnt = SCpnt->device; scsi_release_command(SCpnt); SCpnt = NULL; if (!SDpnt->was_reset && SDpnt->scsi_request_fn) (*SDpnt->scsi_request_fn)(); wake_up(&SDpnt->device_wait); spin_unlock_irqrestore(&io_request_lock, flags); return result; }