|
@@ -737,11 +737,14 @@ static int sym53c8xx_slave_alloc(struct scsi_device *sdev)
|
|
struct sym_hcb *np = sym_get_hcb(sdev->host);
|
|
struct sym_hcb *np = sym_get_hcb(sdev->host);
|
|
struct sym_tcb *tp = &np->target[sdev->id];
|
|
struct sym_tcb *tp = &np->target[sdev->id];
|
|
struct sym_lcb *lp;
|
|
struct sym_lcb *lp;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ int error;
|
|
|
|
|
|
if (sdev->id >= SYM_CONF_MAX_TARGET || sdev->lun >= SYM_CONF_MAX_LUN)
|
|
if (sdev->id >= SYM_CONF_MAX_TARGET || sdev->lun >= SYM_CONF_MAX_LUN)
|
|
return -ENXIO;
|
|
return -ENXIO;
|
|
|
|
|
|
- tp->starget = sdev->sdev_target;
|
|
|
|
|
|
+ spin_lock_irqsave(np->s.host->host_lock, flags);
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Fail the device init if the device is flagged NOSCAN at BOOT in
|
|
* Fail the device init if the device is flagged NOSCAN at BOOT in
|
|
* the NVRAM. This may speed up boot and maintain coherency with
|
|
* the NVRAM. This may speed up boot and maintain coherency with
|
|
@@ -753,26 +756,37 @@ static int sym53c8xx_slave_alloc(struct scsi_device *sdev)
|
|
|
|
|
|
if (tp->usrflags & SYM_SCAN_BOOT_DISABLED) {
|
|
if (tp->usrflags & SYM_SCAN_BOOT_DISABLED) {
|
|
tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED;
|
|
tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED;
|
|
- starget_printk(KERN_INFO, tp->starget,
|
|
|
|
|
|
+ starget_printk(KERN_INFO, sdev->sdev_target,
|
|
"Scan at boot disabled in NVRAM\n");
|
|
"Scan at boot disabled in NVRAM\n");
|
|
- return -ENXIO;
|
|
|
|
|
|
+ error = -ENXIO;
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
if (tp->usrflags & SYM_SCAN_LUNS_DISABLED) {
|
|
if (tp->usrflags & SYM_SCAN_LUNS_DISABLED) {
|
|
- if (sdev->lun != 0)
|
|
|
|
- return -ENXIO;
|
|
|
|
- starget_printk(KERN_INFO, tp->starget,
|
|
|
|
|
|
+ if (sdev->lun != 0) {
|
|
|
|
+ error = -ENXIO;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ starget_printk(KERN_INFO, sdev->sdev_target,
|
|
"Multiple LUNs disabled in NVRAM\n");
|
|
"Multiple LUNs disabled in NVRAM\n");
|
|
}
|
|
}
|
|
|
|
|
|
lp = sym_alloc_lcb(np, sdev->id, sdev->lun);
|
|
lp = sym_alloc_lcb(np, sdev->id, sdev->lun);
|
|
- if (!lp)
|
|
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ if (!lp) {
|
|
|
|
+ error = -ENOMEM;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ if (tp->nlcb == 1)
|
|
|
|
+ tp->starget = sdev->sdev_target;
|
|
|
|
|
|
spi_min_period(tp->starget) = tp->usr_period;
|
|
spi_min_period(tp->starget) = tp->usr_period;
|
|
spi_max_width(tp->starget) = tp->usr_width;
|
|
spi_max_width(tp->starget) = tp->usr_width;
|
|
|
|
|
|
- return 0;
|
|
|
|
|
|
+ error = 0;
|
|
|
|
+out:
|
|
|
|
+ spin_unlock_irqrestore(np->s.host->host_lock, flags);
|
|
|
|
+
|
|
|
|
+ return error;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -819,12 +833,34 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev)
|
|
static void sym53c8xx_slave_destroy(struct scsi_device *sdev)
|
|
static void sym53c8xx_slave_destroy(struct scsi_device *sdev)
|
|
{
|
|
{
|
|
struct sym_hcb *np = sym_get_hcb(sdev->host);
|
|
struct sym_hcb *np = sym_get_hcb(sdev->host);
|
|
- struct sym_lcb *lp = sym_lp(&np->target[sdev->id], sdev->lun);
|
|
|
|
|
|
+ struct sym_tcb *tp = &np->target[sdev->id];
|
|
|
|
+ struct sym_lcb *lp = sym_lp(tp, sdev->lun);
|
|
|
|
+ unsigned long flags;
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(np->s.host->host_lock, flags);
|
|
|
|
+
|
|
|
|
+ if (lp->busy_itlq || lp->busy_itl) {
|
|
|
|
+ /*
|
|
|
|
+ * This really shouldn't happen, but we can't return an error
|
|
|
|
+ * so let's try to stop all on-going I/O.
|
|
|
|
+ */
|
|
|
|
+ starget_printk(KERN_WARNING, tp->starget,
|
|
|
|
+ "Removing busy LCB (%d)\n", sdev->lun);
|
|
|
|
+ sym_reset_scsi_bus(np, 1);
|
|
|
|
+ }
|
|
|
|
|
|
- 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");
|
|
|
|
|
|
+ if (sym_free_lcb(np, sdev->id, sdev->lun) == 0) {
|
|
|
|
+ /*
|
|
|
|
+ * It was the last unit for this target.
|
|
|
|
+ */
|
|
|
|
+ tp->head.sval = 0;
|
|
|
|
+ tp->head.wval = np->rv_scntl3;
|
|
|
|
+ tp->head.uval = 0;
|
|
|
|
+ tp->tgoal.check_nego = 1;
|
|
|
|
+ tp->starget = NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ spin_unlock_irqrestore(np->s.host->host_lock, flags);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -890,6 +926,8 @@ static void sym_exec_user_command (struct sym_hcb *np, struct sym_usrcmd *uc)
|
|
if (!((uc->target >> t) & 1))
|
|
if (!((uc->target >> t) & 1))
|
|
continue;
|
|
continue;
|
|
tp = &np->target[t];
|
|
tp = &np->target[t];
|
|
|
|
+ if (!tp->nlcb)
|
|
|
|
+ continue;
|
|
|
|
|
|
switch (uc->cmd) {
|
|
switch (uc->cmd) {
|
|
|
|
|