Commit 1558c0fe authored by Justin T. Gibbs's avatar Justin T. Gibbs

Aic79xx Driver Update (version 1.3.6)

 o Correct bus hang on SE->LVD/LVD->SE tranceiver changes
 o Close a race condition in handling bad scsi status that could
   allow the driver to modify the waiting for selection queue while
   selections were enabled.
 o Perform an audit on use of del_timer() and switch to del_timer_sync()
   where appropriate.
 o Remove the reboot notifier hook which is unused in 2.5.X.
 o Correct some driver unload bugs.
parent aa19646a
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES. * POSSIBILITY OF SUCH DAMAGES.
* *
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#178 $ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#182 $
* *
* $FreeBSD$ * $FreeBSD$
*/ */
...@@ -1166,7 +1166,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) ...@@ -1166,7 +1166,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
/* /*
* A change in I/O mode is equivalent to a bus reset. * A change in I/O mode is equivalent to a bus reset.
*/ */
ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE); ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
ahd_pause(ahd); ahd_pause(ahd);
ahd_setup_iocell_workaround(ahd); ahd_setup_iocell_workaround(ahd);
ahd_unpause(ahd); ahd_unpause(ahd);
...@@ -4887,7 +4887,6 @@ ahd_free(struct ahd_softc *ahd) ...@@ -4887,7 +4887,6 @@ ahd_free(struct ahd_softc *ahd)
{ {
int i; int i;
ahd_fini_scbdata(ahd);
switch (ahd->init_level) { switch (ahd->init_level) {
default: default:
case 5: case 5:
...@@ -4919,6 +4918,7 @@ ahd_free(struct ahd_softc *ahd) ...@@ -4919,6 +4918,7 @@ ahd_free(struct ahd_softc *ahd)
ahd_dma_tag_destroy(ahd, ahd->parent_dmat); ahd_dma_tag_destroy(ahd, ahd->parent_dmat);
#endif #endif
ahd_platform_free(ahd); ahd_platform_free(ahd);
ahd_fini_scbdata(ahd);
for (i = 0; i < AHD_NUM_TARGETS; i++) { for (i = 0; i < AHD_NUM_TARGETS; i++) {
struct ahd_tmode_tstate *tstate; struct ahd_tmode_tstate *tstate;
...@@ -5584,8 +5584,8 @@ ahd_alloc_scbs(struct ahd_softc *ahd) ...@@ -5584,8 +5584,8 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
if (scb_data->sgs_left != 0) { if (scb_data->sgs_left != 0) {
int offset; int offset;
offset = ahd_sglist_allocsize(ahd) offset = ((ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd))
- (scb_data->sgs_left * ahd_sglist_size(ahd)); - scb_data->sgs_left) * ahd_sglist_size(ahd);
sg_map = SLIST_FIRST(&scb_data->sg_maps); sg_map = SLIST_FIRST(&scb_data->sg_maps);
segs = sg_map->vaddr + offset; segs = sg_map->vaddr + offset;
sg_busaddr = sg_map->physaddr + offset; sg_busaddr = sg_map->physaddr + offset;
...@@ -6605,56 +6605,55 @@ ahd_enable_coalessing(struct ahd_softc *ahd, int enable) ...@@ -6605,56 +6605,55 @@ ahd_enable_coalessing(struct ahd_softc *ahd, int enable)
void void
ahd_pause_and_flushwork(struct ahd_softc *ahd) ahd_pause_and_flushwork(struct ahd_softc *ahd)
{ {
ahd_mode_state saved_modes;
u_int intstat; u_int intstat;
u_int maxloops; u_int maxloops;
int paused; u_int qfreeze_cnt;
maxloops = 1000; maxloops = 1000;
ahd->flags |= AHD_ALL_INTERRUPTS; ahd->flags |= AHD_ALL_INTERRUPTS;
paused = FALSE; ahd_pause(ahd);
/*
* Increment the QFreeze Count so that the sequencer
* will not start new selections. We do this only
* until we are safely paused without further selections
* pending.
*/
ahd_outw(ahd, QFREEZE_COUNT, ahd_inw(ahd, QFREEZE_COUNT) + 1);
ahd_outb(ahd, SEQ_FLAGS2, ahd_inb(ahd, SEQ_FLAGS2) | SELECTOUT_QFROZEN);
do { do {
struct scb *waiting_scb;
if (paused) ahd_unpause(ahd);
ahd_unpause(ahd);
ahd_intr(ahd); ahd_intr(ahd);
ahd_pause(ahd); ahd_pause(ahd);
paused = TRUE;
ahd_clear_critical_section(ahd); ahd_clear_critical_section(ahd);
saved_modes = ahd_save_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
if ((ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0)
ahd_outb(ahd, SCSISEQ0,
ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
/*
* In the non-packetized case, the sequencer (for Rev A),
* relies on ENSELO remaining set after SELDO. The hardware
* auto-clears ENSELO in the packetized case.
*/
waiting_scb = ahd_lookup_scb(ahd,
ahd_inw(ahd, WAITING_TID_HEAD));
if (waiting_scb != NULL
&& (waiting_scb->flags & SCB_PACKETIZED) == 0
&& (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0)
ahd_outb(ahd, SCSISEQ0,
ahd_inb(ahd, SCSISEQ0) | ENSELO);
intstat = ahd_inb(ahd, INTSTAT); intstat = ahd_inb(ahd, INTSTAT);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
} while (--maxloops } while (--maxloops
&& (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0) && (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0)
&& ((intstat & INT_PEND) != 0 && ((intstat & INT_PEND) != 0
|| (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)))); || (ahd_inb(ahd, SCSISEQ0) & ENSELO) != 0
|| (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0));
if (maxloops == 0) { if (maxloops == 0) {
printf("Infinite interrupt loop, INTSTAT = %x", printf("Infinite interrupt loop, INTSTAT = %x",
ahd_inb(ahd, INTSTAT)); ahd_inb(ahd, INTSTAT));
} }
qfreeze_cnt = ahd_inw(ahd, QFREEZE_COUNT);
if (qfreeze_cnt == 0) {
printf("%s: ahd_pause_and_flushwork with 0 qfreeze count!\n",
ahd_name(ahd));
} else {
qfreeze_cnt--;
}
ahd_outw(ahd, QFREEZE_COUNT, qfreeze_cnt);
if (qfreeze_cnt == 0)
ahd_outb(ahd, SEQ_FLAGS2,
ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN);
ahd_flush_qoutfifo(ahd); ahd_flush_qoutfifo(ahd);
ahd_platform_flushwork(ahd); ahd_platform_flushwork(ahd);
ahd->flags &= ~AHD_ALL_INTERRUPTS; ahd->flags &= ~AHD_ALL_INTERRUPTS;
ahd_restore_modes(ahd, saved_modes);
} }
int int
...@@ -7514,14 +7513,17 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) ...@@ -7514,14 +7513,17 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
ahd_outb(ahd, DFFSTAT, next_fifo); ahd_outb(ahd, DFFSTAT, next_fifo);
} while (next_fifo != fifo); } while (next_fifo != fifo);
/* /*
* Reset the bus if we are initiating this reset * Reset the bus if we are initiating this reset
*/ */
ahd_clear_msg_state(ahd); ahd_clear_msg_state(ahd);
ahd_outb(ahd, SIMODE1, ahd_outb(ahd, SIMODE1,
ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST|ENBUSFREE)); ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST|ENBUSFREE));
if (initiate_reset) if (initiate_reset)
ahd_reset_current_bus(ahd); ahd_reset_current_bus(ahd);
ahd_clear_intstat(ahd); ahd_clear_intstat(ahd);
/* /*
...@@ -7709,6 +7711,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) ...@@ -7709,6 +7711,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
{ {
struct hardware_scb *hscb; struct hardware_scb *hscb;
u_int qfreeze_cnt; u_int qfreeze_cnt;
u_int maxloops;
/* /*
* The sequencer freezes its select-out queue * The sequencer freezes its select-out queue
...@@ -7718,10 +7721,23 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) ...@@ -7718,10 +7721,23 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
*/ */
hscb = scb->hscb; hscb = scb->hscb;
/*
* Wait until any pending selections have been processed.
*/
maxloops = 1000;
do {
ahd_pause(ahd);
ahd_clear_critical_section(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
if (((ahd_inb(ahd, SCSISEQ0) & ENSELO) == 0
&& (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0)
|| (ahd_inb(ahd, SSTAT1) & SELTO) != 0)
break;
ahd_unpause(ahd);
ahd_delay(200);
} while (--maxloops);
/* Freeze the queue until the client sees the error. */ /* Freeze the queue until the client sees the error. */
ahd_pause(ahd);
ahd_clear_critical_section(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
ahd_freeze_devq(ahd, scb); ahd_freeze_devq(ahd, scb);
ahd_freeze_scb(scb); ahd_freeze_scb(scb);
qfreeze_cnt = ahd_inw(ahd, QFREEZE_COUNT); qfreeze_cnt = ahd_inw(ahd, QFREEZE_COUNT);
......
/* /*
* Adaptec AIC79xx device driver for Linux. * Adaptec AIC79xx device driver for Linux.
* *
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#141 $ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#147 $
* *
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
* Copyright (c) 1994-2000 Justin T. Gibbs. * Copyright (c) 1994-2000 Justin T. Gibbs.
...@@ -548,7 +548,6 @@ static aic_option_callback_t ahd_linux_setup_dv; ...@@ -548,7 +548,6 @@ static aic_option_callback_t ahd_linux_setup_dv;
static aic_option_callback_t ahd_linux_setup_iocell_info; static aic_option_callback_t ahd_linux_setup_iocell_info;
static int ahd_linux_next_unit(void); static int ahd_linux_next_unit(void);
static void ahd_runq_tasklet(unsigned long data); static void ahd_runq_tasklet(unsigned long data);
static int ahd_linux_halt(struct notifier_block *nb, u_long event, void *buf);
static int aic79xx_setup(char *c); static int aic79xx_setup(char *c);
/****************************** Inlines ***************************************/ /****************************** Inlines ***************************************/
...@@ -1087,7 +1086,8 @@ ahd_linux_slave_destroy(Scsi_Device *device) ...@@ -1087,7 +1086,8 @@ ahd_linux_slave_destroy(Scsi_Device *device)
&& (dev->flags & AHD_DEV_SLAVE_CONFIGURED) != 0) { && (dev->flags & AHD_DEV_SLAVE_CONFIGURED) != 0) {
dev->flags |= AHD_DEV_UNCONFIGURED; dev->flags |= AHD_DEV_UNCONFIGURED;
if (TAILQ_EMPTY(&dev->busyq) if (TAILQ_EMPTY(&dev->busyq)
&& dev->active == 0) && dev->active == 0
&& (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0)
ahd_linux_free_device(ahd, dev); ahd_linux_free_device(ahd, dev);
} }
ahd_midlayer_entrypoint_unlock(ahd, &flags); ahd_midlayer_entrypoint_unlock(ahd, &flags);
...@@ -1476,7 +1476,7 @@ ahd_linux_abort(Scsi_Cmnd *cmd) ...@@ -1476,7 +1476,7 @@ ahd_linux_abort(Scsi_Cmnd *cmd)
printf("Recovery code sleeping\n"); printf("Recovery code sleeping\n");
down(&ahd->platform_data->eh_sem); down(&ahd->platform_data->eh_sem);
printf("Recovery code awake\n"); printf("Recovery code awake\n");
ret = del_timer(&timer); ret = del_timer_sync(&timer);
if (ret == 0) { if (ret == 0) {
printf("Timer Expired\n"); printf("Timer Expired\n");
retval = FAILED; retval = FAILED;
...@@ -1581,7 +1581,7 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd) ...@@ -1581,7 +1581,7 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd)
down(&ahd->platform_data->eh_sem); down(&ahd->platform_data->eh_sem);
printf("Recovery code awake\n"); printf("Recovery code awake\n");
retval = SUCCESS; retval = SUCCESS;
if (del_timer(&timer) == 0) { if (del_timer_sync(&timer) == 0) {
printf("Timer Expired\n"); printf("Timer Expired\n");
retval = FAILED; retval = FAILED;
} }
...@@ -1717,35 +1717,6 @@ ahd_runq_tasklet(unsigned long data) ...@@ -1717,35 +1717,6 @@ ahd_runq_tasklet(unsigned long data)
#endif #endif
} }
/************************ Shutdown/halt/reboot hook ***************************/
#include <linux/notifier.h>
#include <linux/reboot.h>
static struct notifier_block ahd_linux_notifier = {
ahd_linux_halt, NULL, 0
};
static int ahd_linux_halt(struct notifier_block *nb, u_long event, void *buf)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
struct ahd_softc *ahd;
/*
* In 2.5.X, this is called prior to the filesystems
* being synced and the SCSI layer being properly
* shutdown. A different API is required there,
* but the device hooks for this don't quite look
* right.
*/
if (event == SYS_DOWN || event == SYS_HALT) {
TAILQ_FOREACH(ahd, &ahd_tailq, links) {
ahd_shutdown(ahd);
}
}
#endif
return (NOTIFY_OK);
}
/******************************** Bus DMA *************************************/ /******************************** Bus DMA *************************************/
int int
ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent, ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent,
...@@ -1927,7 +1898,7 @@ ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd) ...@@ -1927,7 +1898,7 @@ ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
} }
static void static void
ahd_linux_setup_tag_info(void *arg, int instance, int targ, int32_t value) ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
{ {
if ((instance >= 0) && (targ >= 0) if ((instance >= 0) && (targ >= 0)
...@@ -1940,18 +1911,18 @@ ahd_linux_setup_tag_info(void *arg, int instance, int targ, int32_t value) ...@@ -1940,18 +1911,18 @@ ahd_linux_setup_tag_info(void *arg, int instance, int targ, int32_t value)
} }
static void static void
ahd_linux_setup_rd_strm_info(void *arg, int instance, int targ, int32_t value) ahd_linux_setup_rd_strm_info(u_long arg, int instance, int targ, int32_t value)
{ {
if ((instance >= 0) if ((instance >= 0)
&& (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) { && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) {
aic79xx_rd_strm_info[instance] = value * 0xFFFF; aic79xx_rd_strm_info[instance] = value & 0xFFFF;
if (bootverbose) if (bootverbose)
printf("rd_strm[%d] = 0x%x\n", instance, value); printf("rd_strm[%d] = 0x%x\n", instance, value);
} }
} }
static void static void
ahd_linux_setup_dv(void *arg, int instance, int targ, int32_t value) ahd_linux_setup_dv(u_long arg, int instance, int targ, int32_t value)
{ {
if ((instance >= 0) if ((instance >= 0)
&& (instance < NUM_ELEMENTS(aic79xx_dv_settings))) { && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) {
...@@ -1962,11 +1933,9 @@ ahd_linux_setup_dv(void *arg, int instance, int targ, int32_t value) ...@@ -1962,11 +1933,9 @@ ahd_linux_setup_dv(void *arg, int instance, int targ, int32_t value)
} }
static void static void
ahd_linux_setup_iocell_info(void *arg, int instance, int targ, int32_t value) ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value)
{ {
u_int index;
index = (u_int)arg;
if ((instance >= 0) if ((instance >= 0)
&& (instance < NUM_ELEMENTS(aic79xx_iocell_info))) { && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) {
uint8_t *iocell_info; uint8_t *iocell_info;
...@@ -1974,7 +1943,7 @@ ahd_linux_setup_iocell_info(void *arg, int instance, int targ, int32_t value) ...@@ -1974,7 +1943,7 @@ ahd_linux_setup_iocell_info(void *arg, int instance, int targ, int32_t value)
iocell_info = (uint8_t*)&aic79xx_iocell_info[instance]; iocell_info = (uint8_t*)&aic79xx_iocell_info[instance];
iocell_info[index] = value & 0xFFFF; iocell_info[index] = value & 0xFFFF;
if (bootverbose) if (bootverbose)
printf("iocell[%d:%d] = %d\n", instance, index, value); printf("iocell[%d:%ld] = %d\n", instance, index, value);
} }
} }
...@@ -2053,26 +2022,26 @@ aic79xx_setup(char *s) ...@@ -2053,26 +2022,26 @@ aic79xx_setup(char *s)
ahd_linux_setup_tag_info_global(p + n); ahd_linux_setup_tag_info_global(p + n);
} else if (strncmp(p, "tag_info", n) == 0) { } else if (strncmp(p, "tag_info", n) == 0) {
s = aic_parse_brace_option("tag_info", p + n, end, s = aic_parse_brace_option("tag_info", p + n, end,
2, ahd_linux_setup_tag_info, NULL); 2, ahd_linux_setup_tag_info, 0);
} else if (strncmp(p, "rd_strm", n) == 0) { } else if (strncmp(p, "rd_strm", n) == 0) {
printf("Calling brace parse for %s\n", p); printf("Calling brace parse for %s\n", p);
s = aic_parse_brace_option("rd_strm", p + n, end, s = aic_parse_brace_option("rd_strm", p + n, end,
1, ahd_linux_setup_rd_strm_info, NULL); 1, ahd_linux_setup_rd_strm_info, 0);
} else if (strncmp(p, "dv", n) == 0) { } else if (strncmp(p, "dv", n) == 0) {
s = aic_parse_brace_option("dv", p + n, end, 1, s = aic_parse_brace_option("dv", p + n, end, 1,
ahd_linux_setup_dv, NULL); ahd_linux_setup_dv, 0);
} else if (strncmp(p, "slewrate", n) == 0) { } else if (strncmp(p, "slewrate", n) == 0) {
s = aic_parse_brace_option("slewrate", s = aic_parse_brace_option("slewrate",
p + n, end, 1, ahd_linux_setup_iocell_info, p + n, end, 1, ahd_linux_setup_iocell_info,
(void *)AIC79XX_SLEWRATE_INDEX); AIC79XX_SLEWRATE_INDEX);
} else if (strncmp(p, "precomp", n) == 0) { } else if (strncmp(p, "precomp", n) == 0) {
s = aic_parse_brace_option("precomp", s = aic_parse_brace_option("precomp",
p + n, end, 1, ahd_linux_setup_iocell_info, p + n, end, 1, ahd_linux_setup_iocell_info,
(void *)AIC79XX_PRECOMP_INDEX); AIC79XX_PRECOMP_INDEX);
} else if (strncmp(p, "amplitude", n) == 0) { } else if (strncmp(p, "amplitude", n) == 0) {
s = aic_parse_brace_option("amplitude", s = aic_parse_brace_option("amplitude",
p + n, end, 1, ahd_linux_setup_iocell_info, p + n, end, 1, ahd_linux_setup_iocell_info,
(void *)AIC79XX_AMPLITUDE_INDEX); AIC79XX_AMPLITUDE_INDEX);
} else if (p[n] == ':') { } else if (p[n] == ':') {
*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
} else if (!strncmp(p, "verbose", n)) { } else if (!strncmp(p, "verbose", n)) {
...@@ -2291,8 +2260,6 @@ ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) ...@@ -2291,8 +2260,6 @@ ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
#endif #endif
ahd_setup_runq_tasklet(ahd); ahd_setup_runq_tasklet(ahd);
ahd->seltime = (aic79xx_seltime & 0x3) << 4; ahd->seltime = (aic79xx_seltime & 0x3) << 4;
if (TAILQ_EMPTY(&ahd_tailq))
register_reboot_notifier(&ahd_linux_notifier);
return (0); return (0);
} }
...@@ -2304,6 +2271,7 @@ ahd_platform_free(struct ahd_softc *ahd) ...@@ -2304,6 +2271,7 @@ ahd_platform_free(struct ahd_softc *ahd)
int i, j; int i, j;
if (ahd->platform_data != NULL) { if (ahd->platform_data != NULL) {
del_timer_sync(&ahd->platform_data->completeq_timer);
ahd_linux_kill_dv_thread(ahd); ahd_linux_kill_dv_thread(ahd);
ahd_teardown_runq_tasklet(ahd); ahd_teardown_runq_tasklet(ahd);
if (ahd->platform_data->host != NULL) { if (ahd->platform_data->host != NULL) {
...@@ -2317,15 +2285,20 @@ ahd_platform_free(struct ahd_softc *ahd) ...@@ -2317,15 +2285,20 @@ ahd_platform_free(struct ahd_softc *ahd)
for (i = 0; i < AHD_NUM_TARGETS; i++) { for (i = 0; i < AHD_NUM_TARGETS; i++) {
targ = ahd->platform_data->targets[i]; targ = ahd->platform_data->targets[i];
if (targ != NULL) { if (targ != NULL) {
/* Keep target around through the loop. */
targ->refcount++;
for (j = 0; j < AHD_NUM_LUNS; j++) { for (j = 0; j < AHD_NUM_LUNS; j++) {
if (targ->devices[j] != NULL) {
dev = targ->devices[j]; if (targ->devices[j] == NULL)
ahd_linux_free_device(ahd, dev); continue;
} dev = targ->devices[j];
if (ahd->platform_data->targets[i] == ahd_linux_free_device(ahd, dev);
NULL)
break;
} }
/*
* Forcibly free the target now that
* all devices are gone.
*/
ahd_linux_free_target(ahd, targ);
} }
} }
...@@ -2921,10 +2894,14 @@ ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset) ...@@ -2921,10 +2894,14 @@ ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset)
} }
ahd_lock(ahd, &s); ahd_lock(ahd, &s);
if (targ->dv_buffer != NULL) if (targ->dv_buffer != NULL) {
free(targ->dv_buffer, M_DEVBUF); free(targ->dv_buffer, M_DEVBUF);
if (targ->dv_buffer1 != NULL) targ->dv_buffer = NULL;
}
if (targ->dv_buffer1 != NULL) {
free(targ->dv_buffer1, M_DEVBUF); free(targ->dv_buffer1, M_DEVBUF);
targ->dv_buffer1 = NULL;
}
targ->flags &= ~AHD_DV_REQUIRED; targ->flags &= ~AHD_DV_REQUIRED;
if (targ->refcount == 0) if (targ->refcount == 0)
ahd_linux_free_target(ahd, targ); ahd_linux_free_target(ahd, targ);
...@@ -4542,7 +4519,8 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) ...@@ -4542,7 +4519,8 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb)
if (TAILQ_EMPTY(&dev->busyq)) { if (TAILQ_EMPTY(&dev->busyq)) {
if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0
&& dev->active == 0) && dev->active == 0
&& (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0)
ahd_linux_free_device(ahd, dev); ahd_linux_free_device(ahd, dev);
} else if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) { } else if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) {
TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links);
...@@ -5065,6 +5043,9 @@ ahd_linux_dev_timed_unfreeze(u_long arg) ...@@ -5065,6 +5043,9 @@ ahd_linux_dev_timed_unfreeze(u_long arg)
if (dev->qfrozen == 0 if (dev->qfrozen == 0
&& (dev->flags & AHD_DEV_ON_RUN_LIST) == 0) && (dev->flags & AHD_DEV_ON_RUN_LIST) == 0)
ahd_linux_run_device_queue(ahd, dev); ahd_linux_run_device_queue(ahd, dev);
if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0
&& dev->active == 0)
ahd_linux_free_device(ahd, dev);
ahd_unlock(ahd, &s); ahd_unlock(ahd, &s);
} }
...@@ -5143,8 +5124,6 @@ ahd_linux_exit(void) ...@@ -5143,8 +5124,6 @@ ahd_linux_exit(void)
scsi_unregister_module(MODULE_SCSI_HA, &aic79xx_driver_template); scsi_unregister_module(MODULE_SCSI_HA, &aic79xx_driver_template);
#endif #endif
ahd_linux_pci_exit(); ahd_linux_pci_exit();
unregister_reboot_notifier(&ahd_linux_notifier);
} }
module_init(ahd_linux_init); module_init(ahd_linux_init);
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES. * POSSIBILITY OF SUCH DAMAGES.
* *
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#121 $ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#123 $
* *
*/ */
#ifndef _AIC79XX_LINUX_H_ #ifndef _AIC79XX_LINUX_H_
...@@ -255,7 +255,7 @@ typedef struct timer_list ahd_timer_t; ...@@ -255,7 +255,7 @@ typedef struct timer_list ahd_timer_t;
/***************************** Timer Facilities *******************************/ /***************************** Timer Facilities *******************************/
#define ahd_timer_init init_timer #define ahd_timer_init init_timer
#define ahd_timer_stop del_timer #define ahd_timer_stop del_timer_sync
typedef void ahd_linux_callback_t (u_long); typedef void ahd_linux_callback_t (u_long);
static __inline void ahd_timer_reset(ahd_timer_t *timer, u_int usec, static __inline void ahd_timer_reset(ahd_timer_t *timer, u_int usec,
ahd_callback_t *func, void *arg); ahd_callback_t *func, void *arg);
...@@ -293,7 +293,7 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec) ...@@ -293,7 +293,7 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec)
#define AHD_SCSI_HAS_HOST_LOCK 0 #define AHD_SCSI_HAS_HOST_LOCK 0
#endif #endif
#define AIC79XX_DRIVER_VERSION "1.3.5" #define AIC79XX_DRIVER_VERSION "1.3.6"
/**************************** Front End Queues ********************************/ /**************************** Front End Queues ********************************/
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment