diff options
Diffstat (limited to 'drivers/scsi/megaraid.c')
-rw-r--r-- | drivers/scsi/megaraid.c | 131 |
1 files changed, 77 insertions, 54 deletions
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 6f308ebe3e7..f9792528e33 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -362,6 +362,7 @@ megaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *)) adapter_t *adapter; scb_t *scb; int busy=0; + unsigned long flags; adapter = (adapter_t *)scmd->device->host->hostdata; @@ -377,23 +378,25 @@ megaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *)) * return 0 in that case. */ + spin_lock_irqsave(&adapter->lock, flags); scb = mega_build_cmd(adapter, scmd, &busy); + if (!scb) + goto out; - if(scb) { - scb->state |= SCB_PENDQ; - list_add_tail(&scb->list, &adapter->pending_list); + scb->state |= SCB_PENDQ; + list_add_tail(&scb->list, &adapter->pending_list); - /* - * Check if the HBA is in quiescent state, e.g., during a - * delete logical drive opertion. If it is, don't run - * the pending_list. - */ - if(atomic_read(&adapter->quiescent) == 0) { - mega_runpendq(adapter); - } - return 0; - } + /* + * Check if the HBA is in quiescent state, e.g., during a + * delete logical drive opertion. If it is, don't run + * the pending_list. + */ + if (atomic_read(&adapter->quiescent) == 0) + mega_runpendq(adapter); + busy = 0; + out: + spin_unlock_irqrestore(&adapter->lock, flags); return busy; } @@ -621,8 +624,6 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) if(islogical) { switch (cmd->cmnd[0]) { case TEST_UNIT_READY: - memset(cmd->request_buffer, 0, cmd->request_bufflen); - #if MEGA_HAVE_CLUSTERING /* * Do we support clustering and is the support enabled @@ -652,11 +653,28 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) return NULL; #endif - case MODE_SENSE: + case MODE_SENSE: { + char *buf; + + if (cmd->use_sg) { + struct scatterlist *sg; + + sg = (struct scatterlist *)cmd->request_buffer; + buf = kmap_atomic(sg->page, KM_IRQ0) + + sg->offset; + } else + buf = cmd->request_buffer; memset(cmd->request_buffer, 0, cmd->cmnd[4]); + if (cmd->use_sg) { + struct scatterlist *sg; + + sg = (struct scatterlist *)cmd->request_buffer; + kunmap_atomic(buf - sg->offset, KM_IRQ0); + } cmd->result = (DID_OK << 16); cmd->scsi_done(cmd); return NULL; + } case READ_CAPACITY: case INQUIRY: @@ -1668,7 +1686,7 @@ mega_rundoneq (adapter_t *adapter) list_for_each(pos, &adapter->completed_list) { - Scsi_Pointer* spos = (Scsi_Pointer *)pos; + struct scsi_pointer* spos = (struct scsi_pointer *)pos; cmd = list_entry(spos, Scsi_Cmnd, SCp); cmd->scsi_done(cmd); @@ -1685,14 +1703,23 @@ mega_rundoneq (adapter_t *adapter) static void mega_free_scb(adapter_t *adapter, scb_t *scb) { + unsigned long length; + switch( scb->dma_type ) { case MEGA_DMA_TYPE_NONE: break; case MEGA_BULK_DATA: + if (scb->cmd->use_sg == 0) + length = scb->cmd->request_bufflen; + else { + struct scatterlist *sgl = + (struct scatterlist *)scb->cmd->request_buffer; + length = sgl->length; + } pci_unmap_page(adapter->dev, scb->dma_h_bulkdata, - scb->cmd->request_bufflen, scb->dma_direction); + length, scb->dma_direction); break; case MEGA_SGLIST: @@ -1741,6 +1768,7 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len) struct scatterlist *sgl; struct page *page; unsigned long offset; + unsigned int length; Scsi_Cmnd *cmd; int sgcnt; int idx; @@ -1748,14 +1776,23 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len) cmd = scb->cmd; /* Scatter-gather not used */ - if( !cmd->use_sg ) { - - page = virt_to_page(cmd->request_buffer); - offset = offset_in_page(cmd->request_buffer); + if( cmd->use_sg == 0 || (cmd->use_sg == 1 && + !adapter->has_64bit_addr)) { + + if (cmd->use_sg == 0) { + page = virt_to_page(cmd->request_buffer); + offset = offset_in_page(cmd->request_buffer); + length = cmd->request_bufflen; + } else { + sgl = (struct scatterlist *)cmd->request_buffer; + page = sgl->page; + offset = sgl->offset; + length = sgl->length; + } scb->dma_h_bulkdata = pci_map_page(adapter->dev, page, offset, - cmd->request_bufflen, + length, scb->dma_direction); scb->dma_type = MEGA_BULK_DATA; @@ -1765,14 +1802,14 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len) */ if( adapter->has_64bit_addr ) { scb->sgl64[0].address = scb->dma_h_bulkdata; - scb->sgl64[0].length = cmd->request_bufflen; + scb->sgl64[0].length = length; *buf = (u32)scb->sgl_dma_addr; - *len = (u32)cmd->request_bufflen; + *len = (u32)length; return 1; } else { *buf = (u32)scb->dma_h_bulkdata; - *len = (u32)cmd->request_bufflen; + *len = (u32)length; } return 0; } @@ -1791,27 +1828,23 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len) if( sgcnt > adapter->sglen ) BUG(); + *len = 0; + for( idx = 0; idx < sgcnt; idx++, sgl++ ) { if( adapter->has_64bit_addr ) { scb->sgl64[idx].address = sg_dma_address(sgl); - scb->sgl64[idx].length = sg_dma_len(sgl); + *len += scb->sgl64[idx].length = sg_dma_len(sgl); } else { scb->sgl[idx].address = sg_dma_address(sgl); - scb->sgl[idx].length = sg_dma_len(sgl); + *len += scb->sgl[idx].length = sg_dma_len(sgl); } } /* Reset pointer and length fields */ *buf = scb->sgl_dma_addr; - /* - * For passthru command, dataxferlen must be set, even for commands - * with a sg list - */ - *len = (u32)cmd->request_bufflen; - /* Return count of SG requests */ return sgcnt; } @@ -1951,7 +1984,7 @@ megaraid_reset(struct scsi_cmnd *cmd) mc.cmd = MEGA_CLUSTER_CMD; mc.opcode = MEGA_RESET_RESERVATIONS; - if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) != 0 ) { + if( mega_internal_command(adapter, &mc, NULL) != 0 ) { printk(KERN_WARNING "megaraid: reservation reset failed.\n"); } @@ -2981,7 +3014,7 @@ proc_rdrv(adapter_t *adapter, char *page, int start, int end ) mc.cmd = FC_NEW_CONFIG; mc.opcode = OP_DCMD_READ_CONFIG; - if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) ) { + if( mega_internal_command(adapter, &mc, NULL) ) { len = sprintf(page, "40LD read config failed.\n"); @@ -2999,11 +3032,11 @@ proc_rdrv(adapter_t *adapter, char *page, int start, int end ) else { mc.cmd = NEW_READ_CONFIG_8LD; - if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) ) { + if( mega_internal_command(adapter, &mc, NULL) ) { mc.cmd = READ_CONFIG_8LD; - if( mega_internal_command(adapter, LOCK_INT, &mc, + if( mega_internal_command(adapter, &mc, NULL) ){ len = sprintf(page, @@ -3602,7 +3635,7 @@ megadev_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, /* * Issue the command */ - mega_internal_command(adapter, LOCK_INT, &mc, pthru); + mega_internal_command(adapter, &mc, pthru); rval = mega_n_to_m((void __user *)arg, &mc); @@ -3685,7 +3718,7 @@ freemem_and_return: /* * Issue the command */ - mega_internal_command(adapter, LOCK_INT, &mc, NULL); + mega_internal_command(adapter, &mc, NULL); rval = mega_n_to_m((void __user *)arg, &mc); @@ -4204,7 +4237,7 @@ mega_do_del_logdrv(adapter_t *adapter, int logdrv) mc.opcode = OP_DEL_LOGDRV; mc.subopcode = logdrv; - rval = mega_internal_command(adapter, LOCK_INT, &mc, NULL); + rval = mega_internal_command(adapter, &mc, NULL); /* log this event */ if(rval) { @@ -4337,7 +4370,7 @@ mega_adapinq(adapter_t *adapter, dma_addr_t dma_handle) mc.xferaddr = (u32)dma_handle; - if ( mega_internal_command(adapter, LOCK_INT, &mc, NULL) != 0 ) { + if ( mega_internal_command(adapter, &mc, NULL) != 0 ) { return -1; } @@ -4405,7 +4438,7 @@ mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt, mc.cmd = MEGA_MBOXCMD_PASSTHRU; mc.xferaddr = (u32)pthru_dma_handle; - rval = mega_internal_command(adapter, LOCK_INT, &mc, pthru); + rval = mega_internal_command(adapter, &mc, pthru); pci_free_consistent(pdev, sizeof(mega_passthru), pthru, pthru_dma_handle); @@ -4419,7 +4452,6 @@ mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt, /** * mega_internal_command() * @adapter - pointer to our soft state - * @ls - the scope of the exclusion lock. * @mc - the mailbox command * @pthru - Passthru structure for DCDB commands * @@ -4433,8 +4465,7 @@ mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt, * Note: parameter 'pthru' is null for non-passthru commands. */ static int -mega_internal_command(adapter_t *adapter, lockscope_t ls, megacmd_t *mc, - mega_passthru *pthru ) +mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru) { Scsi_Cmnd *scmd; struct scsi_device *sdev; @@ -4478,15 +4509,8 @@ mega_internal_command(adapter_t *adapter, lockscope_t ls, megacmd_t *mc, scb->idx = CMDID_INT_CMDS; - /* - * Get the lock only if the caller has not acquired it already - */ - if( ls == LOCK_INT ) spin_lock_irqsave(&adapter->lock, flags); - megaraid_queue(scmd, mega_internal_done); - if( ls == LOCK_INT ) spin_unlock_irqrestore(&adapter->lock, flags); - wait_for_completion(&adapter->int_waitq); rval = scmd->result; @@ -4653,7 +4677,6 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) adapter->flag = flag; spin_lock_init(&adapter->lock); - scsi_assign_lock(host, &adapter->lock); host->cmd_per_lun = max_cmd_per_lun; host->max_sectors = max_sectors_per_io; |