aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sym53c8xx_2/sym_hipd.c
diff options
context:
space:
mode:
authorAaro Koskinen <Aaro.Koskinen@nokia.com>2009-04-14 16:47:00 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-05-20 18:21:14 -0400
commitfa8584566cc9cdaf067dbc12132792887a521da9 (patch)
treee103d0c9b1885ad8c017ea5f20b7881f06e85239 /drivers/scsi/sym53c8xx_2/sym_hipd.c
parent410604d25faddb1b4f0f9667b7452c06cc06cea1 (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.c40
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 */
5101int 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 */
5099int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp) 5137int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)