]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/aic7xxx/aic7xxx_core.c
[SCSI] SCSI: aic7xxx_osm_pci resource leak fix.
[linux-2.6-omap-h63xx.git] / drivers / scsi / aic7xxx / aic7xxx_core.c
index 7bc01e41bcce79a070348e5ab1138db5154384ef..d37566978fba5b69a9b836a1b02c8c39dd91dad8 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__
@@ -287,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);
 }
 
@@ -1174,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);
@@ -2453,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",
@@ -2474,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",
@@ -2497,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, "
@@ -3763,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))
@@ -4003,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;
@@ -5036,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