static void scsi_capacity_enter(struct scsi_dev *dev) { struct scsi_cmd cmd = scsi_cmd_template_cap10; cmd.scmd_obuf = dev->scsi_data_scratchpad; cmd.scmd_olen = sizeof(struct scsi_data_cap10); scsi_do_cmd(dev, &cmd); }
static void scsi_sense_enter(struct scsi_dev *dev) { struct scsi_cmd cmd = scsi_cmd_template_sense; cmd.scmd_obuf = dev->scsi_data_scratchpad; cmd.scmd_olen = sizeof(struct scsi_data_sense); scsi_do_cmd(dev, &cmd); }
/* Flush the write buffer */ static int flush_write_buffer(int dev) { int offset, transfer, blks; int result; unsigned char cmd[10]; Scsi_Cmnd *SCpnt; #if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS if (scsi_tapes[dev].buffer->writing) { write_behind_check(dev); if (scsi_tapes[dev].buffer->last_result) { #ifdef DEBUG printk("st%d: Async write error %x.\n", dev, scsi_tapes[dev].buffer->last_result); #endif return (-EIO); } } #endif result = 0; if (scsi_tapes[dev].dirty==1) { SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1); offset = scsi_tapes[dev].buffer->buffer_bytes; transfer = ((offset + scsi_tapes[dev].block_size - 1) / scsi_tapes[dev].block_size) * scsi_tapes[dev].block_size; #ifdef DEBUG printk("st%d: Flushing %d bytes.\n", dev, transfer); #endif memset(scsi_tapes[dev].buffer->b_data + offset, 0, transfer - offset); SCpnt->sense_buffer[0] = 0; memset(cmd, 0, 10); cmd[0] = WRITE_6; cmd[1] = 1; blks = transfer / scsi_tapes[dev].block_size; cmd[2] = blks >> 16; cmd[3] = blks >> 8; cmd[4] = blks; SCpnt->request.dev = dev; scsi_do_cmd (SCpnt, (void *) cmd, scsi_tapes[dev].buffer->b_data, transfer, st_sleep_done, ST_TIMEOUT, MAX_RETRIES); if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->result != 0) { printk("st%d: Error on flush:\n", dev); #ifdef DEBUG st_chk_result(dev, SCpnt->result, SCpnt->sense_buffer); #endif result = (-EIO); } else { scsi_tapes[dev].dirty = 0; scsi_tapes[dev].buffer->buffer_bytes = 0; } SCpnt->request.dev = -1; /* Mark as not busy */ }
static int ioctl_internal_command(Scsi_Device *dev, char * cmd, int timeout, int retries) { int result; Scsi_Cmnd * SCpnt; SCpnt = 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); down(&sem); } 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){ 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 */ 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; SCpnt->request.rq_status = RQ_INACTIVE; if (!SCpnt->device->was_reset && SCpnt->device->scsi_request_fn) (*SCpnt->device->scsi_request_fn)(); wake_up(&SCpnt->device->device_wait); return result; }
static int ioctl_internal_command(Scsi_Device *dev, char * cmd) { int host, result; Scsi_Cmnd * SCpnt; host = dev->host_no; SCpnt = allocate_device(NULL, dev->index, 1); scsi_do_cmd(SCpnt, cmd, NULL, 0, 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(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){ printk("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 */ printk("Disc change detected.\n"); break; }; default: /* Fall through for non-removable media */ printk("SCSI CD error: host %d id %d lun %d return code = %x\n", dev->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; SCpnt->request.dev = -1; /* Mark as not busy */ wake_up(&scsi_devices[SCpnt->index].device_wait); return result; }
static int do_ioctl( void ) { int retries = IOCTL_RETRIES; retry: the_result = -1; scsi_do_cmd(scsi_CDs[target].device->host_no, scsi_CDs[target].device->id, (void *) sr_cmd, (void *) data_buffer, 255, sr_ioctl_done, IOCTL_TIMEOUT, (void *) sense_buffer, 0); while (the_result < 0) sleep_on(&sr_cmd_wait); if(driver_byte(the_result) != 0 && (sense_buffer[2] & 0xf) == UNIT_ATTENTION) { scsi_CDs[target].changed = 1; printk("Disc change detected.\n"); }; if (the_result && retries) { retries--; goto retry; } /* Minimal error checking. Ignore cases we know about, and report the rest. */ if(driver_byte(the_result) != 0) switch(sense_buffer[2] & 0xf) { case UNIT_ATTENTION: scsi_CDs[target].changed = 1; printk("Disc change detected.\n"); break; case NOT_READY: /* This happens if there is no disc in drive */ printk("CDROM not ready. Make sure there is a disc in the drive.\n"); break; case ILLEGAL_REQUEST: printk("CDROM (ioctl) reports ILLEGAL REQUEST.\n"); break; default: printk("SCSI CD error: host %d id %d lun %d return code = %03x\n", scsi_CDs[target].device->host_no, scsi_CDs[target].device->id, scsi_CDs[target].device->lun, the_result); printk("\tSense class %x, sense error %x, extended sense %x\n", sense_class(sense_buffer[0]), sense_error(sense_buffer[0]), sense_buffer[2] & 0xf); }; return the_result; }
static int do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength) { Scsi_Cmnd * SCpnt; int result; SCpnt = allocate_device(NULL, scsi_CDs[target].device->index, 1); scsi_do_cmd(SCpnt, (void *) sr_cmd, buffer, buflength, sr_ioctl_done, IOCTL_TIMEOUT, IOCTL_RETRIES); if (SCpnt->request.dev != 0xfffe) { SCpnt->request.waiting = current; current->state = TASK_UNINTERRUPTIBLE; while (SCpnt->request.dev != 0xfffe) schedule(); }; result = SCpnt->result; /* Minimal error checking. Ignore cases we know about, and report the rest. */ if(driver_byte(result) != 0) switch(SCpnt->sense_buffer[2] & 0xf) { case UNIT_ATTENTION: scsi_CDs[target].device->changed = 1; printk("Disc change detected.\n"); break; case NOT_READY: /* This happens if there is no disc in drive */ printk("CDROM not ready. Make sure there is a disc in the drive.\n"); break; case ILLEGAL_REQUEST: printk("CDROM (ioctl) reports ILLEGAL REQUEST.\n"); break; default: printk("SCSI CD error: host %d id %d lun %d return code = %03x\n", scsi_CDs[target].device->host_no, scsi_CDs[target].device->id, scsi_CDs[target].device->lun, 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; SCpnt->request.dev = -1; /* Deallocate */ wake_up(&scsi_devices[SCpnt->index].device_wait); /* Wake up a process waiting for device*/ return result; }
static int scsi_wait_cmd_complete(struct scsi_dev *dev, struct scsi_cmd *cmd) { /* guards to send only one command */ if (!dev->in_cmd) { dev->in_cmd = 1; dev->cmd_complete = scsi_do_cmd(dev, cmd); } if (dev->cmd_complete) { dev->in_cmd = 0; return dev->cmd_complete; } return 0; }
static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) { int orig_length, drive, wb_mode; char cmnd[12]; int i, j, found; gdth_ha_str *ha; gdth_cmd_str gdtcmd; gdth_cpar_str *pcpar; TRACE2(("gdth_set_asc_info() ha %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); memset(cmnd, 0,10); orig_length = length + 5; drive = -1; wb_mode = 0; found = FALSE; if (length >= 5 && strncmp(buffer,"flush",5)==0) { buffer += 6; length -= 6; if (length && *buffer>='0' && *buffer<='9') { drive = (int)(*buffer-'0'); ++buffer; --length; if (length && *buffer>='0' && *buffer<='9') { drive = drive*10 + (int)(*buffer-'0'); ++buffer; --length; } printk("GDT: Flushing host drive %d .. ",drive); } else { printk("GDT: Flushing all host drives .. "); } for (i = 0; i < MAXBUS; ++i) { for (j = 0; j < MAXID; ++j) { if (ha->id[i][j].type == CACHE_DTYP) { if (drive != -1 && ha->id[i][j].hostdrive != (ushort)drive) continue; found = TRUE; gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_FLUSH; gdtcmd.u.cache.DeviceNo = ha->id[i][j].hostdrive; gdtcmd.u.cache.BlockNo = 1; gdtcmd.u.cache.sg_canz = 0; { struct semaphore sem = MUTEX_LOCKED; scp.request.rq_status = RQ_SCSI_BUSY; scp.request.sem = &sem; scsi_do_cmd(&scp, cmnd, &gdtcmd, sizeof(gdth_cmd_str), gdth_scsi_done, 30*HZ, 1); down(&sem); } } } } if (!found) printk("\nNo host drive found !\n"); else printk("Done.\n"); return(orig_length); } if (length >= 7 && strncmp(buffer,"wbp_off",7)==0) { buffer += 8; length -= 8; printk("GDT: Disabling write back permanently .. "); wb_mode = 1; } else if (length >= 6 && strncmp(buffer,"wbp_on",6)==0) { buffer += 7; length -= 7; printk("GDT: Enabling write back permanently .. "); wb_mode = 2; } else if (length >= 6 && strncmp(buffer,"wb_off",6)==0) { buffer += 7; length -= 7; printk("GDT: Disabling write back commands .. "); if (ha->cache_feat & GDT_WR_THROUGH) { gdth_write_through = TRUE; printk("Done.\n"); } else { printk("Not supported !\n"); } return(orig_length); } else if (length >= 5 && strncmp(buffer,"wb_on",5)==0) { buffer += 6; length -= 6; printk("GDT: Enabling write back commands .. "); gdth_write_through = FALSE; printk("Done.\n"); return(orig_length); } if (wb_mode) { pcpar = (gdth_cpar_str *)kmalloc( sizeof(gdth_cpar_str), GFP_ATOMIC | GFP_DMA ); if (pcpar == NULL) { TRACE2(("gdth_set_info(): Unable to allocate memory.\n")); printk("Unable to allocate memory.\n"); return(-EINVAL); } memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) ); gdtcmd.BoardNode = LOCALBOARD; gdtcmd.Service = CACHESERVICE; gdtcmd.OpCode = GDT_IOCTL; gdtcmd.u.ioctl.p_param = (ulong)pcpar; gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str); gdtcmd.u.ioctl.subfunc = CACHE_CONFIG; gdtcmd.u.ioctl.channel = INVALID_CHANNEL; pcpar->write_back = wb_mode==1 ? 0:1; { struct semaphore sem = MUTEX_LOCKED; scp.request.rq_status = RQ_SCSI_BUSY; scp.request.sem = &sem; scsi_do_cmd(&scp, cmnd, &gdtcmd, sizeof(gdth_cmd_str), gdth_scsi_done, 30*HZ, 1); down(&sem); } kfree( pcpar ); printk("Done.\n"); return(orig_length); } printk("GDT: Unknown command: %s Length: %d\n",buffer,length); return(-EINVAL); }
static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) { char cmnd[12]; int id; unchar i, j, k, found; gdth_ha_str *ha; gdth_iowr_str *piowr; gdth_iord_str *piord; gdth_cmd_str *pcmd; ulong *ppadd; ulong add_size, flags; TRACE2(("gdth_set_bin_info() ha %d\n",hanum)); ha = HADATA(gdth_ctr_tab[hanum]); memset(cmnd, 0,10); piowr = (gdth_iowr_str *)buffer; piord = NULL; pcmd = NULL; if (length < GDTOFFSOF(gdth_iowr_str,iu)) return(-EINVAL); switch (piowr->ioctl) { case GDTIOCTL_GENERAL: if (length < GDTOFFSOF(gdth_iowr_str,iu.general.data[0])) return(-EINVAL); pcmd = (gdth_cmd_str *)piowr->iu.general.command; pcmd->Service = piowr->service; if (pcmd->OpCode == GDT_IOCTL) { ppadd = &pcmd->u.ioctl.p_param; add_size = pcmd->u.ioctl.param_size; } else if (piowr->service == CACHESERVICE) { add_size = pcmd->u.cache.BlockCnt * SECTOR_SIZE; if (ha->cache_feat & SCATTER_GATHER) { ppadd = &pcmd->u.cache.sg_lst[0].sg_ptr; pcmd->u.cache.DestAddr = -1UL; pcmd->u.cache.sg_lst[0].sg_len = add_size; pcmd->u.cache.sg_canz = 1; } else { ppadd = &pcmd->u.cache.DestAddr; pcmd->u.cache.sg_canz = 0; } } else if (piowr->service == SCSIRAWSERVICE) { add_size = pcmd->u.raw.sdlen; if (ha->raw_feat & SCATTER_GATHER) { ppadd = &pcmd->u.raw.sg_lst[0].sg_ptr; pcmd->u.raw.sdata = -1UL; pcmd->u.raw.sg_lst[0].sg_len = add_size; pcmd->u.raw.sg_ranz = 1; } else { ppadd = &pcmd->u.raw.sdata; pcmd->u.raw.sg_ranz = 0; } } else { return(-EINVAL); } id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) + add_size ); if (id == -1) return(-EBUSY); piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum]; piord->size = sizeof(gdth_iord_str) + add_size; if (add_size > 0) { memcpy(piord->iu.general.data, piowr->iu.general.data, add_size); *ppadd = (ulong)piord->iu.general.data; } /* do IOCTL */ { struct semaphore sem = MUTEX_LOCKED; scp.request.rq_status = RQ_SCSI_BUSY; scp.request.sem = &sem; scp.SCp.this_residual = IOCTL_PRI; scsi_do_cmd(&scp, cmnd, pcmd, sizeof(gdth_cmd_str), gdth_scsi_done, piowr->timeout*HZ, 1); down(&sem); piord->status = (ulong)scp.SCp.Message; } break; case GDTIOCTL_DRVERS: id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ); if (id == -1) return(-EBUSY); piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum]; piord->size = sizeof(gdth_iord_str); piord->status = S_OK; piord->iu.drvers.version = (GDTH_VERSION<<8) | GDTH_SUBVERSION; break; case GDTIOCTL_CTRTYPE: id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ); if (id == -1) return(-EBUSY); piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum]; piord->size = sizeof(gdth_iord_str); piord->status = S_OK; if (ha->type == GDT_ISA || ha->type == GDT_EISA) { piord->iu.ctrtype.type = (unchar)((ha->stype>>20) - 10); } else if (ha->type != GDT_PCIMPR) {
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_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 }
/* * 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_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; }