aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2006-04-03 02:19:34 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-04-13 13:56:15 -0400
commitf41b5cec9bd6fec1b11b74500f5fb9c3e6e808b2 (patch)
tree0098b82ba59ae525d2ed7528435e5d4e46ce76dc /drivers/scsi
parent4d7db04a7a69099accd84984a78c64d2178252f1 (diff)
[SCSI] aic79xx bus reset update
As James B. correctly noted, ahd_reset_channel() in ahd_linux_bus_reset() should be protected by ahd_lock(). However, the main reason for not doing so was a deadlock with the interesting polling mechanism to detect the end a bus reset. This patch replaces the polling mechanism with a saner signalling via flags; it also gives us the benefit of detecting any multiple calls to ahd_reset_channel(). Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c114
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c4
3 files changed, 58 insertions, 62 deletions
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index 1d11f7e77564..933e5101edf6 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -372,7 +372,7 @@ typedef enum {
372 AHD_CURRENT_SENSING = 0x40000, 372 AHD_CURRENT_SENSING = 0x40000,
373 AHD_SCB_CONFIG_USED = 0x80000,/* No SEEPROM but SCB had info. */ 373 AHD_SCB_CONFIG_USED = 0x80000,/* No SEEPROM but SCB had info. */
374 AHD_HP_BOARD = 0x100000, 374 AHD_HP_BOARD = 0x100000,
375 AHD_RESET_POLL_ACTIVE = 0x200000, 375 AHD_BUS_RESET_ACTIVE = 0x200000,
376 AHD_UPDATE_PEND_CMDS = 0x400000, 376 AHD_UPDATE_PEND_CMDS = 0x400000,
377 AHD_RUNNING_QOUTFIFO = 0x800000, 377 AHD_RUNNING_QOUTFIFO = 0x800000,
378 AHD_HAD_FIRST_SEL = 0x1000000 378 AHD_HAD_FIRST_SEL = 0x1000000
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 326a62226235..880a10def1aa 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -207,7 +207,6 @@ static void ahd_add_scb_to_free_list(struct ahd_softc *ahd,
207static u_int ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid, 207static u_int ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid,
208 u_int prev, u_int next, u_int tid); 208 u_int prev, u_int next, u_int tid);
209static void ahd_reset_current_bus(struct ahd_softc *ahd); 209static void ahd_reset_current_bus(struct ahd_softc *ahd);
210static ahd_callback_t ahd_reset_poll;
211static ahd_callback_t ahd_stat_timer; 210static ahd_callback_t ahd_stat_timer;
212#ifdef AHD_DUMP_SEQ 211#ifdef AHD_DUMP_SEQ
213static void ahd_dumpseq(struct ahd_softc *ahd); 212static void ahd_dumpseq(struct ahd_softc *ahd);
@@ -1534,6 +1533,18 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
1534 lqistat1 = ahd_inb(ahd, LQISTAT1); 1533 lqistat1 = ahd_inb(ahd, LQISTAT1);
1535 lqostat0 = ahd_inb(ahd, LQOSTAT0); 1534 lqostat0 = ahd_inb(ahd, LQOSTAT0);
1536 busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME; 1535 busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME;
1536
1537 /*
1538 * Ignore external resets after a bus reset.
1539 */
1540 if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE))
1541 return;
1542
1543 /*
1544 * Clear bus reset flag
1545 */
1546 ahd->flags &= ~AHD_BUS_RESET_ACTIVE;
1547
1537 if ((status0 & (SELDI|SELDO)) != 0) { 1548 if ((status0 & (SELDI|SELDO)) != 0) {
1538 u_int simode0; 1549 u_int simode0;
1539 1550
@@ -7847,6 +7858,17 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
7847 int found; 7858 int found;
7848 u_int fifo; 7859 u_int fifo;
7849 u_int next_fifo; 7860 u_int next_fifo;
7861 uint8_t scsiseq;
7862
7863 /*
7864 * Check if the last bus reset is cleared
7865 */
7866 if (ahd->flags & AHD_BUS_RESET_ACTIVE) {
7867 printf("%s: bus reset still active\n",
7868 ahd_name(ahd));
7869 return 0;
7870 }
7871 ahd->flags |= AHD_BUS_RESET_ACTIVE;
7850 7872
7851 ahd->pending_device = NULL; 7873 ahd->pending_device = NULL;
7852 7874
@@ -7860,6 +7882,12 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
7860 /* Make sure the sequencer is in a safe location. */ 7882 /* Make sure the sequencer is in a safe location. */
7861 ahd_clear_critical_section(ahd); 7883 ahd_clear_critical_section(ahd);
7862 7884
7885 /*
7886 * Run our command complete fifos to ensure that we perform
7887 * completion processing on any commands that 'completed'
7888 * before the reset occurred.
7889 */
7890 ahd_run_qoutfifo(ahd);
7863#ifdef AHD_TARGET_MODE 7891#ifdef AHD_TARGET_MODE
7864 if ((ahd->flags & AHD_TARGETROLE) != 0) { 7892 if ((ahd->flags & AHD_TARGETROLE) != 0) {
7865 ahd_run_tqinfifo(ahd, /*paused*/TRUE); 7893 ahd_run_tqinfifo(ahd, /*paused*/TRUE);
@@ -7924,30 +7952,14 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
7924 ahd_clear_fifo(ahd, 1); 7952 ahd_clear_fifo(ahd, 1);
7925 7953
7926 /* 7954 /*
7927 * Revert to async/narrow transfers until we renegotiate. 7955 * Reenable selections
7928 */ 7956 */
7929 max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7; 7957 ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST);
7930 for (target = 0; target <= max_scsiid; target++) { 7958 scsiseq = ahd_inb(ahd, SCSISEQ_TEMPLATE);
7931 7959 ahd_outb(ahd, SCSISEQ1, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP));
7932 if (ahd->enabled_targets[target] == NULL)
7933 continue;
7934 for (initiator = 0; initiator <= max_scsiid; initiator++) {
7935 struct ahd_devinfo devinfo;
7936
7937 ahd_compile_devinfo(&devinfo, target, initiator,
7938 CAM_LUN_WILDCARD,
7939 'A', ROLE_UNKNOWN);
7940 ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
7941 AHD_TRANS_CUR, /*paused*/TRUE);
7942 ahd_set_syncrate(ahd, &devinfo, /*period*/0,
7943 /*offset*/0, /*ppr_options*/0,
7944 AHD_TRANS_CUR, /*paused*/TRUE);
7945 }
7946 }
7947 7960
7948#ifdef AHD_TARGET_MODE
7949 max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7; 7961 max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7;
7950 7962#ifdef AHD_TARGET_MODE
7951 /* 7963 /*
7952 * Send an immediate notify ccb to all target more peripheral 7964 * Send an immediate notify ccb to all target more peripheral
7953 * drivers affected by this action. 7965 * drivers affected by this action.
@@ -7975,51 +7987,31 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
7975 /* Notify the XPT that a bus reset occurred */ 7987 /* Notify the XPT that a bus reset occurred */
7976 ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD, 7988 ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD,
7977 CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); 7989 CAM_LUN_WILDCARD, AC_BUS_RESET, NULL);
7978 ahd_restart(ahd); 7990
7979 /* 7991 /*
7980 * Freeze the SIMQ until our poller can determine that 7992 * Revert to async/narrow transfers until we renegotiate.
7981 * the bus reset has really gone away. We set the initial
7982 * timer to 0 to have the check performed as soon as possible
7983 * from the timer context.
7984 */ 7993 */
7985 if ((ahd->flags & AHD_RESET_POLL_ACTIVE) == 0) { 7994 for (target = 0; target <= max_scsiid; target++) {
7986 ahd->flags |= AHD_RESET_POLL_ACTIVE;
7987 ahd_freeze_simq(ahd);
7988 ahd_timer_reset(&ahd->reset_timer, 0, ahd_reset_poll, ahd);
7989 }
7990 return (found);
7991}
7992 7995
7996 if (ahd->enabled_targets[target] == NULL)
7997 continue;
7998 for (initiator = 0; initiator <= max_scsiid; initiator++) {
7999 struct ahd_devinfo devinfo;
7993 8000
7994#define AHD_RESET_POLL_US 1000 8001 ahd_compile_devinfo(&devinfo, target, initiator,
7995static void 8002 CAM_LUN_WILDCARD,
7996ahd_reset_poll(void *arg) 8003 'A', ROLE_UNKNOWN);
7997{ 8004 ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
7998 struct ahd_softc *ahd = arg; 8005 AHD_TRANS_CUR, /*paused*/TRUE);
7999 u_int scsiseq1; 8006 ahd_set_syncrate(ahd, &devinfo, /*period*/0,
8000 u_long s; 8007 /*offset*/0, /*ppr_options*/0,
8001 8008 AHD_TRANS_CUR, /*paused*/TRUE);
8002 ahd_lock(ahd, &s); 8009 }
8003 ahd_pause(ahd);
8004 ahd_update_modes(ahd);
8005 ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
8006 ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI);
8007 if ((ahd_inb(ahd, SSTAT1) & SCSIRSTI) != 0) {
8008 ahd_timer_reset(&ahd->reset_timer, AHD_RESET_POLL_US,
8009 ahd_reset_poll, ahd);
8010 ahd_unpause(ahd);
8011 ahd_unlock(ahd, &s);
8012 return;
8013 } 8010 }
8014 8011
8015 /* Reset is now low. Complete chip reinitialization. */ 8012 ahd_restart(ahd);
8016 ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST); 8013
8017 scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE); 8014 return (found);
8018 ahd_outb(ahd, SCSISEQ1, scsiseq1 & (ENSELI|ENRSELI|ENAUTOATNP));
8019 ahd_unpause(ahd);
8020 ahd->flags &= ~AHD_RESET_POLL_ACTIVE;
8021 ahd_unlock(ahd, &s);
8022 ahd_release_simq(ahd);
8023} 8015}
8024 8016
8025/**************************** Statistics Processing ***************************/ 8017/**************************** Statistics Processing ***************************/
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index bcced0a417e6..66e4a47bb9ee 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -782,6 +782,7 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd)
782{ 782{
783 struct ahd_softc *ahd; 783 struct ahd_softc *ahd;
784 int found; 784 int found;
785 unsigned long flags;
785 786
786 ahd = *(struct ahd_softc **)cmd->device->host->hostdata; 787 ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
787#ifdef AHD_DEBUG 788#ifdef AHD_DEBUG
@@ -789,8 +790,11 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd)
789 printf("%s: Bus reset called for cmd %p\n", 790 printf("%s: Bus reset called for cmd %p\n",
790 ahd_name(ahd), cmd); 791 ahd_name(ahd), cmd);
791#endif 792#endif
793 ahd_lock(ahd, &flags);
794
792 found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A', 795 found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A',
793 /*initiate reset*/TRUE); 796 /*initiate reset*/TRUE);
797 ahd_unlock(ahd, &flags);
794 798
795 if (bootverbose) 799 if (bootverbose)
796 printf("%s: SCSI bus reset delivered. " 800 printf("%s: SCSI bus reset delivered. "