Commit 51c928c3 authored by James Bottomley's avatar James Bottomley Committed by James Bottomley

[SCSI] Legacy MegaRAID: Fix READ CAPACITY

Some Legacy megaraid cards can't actually cope with the scatter/gather
version of the READ CAPACITY command (which is what we now send them
since altering all SCSI internal I/O to go via the block layer).  Fix
this (and a few other broken megaraid driver assumptions) by sending
the non-sg version of the command if the sg list only has a single
element.
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 97af50f6
...@@ -621,8 +621,6 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) ...@@ -621,8 +621,6 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
if(islogical) { if(islogical) {
switch (cmd->cmnd[0]) { switch (cmd->cmnd[0]) {
case TEST_UNIT_READY: case TEST_UNIT_READY:
memset(cmd->request_buffer, 0, cmd->request_bufflen);
#if MEGA_HAVE_CLUSTERING #if MEGA_HAVE_CLUSTERING
/* /*
* Do we support clustering and is the support enabled * Do we support clustering and is the support enabled
...@@ -652,11 +650,28 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) ...@@ -652,11 +650,28 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
return NULL; return NULL;
#endif #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]); 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->result = (DID_OK << 16);
cmd->scsi_done(cmd); cmd->scsi_done(cmd);
return NULL; return NULL;
}
case READ_CAPACITY: case READ_CAPACITY:
case INQUIRY: case INQUIRY:
...@@ -1685,14 +1700,23 @@ mega_rundoneq (adapter_t *adapter) ...@@ -1685,14 +1700,23 @@ mega_rundoneq (adapter_t *adapter)
static void static void
mega_free_scb(adapter_t *adapter, scb_t *scb) mega_free_scb(adapter_t *adapter, scb_t *scb)
{ {
unsigned long length;
switch( scb->dma_type ) { switch( scb->dma_type ) {
case MEGA_DMA_TYPE_NONE: case MEGA_DMA_TYPE_NONE:
break; break;
case MEGA_BULK_DATA: 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, pci_unmap_page(adapter->dev, scb->dma_h_bulkdata,
scb->cmd->request_bufflen, scb->dma_direction); length, scb->dma_direction);
break; break;
case MEGA_SGLIST: case MEGA_SGLIST:
...@@ -1741,6 +1765,7 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len) ...@@ -1741,6 +1765,7 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len)
struct scatterlist *sgl; struct scatterlist *sgl;
struct page *page; struct page *page;
unsigned long offset; unsigned long offset;
unsigned int length;
Scsi_Cmnd *cmd; Scsi_Cmnd *cmd;
int sgcnt; int sgcnt;
int idx; int idx;
...@@ -1748,14 +1773,23 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len) ...@@ -1748,14 +1773,23 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len)
cmd = scb->cmd; cmd = scb->cmd;
/* Scatter-gather not used */ /* Scatter-gather not used */
if( !cmd->use_sg ) { 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); page = virt_to_page(cmd->request_buffer);
offset = offset_in_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, scb->dma_h_bulkdata = pci_map_page(adapter->dev,
page, offset, page, offset,
cmd->request_bufflen, length,
scb->dma_direction); scb->dma_direction);
scb->dma_type = MEGA_BULK_DATA; scb->dma_type = MEGA_BULK_DATA;
...@@ -1765,14 +1799,14 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len) ...@@ -1765,14 +1799,14 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len)
*/ */
if( adapter->has_64bit_addr ) { if( adapter->has_64bit_addr ) {
scb->sgl64[0].address = scb->dma_h_bulkdata; 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; *buf = (u32)scb->sgl_dma_addr;
*len = (u32)cmd->request_bufflen; *len = (u32)length;
return 1; return 1;
} }
else { else {
*buf = (u32)scb->dma_h_bulkdata; *buf = (u32)scb->dma_h_bulkdata;
*len = (u32)cmd->request_bufflen; *len = (u32)length;
} }
return 0; return 0;
} }
...@@ -1791,27 +1825,23 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len) ...@@ -1791,27 +1825,23 @@ mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len)
if( sgcnt > adapter->sglen ) BUG(); if( sgcnt > adapter->sglen ) BUG();
*len = 0;
for( idx = 0; idx < sgcnt; idx++, sgl++ ) { for( idx = 0; idx < sgcnt; idx++, sgl++ ) {
if( adapter->has_64bit_addr ) { if( adapter->has_64bit_addr ) {
scb->sgl64[idx].address = sg_dma_address(sgl); 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 { else {
scb->sgl[idx].address = sg_dma_address(sgl); 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 */ /* Reset pointer and length fields */
*buf = scb->sgl_dma_addr; *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 count of SG requests */
return sgcnt; return sgcnt;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment