diff options
author | Aaro Koskinen <Aaro.Koskinen@nokia.com> | 2009-04-14 16:47:00 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-05-20 18:21:14 -0400 |
commit | fa8584566cc9cdaf067dbc12132792887a521da9 (patch) | |
tree | e103d0c9b1885ad8c017ea5f20b7881f06e85239 /drivers/scsi/sym53c8xx_2/sym_hipd.c | |
parent | 410604d25faddb1b4f0f9667b7452c06cc06cea1 (diff) |
[SCSI] sym53c8xx_2: slave_alloc/destroy safety (2.6.27.5)
Make the sym53c8xx_2 driver slave_alloc/destroy less unsafe. References
to the destroyed LCB are cleared from the target structure (instead of
leaving a dangling pointer), and when the last LCB for the target is
destroyed the reference to the upper layer target data is cleared. The
host lock is used to prevent a race with the interrupt handler. Also
user commands are prevented for targets with all LCBs destroyed.
Signed-off-by: Aaro Koskinen <Aaro.Koskinen@nokia.com>
Tested-by: Tony Battersby <tonyb@cybernetics.com>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/sym53c8xx_2/sym_hipd.c')
-rw-r--r-- | drivers/scsi/sym53c8xx_2/sym_hipd.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 60d6a6d2308..69ad4945c93 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c | |||
@@ -4997,7 +4997,7 @@ struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln) | |||
4997 | */ | 4997 | */ |
4998 | if (ln && !tp->lunmp) { | 4998 | if (ln && !tp->lunmp) { |
4999 | tp->lunmp = kcalloc(SYM_CONF_MAX_LUN, sizeof(struct sym_lcb *), | 4999 | tp->lunmp = kcalloc(SYM_CONF_MAX_LUN, sizeof(struct sym_lcb *), |
5000 | GFP_KERNEL); | 5000 | GFP_ATOMIC); |
5001 | if (!tp->lunmp) | 5001 | if (!tp->lunmp) |
5002 | goto fail; | 5002 | goto fail; |
5003 | } | 5003 | } |
@@ -5017,6 +5017,7 @@ struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln) | |||
5017 | tp->lun0p = lp; | 5017 | tp->lun0p = lp; |
5018 | tp->head.lun0_sa = cpu_to_scr(vtobus(lp)); | 5018 | tp->head.lun0_sa = cpu_to_scr(vtobus(lp)); |
5019 | } | 5019 | } |
5020 | tp->nlcb++; | ||
5020 | 5021 | ||
5021 | /* | 5022 | /* |
5022 | * Let the itl task point to error handling. | 5023 | * Let the itl task point to error handling. |
@@ -5094,6 +5095,43 @@ fail: | |||
5094 | } | 5095 | } |
5095 | 5096 | ||
5096 | /* | 5097 | /* |
5098 | * Lun control block deallocation. Returns the number of valid remaing LCBs | ||
5099 | * for the target. | ||
5100 | */ | ||
5101 | int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln) | ||
5102 | { | ||
5103 | struct sym_tcb *tp = &np->target[tn]; | ||
5104 | struct sym_lcb *lp = sym_lp(tp, ln); | ||
5105 | |||
5106 | tp->nlcb--; | ||
5107 | |||
5108 | if (ln) { | ||
5109 | if (!tp->nlcb) { | ||
5110 | kfree(tp->lunmp); | ||
5111 | sym_mfree_dma(tp->luntbl, 256, "LUNTBL"); | ||
5112 | tp->lunmp = NULL; | ||
5113 | tp->luntbl = NULL; | ||
5114 | tp->head.luntbl_sa = cpu_to_scr(vtobus(np->badluntbl)); | ||
5115 | } else { | ||
5116 | tp->luntbl[ln] = cpu_to_scr(vtobus(&np->badlun_sa)); | ||
5117 | tp->lunmp[ln] = NULL; | ||
5118 | } | ||
5119 | } else { | ||
5120 | tp->lun0p = NULL; | ||
5121 | tp->head.lun0_sa = cpu_to_scr(vtobus(&np->badlun_sa)); | ||
5122 | } | ||
5123 | |||
5124 | if (lp->itlq_tbl) { | ||
5125 | sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); | ||
5126 | kfree(lp->cb_tags); | ||
5127 | } | ||
5128 | |||
5129 | sym_mfree_dma(lp, sizeof(*lp), "LCB"); | ||
5130 | |||
5131 | return tp->nlcb; | ||
5132 | } | ||
5133 | |||
5134 | /* | ||
5097 | * Queue a SCSI IO to the controller. | 5135 | * Queue a SCSI IO to the controller. |
5098 | */ | 5136 | */ |
5099 | int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp) | 5137 | int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp) |