From fa8584566cc9cdaf067dbc12132792887a521da9 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Tue, 14 Apr 2009 15:47:00 -0500 Subject: [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 Tested-by: Tony Battersby Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/sym53c8xx_2/sym_hipd.c | 40 ++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/sym53c8xx_2/sym_hipd.c') 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) */ if (ln && !tp->lunmp) { tp->lunmp = kcalloc(SYM_CONF_MAX_LUN, sizeof(struct sym_lcb *), - GFP_KERNEL); + GFP_ATOMIC); if (!tp->lunmp) goto fail; } @@ -5017,6 +5017,7 @@ struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln) tp->lun0p = lp; tp->head.lun0_sa = cpu_to_scr(vtobus(lp)); } + tp->nlcb++; /* * Let the itl task point to error handling. @@ -5093,6 +5094,43 @@ fail: return; } +/* + * Lun control block deallocation. Returns the number of valid remaing LCBs + * for the target. + */ +int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln) +{ + struct sym_tcb *tp = &np->target[tn]; + struct sym_lcb *lp = sym_lp(tp, ln); + + tp->nlcb--; + + if (ln) { + if (!tp->nlcb) { + kfree(tp->lunmp); + sym_mfree_dma(tp->luntbl, 256, "LUNTBL"); + tp->lunmp = NULL; + tp->luntbl = NULL; + tp->head.luntbl_sa = cpu_to_scr(vtobus(np->badluntbl)); + } else { + tp->luntbl[ln] = cpu_to_scr(vtobus(&np->badlun_sa)); + tp->lunmp[ln] = NULL; + } + } else { + tp->lun0p = NULL; + tp->head.lun0_sa = cpu_to_scr(vtobus(&np->badlun_sa)); + } + + if (lp->itlq_tbl) { + sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); + kfree(lp->cb_tags); + } + + sym_mfree_dma(lp, sizeof(*lp), "LCB"); + + return tp->nlcb; +} + /* * Queue a SCSI IO to the controller. */ -- cgit v1.2.3-70-g09d2