]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/scsi/aic7xxx/aic79xx_core.c
[SCSI] aic79xx bus reset update
[mv-sheeva.git] / drivers / scsi / aic7xxx / aic79xx_core.c
index 326a622262352ea78aef9eed737365442eed025e..880a10def1aa78a9f4926e72f82145f945f3ddfb 100644 (file)
@@ -207,7 +207,6 @@ static void         ahd_add_scb_to_free_list(struct ahd_softc *ahd,
 static u_int           ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid,
                                     u_int prev, u_int next, u_int tid);
 static void            ahd_reset_current_bus(struct ahd_softc *ahd);
-static ahd_callback_t  ahd_reset_poll;
 static ahd_callback_t  ahd_stat_timer;
 #ifdef AHD_DUMP_SEQ
 static void            ahd_dumpseq(struct ahd_softc *ahd);
@@ -1534,6 +1533,18 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
        lqistat1 = ahd_inb(ahd, LQISTAT1);
        lqostat0 = ahd_inb(ahd, LQOSTAT0);
        busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME;
+
+       /*
+        * Ignore external resets after a bus reset.
+        */
+       if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE))
+               return;
+
+       /*
+        * Clear bus reset flag
+        */
+       ahd->flags &= ~AHD_BUS_RESET_ACTIVE;
+
        if ((status0 & (SELDI|SELDO)) != 0) {
                u_int simode0;
 
@@ -7847,6 +7858,17 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
        int     found;
        u_int   fifo;
        u_int   next_fifo;
+       uint8_t scsiseq;
+
+       /*
+        * Check if the last bus reset is cleared
+        */
+       if (ahd->flags & AHD_BUS_RESET_ACTIVE) {
+               printf("%s: bus reset still active\n",
+                      ahd_name(ahd));
+               return 0;
+       }
+       ahd->flags |= AHD_BUS_RESET_ACTIVE;
 
        ahd->pending_device = NULL;
 
@@ -7860,6 +7882,12 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
        /* Make sure the sequencer is in a safe location. */
        ahd_clear_critical_section(ahd);
 
+       /*
+        * Run our command complete fifos to ensure that we perform
+        * completion processing on any commands that 'completed'
+        * before the reset occurred.
+        */
+       ahd_run_qoutfifo(ahd);
 #ifdef AHD_TARGET_MODE
        if ((ahd->flags & AHD_TARGETROLE) != 0) {
                ahd_run_tqinfifo(ahd, /*paused*/TRUE);
@@ -7924,30 +7952,14 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
        ahd_clear_fifo(ahd, 1);
 
        /*
-        * Revert to async/narrow transfers until we renegotiate.
+        * Reenable selections
         */
-       max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7;
-       for (target = 0; target <= max_scsiid; target++) {
-
-               if (ahd->enabled_targets[target] == NULL)
-                       continue;
-               for (initiator = 0; initiator <= max_scsiid; initiator++) {
-                       struct ahd_devinfo devinfo;
-
-                       ahd_compile_devinfo(&devinfo, target, initiator,
-                                           CAM_LUN_WILDCARD,
-                                           'A', ROLE_UNKNOWN);
-                       ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
-                                     AHD_TRANS_CUR, /*paused*/TRUE);
-                       ahd_set_syncrate(ahd, &devinfo, /*period*/0,
-                                        /*offset*/0, /*ppr_options*/0,
-                                        AHD_TRANS_CUR, /*paused*/TRUE);
-               }
-       }
+       ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST);
+       scsiseq = ahd_inb(ahd, SCSISEQ_TEMPLATE);
+       ahd_outb(ahd, SCSISEQ1, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP));
 
-#ifdef AHD_TARGET_MODE
        max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7;
-
+#ifdef AHD_TARGET_MODE
        /*
         * Send an immediate notify ccb to all target more peripheral
         * drivers affected by this action.
@@ -7975,51 +7987,31 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
        /* Notify the XPT that a bus reset occurred */
        ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD,
                       CAM_LUN_WILDCARD, AC_BUS_RESET, NULL);
-       ahd_restart(ahd);
+
        /*
-        * Freeze the SIMQ until our poller can determine that
-        * the bus reset has really gone away.  We set the initial
-        * timer to 0 to have the check performed as soon as possible
-        * from the timer context.
+        * Revert to async/narrow transfers until we renegotiate.
         */
-       if ((ahd->flags & AHD_RESET_POLL_ACTIVE) == 0) {
-               ahd->flags |= AHD_RESET_POLL_ACTIVE;
-               ahd_freeze_simq(ahd);
-               ahd_timer_reset(&ahd->reset_timer, 0, ahd_reset_poll, ahd);
-       }
-       return (found);
-}
+       for (target = 0; target <= max_scsiid; target++) {
 
+               if (ahd->enabled_targets[target] == NULL)
+                       continue;
+               for (initiator = 0; initiator <= max_scsiid; initiator++) {
+                       struct ahd_devinfo devinfo;
 
-#define AHD_RESET_POLL_US 1000
-static void
-ahd_reset_poll(void *arg)
-{
-       struct  ahd_softc *ahd = arg;
-       u_int   scsiseq1;
-       u_long  s;
-       
-       ahd_lock(ahd, &s);
-       ahd_pause(ahd);
-       ahd_update_modes(ahd);
-       ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
-       ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI);
-       if ((ahd_inb(ahd, SSTAT1) & SCSIRSTI) != 0) {
-               ahd_timer_reset(&ahd->reset_timer, AHD_RESET_POLL_US,
-                               ahd_reset_poll, ahd);
-               ahd_unpause(ahd);
-               ahd_unlock(ahd, &s);
-               return;
+                       ahd_compile_devinfo(&devinfo, target, initiator,
+                                           CAM_LUN_WILDCARD,
+                                           'A', ROLE_UNKNOWN);
+                       ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+                                     AHD_TRANS_CUR, /*paused*/TRUE);
+                       ahd_set_syncrate(ahd, &devinfo, /*period*/0,
+                                        /*offset*/0, /*ppr_options*/0,
+                                        AHD_TRANS_CUR, /*paused*/TRUE);
+               }
        }
 
-       /* Reset is now low.  Complete chip reinitialization. */
-       ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST);
-       scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE);
-       ahd_outb(ahd, SCSISEQ1, scsiseq1 & (ENSELI|ENRSELI|ENAUTOATNP));
-       ahd_unpause(ahd);
-       ahd->flags &= ~AHD_RESET_POLL_ACTIVE;
-       ahd_unlock(ahd, &s);
-       ahd_release_simq(ahd);
+       ahd_restart(ahd);
+
+       return (found);
 }
 
 /**************************** Statistics Processing ***************************/