patch-2.4.14 linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
Next file: linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
Previous file: linux/drivers/scsi/aic7xxx/aic7xxx_inline.h
Back to the patch index
Back to the overall index
- Lines: 515
- Date:
Thu Oct 25 13:53:49 2001
- Orig file:
v2.4.13/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
- Orig date:
Tue Oct 9 17:06:52 2001
diff -u --recursive --new-file v2.4.13/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
@@ -1,7 +1,7 @@
/*
* Adaptec AIC7xxx device driver for Linux.
*
- * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#72 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#79 $
*
* Copyright (c) 1994 John Aycock
* The University of Calgary Department of Computer Science.
@@ -38,8 +38,8 @@
* SCB paging, and other rework of the code.
*
* --------------------------------------------------------------------------
- * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000 Justin T. Gibbs.
- * Copyright (c) 2000 Adaptec Inc.
+ * Copyright (c) 1994-2000 Justin T. Gibbs.
+ * Copyright (c) 2000-2001 Adaptec Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,23 +48,31 @@
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL").
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
*
*---------------------------------------------------------------------------
*
@@ -79,8 +87,6 @@
*
* Form: aic7xxx=extended
* aic7xxx=no_reset
- * aic7xxx=ultra
- * aic7xxx=irq_trigger:[0,1] # 0 edge, 1 level
* aic7xxx=verbose
*
* Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
@@ -113,15 +119,6 @@
*
*/
-/*
- * The next three defines are user configurable. These should be the only
- * defines a user might need to get in here and change. There are other
- * defines buried deeper in the code, but those really shouldn't need touched
- * under normal conditions.
- */
-
-#include <linux/module.h>
-
#include "aic7xxx_osm.h"
#include "aic7xxx_inline.h"
@@ -324,83 +321,6 @@
static uint32_t aic7xxx_extended = 0;
/*
- * The IRQ trigger method used on EISA controllers. Does not effect PCI cards.
- * -1 = Use detected settings.
- * 0 = Force Edge triggered mode.
- * 1 = Force Level triggered mode.
- */
-static int aic7xxx_irq_trigger = -1;
-
-/*
- * This variable is used to override the termination settings on a controller.
- * This should not be used under normal conditions. However, in the case
- * that a controller does not have a readable SEEPROM (so that we can't
- * read the SEEPROM settings directly) and that a controller has a buggered
- * version of the cable detection logic, this can be used to force the
- * correct termination. It is preferable to use the manual termination
- * settings in the BIOS if possible, but some motherboard controllers store
- * those settings in a format we can't read. In other cases, auto term
- * should also work, but the chipset was put together with no auto term
- * logic (common on motherboard controllers). In those cases, we have
- * 32 bits here to work with. That's good for 8 controllers/channels. The
- * bits are organized as 4 bits per channel, with scsi0 getting the lowest
- * 4 bits in the int. A 1 in a bit position indicates the termination setting
- * that corresponds to that bit should be enabled, a 0 is disabled.
- * It looks something like this:
- *
- * 0x0f = 1111-Single Ended Low Byte Termination on/off
- * ||\-Single Ended High Byte Termination on/off
- * |\-LVD Low Byte Termination on/off
- * \-LVD High Byte Termination on/off
- *
- * For non-Ultra2 controllers, the upper 2 bits are not important. So, to
- * enable both high byte and low byte termination on scsi0, I would need to
- * make sure that the override_term variable was set to 0x03 (bits 0011).
- * To make sure that all termination is enabled on an Ultra2 controller at
- * scsi2 and only high byte termination on scsi1 and high and low byte
- * termination on scsi0, I would set override_term=0xf23 (bits 1111 0010 0011)
- *
- * For the most part, users should never have to use this, that's why I
- * left it fairly cryptic instead of easy to understand. If you need it,
- * most likely someone will be telling you what your's needs to be set to.
- */
-static int aic7xxx_override_term = -1;
-
-/*
- * Certain motherboard chipset controllers tend to screw
- * up the polarity of the term enable output pin. Use this variable
- * to force the correct polarity for your system. This is a bitfield variable
- * similar to the previous one, but this one has one bit per channel instead
- * of four.
- * 0 = Force the setting to active low.
- * 1 = Force setting to active high.
- * Most Adaptec cards are active high, several motherboards are active low.
- * To force a 2940 card at SCSI 0 to active high and a motherboard 7895
- * controller at scsi1 and scsi2 to active low, and a 2910 card at scsi3
- * to active high, you would need to set stpwlev=0x9 (bits 1001).
- *
- * People shouldn't need to use this, but if you are experiencing lots of
- * SCSI timeout problems, this may help. There is one sure way to test what
- * this option needs to be. Using a boot floppy to boot the system, configure
- * your system to enable all SCSI termination (in the Adaptec SCSI BIOS) and
- * if needed then also pass a value to override_term to make sure that the
- * driver is enabling SCSI termination, then set this variable to either 0
- * or 1. When the driver boots, make sure there are *NO* SCSI cables
- * connected to your controller. If it finds and inits the controller
- * without problem, then the setting you passed to stpwlev was correct. If
- * the driver goes into a reset loop and hangs the system, then you need the
- * other setting for this variable. If neither setting lets the machine
- * boot then you have definite termination problems that may not be fixable.
- */
-static int aic7xxx_stpwlev = -1;
-
-/*
- * Set this to non-0 in order to force the driver to panic the kernel
- * and print out debugging info on a SCSI abort or reset cycle.
- */
-static int aic7xxx_panic_on_abort = 0;
-
-/*
* PCI bus parity checking of the Adaptec controllers. This is somewhat
* dubious at best. To my knowledge, this option has never actually
* solved a PCI parity problem, but on certain machines with broken PCI
@@ -418,15 +338,6 @@
static int aic7xxx_pci_parity = 0;
/*
- * Set this to a non-0 value to make us dump out the 32 bit instruction
- * registers on the card after completing the sequencer download. This
- * allows the actual sequencer download to be verified. It is possible
- * to use this option and still boot up and run your system. This is
- * only intended for debugging purposes.
- */
-static int aic7xxx_dump_sequencer = 0;
-
-/*
* Certain newer motherboards have put new PCI based devices into the
* IO spaces that used to typically be occupied by VLB or EISA cards.
* This overlap can cause these newer motherboards to lock up when scanned
@@ -458,13 +369,20 @@
static int aic7xxx_seltime = 0x00;
/*
- * So that insmod can find the variable and make it point to something
+ * Certain devices do not perform any aging on commands. Should the
+ * device be saturated by commands in one portion of the disk, it is
+ * possible for transactions on far away sectors to never be serviced.
+ * To handle these devices, we can periodically send an ordered tag to
+ * force all outstanding transactions to be serviced prior to a new
+ * transaction.
+ */
+int aic7xxx_periodic_otag;
+
+/*
+ * Module information and settable options.
*/
#ifdef MODULE
static char *aic7xxx = NULL;
-
-MODULE_PARM(aic7xxx, "s");
-
/*
* Just in case someone uses commas to separate items on the insmod
* command line, we define a dummy buffer here to avoid having insmod
@@ -472,6 +390,32 @@
*/
static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n";
+MODULE_AUTHOR("Maintainer: Justin T. Gibbs <gibbs@scsiguy.com>");
+MODULE_DESCRIPTION("Adaptec Aic77XX/78XX SCSI Host Bus Adapter driver");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)
+MODULE_LICENSE("Dual BSD/GPL");
+#endif
+MODULE_PARM(aic7xxx, "s");
+MODULE_PARM_DESC(aic7xxx, "period delimited, options string.
+ verbose Enable verbose/diagnostic logging
+ no_probe Disable EISA/VLB controller probing
+ no_reset Supress initial bus resets
+ extended Enable extended geometry on all controllers
+ periodic_otag Send an ordered tagged transaction periodically
+ to prevent tag starvation. This may be
+ required by some older disk drives/RAID arrays.
+ reverse_scan Sort PCI devices highest Bus/Slot to lowest
+ tag_info:<tag_str> Set per-target tag depth
+ seltime:<int> Selection Timeout(0/256ms,1/128ms,2/64ms,3/32ms)
+
+ Sample /etc/modules.conf line:
+ Enable verbose logging
+ Disable EISA/VLB probing
+ Set tag depth on Controller 2/Target 2 to 10 tags
+ Shorten the selection timeout to 128ms from its default of 256
+
+ options aic7xxx='\"verbose.no_probe.tag_info:{{}.{}.{..10}}.seltime:1\"'
+");
#endif
static void ahc_linux_handle_scsi_status(struct ahc_softc *,
@@ -661,11 +605,17 @@
sg = (struct scatterlist *)cmd->request_buffer;
pci_unmap_sg(ahc->dev_softc, sg, cmd->use_sg,
scsi_to_pci_dma_dir(cmd->sc_data_direction));
- } else if (cmd->request_bufflen != 0)
+ } else if (cmd->request_bufflen != 0) {
+ u_int32_t high_addr;
+
+ high_addr = ahc_le32toh(scb->sg_list[0].len)
+ & AHC_SG_HIGH_ADDR_MASK;
pci_unmap_single(ahc->dev_softc,
- ahc_le32toh(scb->sg_list[0].addr),
+ ahc_le32toh(scb->sg_list[0].addr)
+ | (((dma_addr_t)high_addr) << 8),
cmd->request_bufflen,
scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ }
}
static __inline int
@@ -722,8 +672,10 @@
{
struct ahc_softc *ahc;
- TAILQ_FOREACH(ahc, &ahc_tailq, links) {
- ahc_shutdown(ahc);
+ if (event == SYS_DOWN || event == SYS_HALT) {
+ TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+ ahc_shutdown(ahc);
+ }
}
return (NOTIFY_OK);
}
@@ -786,22 +738,24 @@
* address). For this reason, we have to reset
* our dma mask when doing allocations.
*/
+ if(ahc->dev_softc)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3)
- pci_set_dma_mask(ahc->dev_softc, 0xFFFFFFFF);
+ pci_set_dma_mask(ahc->dev_softc, 0xFFFFFFFF);
#else
- ahc->dev_softc->dma_mask = 0xFFFFFFFF;
+ ahc->dev_softc->dma_mask = 0xFFFFFFFF;
#endif
*vaddr = pci_alloc_consistent(ahc->dev_softc,
dmat->maxsize, &map->bus_addr);
+ if (ahc->dev_softc)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3)
- pci_set_dma_mask(ahc->dev_softc, ahc->platform_data->hw_dma_mask);
+ pci_set_dma_mask(ahc->dev_softc, ahc->platform_data->hw_dma_mask);
#else
- ahc->dev_softc->dma_mask = ahc->platform_data->hw_dma_mask;
+ ahc->dev_softc->dma_mask = ahc->platform_data->hw_dma_mask;
#endif
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) */
/*
* At least in 2.2.14, malloc is a slab allocator so all
- * allocations are aligned. We assume, for these kernel versions
+ * allocations are aligned. We assume for these kernel versions
* that all allocations will be bellow 4Gig, physically contiguous,
* and accessable via DMA by the controller.
*/
@@ -906,12 +860,20 @@
{
char primary_channel;
- value = ahc_get_pci_bus(lahc->dev_softc)
- - ahc_get_pci_bus(rahc->dev_softc);
+ if (aic7xxx_reverse_scan != 0)
+ value = ahc_get_pci_bus(rahc->dev_softc)
+ - ahc_get_pci_bus(lahc->dev_softc);
+ else
+ value = ahc_get_pci_bus(lahc->dev_softc)
+ - ahc_get_pci_bus(rahc->dev_softc);
if (value != 0)
break;
- value = ahc_get_pci_slot(lahc->dev_softc)
- - ahc_get_pci_slot(rahc->dev_softc);
+ if (aic7xxx_reverse_scan != 0)
+ value = ahc_get_pci_slot(rahc->dev_softc)
+ - ahc_get_pci_slot(lahc->dev_softc);
+ else
+ value = ahc_get_pci_slot(lahc->dev_softc)
+ - ahc_get_pci_slot(rahc->dev_softc);
if (value != 0)
break;
/*
@@ -1028,7 +990,7 @@
/*
* Handle Linux boot parameters. This routine allows for assigning a value
* to a parameter with a ':' between the parameter and the value.
- * ie. aic7xxx=unpause:0x0A,extended
+ * ie. aic7xxx=stpwlev:1,extended
*/
int
aic7xxx_setup(char *s)
@@ -1043,15 +1005,11 @@
} options[] = {
{ "extended", &aic7xxx_extended },
{ "no_reset", &aic7xxx_no_reset },
- { "irq_trigger", &aic7xxx_irq_trigger },
{ "verbose", &aic7xxx_verbose },
{ "reverse_scan", &aic7xxx_reverse_scan },
- { "override_term", &aic7xxx_override_term },
- { "stpwlev", &aic7xxx_stpwlev },
{ "no_probe", &aic7xxx_no_probe },
- { "panic_on_abort", &aic7xxx_panic_on_abort },
+ { "periodic_otag", &aic7xxx_periodic_otag },
{ "pci_parity", &aic7xxx_pci_parity },
- { "dump_sequencer", &aic7xxx_dump_sequencer },
{ "seltime", &aic7xxx_seltime },
{ "tag_info", NULL }
};
@@ -1133,7 +1091,8 @@
ahc_linux_pci_probe(template);
#endif
- aic7770_linux_probe(template);
+ if (aic7xxx_no_probe == 0)
+ aic7770_linux_probe(template);
/*
* Register with the SCSI layer all
@@ -1174,8 +1133,8 @@
host->this_id = ahc->our_id;
host->irq = ahc->platform_data->irq;
host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8;
- host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0;
host->max_lun = AHC_NUM_LUNS;
+ host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0;
ahc_set_unit(ahc, ahc_linux_next_unit());
sprintf(buf, "scsi%d", host->host_no);
new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
@@ -1387,7 +1346,7 @@
dev->qfrozen++;
}
- dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED);
+ dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED|AHC_DEV_PERIODIC_OTAG);
if (now_queuing) {
if (!was_queuing) {
@@ -1399,9 +1358,11 @@
dev->maxtags = AHC_MAX_QUEUE;
dev->openings = dev->maxtags - dev->active;
}
- if (alg == AHC_QUEUE_TAGGED)
+ if (alg == AHC_QUEUE_TAGGED) {
dev->flags |= AHC_DEV_Q_TAGGED;
- else
+ if (aic7xxx_periodic_otag != 0)
+ dev->flags |= AHC_DEV_PERIODIC_OTAG;
+ } else
dev->flags |= AHC_DEV_Q_BASIC;
} else {
/* We can only have one opening */
@@ -1548,8 +1509,8 @@
if (tags != 0) {
device->queue_depth = tags;
ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
- printf("scsi%d:%d:%d:%d: Tagged Queuing enabled. Depth %d\n",
- ahc->platform_data->host->host_no, device->channel,
+ printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n",
+ ahc->platform_data->host->host_no, device->channel + 'A',
device->id, device->lun, tags);
} else {
/*
@@ -1770,7 +1731,8 @@
dev->openings--;
dev->active++;
dev->commands_issued++;
- dev->commands_since_idle_or_otag++;
+ if ((dev->flags & AHC_DEV_PERIODIC_OTAG) != 0)
+ dev->commands_since_idle_or_otag++;
/*
* We only allow one untagged transaction
@@ -2324,10 +2286,10 @@
* are not large enough for us to pull the spi3 bits.
* In this case, we assume that a device that tells us
* they can provide inquiry data that spans the SPI3
- * bits can handle a PPR request. If the inquiry
- * request has sufficient buffer space to cover these
- * bits, we check them to see if any ppr options are
- * available.
+ * bits and says its SCSI3 can handle a PPR request.
+ * If the inquiry request has sufficient buffer space to
+ * cover these bits, we check them to see if any ppr options
+ * are available.
*/
if ((sid->additional_length + 4) >= minlen) {
if (transferred_len >= minlen
@@ -2336,6 +2298,8 @@
if (targ_info->curr.protocol_version > SCSI_REV_2)
targ_info->curr.transport_version = 3;
+ else
+ ppr_options = 0;
} else {
ppr_options = 0;
}
@@ -2536,8 +2500,7 @@
ahc->flags &= ~AHC_ALL_INTERRUPTS;
paused = TRUE;
- if (bootverbose)
- ahc_dump_card_state(ahc);
+ ahc_dump_card_state(ahc);
if ((pending_scb->flags & SCB_ACTIVE) == 0) {
printf("%s:%d:%d:%d: Command already completed\n",
@@ -2597,7 +2560,7 @@
* Actually re-queue this SCB in an attempt
* to select the device before it reconnects.
* In either case (selection or reselection),
- * we will now issue a the approprate message
+ * we will now issue the approprate message
* to the timed-out device.
*
* Set the MK_MESSAGE control bit indicating
@@ -2672,7 +2635,7 @@
if (paused)
ahc_unpause(ahc);
if (wait) {
- struct timer_list timer;
+ struct timer_list timer;
int ret;
ahc_unlock(ahc, &s);
@@ -2711,7 +2674,7 @@
error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT);
if (error != 0)
- printf("aic7xxx_abort returns %d\n", error);
+ printf("aic7xxx_abort returns 0x%x\n", error);
return (error);
}
@@ -2725,7 +2688,7 @@
error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
if (error != 0)
- printf("aic7xxx_dev_reset returns %d\n", error);
+ printf("aic7xxx_dev_reset returns 0x%x\n", error);
return (error);
}
@@ -2792,7 +2755,9 @@
sectors = 32;
cylinders = disk->capacity / (heads * sectors);
- if (disk->device->channel == 0)
+ if (aic7xxx_extended != 0)
+ extended = 1;
+ else if (disk->device->channel == 0)
extended = (ahc->flags & AHC_EXTENDED_TRANS_A) != 0;
else
extended = (ahc->flags & AHC_EXTENDED_TRANS_B) != 0;
@@ -2868,8 +2833,6 @@
}
}
}
-
-MODULE_LICENSE("Dual BSD/GPL");
#if defined(MODULE) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
static Scsi_Host_Template driver_template = AIC7XXX;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)