diff options
author | Matthew Wilcox <matthew@wil.cx> | 2007-10-02 21:55:25 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.localdomain> | 2007-10-12 14:53:02 -0400 |
commit | 05848b6e66ee237c4496c2b49821d2622b0f677e (patch) | |
tree | 49055abae9e9387934be0734aa8ff3eb3ee4664d /drivers/scsi | |
parent | 41d2493d3478942f891b21dff60951ff939c08d9 (diff) |
[SCSI] advansys: Fix simultaneous calls to ->queuecommand
The narrow board used two global structures to set up a command;
unfortunately they weren't locked, so with two boards in the machine,
one call to queuecommand could corrupt the data being used by the other
call to queuecommand.
Fix this by allocating asc_scsi_q on the stack (64 bytes) and using kmalloc
for the asc_sg_head (2k)
Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/advansys.c | 88 |
1 files changed, 39 insertions, 49 deletions
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 3dd785617602..fd4d6695fea9 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c | |||
@@ -380,7 +380,7 @@ typedef struct asc_sg_head { | |||
380 | ushort queue_cnt; | 380 | ushort queue_cnt; |
381 | ushort entry_to_copy; | 381 | ushort entry_to_copy; |
382 | ushort res; | 382 | ushort res; |
383 | ASC_SG_LIST sg_list[ASC_MAX_SG_LIST]; | 383 | ASC_SG_LIST sg_list[0]; |
384 | } ASC_SG_HEAD; | 384 | } ASC_SG_HEAD; |
385 | 385 | ||
386 | typedef struct asc_scsi_q { | 386 | typedef struct asc_scsi_q { |
@@ -2559,12 +2559,6 @@ static int asc_board_count; | |||
2559 | /* Overrun buffer used by all narrow boards. */ | 2559 | /* Overrun buffer used by all narrow boards. */ |
2560 | static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 }; | 2560 | static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 }; |
2561 | 2561 | ||
2562 | /* | ||
2563 | * Global structures required to issue a command. | ||
2564 | */ | ||
2565 | static ASC_SCSI_Q asc_scsi_q = { {0} }; | ||
2566 | static ASC_SG_HEAD asc_sg_head = { 0 }; | ||
2567 | |||
2568 | #ifdef ADVANSYS_DEBUG | 2562 | #ifdef ADVANSYS_DEBUG |
2569 | static int asc_dbglvl = 3; | 2563 | static int asc_dbglvl = 3; |
2570 | 2564 | ||
@@ -10192,39 +10186,28 @@ static int advansys_slave_configure(struct scsi_device *sdev) | |||
10192 | return 0; | 10186 | return 0; |
10193 | } | 10187 | } |
10194 | 10188 | ||
10195 | /* | 10189 | static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp, |
10196 | * Build a request structure for the Asc Library (Narrow Board). | 10190 | struct asc_scsi_q *asc_scsi_q) |
10197 | * | ||
10198 | * The global structures 'asc_scsi_q' and 'asc_sg_head' are | ||
10199 | * used to build the request. | ||
10200 | * | ||
10201 | * If an error occurs, then return ASC_ERROR. | ||
10202 | */ | ||
10203 | static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp) | ||
10204 | { | 10191 | { |
10205 | /* | 10192 | memset(asc_scsi_q, 0, sizeof(*asc_scsi_q)); |
10206 | * Mutually exclusive access is required to 'asc_scsi_q' and | ||
10207 | * 'asc_sg_head' until after the request is started. | ||
10208 | */ | ||
10209 | memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q)); | ||
10210 | 10193 | ||
10211 | /* | 10194 | /* |
10212 | * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'. | 10195 | * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'. |
10213 | */ | 10196 | */ |
10214 | asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp); | 10197 | asc_scsi_q->q2.srb_ptr = ASC_VADDR_TO_U32(scp); |
10215 | 10198 | ||
10216 | /* | 10199 | /* |
10217 | * Build the ASC_SCSI_Q request. | 10200 | * Build the ASC_SCSI_Q request. |
10218 | */ | 10201 | */ |
10219 | asc_scsi_q.cdbptr = &scp->cmnd[0]; | 10202 | asc_scsi_q->cdbptr = &scp->cmnd[0]; |
10220 | asc_scsi_q.q2.cdb_len = scp->cmd_len; | 10203 | asc_scsi_q->q2.cdb_len = scp->cmd_len; |
10221 | asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id); | 10204 | asc_scsi_q->q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id); |
10222 | asc_scsi_q.q1.target_lun = scp->device->lun; | 10205 | asc_scsi_q->q1.target_lun = scp->device->lun; |
10223 | asc_scsi_q.q2.target_ix = | 10206 | asc_scsi_q->q2.target_ix = |
10224 | ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun); | 10207 | ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun); |
10225 | asc_scsi_q.q1.sense_addr = | 10208 | asc_scsi_q->q1.sense_addr = |
10226 | cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); | 10209 | cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); |
10227 | asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer); | 10210 | asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer); |
10228 | 10211 | ||
10229 | /* | 10212 | /* |
10230 | * If there are any outstanding requests for the current target, | 10213 | * If there are any outstanding requests for the current target, |
@@ -10239,9 +10222,9 @@ static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp) | |||
10239 | */ | 10222 | */ |
10240 | if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) && | 10223 | if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) && |
10241 | (boardp->reqcnt[scp->device->id] % 255) == 0) { | 10224 | (boardp->reqcnt[scp->device->id] % 255) == 0) { |
10242 | asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG; | 10225 | asc_scsi_q->q2.tag_code = MSG_ORDERED_TAG; |
10243 | } else { | 10226 | } else { |
10244 | asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG; | 10227 | asc_scsi_q->q2.tag_code = MSG_SIMPLE_TAG; |
10245 | } | 10228 | } |
10246 | 10229 | ||
10247 | /* | 10230 | /* |
@@ -10257,12 +10240,12 @@ static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp) | |||
10257 | dma_map_single(boardp->dev, scp->request_buffer, | 10240 | dma_map_single(boardp->dev, scp->request_buffer, |
10258 | scp->request_bufflen, | 10241 | scp->request_bufflen, |
10259 | scp->sc_data_direction) : 0; | 10242 | scp->sc_data_direction) : 0; |
10260 | asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle); | 10243 | asc_scsi_q->q1.data_addr = cpu_to_le32(scp->SCp.dma_handle); |
10261 | asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen); | 10244 | asc_scsi_q->q1.data_cnt = cpu_to_le32(scp->request_bufflen); |
10262 | ASC_STATS_ADD(scp->device->host, cont_xfer, | 10245 | ASC_STATS_ADD(scp->device->host, cont_xfer, |
10263 | ASC_CEILING(scp->request_bufflen, 512)); | 10246 | ASC_CEILING(scp->request_bufflen, 512)); |
10264 | asc_scsi_q.q1.sg_queue_cnt = 0; | 10247 | asc_scsi_q->q1.sg_queue_cnt = 0; |
10265 | asc_scsi_q.sg_head = NULL; | 10248 | asc_scsi_q->sg_head = NULL; |
10266 | } else { | 10249 | } else { |
10267 | /* | 10250 | /* |
10268 | * CDB scatter-gather request list. | 10251 | * CDB scatter-gather request list. |
@@ -10270,6 +10253,7 @@ static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp) | |||
10270 | int sgcnt; | 10253 | int sgcnt; |
10271 | int use_sg; | 10254 | int use_sg; |
10272 | struct scatterlist *slp; | 10255 | struct scatterlist *slp; |
10256 | struct asc_sg_head *asc_sg_head; | ||
10273 | 10257 | ||
10274 | slp = (struct scatterlist *)scp->request_buffer; | 10258 | slp = (struct scatterlist *)scp->request_buffer; |
10275 | use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg, | 10259 | use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg, |
@@ -10287,28 +10271,31 @@ static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp) | |||
10287 | 10271 | ||
10288 | ASC_STATS(scp->device->host, sg_cnt); | 10272 | ASC_STATS(scp->device->host, sg_cnt); |
10289 | 10273 | ||
10290 | /* | 10274 | asc_sg_head = kzalloc(sizeof(asc_scsi_q->sg_head) + |
10291 | * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q | 10275 | use_sg * sizeof(struct asc_sg_list), GFP_ATOMIC); |
10292 | * structure to point to it. | 10276 | if (!asc_sg_head) { |
10293 | */ | 10277 | dma_unmap_sg(boardp->dev, slp, scp->use_sg, |
10294 | memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD)); | 10278 | scp->sc_data_direction); |
10279 | scp->result = HOST_BYTE(DID_SOFT_ERROR); | ||
10280 | return ASC_ERROR; | ||
10281 | } | ||
10295 | 10282 | ||
10296 | asc_scsi_q.q1.cntl |= QC_SG_HEAD; | 10283 | asc_scsi_q->q1.cntl |= QC_SG_HEAD; |
10297 | asc_scsi_q.sg_head = &asc_sg_head; | 10284 | asc_scsi_q->sg_head = asc_sg_head; |
10298 | asc_scsi_q.q1.data_cnt = 0; | 10285 | asc_scsi_q->q1.data_cnt = 0; |
10299 | asc_scsi_q.q1.data_addr = 0; | 10286 | asc_scsi_q->q1.data_addr = 0; |
10300 | /* This is a byte value, otherwise it would need to be swapped. */ | 10287 | /* This is a byte value, otherwise it would need to be swapped. */ |
10301 | asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg; | 10288 | asc_sg_head->entry_cnt = asc_scsi_q->q1.sg_queue_cnt = use_sg; |
10302 | ASC_STATS_ADD(scp->device->host, sg_elem, | 10289 | ASC_STATS_ADD(scp->device->host, sg_elem, |
10303 | asc_sg_head.entry_cnt); | 10290 | asc_sg_head->entry_cnt); |
10304 | 10291 | ||
10305 | /* | 10292 | /* |
10306 | * Convert scatter-gather list into ASC_SG_HEAD list. | 10293 | * Convert scatter-gather list into ASC_SG_HEAD list. |
10307 | */ | 10294 | */ |
10308 | for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) { | 10295 | for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) { |
10309 | asc_sg_head.sg_list[sgcnt].addr = | 10296 | asc_sg_head->sg_list[sgcnt].addr = |
10310 | cpu_to_le32(sg_dma_address(slp)); | 10297 | cpu_to_le32(sg_dma_address(slp)); |
10311 | asc_sg_head.sg_list[sgcnt].bytes = | 10298 | asc_sg_head->sg_list[sgcnt].bytes = |
10312 | cpu_to_le32(sg_dma_len(slp)); | 10299 | cpu_to_le32(sg_dma_len(slp)); |
10313 | ASC_STATS_ADD(scp->device->host, sg_xfer, | 10300 | ASC_STATS_ADD(scp->device->host, sg_xfer, |
10314 | ASC_CEILING(sg_dma_len(slp), 512)); | 10301 | ASC_CEILING(sg_dma_len(slp), 512)); |
@@ -11338,14 +11325,17 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp) | |||
11338 | 11325 | ||
11339 | if (ASC_NARROW_BOARD(boardp)) { | 11326 | if (ASC_NARROW_BOARD(boardp)) { |
11340 | ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var; | 11327 | ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var; |
11328 | struct asc_scsi_q asc_scsi_q; | ||
11341 | 11329 | ||
11342 | /* asc_build_req() can not return ASC_BUSY. */ | 11330 | /* asc_build_req() can not return ASC_BUSY. */ |
11343 | if (asc_build_req(boardp, scp) == ASC_ERROR) { | 11331 | ret = asc_build_req(boardp, scp, &asc_scsi_q); |
11332 | if (ret == ASC_ERROR) { | ||
11344 | ASC_STATS(scp->device->host, build_error); | 11333 | ASC_STATS(scp->device->host, build_error); |
11345 | return ASC_ERROR; | 11334 | return ASC_ERROR; |
11346 | } | 11335 | } |
11347 | 11336 | ||
11348 | ret = AscExeScsiQueue(asc_dvc, &asc_scsi_q); | 11337 | ret = AscExeScsiQueue(asc_dvc, &asc_scsi_q); |
11338 | kfree(asc_scsi_q.sg_head); | ||
11349 | err_code = asc_dvc->err_code; | 11339 | err_code = asc_dvc->err_code; |
11350 | } else { | 11340 | } else { |
11351 | ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var; | 11341 | ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var; |