diff options
author | Stephen M. Cameron <scameron@beardog.cce.hp.com> | 2010-02-26 17:01:53 -0500 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2010-02-28 13:42:32 -0500 |
commit | 87c3a922a7ee8cfb9ab837f4ae38c993e9b30711 (patch) | |
tree | 84d896c43d9aacb6c575150ba4afca9a97b6c482 /drivers/block/cciss_scsi.c | |
parent | bf8873781831c7799255e0932848401070185dd0 (diff) |
cciss: Fix problem with scatter gather elements in the scsi half of the driver
cciss: Fix problem with scatter gather elements in the scsi half of the driver
When support for more than 31 scatter gather elements was added to the block
half of the driver, the SCSI half of the driver was not addressed, and the bump
from 31 to 32 scatter gather elements in the command block itself (not chained)
actually broke the SCSI half of the driver, so that any transfer requiring 32
scatter gather elements wouldn't work. This fix also increases the max transfer
size and size of the scatter gather table to the limit supported by the controller
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'drivers/block/cciss_scsi.c')
-rw-r--r-- | drivers/block/cciss_scsi.c | 85 |
1 files changed, 59 insertions, 26 deletions
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 6dc15b669694..e1d0e2cfec72 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c | |||
@@ -84,7 +84,6 @@ static struct scsi_host_template cciss_driver_template = { | |||
84 | .queuecommand = cciss_scsi_queue_command, | 84 | .queuecommand = cciss_scsi_queue_command, |
85 | .can_queue = SCSI_CCISS_CAN_QUEUE, | 85 | .can_queue = SCSI_CCISS_CAN_QUEUE, |
86 | .this_id = 7, | 86 | .this_id = 7, |
87 | .sg_tablesize = MAXSGENTRIES, | ||
88 | .cmd_per_lun = 1, | 87 | .cmd_per_lun = 1, |
89 | .use_clustering = DISABLE_CLUSTERING, | 88 | .use_clustering = DISABLE_CLUSTERING, |
90 | /* Can't have eh_bus_reset_handler or eh_host_reset_handler for cciss */ | 89 | /* Can't have eh_bus_reset_handler or eh_host_reset_handler for cciss */ |
@@ -94,13 +93,14 @@ static struct scsi_host_template cciss_driver_template = { | |||
94 | 93 | ||
95 | #pragma pack(1) | 94 | #pragma pack(1) |
96 | 95 | ||
97 | #define SCSI_PAD_32 4 | 96 | #define SCSI_PAD_32 0 |
98 | #define SCSI_PAD_64 4 | 97 | #define SCSI_PAD_64 0 |
99 | 98 | ||
100 | struct cciss_scsi_cmd_stack_elem_t { | 99 | struct cciss_scsi_cmd_stack_elem_t { |
101 | CommandList_struct cmd; | 100 | CommandList_struct cmd; |
102 | ErrorInfo_struct Err; | 101 | ErrorInfo_struct Err; |
103 | __u32 busaddr; | 102 | __u32 busaddr; |
103 | int cmdindex; | ||
104 | u8 pad[IS_32_BIT * SCSI_PAD_32 + IS_64_BIT * SCSI_PAD_64]; | 104 | u8 pad[IS_32_BIT * SCSI_PAD_32 + IS_64_BIT * SCSI_PAD_64]; |
105 | }; | 105 | }; |
106 | 106 | ||
@@ -122,6 +122,7 @@ struct cciss_scsi_cmd_stack_t { | |||
122 | struct cciss_scsi_adapter_data_t { | 122 | struct cciss_scsi_adapter_data_t { |
123 | struct Scsi_Host *scsi_host; | 123 | struct Scsi_Host *scsi_host; |
124 | struct cciss_scsi_cmd_stack_t cmd_stack; | 124 | struct cciss_scsi_cmd_stack_t cmd_stack; |
125 | SGDescriptor_struct **cmd_sg_list; | ||
125 | int registered; | 126 | int registered; |
126 | spinlock_t lock; // to protect ccissscsi[ctlr]; | 127 | spinlock_t lock; // to protect ccissscsi[ctlr]; |
127 | }; | 128 | }; |
@@ -156,6 +157,7 @@ scsi_cmd_alloc(ctlr_info_t *h) | |||
156 | memset(&c->Err, 0, sizeof(c->Err)); | 157 | memset(&c->Err, 0, sizeof(c->Err)); |
157 | /* set physical addr of cmd and addr of scsi parameters */ | 158 | /* set physical addr of cmd and addr of scsi parameters */ |
158 | c->cmd.busaddr = c->busaddr; | 159 | c->cmd.busaddr = c->busaddr; |
160 | c->cmd.cmdindex = c->cmdindex; | ||
159 | /* (__u32) (stk->cmd_pool_handle + | 161 | /* (__u32) (stk->cmd_pool_handle + |
160 | (sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top)); */ | 162 | (sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top)); */ |
161 | 163 | ||
@@ -201,6 +203,11 @@ scsi_cmd_stack_setup(int ctlr, struct cciss_scsi_adapter_data_t *sa) | |||
201 | struct cciss_scsi_cmd_stack_t *stk; | 203 | struct cciss_scsi_cmd_stack_t *stk; |
202 | size_t size; | 204 | size_t size; |
203 | 205 | ||
206 | sa->cmd_sg_list = cciss_allocate_sg_chain_blocks(hba[ctlr], | ||
207 | hba[ctlr]->chainsize, CMD_STACK_SIZE); | ||
208 | if (!sa->cmd_sg_list && hba[ctlr]->chainsize > 0) | ||
209 | return -ENOMEM; | ||
210 | |||
204 | stk = &sa->cmd_stack; | 211 | stk = &sa->cmd_stack; |
205 | size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE; | 212 | size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE; |
206 | 213 | ||
@@ -211,14 +218,16 @@ scsi_cmd_stack_setup(int ctlr, struct cciss_scsi_adapter_data_t *sa) | |||
211 | pci_alloc_consistent(hba[ctlr]->pdev, size, &stk->cmd_pool_handle); | 218 | pci_alloc_consistent(hba[ctlr]->pdev, size, &stk->cmd_pool_handle); |
212 | 219 | ||
213 | if (stk->pool == NULL) { | 220 | if (stk->pool == NULL) { |
214 | printk("stk->pool is null\n"); | 221 | cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE); |
215 | return -1; | 222 | sa->cmd_sg_list = NULL; |
223 | return -ENOMEM; | ||
216 | } | 224 | } |
217 | 225 | ||
218 | for (i=0; i<CMD_STACK_SIZE; i++) { | 226 | for (i=0; i<CMD_STACK_SIZE; i++) { |
219 | stk->elem[i] = &stk->pool[i]; | 227 | stk->elem[i] = &stk->pool[i]; |
220 | stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle + | 228 | stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle + |
221 | (sizeof(struct cciss_scsi_cmd_stack_elem_t) * i)); | 229 | (sizeof(struct cciss_scsi_cmd_stack_elem_t) * i)); |
230 | stk->elem[i]->cmdindex = i; | ||
222 | } | 231 | } |
223 | stk->top = CMD_STACK_SIZE-1; | 232 | stk->top = CMD_STACK_SIZE-1; |
224 | return 0; | 233 | return 0; |
@@ -243,6 +252,7 @@ scsi_cmd_stack_free(int ctlr) | |||
243 | 252 | ||
244 | pci_free_consistent(hba[ctlr]->pdev, size, stk->pool, stk->cmd_pool_handle); | 253 | pci_free_consistent(hba[ctlr]->pdev, size, stk->pool, stk->cmd_pool_handle); |
245 | stk->pool = NULL; | 254 | stk->pool = NULL; |
255 | cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE); | ||
246 | } | 256 | } |
247 | 257 | ||
248 | #if 0 | 258 | #if 0 |
@@ -726,6 +736,8 @@ complete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag) | |||
726 | ctlr = hba[cp->ctlr]; | 736 | ctlr = hba[cp->ctlr]; |
727 | 737 | ||
728 | scsi_dma_unmap(cmd); | 738 | scsi_dma_unmap(cmd); |
739 | if (cp->Header.SGTotal > ctlr->max_cmd_sgentries) | ||
740 | cciss_unmap_sg_chain_block(ctlr, cp); | ||
729 | 741 | ||
730 | cmd->result = (DID_OK << 16); /* host byte */ | 742 | cmd->result = (DID_OK << 16); /* host byte */ |
731 | cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ | 743 | cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ |
@@ -848,6 +860,7 @@ cciss_scsi_detect(int ctlr) | |||
848 | sh->io_port = 0; // good enough? FIXME, | 860 | sh->io_port = 0; // good enough? FIXME, |
849 | sh->n_io_port = 0; // I don't think we use these two... | 861 | sh->n_io_port = 0; // I don't think we use these two... |
850 | sh->this_id = SELF_SCSI_ID; | 862 | sh->this_id = SELF_SCSI_ID; |
863 | sh->sg_tablesize = hba[ctlr]->maxsgentries; | ||
851 | 864 | ||
852 | ((struct cciss_scsi_adapter_data_t *) | 865 | ((struct cciss_scsi_adapter_data_t *) |
853 | hba[ctlr]->scsi_ctlr)->scsi_host = sh; | 866 | hba[ctlr]->scsi_ctlr)->scsi_host = sh; |
@@ -1365,34 +1378,54 @@ cciss_scsi_proc_info(struct Scsi_Host *sh, | |||
1365 | dma mapping and fills in the scatter gather entries of the | 1378 | dma mapping and fills in the scatter gather entries of the |
1366 | cciss command, cp. */ | 1379 | cciss command, cp. */ |
1367 | 1380 | ||
1368 | static void | 1381 | static void cciss_scatter_gather(ctlr_info_t *h, CommandList_struct *cp, |
1369 | cciss_scatter_gather(struct pci_dev *pdev, | 1382 | struct scsi_cmnd *cmd) |
1370 | CommandList_struct *cp, | ||
1371 | struct scsi_cmnd *cmd) | ||
1372 | { | 1383 | { |
1373 | unsigned int len; | 1384 | unsigned int len; |
1374 | struct scatterlist *sg; | 1385 | struct scatterlist *sg; |
1375 | __u64 addr64; | 1386 | __u64 addr64; |
1376 | int use_sg, i; | 1387 | int request_nsgs, i, chained, sg_index; |
1377 | 1388 | struct cciss_scsi_adapter_data_t *sa = h->scsi_ctlr; | |
1378 | BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES); | 1389 | SGDescriptor_struct *curr_sg; |
1379 | 1390 | ||
1380 | use_sg = scsi_dma_map(cmd); | 1391 | BUG_ON(scsi_sg_count(cmd) > h->maxsgentries); |
1381 | if (use_sg) { /* not too many addrs? */ | 1392 | |
1382 | scsi_for_each_sg(cmd, sg, use_sg, i) { | 1393 | chained = 0; |
1394 | sg_index = 0; | ||
1395 | curr_sg = cp->SG; | ||
1396 | request_nsgs = scsi_dma_map(cmd); | ||
1397 | if (request_nsgs) { | ||
1398 | scsi_for_each_sg(cmd, sg, request_nsgs, i) { | ||
1399 | if (sg_index + 1 == h->max_cmd_sgentries && | ||
1400 | !chained && request_nsgs - i > 1) { | ||
1401 | chained = 1; | ||
1402 | sg_index = 0; | ||
1403 | curr_sg = sa->cmd_sg_list[cp->cmdindex]; | ||
1404 | } | ||
1383 | addr64 = (__u64) sg_dma_address(sg); | 1405 | addr64 = (__u64) sg_dma_address(sg); |
1384 | len = sg_dma_len(sg); | 1406 | len = sg_dma_len(sg); |
1385 | cp->SG[i].Addr.lower = | 1407 | curr_sg[sg_index].Addr.lower = |
1386 | (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF); | 1408 | (__u32) (addr64 & 0x0FFFFFFFFULL); |
1387 | cp->SG[i].Addr.upper = | 1409 | curr_sg[sg_index].Addr.upper = |
1388 | (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF); | 1410 | (__u32) ((addr64 >> 32) & 0x0FFFFFFFFULL); |
1389 | cp->SG[i].Len = len; | 1411 | curr_sg[sg_index].Len = len; |
1390 | cp->SG[i].Ext = 0; // we are not chaining | 1412 | curr_sg[sg_index].Ext = 0; |
1413 | ++sg_index; | ||
1391 | } | 1414 | } |
1415 | if (chained) | ||
1416 | cciss_map_sg_chain_block(h, cp, | ||
1417 | sa->cmd_sg_list[cp->cmdindex], | ||
1418 | (request_nsgs - (h->max_cmd_sgentries - 1)) * | ||
1419 | sizeof(SGDescriptor_struct)); | ||
1392 | } | 1420 | } |
1393 | 1421 | /* track how many SG entries we are using */ | |
1394 | cp->Header.SGList = (__u8) use_sg; /* no. SGs contig in this cmd */ | 1422 | if (request_nsgs > h->maxSG) |
1395 | cp->Header.SGTotal = (__u16) use_sg; /* total sgs in this cmd list */ | 1423 | h->maxSG = request_nsgs; |
1424 | cp->Header.SGTotal = (__u8) request_nsgs + chained; | ||
1425 | if (request_nsgs > h->max_cmd_sgentries) | ||
1426 | cp->Header.SGList = h->max_cmd_sgentries; | ||
1427 | else | ||
1428 | cp->Header.SGList = cp->Header.SGTotal; | ||
1396 | return; | 1429 | return; |
1397 | } | 1430 | } |
1398 | 1431 | ||
@@ -1490,7 +1523,7 @@ cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd | |||
1490 | BUG(); | 1523 | BUG(); |
1491 | break; | 1524 | break; |
1492 | } | 1525 | } |
1493 | cciss_scatter_gather(c->pdev, cp, cmd); | 1526 | cciss_scatter_gather(c, cp, cmd); |
1494 | 1527 | ||
1495 | /* Put the request on the tail of the request queue */ | 1528 | /* Put the request on the tail of the request queue */ |
1496 | 1529 | ||