Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / scsi / aic7xxx / aic7xxx_core.c
index 9a6b4a5..d375669 100644 (file)
@@ -37,9 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#134 $
- *
- * $FreeBSD$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#155 $
  */
 
 #ifdef __linux__
@@ -52,9 +50,6 @@
 #include <dev/aic7xxx/aicasm/aicasm_insformat.h>
 #endif
 
-/****************************** Softc Data ************************************/
-struct ahc_softc_tailq ahc_tailq = TAILQ_HEAD_INITIALIZER(ahc_tailq);
-
 /***************************** Lookup Tables **********************************/
 char *ahc_chip_names[] =
 {
@@ -290,10 +285,19 @@ ahc_restart(struct ahc_softc *ahc)
                ahc_outb(ahc, SEQ_FLAGS2,
                         ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA);
        }
+
+       /*
+        * Clear any pending sequencer interrupt.  It is no
+        * longer relevant since we're resetting the Program
+        * Counter.
+        */
+       ahc_outb(ahc, CLRINT, CLRSEQINT);
+
        ahc_outb(ahc, MWI_RESIDUAL, 0);
        ahc_outb(ahc, SEQCTL, ahc->seqctl);
        ahc_outb(ahc, SEQADDR0, 0);
        ahc_outb(ahc, SEQADDR1, 0);
+
        ahc_unpause(ahc);
 }
 
@@ -1177,19 +1181,20 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
                                       scb_index);
                        }
 #endif
-                       /*
-                        * Force a renegotiation with this target just in
-                        * case the cable was pulled and will later be
-                        * re-attached.  The target may forget its negotiation
-                        * settings with us should it attempt to reselect
-                        * during the interruption.  The target will not issue
-                        * a unit attention in this case, so we must always
-                        * renegotiate.
-                        */
                        ahc_scb_devinfo(ahc, &devinfo, scb);
-                       ahc_force_renegotiation(ahc, &devinfo);
                        ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
                        ahc_freeze_devq(ahc, scb);
+
+                       /*
+                        * Cancel any pending transactions on the device
+                        * now that it seems to be missing.  This will
+                        * also revert us to async/narrow transfers until
+                        * we can renegotiate with the device.
+                        */
+                       ahc_handle_devreset(ahc, &devinfo,
+                                           CAM_SEL_TIMEOUT,
+                                           "Selection Timeout",
+                                           /*verbose_level*/1);
                }
                ahc_outb(ahc, CLRINT, CLRSCSIINT);
                ahc_restart(ahc);
@@ -2456,11 +2461,8 @@ ahc_construct_sdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
 {
        if (offset == 0)
                period = AHC_ASYNC_XFER_PERIOD;
-       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
-       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR_LEN;
-       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR;
-       ahc->msgout_buf[ahc->msgout_index++] = period;
-       ahc->msgout_buf[ahc->msgout_index++] = offset;
+       ahc->msgout_index += spi_populate_sync_msg(
+                       ahc->msgout_buf + ahc->msgout_index, period, offset);
        ahc->msgout_len += 5;
        if (bootverbose) {
                printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
@@ -2477,10 +2479,8 @@ static void
 ahc_construct_wdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
                   u_int bus_width)
 {
-       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
-       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR_LEN;
-       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR;
-       ahc->msgout_buf[ahc->msgout_index++] = bus_width;
+       ahc->msgout_index += spi_populate_width_msg(
+                       ahc->msgout_buf + ahc->msgout_index, bus_width);
        ahc->msgout_len += 4;
        if (bootverbose) {
                printf("(%s:%c:%d:%d): Sending WDTR %x\n",
@@ -2500,14 +2500,9 @@ ahc_construct_ppr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
 {
        if (offset == 0)
                period = AHC_ASYNC_XFER_PERIOD;
-       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
-       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR_LEN;
-       ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR;
-       ahc->msgout_buf[ahc->msgout_index++] = period;
-       ahc->msgout_buf[ahc->msgout_index++] = 0;
-       ahc->msgout_buf[ahc->msgout_index++] = offset;
-       ahc->msgout_buf[ahc->msgout_index++] = bus_width;
-       ahc->msgout_buf[ahc->msgout_index++] = ppr_options;
+       ahc->msgout_index += spi_populate_ppr_msg(
+                       ahc->msgout_buf + ahc->msgout_index, period, offset,
+                       bus_width, ppr_options);
        ahc->msgout_len += 8;
        if (bootverbose) {
                printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
@@ -3766,8 +3761,9 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
                         /*period*/0, /*offset*/0, /*ppr_options*/0,
                         AHC_TRANS_CUR, /*paused*/TRUE);
        
-       ahc_send_async(ahc, devinfo->channel, devinfo->target,
-                      CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
+       if (status != CAM_SEL_TIMEOUT)
+               ahc_send_async(ahc, devinfo->channel, devinfo->target,
+                              CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
 
        if (message != NULL
         && (verbose_level <= bootverbose))
@@ -3878,78 +3874,6 @@ ahc_softc_init(struct ahc_softc *ahc)
        return (0);
 }
 
-void
-ahc_softc_insert(struct ahc_softc *ahc)
-{
-       struct ahc_softc *list_ahc;
-
-#if AHC_PCI_CONFIG > 0
-       /*
-        * Second Function PCI devices need to inherit some
-        * settings from function 0.
-        */
-       if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI
-        && (ahc->features & AHC_MULTI_FUNC) != 0) {
-               TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
-                       ahc_dev_softc_t list_pci;
-                       ahc_dev_softc_t pci;
-
-                       list_pci = list_ahc->dev_softc;
-                       pci = ahc->dev_softc;
-                       if (ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci)
-                        && ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)) {
-                               struct ahc_softc *master;
-                               struct ahc_softc *slave;
-
-                               if (ahc_get_pci_function(list_pci) == 0) {
-                                       master = list_ahc;
-                                       slave = ahc;
-                               } else {
-                                       master = ahc;
-                                       slave = list_ahc;
-                               }
-                               slave->flags &= ~AHC_BIOS_ENABLED; 
-                               slave->flags |=
-                                   master->flags & AHC_BIOS_ENABLED;
-                               slave->flags &= ~AHC_PRIMARY_CHANNEL; 
-                               slave->flags |=
-                                   master->flags & AHC_PRIMARY_CHANNEL;
-                               break;
-                       }
-               }
-       }
-#endif
-
-       /*
-        * Insertion sort into our list of softcs.
-        */
-       list_ahc = TAILQ_FIRST(&ahc_tailq);
-       while (list_ahc != NULL
-           && ahc_softc_comp(ahc, list_ahc) <= 0)
-               list_ahc = TAILQ_NEXT(list_ahc, links);
-       if (list_ahc != NULL)
-               TAILQ_INSERT_BEFORE(list_ahc, ahc, links);
-       else
-               TAILQ_INSERT_TAIL(&ahc_tailq, ahc, links);
-       ahc->init_level++;
-}
-
-/*
- * Verify that the passed in softc pointer is for a
- * controller that is still configured.
- */
-struct ahc_softc *
-ahc_find_softc(struct ahc_softc *ahc)
-{
-       struct ahc_softc *list_ahc;
-
-       TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
-               if (list_ahc == ahc)
-                       return (ahc);
-       }
-       return (NULL);
-}
-
 void
 ahc_set_unit(struct ahc_softc *ahc, int unit)
 {
@@ -4078,14 +4002,6 @@ ahc_reset(struct ahc_softc *ahc, int reinit)
         * to disturb the integrity of the bus.
         */
        ahc_pause(ahc);
-       if ((ahc_inb(ahc, HCNTRL) & CHIPRST) != 0) {
-               /*
-                * The chip has not been initialized since
-                * PCI/EISA/VLB bus reset.  Don't trust
-                * "left over BIOS data".
-                */
-               ahc->flags |= AHC_NO_BIOS_INIT;
-       }
        sxfrctl1_b = 0;
        if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) {
                u_int sblkctl;
@@ -5111,14 +5027,23 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
        ahc->flags |= AHC_ALL_INTERRUPTS;
        paused = FALSE;
        do {
-               if (paused)
+               if (paused) {
                        ahc_unpause(ahc);
+                       /*
+                        * Give the sequencer some time to service
+                        * any active selections.
+                        */
+                       ahc_delay(500);
+               }
                ahc_intr(ahc);
                ahc_pause(ahc);
                paused = TRUE;
                ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO);
-               ahc_clear_critical_section(ahc);
                intstat = ahc_inb(ahc, INTSTAT);
+               if ((intstat & INT_PEND) == 0) {
+                       ahc_clear_critical_section(ahc);
+                       intstat = ahc_inb(ahc, INTSTAT);
+               }
        } while (--maxloops
              && (intstat != 0xFF || (ahc->features & AHC_REMOVABLE) == 0)
              && ((intstat & INT_PEND) != 0