diff options
Diffstat (limited to 'drivers/scsi/dpt_i2o.c')
| -rw-r--r-- | drivers/scsi/dpt_i2o.c | 225 |
1 files changed, 83 insertions, 142 deletions
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 496764349c4..c0ae8fa57a3 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -49,7 +49,6 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver"); #include <linux/kernel.h> /* for printk */ #include <linux/sched.h> #include <linux/reboot.h> -#include <linux/smp_lock.h> #include <linux/spinlock.h> #include <linux/dma-mapping.h> @@ -76,6 +75,7 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver"); * Needed for our management apps *============================================================================ */ +static DEFINE_MUTEX(adpt_mutex); static dpt_sig_S DPTI_sig = { {'d', 'P', 't', 'S', 'i', 'G'}, SIG_VERSION, #ifdef __i386__ @@ -114,17 +114,19 @@ static int hba_count = 0; static struct class *adpt_sysfs_class; +static long adpt_unlocked_ioctl(struct file *, unsigned int, unsigned long); #ifdef CONFIG_COMPAT static long compat_adpt_ioctl(struct file *, unsigned int, unsigned long); #endif static const struct file_operations adpt_fops = { - .ioctl = adpt_ioctl, + .unlocked_ioctl = adpt_unlocked_ioctl, .open = adpt_open, .release = adpt_close, #ifdef CONFIG_COMPAT .compat_ioctl = compat_adpt_ioctl, #endif + .llseek = noop_llseek, }; /* Structures and definitions for synchronous message posting. @@ -188,7 +190,8 @@ MODULE_DEVICE_TABLE(pci,dptids); static int adpt_detect(struct scsi_host_template* sht) { struct pci_dev *pDev = NULL; - adpt_hba* pHba; + adpt_hba *pHba; + adpt_hba *next; PINFO("Detecting Adaptec I2O RAID controllers...\n"); @@ -206,7 +209,8 @@ static int adpt_detect(struct scsi_host_template* sht) } /* In INIT state, Activate IOPs */ - for (pHba = hba_chain; pHba; pHba = pHba->next) { + for (pHba = hba_chain; pHba; pHba = next) { + next = pHba->next; // Activate does get status , init outbound, and get hrt if (adpt_i2o_activate_hba(pHba) < 0) { adpt_i2o_delete_hba(pHba); @@ -243,7 +247,8 @@ rebuild_sys_tab: PDEBUG("HBA's in OPERATIONAL state\n"); printk("dpti: If you have a lot of devices this could take a few minutes.\n"); - for (pHba = hba_chain; pHba; pHba = pHba->next) { + for (pHba = hba_chain; pHba; pHba = next) { + next = pHba->next; printk(KERN_INFO"%s: Reading the hardware resource table.\n", pHba->name); if (adpt_i2o_lct_get(pHba) < 0){ adpt_i2o_delete_hba(pHba); @@ -263,7 +268,8 @@ rebuild_sys_tab: adpt_sysfs_class = NULL; } - for (pHba = hba_chain; pHba; pHba = pHba->next) { + for (pHba = hba_chain; pHba; pHba = next) { + next = pHba->next; if (adpt_scsi_host_alloc(pHba, sht) < 0){ adpt_i2o_delete_hba(pHba); continue; @@ -417,7 +423,7 @@ static int adpt_slave_configure(struct scsi_device * device) return 0; } -static int adpt_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *)) +static int adpt_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *)) { adpt_hba* pHba = NULL; struct adpt_device* pDev = NULL; /* dpt per device information */ @@ -442,19 +448,8 @@ static int adpt_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *)) } rmb(); - /* - * TODO: I need to block here if I am processing ioctl cmds - * but if the outstanding cmds all finish before the ioctl, - * the scsi-core will not know to start sending cmds to me again. - * I need to a way to restart the scsi-cores queues or should I block - * calling scsi_done on the outstanding cmds instead - * for now we don't set the IOCTL state - */ - if(((pHba->state) & DPTI_STATE_IOCTL) || ((pHba->state) & DPTI_STATE_RESET)) { - pHba->host->last_reset = jiffies; - pHba->host->resetting = 1; - return 1; - } + if ((pHba->state) & DPTI_STATE_RESET) + return SCSI_MLQUEUE_HOST_BUSY; // TODO if the cmd->device if offline then I may need to issue a bus rescan // followed by a get_lct to see if the device is there anymore @@ -485,6 +480,8 @@ static int adpt_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *)) return adpt_scsi_to_i2o(pHba, cmd, pDev); } +static DEF_SCSI_QCMD(adpt_queue) + static int adpt_bios_param(struct scsi_device *sdev, struct block_device *dev, sector_t capacity, int geom[]) { @@ -545,36 +542,14 @@ static const char *adpt_info(struct Scsi_Host *host) return (char *) (pHba->detail); } -static int adpt_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, - int length, int inout) +static int adpt_show_info(struct seq_file *m, struct Scsi_Host *host) { struct adpt_device* d; int id; int chan; - int len = 0; - int begin = 0; - int pos = 0; adpt_hba* pHba; int unit; - *start = buffer; - if (inout == TRUE) { - /* - * The user has done a write and wants us to take the - * data in the buffer and do something with it. - * proc_scsiwrite calls us with inout = 1 - * - * Read data from buffer (writing to us) - NOT SUPPORTED - */ - return -EINVAL; - } - - /* - * inout = 0 means the user has done a read and wants information - * returned, so we write information about the cards into the buffer - * proc_scsiread() calls us with inout = 0 - */ - // Find HBA (host bus adapter) we are looking for mutex_lock(&adpt_configuration_lock); for (pHba = hba_chain; pHba; pHba = pHba->next) { @@ -588,86 +563,30 @@ static int adpt_proc_info(struct Scsi_Host *host, char *buffer, char **start, of } host = pHba->host; - len = sprintf(buffer , "Adaptec I2O RAID Driver Version: %s\n\n", DPT_I2O_VERSION); - len += sprintf(buffer+len, "%s\n", pHba->detail); - len += sprintf(buffer+len, "SCSI Host=scsi%d Control Node=/dev/%s irq=%d\n", + seq_printf(m, "Adaptec I2O RAID Driver Version: %s\n\n", DPT_I2O_VERSION); + seq_printf(m, "%s\n", pHba->detail); + seq_printf(m, "SCSI Host=scsi%d Control Node=/dev/%s irq=%d\n", pHba->host->host_no, pHba->name, host->irq); - len += sprintf(buffer+len, "\tpost fifo size = %d\n\treply fifo size = %d\n\tsg table size = %d\n\n", + seq_printf(m, "\tpost fifo size = %d\n\treply fifo size = %d\n\tsg table size = %d\n\n", host->can_queue, (int) pHba->reply_fifo_size , host->sg_tablesize); - pos = begin + len; - - /* CHECKPOINT */ - if(pos > offset + length) { - goto stop_output; - } - if(pos <= offset) { - /* - * If we haven't even written to where we last left - * off (the last time we were called), reset the - * beginning pointer. - */ - len = 0; - begin = pos; - } - len += sprintf(buffer+len, "Devices:\n"); + seq_printf(m, "Devices:\n"); for(chan = 0; chan < MAX_CHANNEL; chan++) { for(id = 0; id < MAX_ID; id++) { d = pHba->channel[chan].device[id]; - while(d){ - len += sprintf(buffer+len,"\t%-24.24s", d->pScsi_dev->vendor); - len += sprintf(buffer+len," Rev: %-8.8s\n", d->pScsi_dev->rev); - pos = begin + len; - - - /* CHECKPOINT */ - if(pos > offset + length) { - goto stop_output; - } - if(pos <= offset) { - len = 0; - begin = pos; - } + while(d) { + seq_printf(m,"\t%-24.24s", d->pScsi_dev->vendor); + seq_printf(m," Rev: %-8.8s\n", d->pScsi_dev->rev); unit = d->pI2o_dev->lct_data.tid; - len += sprintf(buffer+len, "\tTID=%d, (Channel=%d, Target=%d, Lun=%d) (%s)\n\n", + seq_printf(m, "\tTID=%d, (Channel=%d, Target=%d, Lun=%d) (%s)\n\n", unit, (int)d->scsi_channel, (int)d->scsi_id, (int)d->scsi_lun, scsi_device_online(d->pScsi_dev)? "online":"offline"); - pos = begin + len; - - /* CHECKPOINT */ - if(pos > offset + length) { - goto stop_output; - } - if(pos <= offset) { - len = 0; - begin = pos; - } - d = d->next_lun; } } } - - /* - * begin is where we last checked our position with regards to offset - * begin is always less than offset. len is relative to begin. It - * is the number of bytes written past begin - * - */ -stop_output: - /* stop the output and calculate the correct length */ - *(buffer + len) = '\0'; - - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); - if(len > length) { - len = length; - } else if(len < 0){ - len = 0; - **start = '\0'; - } - return len; + return 0; } /* @@ -772,7 +691,7 @@ static int adpt_abort(struct scsi_cmnd * cmd) return FAILED; } pHba = (adpt_hba*) cmd->device->host->hostdata[0]; - printk(KERN_INFO"%s: Trying to Abort cmd=%ld\n",pHba->name, cmd->serial_number); + printk(KERN_INFO"%s: Trying to Abort\n",pHba->name); if ((dptdevice = (void*) (cmd->device->hostdata)) == NULL) { printk(KERN_ERR "%s: Unable to abort: No device in cmnd\n",pHba->name); return FAILED; @@ -794,10 +713,10 @@ static int adpt_abort(struct scsi_cmnd * cmd) printk(KERN_INFO"%s: Abort cmd not supported\n",pHba->name); return FAILED; } - printk(KERN_INFO"%s: Abort cmd=%ld failed.\n",pHba->name, cmd->serial_number); + printk(KERN_INFO"%s: Abort failed.\n",pHba->name); return FAILED; } - printk(KERN_INFO"%s: Abort cmd=%ld complete.\n",pHba->name, cmd->serial_number); + printk(KERN_INFO"%s: Abort complete.\n",pHba->name); return SUCCESS; } @@ -1229,11 +1148,10 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba) } } pci_dev_put(pHba->pDev); - kfree(pHba); - if (adpt_sysfs_class) device_destroy(adpt_sysfs_class, MKDEV(DPTI_I2O_MAJOR, pHba->unit)); + kfree(pHba); if(hba_count <= 0){ unregister_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER); @@ -1286,7 +1204,7 @@ static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout) ulong flags = 0; struct adpt_i2o_post_wait_data *p1, *p2; struct adpt_i2o_post_wait_data *wait_data = - kmalloc(sizeof(struct adpt_i2o_post_wait_data),GFP_KERNEL); + kmalloc(sizeof(struct adpt_i2o_post_wait_data), GFP_ATOMIC); DECLARE_WAITQUEUE(wait, current); if (!wait_data) @@ -1728,12 +1646,12 @@ static int adpt_open(struct inode *inode, struct file *file) int minor; adpt_hba* pHba; - lock_kernel(); + mutex_lock(&adpt_mutex); //TODO check for root access // minor = iminor(inode); if (minor >= hba_count) { - unlock_kernel(); + mutex_unlock(&adpt_mutex); return -ENXIO; } mutex_lock(&adpt_configuration_lock); @@ -1744,7 +1662,7 @@ static int adpt_open(struct inode *inode, struct file *file) } if (pHba == NULL) { mutex_unlock(&adpt_configuration_lock); - unlock_kernel(); + mutex_unlock(&adpt_mutex); return -ENXIO; } @@ -1755,7 +1673,7 @@ static int adpt_open(struct inode *inode, struct file *file) pHba->in_use = 1; mutex_unlock(&adpt_configuration_lock); - unlock_kernel(); + mutex_unlock(&adpt_mutex); return 0; } @@ -1882,21 +1800,23 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg) } do { - if(pHba->host) + /* + * Stop any new commands from enterring the + * controller while processing the ioctl + */ + if (pHba->host) { + scsi_block_requests(pHba->host); spin_lock_irqsave(pHba->host->host_lock, flags); - // This state stops any new commands from enterring the - // controller while processing the ioctl -// pHba->state |= DPTI_STATE_IOCTL; -// We can't set this now - The scsi subsystem sets host_blocked and -// the queue empties and stops. We need a way to restart the queue + } rcode = adpt_i2o_post_wait(pHba, msg, size, FOREVER); if (rcode != 0) printk("adpt_i2o_passthru: post wait failed %d %p\n", rcode, reply); -// pHba->state &= ~DPTI_STATE_IOCTL; - if(pHba->host) + if (pHba->host) { spin_unlock_irqrestore(pHba->host->host_lock, flags); - } while(rcode == -ETIMEDOUT); + scsi_unblock_requests(pHba->host); + } + } while (rcode == -ETIMEDOUT); if(rcode){ goto cleanup; @@ -2066,8 +1986,7 @@ static int adpt_system_info(void __user *buffer) return 0; } -static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, - ulong arg) +static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) { int minor; int error = 0; @@ -2150,6 +2069,20 @@ static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, return error; } +static long adpt_unlocked_ioctl(struct file *file, uint cmd, ulong arg) +{ + struct inode *inode; + long ret; + + inode = file_inode(file); + + mutex_lock(&adpt_mutex); + ret = adpt_ioctl(inode, file, cmd, arg); + mutex_unlock(&adpt_mutex); + + return ret; +} + #ifdef CONFIG_COMPAT static long compat_adpt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -2157,9 +2090,9 @@ static long compat_adpt_ioctl(struct file *file, struct inode *inode; long ret; - inode = file->f_dentry->d_inode; + inode = file_inode(file); - lock_kernel(); + mutex_lock(&adpt_mutex); switch(cmd) { case DPT_SIGNATURE: @@ -2177,7 +2110,7 @@ static long compat_adpt_ioctl(struct file *file, ret = -ENOIOCTLCMD; } - unlock_kernel(); + mutex_unlock(&adpt_mutex); return ret; } @@ -2623,6 +2556,13 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) continue; } bus_no = buf[0]>>16; + if (bus_no >= MAX_CHANNEL) { /* Something wrong skip it */ + printk(KERN_WARNING + "%s: Channel number %d out of range\n", + pHba->name, bus_no); + continue; + } + scsi_id = buf[1]; scsi_lun = (buf[2]>>8 )&0xff; pDev = pHba->channel[bus_no].device[scsi_id]; @@ -2634,7 +2574,8 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) pDev = pDev->next_lun; } if(!pDev ) { // Something new add it - d = kmalloc(sizeof(struct i2o_device), GFP_KERNEL); + d = kmalloc(sizeof(struct i2o_device), + GFP_ATOMIC); if(d==NULL) { printk(KERN_CRIT "Out of memory for I2O device data.\n"); @@ -2650,13 +2591,11 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) adpt_i2o_report_hba_unit(pHba, d); adpt_i2o_install_device(pHba, d); - if(bus_no >= MAX_CHANNEL) { // Something wrong skip it - printk(KERN_WARNING"%s: Channel number %d out of range \n", pHba->name, bus_no); - continue; - } pDev = pHba->channel[bus_no].device[scsi_id]; if( pDev == NULL){ - pDev = kzalloc(sizeof(struct adpt_device),GFP_KERNEL); + pDev = + kzalloc(sizeof(struct adpt_device), + GFP_ATOMIC); if(pDev == NULL) { return -ENOMEM; } @@ -2665,7 +2604,9 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) while (pDev->next_lun) { pDev = pDev->next_lun; } - pDev = pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL); + pDev = pDev->next_lun = + kzalloc(sizeof(struct adpt_device), + GFP_ATOMIC); if(pDev == NULL) { return -ENOMEM; } @@ -3110,7 +3051,7 @@ static int adpt_i2o_lct_get(adpt_hba* pHba) if (pHba->lct == NULL) { pHba->lct = dma_alloc_coherent(&pHba->pDev->dev, pHba->lct_size, &pHba->lct_pa, - GFP_KERNEL); + GFP_ATOMIC); if(pHba->lct == NULL) { printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n", pHba->name); @@ -3611,7 +3552,7 @@ static struct scsi_host_template driver_template = { .module = THIS_MODULE, .name = "dpt_i2o", .proc_name = "dpt_i2o", - .proc_info = adpt_proc_info, + .show_info = adpt_show_info, .info = adpt_info, .queuecommand = adpt_queue, .eh_abort_handler = adpt_abort, |
