Commit f33f47a2 authored by Justin T. Gibbs's avatar Justin T. Gibbs

o Kill host template files.

o Move readme files into the Documentation SCSI directory
o Enable highmem_io
o Split out Kconfig files for aic7xxx and aic79xx

Host template and large disk changes provided or inspired by:
	Christoph Hellwig <hch@sgi.com>
parent b1b0a996
AIC7xxx Driver for Linux
Introduction
----------------------------
The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com)
SCSI controllers and chipsets. Major portions of the driver and driver
development are shared between both Linux and FreeBSD. Support for the
AIC-7xxx chipsets have been in the default Linux kernel since approximately
linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
2.1.0 or later.
Supported cards/chipsets
----------------------------
Adaptec Cards
----------------------------
AHA-274x
AHA-274xT
AHA-274xW
AHA-284x
AHA-284xW
All PCI based cards using any of the chipsets listed under motherboard
chipsets. In general, this means *all* of the Adaptec SCSI controllers
except the ones specifically excluded later on in this document.
Motherboard Chipsets
----------------------------
AIC-777x
AIC-785x
AIC-786x
AIC-787x
AIC-788x
AIC-789x
AIC-3860
Bus Types
----------------------------
W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support
SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s.
U - Ultra SCSI, transfer rates up to 40MB/s.
U2- Ultra 2 SCSI, transfer rates up to 80MB/s.
U3- Ultra 3 SCSI, transfer rates up to 160MB/s.
D - Differential SCSI.
T - Twin Channel SCSI. Up to 14 SCSI devices.
AHA-274x - EISA SCSI controller
AHA-284x - VLB SCSI controller
AHA-29xx - PCI SCSI controller
AHA-39xx - PCI controllers with multiple separate SCSI channels on-board.
Not Supported Devices
------------------------------
Adaptec Cards
----------------------------
AHA-2920 (Only the cards that use the Future Domain chipset are not
supported, any 2920 cards based on Adaptec AIC chipsets,
such as the 2920C, are supported)
AAA-13x Raid Adapters
AAA-113x Raid Port Card
Motherboard Chipsets
----------------------------
AIC-781x
Bus Types
----------------------------
R - Raid Port busses are not supported.
The hardware RAID devices sold by Adaptec are *NOT* supported by this
driver (and will people please stop emailing me about them, they are
a totally separate beast from the bare SCSI controllers and this driver
can not be retrofitted in any sane manner to support the hardware RAID
features on those cards - Doug Ledford).
People
------------------------------
Justin T Gibbs gibbs@plutotech.com
(BSD Driver Author)
Dan Eischen deischen@iworks.InterWorks.org
(Original Linux Driver Co-maintainer)
Dean Gehnert deang@teleport.com
(Original Linux FTP/patch maintainer)
Jess Johnson jester@frenzy.com
(AIC7xxx FAQ author)
Doug Ledford dledford@redhat.com
(Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer)
Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
author of the driver. John has since retired from the project. Thanks
again for all his work!
Mailing list
------------------------------
There is a mailing list available for users who want to track development
and converse with other users and developers. This list is for both
FreeBSD and Linux support of the AIC7xxx chipsets.
To subscribe to the AIC7xxx mailing list send mail to the list server,
with "subscribe AIC7xxx" in the body (no Subject: required):
To: majordomo@FreeBSD.ORG
---
subscribe AIC7xxx
To unsubscribe from the list, send mail to the list server with:
To: majordomo@FreeBSD.ORG
---
unsubscribe AIC7xxx
Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
Boot Command line options
------------------------------
"aic7xxx=no_reset" - Eliminate the SCSI bus reset during startup.
Some SCSI devices need the initial reset that this option disables
in order to work. If you have problems at bootup, please make sure
you aren't using this option.
"aic7xxx=reverse_scan" - Certain PCI motherboards scan for devices at
bootup by scanning from the highest numbered PCI device to the
lowest numbered PCI device, others do just the opposite and scan
from lowest to highest numbered PCI device. There is no reliable
way to autodetect this ordering. So, we default to the most common
order, which is lowest to highest. Then, in case your motherboard
scans from highest to lowest, we have this option. If your BIOS
finds the drives on controller A before controller B but the linux
kernel finds your drives on controller B before A, then you should
use this option.
"aic7xxx=extended" - Force the driver to detect extended drive translation
on your controller. This helps those people who have cards without
a SEEPROM make sure that linux and all other operating systems think
the same way about your hard drives.
"aic7xxx=scbram" - Some cards have external SCB RAM that can be used to
give the card more hardware SCB slots. This allows the driver to use
that SCB RAM. Without this option, the driver won't touch the SCB
RAM because it is known to cause problems on a few cards out there
(such as 3985 class cards).
"aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel
to use the correct IRQ type for your card. This only applies to EISA
based controllers. On these controllers, 0 is for Edge triggered
interrupts, and 1 is for Level triggered interrupts. If you aren't
sure or don't know which IRQ trigger type your EISA card uses, then
let the kernel autodetect the trigger type.
"aic7xxx=verbose" - This option can be used in one of two ways. If you
simply specify aic7xxx=verbose, then the kernel will automatically
pick the default set of verbose messages for you to see.
Alternatively, you can specify the command as
"aic7xxx=verbose:0xXXXX" where the X entries are replaced with
hexadecimal digits. This option is a bit field type option. For
a full listing of the available options, search for the
#define VERBOSE_xxxxxx lines in the aic7xxx.c file. If you want
verbose messages, then it is recommended that you simply use the
aic7xxx=verbose variant of this command.
"aic7xxx=pci_parity:x" - This option controls whether or not the driver
enables PCI parity error checking on the PCI bus. By default, this
checking is disabled. To enable the checks, simply specify pci_parity
with no value afterwords. To reverse the parity from even to odd,
supply any number other than 0 or 255. In short:
pci_parity - Even parity checking (even is the normal PCI parity)
pci_parity:x - Where x > 0, Odd parity checking
pci_parity:0 - No check (default)
NOTE: In order to get Even PCI parity checking, you must use the
version of the option that does not include the : and a number at
the end (unless you want to enter exactly 2^32 - 1 as the number).
"aic7xxx=no_probe" - This option will disable the probing for any VLB
based 2842 controllers and any EISA based controllers. This is
needed on certain newer motherboards where the normal EISA I/O ranges
have been claimed by other PCI devices. Probing on those machines
will often result in the machine crashing or spontaneously rebooting
during startup. Examples of machines that need this are the
Dell PowerEdge 6300 machines.
"aic7xxx=seltime:2" - This option controls how long the card waits
during a device selection sequence for the device to respond.
The original SCSI spec says that this "should be" 256ms. This
is generally not required with modern devices. However, some
very old SCSI I devices need the full 256ms. Most modern devices
can run fine with only 64ms. The default for this option is
64ms. If you need to change this option, then use the following
table to set the proper value in the example above:
0 - 256ms
1 - 128ms
2 - 64ms
3 - 32ms
"aic7xxx=panic_on_abort" - This option is for debugging and will cause
the driver to panic the linux kernel and freeze the system the first
time the drivers abort or reset routines are called. This is most
helpful when some problem causes infinite reset loops that scroll too
fast to see. By using this option, you can write down what the errors
actually are and send that information to me so it can be fixed.
"aic7xxx=dump_card" - This option will print out the *entire* set of
configuration registers on the card during the init sequence. This
is a debugging aid used to see exactly what state the card is in
when we finally finish our initialization routines. If you don't
have documentation on the chipsets, this will do you absolutely
no good unless you are simply trying to write all the information
down in order to send it to me.
"aic7xxx=dump_sequencer" - This is the same as the above options except
that instead of dumping the register contents on the card, this
option dumps the contents of the sequencer program RAM. This gives
the ability to verify that the instructions downloaded to the
card's sequencer are indeed what they are suppossed to be. Again,
unless you have documentation to tell you how to interpret these
numbers, then it is totally useless.
"aic7xxx=override_term:0xffffffff" - This option is used to force the
termination on your SCSI controllers to a particular setting. This
is a bit mask variable that applies for up to 8 aic7xxx SCSI channels.
Each channel gets 4 bits, divided as follows:
bit 3 2 1 0
| | | Enable/Disable Single Ended Low Byte Termination
| | En/Disable Single Ended High Byte Termination
| En/Disable Low Byte LVD Termination
En/Disable High Byte LVD Termination
The upper 2 bits that deal with LVD termination only apply to Ultra2
controllers. Futhermore, due to the current Ultra2 controller
designs, these bits are tied together such that setting either bit
enables both low and high byte LVD termination. It is not possible
to only set high or low byte LVD termination in this manner. This is
an artifact of the BIOS definition on Ultra2 controllers. For other
controllers, the only important bits are the two lowest bits. Setting
the higher bits on non-Ultra2 controllers has no effect. A few
examples of how to use this option:
Enable low and high byte termination on a non-ultra2 controller that
is the first aic7xxx controller (the correct bits are 0011),
aic7xxx=override_term:0x3
Enable all termination on the third aic7xxx controller, high byte
termination on the second aic7xxx controller, and low and high byte
SE termination on the first aic7xxx controller
(bits are 1111 0010 0011),
aic7xxx=override_term:0xf23
No attempt has been made to make this option non-cryptic. It really
shouldn't be used except in dire circumstances, and if that happens,
I'm probably going to be telling you what to set this to anyway :)
"aic7xxx=stpwlev:0xffffffff" - This option is used to control the STPWLEV
bit in the DEVCONFIG PCI register. Currently, this is one of the
very few registers that we have absolutely *no* way of detecting
what the variable should be. It depends entirely on how the chipset
and external terminators were coupled by the card/motherboard maker.
Further, a chip reset (at power up) always sets this bit to 0. If
there is no BIOS to run on the chipset/card (such as with a 2910C
or a motherboard controller with the BIOS totally disabled) then
the variable may not get set properly. Of course, if the proper
setting was 0, then that's what it would be after the reset, but if
the proper setting is actually 1.....you get the picture. Now, since
we can't detect this at all, I've added this option to force the
setting. If you have a BIOS on your controller then you should never
need to use this option. However, if you are having lots of SCSI
reset problems and can't seem to get them knocked out, this may help.
Here's a test to know for certain if you need this option. Make
a boot floppy that you can use to boot your computer up and that
will detect the aic7xxx controller. Next, power down your computer.
While it's down, unplug all SCSI cables from your Adaptec SCSI
controller. Boot the system back up to the Adaptec EZ-SCSI BIOS
and then make sure that termination is enabled on your adapter (if
you have an Adaptec BIOS of course). Next, boot up the floppy you
made and wait for it to detect the aic7xxx controller. If the kernel
finds the controller fine, says scsi : x hosts and then tries to
detect your devices like normal, up to the point where it fails to
mount your root file system and panics, then you're fine. If, on
the other hand, the system goes into an infinite reset loop, then
you need to use this option and/or the previous option to force the
proper termination settings on your controller. If this happens,
then you next need to figure out what your settings should be.
To find the correct settings, power your machine back down, connect
back up the SCSI cables, and boot back into your machine like normal.
However, boot with the aic7xxx=verbose:0x39 option. Record the
initial DEVCONFIG values for each of your aic7xxx controllers as
they are listed, and also record what the machine is detecting as
the proper termination on your controllers. NOTE: the order in
which the initial DEVCONFIG values are printed out is not gauranteed
to be the same order as the SCSI controllers are registered. The
above option and this option both work on the order of the SCSI
controllers as they are registered, so make sure you match the right
DEVCONFIG values with the right controllers if you have more than
one aic7xxx controller.
Once you have the detected termination settings and the initial
DEVCONFIG values for each controller, then figure out what the
termination on each of the controllers *should* be. Hopefully, that
part is correct, but it could possibly be wrong if there is
bogus cable detection logic on your controller or something similar.
If all the controllers have the correct termination settings, then
don't set the aic7xxx=override_term variable at all, leave it alone.
Next, on any controllers that go into an infinite reset loop when
you unplug all the SCSI cables, get the starting DEVCONFIG value.
If the initial DEVCONFIG value is divisible by 2, then the correct
setting for that controller is 0. If it's an odd number, then
the correct setting for that controller is 1. For any other
controllers that didn't have an infinite reset problem, then reverse
the above options. If DEVCONFIG was even, then the correct setting
is 1, if not then the correct setting is 0.
Now that you know what the correct setting was for each controller,
we need to encode that into the aic7xxx=stpwlev:0x... variable.
This variable is a bit field encoded variable. Bit 0 is for the first
aic7xxx controller, bit 1 for the next, etc. Put all these bits
together and you get a number. For example, if the third aic7xxx
needed a 1, but the second and first both needed a 0, then the bits
would be 100 in binary. This then translates to 0x04. You would
therefore set aic7xxx=stpwlev:0x04. This is fairly standard binary
to hexadecimal conversions here. If you aren't up to speed on the
binary->hex conversion then send an email to the aic7xxx mailing
list and someone can help you out.
"aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable
or enable Tagged Command Queueing (TCQ) on specific devices. As of
driver version 5.1.11, TCQ is now either on or off by default
according to the setting you choose during the make config process.
In order to en/disable TCQ for certian devices at boot time, a user
may use this boot param. The driver will then parse this message out
and en/disable the specific device entries that are present based upon
the value given. The param line is parsed in the following manner:
{ - first instance indicates the start of this parameter values
second instance is the start of entries for a particular
device entry
} - end the entries for a particular host adapter, or end the entire
set of parameter entries
, - move to next entry. Inside of a set of device entries, this
moves us to the next device on the list. Outside of device
entries, this moves us to the next host adapter
. - Same effect as , but is safe to use with insmod.
x - the number to enter into the array at this position.
0 = Enable tagged queueing on this device and use the default
queue depth
1-254 = Enable tagged queueing on this device and use this
number as the queue depth
255 = Disable tagged queueing on this device.
Note: anything above 32 for an actual queue depth is wasteful
and not recommended.
A few examples of how this can be used:
tag_info:{{8,12,,0,,255,4}}
This line will only effect the first aic7xxx card registered. It
will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2
at the default, set id 3 to tagged queueing enabled and use the
default queue depth, id 4 default, id 5 disabled, and id 6 to 4.
Any not specified entries stay at the default value, repeated
commas with no value specified will simply increment to the next id
without changing anything for the missing values.
tag_info:{,,,{,,,255}}
First, second, and third adapters at default values. Fourth
adapter, id 3 is disabled. Notice that leading commas simply
increment what the first number effects, and there are no need
for trailing commas. When you close out an adapter, or the
entire entry, anything not explicitly set stays at the default
value.
A final note on this option. The scanner I used for this isn't
perfect or highly robust. If you mess the line up, the worst that
should happen is that the line will get ignored. If you don't
close out the entire entry with the final bracket, then any other
aic7xxx options after this will get ignored. So, in general, be
sure of what you are entering, and after you have it right, just
add it to the lilo.conf file so there won't be any mistakes. As
a means of checking this parser, the entire tag_info array for
each card is now printed out in the /proc/scsi/aic7xxx/x file. You
can use that to verify that your options were parsed correctly.
Boot command line options may be combined to form the proper set of options
a user might need. For example, the following is valid:
aic7xxx=verbose,extended,irq_trigger:1
The only requirement is that individual options be separated by a comma or
a period on the command line.
Module Loading command options
------------------------------
When loading the aic7xxx driver as a module, the exact same options are
available to the user. However, the syntax to specify the options changes
slightly. For insmod, you need to wrap the aic7xxx= argument in quotes
and replace all ',' with '.'. So, for example, a valid insmod line
would be:
insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended'
This line should result in the *exact* same behaviour as if you typed
it in at the lilo prompt and the driver was compiled into the kernel
instead of being a module. The reason for the single quote is so that
the shell won't try to interpret anything in the line, such as {.
Insmod assumes any options starting with a letter instead of a number
is a character string (which is what we want) and by switching all of
the commas to periods, insmod won't interpret this as more than one
string and write junk into our binary image. I consider it a bug in
the insmod program that even if you wrap your string in quotes (quotes
that pass the shell mind you and that insmod sees) it still treates
a comma inside of those quotes as starting a new variable, resulting
in memory scribbles if you don't switch the commas to periods.
Kernel Compile options
------------------------------
The various kernel compile time options for this driver are now fairly
well documented in the file Documentation/Configure.help. In order to
see this documentation, you need to use one of the advanced configuration
programs (menuconfig and xconfig). If you are using the "make menuconfig"
method of configuring your kernel, then you would simply highlight the
option in question and hit the ? key. If you are using the "make xconfig"
method of configuring your kernel, then simply click on the help button
next to the option you have questions about. The help information from
the Configure.help file will then get automatically displayed.
/proc support
------------------------------
The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/
directory. That directory contains a file for each SCSI controller in
the system. Each file presents the current configuration and transfer
statistics (enabled with #define in aic7xxx.c) for each controller.
Thanks to Michael Neuffer for his upper-level SCSI help, and
Matthew Jacob for statistics support.
Debugging the driver
------------------------------
Should you have problems with this driver, and would like some help in
getting them solved, there are a couple debugging items built into
the driver to facilitate getting the needed information from the system.
In general, I need a complete description of the problem, with as many
logs as possible concerning what happens. To help with this, there is
a command option aic7xxx=panic_on_abort. This option, when set, forces
the driver to panic the kernel on the first SCSI abort issued by the
mid level SCSI code. If your system is going to reset loops and you
can't read the screen, then this is what you need. Not only will it
stop the system, but it also prints out a large amount of state
information in the process. Second, if you specify the option
"aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much
information as it runs that you won't be able to see anything.
However, this can actually be very useful if your machine simply
locks up when trying to boot, since it will pin-point what was last
happening (in regards to the aic7xxx driver) immediately prior to
the lockup. This is really only useful if your machine simply can
not boot up successfully. If you can get your machine to run, then
this will produce far too much information.
FTP sites
------------------------------
ftp://ftp.redhat.com/pub/aic/
- Out of date. I used to keep stuff here, but too many people
complained about having a hard time getting into Red Hat's ftp
server. So use the web site below instead.
ftp://ftp.pcnet.com/users/eischen/Linux/
- Dan Eischen's driver distribution area
ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
- European Linux mirror of Teleport site
Web sites
------------------------------
http://people.redhat.com/dledford/
- My web site, also the primary aic7xxx site with several related
pages.
Dean W. Gehnert
deang@teleport.com
$Revision: 3.0 $
Modified by Doug Ledford 1998-2000
====================================================================
= Adaptec Aic7xxx Fast -> Ultra160 Family Manager Set v6.2.10 =
= README for =
= The Linux Operating System =
====================================================================
The following information is available in this file:
1. Supported Hardware
2. Command Line Options
3. Contacting Adaptec
1. Supported Hardware
The following Adaptec SCSI Chips and Host Adapters are supported by
the aic7xxx driver.
Chip MIPS Host Bus MaxSync MaxWidth SCBs Notes
---------------------------------------------------------------
aic7770 10 EISA/VL 10MHz 16Bit 4 1
aic7850 10 PCI/32 10MHz 8Bit 3
aic7855 10 PCI/32 10MHz 8Bit 3
aic7856 10 PCI/32 10MHz 8Bit 3
aic7859 10 PCI/32 20MHz 8Bit 3
aic7860 10 PCI/32 20MHz 8Bit 3
aic7870 10 PCI/32 10MHz 16Bit 16
aic7880 10 PCI/32 20MHz 16Bit 16
aic7890 20 PCI/32 40MHz 16Bit 16 3 4 5 6 7 8
aic7891 20 PCI/64 40MHz 16Bit 16 3 4 5 6 7 8
aic7892 20 PCI/64-66 80MHz 16Bit 16 3 4 5 6 7 8
aic7895 15 PCI/32 20MHz 16Bit 16 2 3 4 5
aic7895C 15 PCI/32 20MHz 16Bit 16 2 3 4 5 8
aic7896 20 PCI/32 40MHz 16Bit 16 2 3 4 5 6 7 8
aic7897 20 PCI/64 40MHz 16Bit 16 2 3 4 5 6 7 8
aic7899 20 PCI/64-66 80MHz 16Bit 16 2 3 4 5 6 7 8
1. Multiplexed Twin Channel Device - One controller servicing two
busses.
2. Multi-function Twin Channel Device - Two controllers on one chip.
3. Command Channel Secondary DMA Engine - Allows scatter gather list
and SCB prefetch.
4. 64 Byte SCB Support - Allows disconnected, unttagged request table
for all possible target/lun combinations.
5. Block Move Instruction Support - Doubles the speed of certain
sequencer operations.
6. `Bayonet' style Scatter Gather Engine - Improves S/G prefetch
performance.
7. Queuing Registers - Allows queuing of new transactions without
pausing the sequencer.
8. Multiple Target IDs - Allows the controller to respond to selection
as a target on multiple SCSI IDs.
Controller Chip Host-Bus Int-Connectors Ext-Connectors Notes
--------------------------------------------------------------------------
AHA-274X[A] aic7770 EISA SE-50M SE-HD50F
AHA-274X[A]W aic7770 EISA SE-HD68F SE-HD68F
SE-50M
AHA-274X[A]T aic7770 EISA 2 X SE-50M SE-HD50F
AHA-2842 aic7770 VL SE-50M SE-HD50F
AHA-2940AU aic7860 PCI/32 SE-50M SE-HD50F
AVA-2902I aic7860 PCI/32 SE-50M
AVA-2902E aic7860 PCI/32 SE-50M
AVA-2906 aic7856 PCI/32 SE-50M SE-DB25F
APC-7850 aic7850 PCI/32 SE-50M 1
AVA-2940 aic7860 PCI/32 SE-50M
AHA-2920B aic7860 PCI/32 SE-50M
AHA-2930B aic7860 PCI/32 SE-50M
AHA-2920C aic7856 PCI/32 SE-50M SE-HD50F
AHA-2930C aic7860 PCI/32 SE-50M
AHA-2930C aic7860 PCI/32 SE-50M
AHA-2910C aic7860 PCI/32 SE-50M
AHA-2915C aic7860 PCI/32 SE-50M
AHA-2940AU/CN aic7860 PCI/32 SE-50M SE-HD50F
AHA-2944W aic7870 PCI/32 HVD-HD68F HVD-HD68F
HVD-50M
AHA-3940W aic7870 PCI/32 2 X SE-HD68F SE-HD68F 2
AHA-2940UW aic7880 PCI/32 SE-HD68F
SE-50M SE-HD68F
AHA-2940U aic7880 PCI/32 SE-50M SE-HD50F
AHA-2940D aic7880 PCI/32
AHA-2940 A/T aic7880 PCI/32
AHA-2940D A/T aic7880 PCI/32
AHA-3940UW aic7880 PCI/32 2 X SE-HD68F SE-HD68F 3
AHA-3940UWD aic7880 PCI/32 2 X SE-HD68F 2 X SE-VHD68F 3
AHA-3940U aic7880 PCI/32 2 X SE-50M SE-HD50F 3
AHA-2944UW aic7880 PCI/32 HVD-HD68F HVD-HD68F
HVD-50M
AHA-3944UWD aic7880 PCI/32 2 X HVD-HD68F 2 X HVD-VHD68F 3
AHA-4944UW aic7880 PCI/32
AHA-2930UW aic7880 PCI/32
AHA-2940UW Pro aic7880 PCI/32 SE-HD68F SE-HD68F 4
SE-50M
AHA-2940UW/CN aic7880 PCI/32
AHA-2940UDual aic7895 PCI/32
AHA-2940UWDual aic7895 PCI/32
AHA-3940UWD aic7895 PCI/32
AHA-3940AUW aic7895 PCI/32
AHA-3940AUWD aic7895 PCI/32
AHA-3940AU aic7895 PCI/32
AHA-3944AUWD aic7895 PCI/32 2 X HVD-HD68F 2 X HVD-VHD68F
AHA-2940U2B aic7890 PCI/32 LVD-HD68F LVD-HD68F
AHA-2940U2 OEM aic7891 PCI/64
AHA-2940U2W aic7890 PCI/32 LVD-HD68F LVD-HD68F
SE-HD68F
SE-50M
AHA-2950U2B aic7891 PCI/64 LVD-HD68F LVD-HD68F
AHA-2930U2 aic7890 PCI/32 LVD-HD68F SE-HD50F
SE-50M
AHA-3950U2B aic7897 PCI/64
AHA-3950U2D aic7897 PCI/64
AHA-29160 aic7892 PCI/64-66
AHA-29160 CPQ aic7892 PCI/64-66
AHA-29160N aic7892 PCI/32 LVD-HD68F SE-HD50F
SE-50M
AHA-29160LP aic7892 PCI/64-66
AHA-19160 aic7892 PCI/64-66
AHA-29150LP aic7892 PCI/64-66
AHA-29130LP aic7892 PCI/64-66
AHA-3960D aic7899 PCI/64-66 2 X LVD-HD68F 2 X LVD-VHD68F
LVD-50M
AHA-3960D CPQ aic7899 PCI/64-66 2 X LVD-HD68F 2 X LVD-VHD68F
LVD-50M
AHA-39160 aic7899 PCI/64-66 2 X LVD-HD68F 2 X LVD-VHD68F
LVD-50M
1. No BIOS support
2. DEC21050 PCI-PCI bridge with multiple controller chips on secondary bus
3. DEC2115X PCI-PCI bridge with multiple controller chips on secondary bus
4. All three SCSI connectors may be used simultaneously without
SCSI "stub" effects.
2. Command Line Options
WARNING: ALTERING OR ADDING THESE DRIVER PARAMETERS
INCORRECTLY CAN RENDER YOUR SYSTEM INOPERABLE.
USE THEM WITH CAUTION.
Edit the file "modules.conf" in the directory /etc and add/edit a
line containing 'options aic7xxx=[command[,command...]]' where
'command' is one or more of the following:
-----------------------------------------------------------------
Option: verbose
Definition: enable additional informative messages during
driver operation.
Possible Values: This option is a flag
Default Value: disabled
-----------------------------------------------------------------
Option: debug:[value]
Definition: Enables various levels of debugging information
Possible Values: 0x0000 = no debugging, 0xffff = full debugging
Default Value: 0x0000
-----------------------------------------------------------------
Option: no_reset
Definition: Do not reset the bus during the initial probe
phase
Possible Values: This option is a flag
Default Value: disabled
-----------------------------------------------------------------
Option: extended
Definition: Force extended translation on the controller
Possible Values: This option is a flag
Default Value: disabled
-----------------------------------------------------------------
Option: periodic_otag
Definition: Send an ordered tag periodically to prevent
tag starvation. Needed for some older devices
Possible Values: This option is a flag
Default Value: disabled
-----------------------------------------------------------------
Option: reverse_scan
Definition: Probe the scsi bus in reverse order, starting
with target 15
Possible Values: This option is a flag
Default Value: disabled
-----------------------------------------------------------------
Option: global_tag_depth
Definition: Global tag depth for all targets on all busses.
This option sets the default tag depth which
may be selectively overridden vi the tag_info
option.
Possible Values: 1 - 253
Default Value: 32
-----------------------------------------------------------------
Option: tag_info:{{value[,value...]}[,{value[,value...]}...]}
Definition: Set the per-target tagged queue depth on a
per controller basis. Both controllers and targets
may be ommitted indicating that they should retain
the default tag depth.
Examples: tag_info:{{16,32,32,64,8,8,,32,32,32,32,32,32,32,32,32}
On Controller 0
specifies a tag depth of 16 for target 0
specifies a tag depth of 64 for target 3
specifies a tag depth of 8 for targets 4 and 5
leaves target 6 at the default
specifies a tag depth of 32 for targets 1,2,7-15
All other targets retain the default depth.
tag_info:{{},{32,,32}}
On Controller 1
specifies a tag depth of 32 for targets 0 and 2
All other targets retain the default depth.
Possible Values: 1 - 253
Default Value: 32
-----------------------------------------------------------------
Option: seltime:[value]
Definition: Specifies the selection timeout value
Possible Values: 0 = 256ms, 1 = 128ms, 2 = 64ms, 3 = 32ms
Default Value: 0
-----------------------------------------------------------------
Example: 'options aic7xxx=verbose,no_probe,tag_info:{{},{,,10}},seltime:1"
enables verbose logging, Disable EISA/VLB probing,
and set tag depth on Controller 1/Target 2 to 10 tags.
3. Contacting Adaptec
A Technical Support Identification (TSID) Number is required for
Adaptec technical support.
- The 12-digit TSID can be found on the white barcode-type label
included inside the box with your product. The TSID helps us
provide more efficient service by accurately identifying your
product and support status.
Support Options
- Search the Adaptec Support Knowledgebase (ASK) at
http://ask.adaptec.com for articles, troubleshooting tips, and
frequently asked questions for your product.
- For support via Email, submit your question to Adaptec's
Technical Support Specialists at http://ask.adaptec.com.
North America
- Visit our Web site at http://www.adaptec.com.
- To speak with a Fibre Channel/RAID/External Storage Technical
Support Specialist, call 1-321-207-2000,
Hours: Monday-Friday, 3:00 A.M. to 5:00 P.M., PST.
(Not open on holidays)
- For Technical Support in all other technologies including
SCSI, call 1-408-934-7274,
Hours: Monday-Friday, 6:00 A.M. to 5:00 P.M., PST.
(Not open on holidays)
- For after hours support, call 1-800-416-8066 ($99/call,
$149/call on holidays)
- To order Adaptec products including software and cables, call
1-800-442-7274 or 1-408-957-7274. You can also visit our
online store at http://www.adaptecstore.com
Europe
- Visit our Web site at http://www.adaptec-europe.com.
- English and French: To speak with a Technical Support
Specialist, call one of the following numbers:
- English: +32-2-352-3470
- French: +32-2-352-3460
Hours: Monday-Thursday, 10:00 to 12:30, 13:30 to 17:30 CET
Friday, 10:00 to 12:30, 13:30 to 16:30 CET
- German: To speak with a Technical Support Specialist,
call +49-89-456-40660
Hours: Monday-Thursday, 09:30 to 12:30, 13:30 to 16:30 CET
Friday, 09:30 to 12:30, 13:30 to 15:00 CET
- To order Adaptec products, including accessories and cables:
- UK: +0800-96-65-26 or fax +0800-731-02-95
- Other European countries: +32-11-300-379
Australia and New Zealand
- Visit our Web site at http://www.adaptec.com.au.
- To speak with a Technical Support Specialist, call
+612-9416-0698
Hours: Monday-Friday, 10:00 A.M. to 4:30 P.M., EAT
(Not open on holidays)
Japan
- To speak with a Technical Support Specialist, call
+81-3-5308-6120
Hours: Monday-Friday, 9:00 a.m. to 12:00 p.m., 1:00 p.m. to
6:00 p.m. TSC
Hong Kong and China
- To speak with a Technical Support Specialist, call
+852-2869-7200
Hours: Monday-Friday, 10:00 to 17:00.
- Fax Technical Support at +852-2869-7100.
Singapore
- To speak with a Technical Support Specialist, call
+65-245-7470
Hours: Monday-Friday, 10:00 to 17:00.
- Fax Technical Support at +852-2869-7100
-------------------------------------------------------------------
(c) 2002 Adaptec, Inc. All Rights Reserved. No part of this
publication may be reproduced, stored in a retrieval system, or
transmitted in any form or by any means, electronic, mechanical,
photocopying, recording or otherwise, without prior written consent
of Adaptec, Inc., 691 South Milpitas Blvd., Milpitas, CA 95035.
#
# AIC79XX 2.5.X Kernel configuration File.
# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic79xx#1 $
#
config SCSI_AIC79XX
tristate "Adaptec AIC79xx U320 support"
help
This driver supports all of Adaptec's Ultra 320 PCI-X
based SCSI controllers.
config AIC79XX_CMDS_PER_DEVICE
int "Maximum number of TCQ commands per device"
depends on SCSI_AIC79XX
default "32"
---help---
Specify the number of commands you would like to allocate per SCSI
device when Tagged Command Queueing (TCQ) is enabled on that device.
This is an upper bound value for the number of tagged transactions
to be used for any device. The aic7xxx driver will automatically
vary this number based on device behavior. For devices with a
fixed maximum, the driver will eventually lock to this maximum
and display a console message inidicating this value.
Due to resource allocation issues in the Linux SCSI mid-layer, using
a high number of commands per device may result in memory allocation
failures when many devices are attached to the system. For this reason,
the default is set to 32. Higher values may result in higer performance
on some devices. The upper bound is 253. 0 disables tagged queueing.
Per device tag depth can be controlled via the kernel command line
"tag_info" option. See drivers/scsi/aic7xxx/README.aic79xx
for details.
config AIC79XX_RESET_DELAY_MS
int "Initial bus reset delay in milli-seconds"
depends on SCSI_AIC79XX
default "15000"
---help---
The number of milliseconds to delay after an initial bus reset.
The bus settle delay following all error recovery actions is
dictated by the SCSI layer and is not affected by this value.
Default: 15000 (15 seconds)
config AIC79XX_BUILD_FIRMWARE
bool "Build Adapter Firmware with Kernel Build"
depends on SCSI_AIC79XX
help
This option should only be enabled if you are modifying the firmware
source to the aic79xx driver and wish to have the generated firmware
include files updated during a normal kernel build. The assembler
for the firmware requires lex and yacc or their equivalents, as well
as the db v1 library. You may have to install additional packages
or modify the assembler Makefile or the files it includes if your
build environment is different than that of the author.
config AIC79XX_ENABLE_RD_STRM
bool "Enable Read Streaming for All Targets"
depends on SCSI_AIC79XX
help
Read Streaming is a U320 protocol option that should enhance
performance. Early U320 drive firmware actually performs slower
with read streaming enabled so it is disabled by default. Read
Streaming can be configured in much the same way as tagged queueing
using the "rd_strm" command line option. See
drivers/scsi/aic7xxx/README.aic79xx for details.
config AIC79XX_DEBUG_ENABLE
bool "Compile in Debugging Code"
depends on SCSI_AIC79XX
default y
help
Compile in aic79xx debugging code that can be useful in diagnosing
driver errors.
config AIC79XX_DEBUG_MASK
int "Debug code enable mask (16383 for all debugging)"
depends on SCSI_AIC79XX
default "0"
help
Bit mask of debug options that is only valid if the
CONFIG_AIC79XX_DEBUG_ENBLE option is enabled. The bits in this mask
are defined in the drivers/scsi/aic7xxx/aic79xx.h - search for the
variable ahd_debug in that file to find them.
config AIC79XX_REG_PRETTY_PRINT
bool "Decode registers during diagnostics"
depends on SCSI_AIC79XX
default y
help
Compile in register value tables for the output of expanded register
contents in diagnostics. This make it much easier to understand debug
output without having to refer to a data book and/or the aic7xxx.reg
file.
#
# AIC7XXX and AIC79XX 2.5.X Kernel configuration File.
# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig#2 $
# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic7xxx#2 $
#
config SCSI_AIC7XXX
tristate "Adaptec AIC7xxx Fast -> U160 support"
......@@ -104,89 +104,3 @@ config SCSI_AIC79XX
help
This driver supports all of Adaptec's Ultra 320 PCI-X
based SCSI controllers.
config AIC79XX_CMDS_PER_DEVICE
int "Maximum number of TCQ commands per device"
depends on SCSI_AIC79XX
default "32"
---help---
Specify the number of commands you would like to allocate per SCSI
device when Tagged Command Queueing (TCQ) is enabled on that device.
This is an upper bound value for the number of tagged transactions
to be used for any device. The aic7xxx driver will automatically
vary this number based on device behavior. For devices with a
fixed maximum, the driver will eventually lock to this maximum
and display a console message inidicating this value.
Due to resource allocation issues in the Linux SCSI mid-layer, using
a high number of commands per device may result in memory allocation
failures when many devices are attached to the system. For this reason,
the default is set to 32. Higher values may result in higer performance
on some devices. The upper bound is 253. 0 disables tagged queueing.
Per device tag depth can be controlled via the kernel command line
"tag_info" option. See drivers/scsi/aic7xxx/README.aic79xx
for details.
config AIC79XX_RESET_DELAY_MS
int "Initial bus reset delay in milli-seconds"
depends on SCSI_AIC79XX
default "15000"
---help---
The number of milliseconds to delay after an initial bus reset.
The bus settle delay following all error recovery actions is
dictated by the SCSI layer and is not affected by this value.
Default: 15000 (15 seconds)
config AIC79XX_BUILD_FIRMWARE
bool "Build Adapter Firmware with Kernel Build"
depends on SCSI_AIC79XX
help
This option should only be enabled if you are modifying the firmware
source to the aic79xx driver and wish to have the generated firmware
include files updated during a normal kernel build. The assembler
for the firmware requires lex and yacc or their equivalents, as well
as the db v1 library. You may have to install additional packages
or modify the assembler Makefile or the files it includes if your
build environment is different than that of the author.
config AIC79XX_ENABLE_RD_STRM
bool "Enable Read Streaming for All Targets"
depends on SCSI_AIC79XX
help
Read Streaming is a U320 protocol option that should enhance
performance. Early U320 drive firmware actually performs slower
with read streaming enabled so it is disabled by default. Read
Streaming can be configured in much the same way as tagged queueing
using the "rd_strm" command line option. See
drivers/scsi/aic7xxx/README.aic79xx for details.
config AIC79XX_DEBUG_ENABLE
bool "Compile in Debugging Code"
depends on SCSI_AIC79XX
default y
help
Compile in aic79xx debugging code that can be useful in diagnosing
driver errors.
config AIC79XX_DEBUG_MASK
int "Debug code enable mask (16383 for all debugging)"
depends on SCSI_AIC79XX
default "0"
help
Bit mask of debug options that is only valid if the
CONFIG_AIC79XX_DEBUG_ENBLE option is enabled. The bits in this mask
are defined in the drivers/scsi/aic7xxx/aic79xx.h - search for the
variable ahd_debug in that file to find them.
config AIC79XX_REG_PRETTY_PRINT
bool "Decode registers during diagnostics"
depends on SCSI_AIC79XX
default y
help
Compile in register value tables for the output of expanded register
contents in diagnostics. This make it much easier to understand debug
output without having to refer to a data book and/or the aic7xxx.reg
file.
====================================================================
= Adaptec Aic7xxx Fast -> Ultra160 Family Manager Set v6.2.10 =
= README for =
= The Linux Operating System =
====================================================================
The following information is available in this file:
1. Supported Hardware
2. Command Line Options
3. Contacting Adaptec
1. Supported Hardware
The following Adaptec SCSI Chips and Host Adapters are supported by
the aic7xxx driver.
Chip MIPS Host Bus MaxSync MaxWidth SCBs Notes
---------------------------------------------------------------
aic7770 10 EISA/VL 10MHz 16Bit 4 1
aic7850 10 PCI/32 10MHz 8Bit 3
aic7855 10 PCI/32 10MHz 8Bit 3
aic7856 10 PCI/32 10MHz 8Bit 3
aic7859 10 PCI/32 20MHz 8Bit 3
aic7860 10 PCI/32 20MHz 8Bit 3
aic7870 10 PCI/32 10MHz 16Bit 16
aic7880 10 PCI/32 20MHz 16Bit 16
aic7890 20 PCI/32 40MHz 16Bit 16 3 4 5 6 7 8
aic7891 20 PCI/64 40MHz 16Bit 16 3 4 5 6 7 8
aic7892 20 PCI/64-66 80MHz 16Bit 16 3 4 5 6 7 8
aic7895 15 PCI/32 20MHz 16Bit 16 2 3 4 5
aic7895C 15 PCI/32 20MHz 16Bit 16 2 3 4 5 8
aic7896 20 PCI/32 40MHz 16Bit 16 2 3 4 5 6 7 8
aic7897 20 PCI/64 40MHz 16Bit 16 2 3 4 5 6 7 8
aic7899 20 PCI/64-66 80MHz 16Bit 16 2 3 4 5 6 7 8
1. Multiplexed Twin Channel Device - One controller servicing two
busses.
2. Multi-function Twin Channel Device - Two controllers on one chip.
3. Command Channel Secondary DMA Engine - Allows scatter gather list
and SCB prefetch.
4. 64 Byte SCB Support - Allows disconnected, unttagged request table
for all possible target/lun combinations.
5. Block Move Instruction Support - Doubles the speed of certain
sequencer operations.
6. `Bayonet' style Scatter Gather Engine - Improves S/G prefetch
performance.
7. Queuing Registers - Allows queuing of new transactions without
pausing the sequencer.
8. Multiple Target IDs - Allows the controller to respond to selection
as a target on multiple SCSI IDs.
Controller Chip Host-Bus Int-Connectors Ext-Connectors Notes
--------------------------------------------------------------------------
AHA-274X[A] aic7770 EISA SE-50M SE-HD50F
AHA-274X[A]W aic7770 EISA SE-HD68F SE-HD68F
SE-50M
AHA-274X[A]T aic7770 EISA 2 X SE-50M SE-HD50F
AHA-2842 aic7770 VL SE-50M SE-HD50F
AHA-2940AU aic7860 PCI/32 SE-50M SE-HD50F
AVA-2902I aic7860 PCI/32 SE-50M
AVA-2902E aic7860 PCI/32 SE-50M
AVA-2906 aic7856 PCI/32 SE-50M SE-DB25F
APC-7850 aic7850 PCI/32 SE-50M 1
AVA-2940 aic7860 PCI/32 SE-50M
AHA-2920B aic7860 PCI/32 SE-50M
AHA-2930B aic7860 PCI/32 SE-50M
AHA-2920C aic7856 PCI/32 SE-50M SE-HD50F
AHA-2930C aic7860 PCI/32 SE-50M
AHA-2930C aic7860 PCI/32 SE-50M
AHA-2910C aic7860 PCI/32 SE-50M
AHA-2915C aic7860 PCI/32 SE-50M
AHA-2940AU/CN aic7860 PCI/32 SE-50M SE-HD50F
AHA-2944W aic7870 PCI/32 HVD-HD68F HVD-HD68F
HVD-50M
AHA-3940W aic7870 PCI/32 2 X SE-HD68F SE-HD68F 2
AHA-2940UW aic7880 PCI/32 SE-HD68F
SE-50M SE-HD68F
AHA-2940U aic7880 PCI/32 SE-50M SE-HD50F
AHA-2940D aic7880 PCI/32
AHA-2940 A/T aic7880 PCI/32
AHA-2940D A/T aic7880 PCI/32
AHA-3940UW aic7880 PCI/32 2 X SE-HD68F SE-HD68F 3
AHA-3940UWD aic7880 PCI/32 2 X SE-HD68F 2 X SE-VHD68F 3
AHA-3940U aic7880 PCI/32 2 X SE-50M SE-HD50F 3
AHA-2944UW aic7880 PCI/32 HVD-HD68F HVD-HD68F
HVD-50M
AHA-3944UWD aic7880 PCI/32 2 X HVD-HD68F 2 X HVD-VHD68F 3
AHA-4944UW aic7880 PCI/32
AHA-2930UW aic7880 PCI/32
AHA-2940UW Pro aic7880 PCI/32 SE-HD68F SE-HD68F 4
SE-50M
AHA-2940UW/CN aic7880 PCI/32
AHA-2940UDual aic7895 PCI/32
AHA-2940UWDual aic7895 PCI/32
AHA-3940UWD aic7895 PCI/32
AHA-3940AUW aic7895 PCI/32
AHA-3940AUWD aic7895 PCI/32
AHA-3940AU aic7895 PCI/32
AHA-3944AUWD aic7895 PCI/32 2 X HVD-HD68F 2 X HVD-VHD68F
AHA-2940U2B aic7890 PCI/32 LVD-HD68F LVD-HD68F
AHA-2940U2 OEM aic7891 PCI/64
AHA-2940U2W aic7890 PCI/32 LVD-HD68F LVD-HD68F
SE-HD68F
SE-50M
AHA-2950U2B aic7891 PCI/64 LVD-HD68F LVD-HD68F
AHA-2930U2 aic7890 PCI/32 LVD-HD68F SE-HD50F
SE-50M
AHA-3950U2B aic7897 PCI/64
AHA-3950U2D aic7897 PCI/64
AHA-29160 aic7892 PCI/64-66
AHA-29160 CPQ aic7892 PCI/64-66
AHA-29160N aic7892 PCI/32 LVD-HD68F SE-HD50F
SE-50M
AHA-29160LP aic7892 PCI/64-66
AHA-19160 aic7892 PCI/64-66
AHA-29150LP aic7892 PCI/64-66
AHA-29130LP aic7892 PCI/64-66
AHA-3960D aic7899 PCI/64-66 2 X LVD-HD68F 2 X LVD-VHD68F
LVD-50M
AHA-3960D CPQ aic7899 PCI/64-66 2 X LVD-HD68F 2 X LVD-VHD68F
LVD-50M
AHA-39160 aic7899 PCI/64-66 2 X LVD-HD68F 2 X LVD-VHD68F
LVD-50M
1. No BIOS support
2. DEC21050 PCI-PCI bridge with multiple controller chips on secondary bus
3. DEC2115X PCI-PCI bridge with multiple controller chips on secondary bus
4. All three SCSI connectors may be used simultaneously without
SCSI "stub" effects.
2. Command Line Options
WARNING: ALTERING OR ADDING THESE DRIVER PARAMETERS
INCORRECTLY CAN RENDER YOUR SYSTEM INOPERABLE.
USE THEM WITH CAUTION.
Edit the file "modules.conf" in the directory /etc and add/edit a
line containing 'options aic7xxx=[command[,command...]]' where
'command' is one or more of the following:
-----------------------------------------------------------------
Option: verbose
Definition: enable additional informative messages during
driver operation.
Possible Values: This option is a flag
Default Value: disabled
-----------------------------------------------------------------
Option: debug:[value]
Definition: Enables various levels of debugging information
Possible Values: 0x0000 = no debugging, 0xffff = full debugging
Default Value: 0x0000
-----------------------------------------------------------------
Option: no_reset
Definition: Do not reset the bus during the initial probe
phase
Possible Values: This option is a flag
Default Value: disabled
-----------------------------------------------------------------
Option: extended
Definition: Force extended translation on the controller
Possible Values: This option is a flag
Default Value: disabled
-----------------------------------------------------------------
Option: periodic_otag
Definition: Send an ordered tag periodically to prevent
tag starvation. Needed for some older devices
Possible Values: This option is a flag
Default Value: disabled
-----------------------------------------------------------------
Option: reverse_scan
Definition: Probe the scsi bus in reverse order, starting
with target 15
Possible Values: This option is a flag
Default Value: disabled
-----------------------------------------------------------------
Option: global_tag_depth
Definition: Global tag depth for all targets on all busses.
This option sets the default tag depth which
may be selectively overridden vi the tag_info
option.
Possible Values: 1 - 253
Default Value: 32
-----------------------------------------------------------------
Option: tag_info:{{value[,value...]}[,{value[,value...]}...]}
Definition: Set the per-target tagged queue depth on a
per controller basis. Both controllers and targets
may be ommitted indicating that they should retain
the default tag depth.
Examples: tag_info:{{16,32,32,64,8,8,,32,32,32,32,32,32,32,32,32}
On Controller 0
specifies a tag depth of 16 for target 0
specifies a tag depth of 64 for target 3
specifies a tag depth of 8 for targets 4 and 5
leaves target 6 at the default
specifies a tag depth of 32 for targets 1,2,7-15
All other targets retain the default depth.
tag_info:{{},{32,,32}}
On Controller 1
specifies a tag depth of 32 for targets 0 and 2
All other targets retain the default depth.
Possible Values: 1 - 253
Default Value: 32
-----------------------------------------------------------------
Option: seltime:[value]
Definition: Specifies the selection timeout value
Possible Values: 0 = 256ms, 1 = 128ms, 2 = 64ms, 3 = 32ms
Default Value: 0
-----------------------------------------------------------------
Example: 'options aic7xxx=verbose,no_probe,tag_info:{{},{,,10}},seltime:1"
enables verbose logging, Disable EISA/VLB probing,
and set tag depth on Controller 1/Target 2 to 10 tags.
3. Contacting Adaptec
A Technical Support Identification (TSID) Number is required for
Adaptec technical support.
- The 12-digit TSID can be found on the white barcode-type label
included inside the box with your product. The TSID helps us
provide more efficient service by accurately identifying your
product and support status.
Support Options
- Search the Adaptec Support Knowledgebase (ASK) at
http://ask.adaptec.com for articles, troubleshooting tips, and
frequently asked questions for your product.
- For support via Email, submit your question to Adaptec's
Technical Support Specialists at http://ask.adaptec.com.
North America
- Visit our Web site at http://www.adaptec.com.
- To speak with a Fibre Channel/RAID/External Storage Technical
Support Specialist, call 1-321-207-2000,
Hours: Monday-Friday, 3:00 A.M. to 5:00 P.M., PST.
(Not open on holidays)
- For Technical Support in all other technologies including
SCSI, call 1-408-934-7274,
Hours: Monday-Friday, 6:00 A.M. to 5:00 P.M., PST.
(Not open on holidays)
- For after hours support, call 1-800-416-8066 ($99/call,
$149/call on holidays)
- To order Adaptec products including software and cables, call
1-800-442-7274 or 1-408-957-7274. You can also visit our
online store at http://www.adaptecstore.com
Europe
- Visit our Web site at http://www.adaptec-europe.com.
- English and French: To speak with a Technical Support
Specialist, call one of the following numbers:
- English: +32-2-352-3470
- French: +32-2-352-3460
Hours: Monday-Thursday, 10:00 to 12:30, 13:30 to 17:30 CET
Friday, 10:00 to 12:30, 13:30 to 16:30 CET
- German: To speak with a Technical Support Specialist,
call +49-89-456-40660
Hours: Monday-Thursday, 09:30 to 12:30, 13:30 to 16:30 CET
Friday, 09:30 to 12:30, 13:30 to 15:00 CET
- To order Adaptec products, including accessories and cables:
- UK: +0800-96-65-26 or fax +0800-731-02-95
- Other European countries: +32-11-300-379
Australia and New Zealand
- Visit our Web site at http://www.adaptec.com.au.
- To speak with a Technical Support Specialist, call
+612-9416-0698
Hours: Monday-Friday, 10:00 A.M. to 4:30 P.M., EAT
(Not open on holidays)
Japan
- To speak with a Technical Support Specialist, call
+81-3-5308-6120
Hours: Monday-Friday, 9:00 a.m. to 12:00 p.m., 1:00 p.m. to
6:00 p.m. TSC
Hong Kong and China
- To speak with a Technical Support Specialist, call
+852-2869-7200
Hours: Monday-Friday, 10:00 to 17:00.
- Fax Technical Support at +852-2869-7100.
Singapore
- To speak with a Technical Support Specialist, call
+65-245-7470
Hours: Monday-Friday, 10:00 to 17:00.
- Fax Technical Support at +852-2869-7100
-------------------------------------------------------------------
(c) 2002 Adaptec, Inc. All Rights Reserved. No part of this
publication may be reproduced, stored in a retrieval system, or
transmitted in any form or by any means, electronic, mechanical,
photocopying, recording or otherwise, without prior written consent
of Adaptec, Inc., 691 South Milpitas Blvd., Milpitas, CA 95035.
/*
* Adaptec AIC79xx device driver host template for Linux.
*
* Copyright (c) 2000-2001 Adaptec Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 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") version 2 as published by the Free
* Software Foundation.
*
* 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 DAMAGES.
*
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_host.h#11 $
*/
#ifndef _AIC79XX_LINUX_HOST_H_
#define _AIC79XX_LINUX_HOST_H_
int ahd_linux_proc_info(char *, char **, off_t, int, int, int);
int ahd_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
int ahd_linux_detect(Scsi_Host_Template *);
int ahd_linux_release(struct Scsi_Host *);
const char *ahd_linux_info(struct Scsi_Host *);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
int ahd_linux_slave_alloc(Scsi_Device *);
int ahd_linux_slave_configure(Scsi_Device *);
void ahd_linux_slave_destroy(Scsi_Device *);
int ahd_linux_biosparam(struct scsi_device*, struct block_device*,
sector_t, int[]);
#else
void ahd_linux_select_queue_depth(struct Scsi_Host *host,
Scsi_Device *scsi_devs);
int ahd_linux_biosparam(Disk *, kdev_t, int[]);
#endif
int ahd_linux_bus_reset(Scsi_Cmnd *);
int ahd_linux_dev_reset(Scsi_Cmnd *);
int ahd_linux_abort(Scsi_Cmnd *);
#if defined(__i386__)
# define AIC79XX_BIOSPARAM ahd_linux_biosparam
#else
# define AIC79XX_BIOSPARAM NULL
#endif
#if defined BLK_BOUNCE_HIGH
#define AIC79XX_TEMPLATE_HIGHMEM_IO \
highmem_io: 1,
#else
#define AIC79XX_TEMPLATE_HIGHMEM_IO
#endif
/*
* Scsi_Host_Template (see hosts.h) for AIC-79xx - some fields
* to do with card config are filled in after the card is detected.
*/
#define AIC79XX_TEMPLATE_CORE \
proc_info: ahd_linux_proc_info, \
detect: ahd_linux_detect, \
release: ahd_linux_release, \
info: ahd_linux_info, \
queuecommand: ahd_linux_queue, \
eh_abort_handler: ahd_linux_abort, \
eh_device_reset_handler: ahd_linux_dev_reset, \
eh_bus_reset_handler: ahd_linux_bus_reset, \
bios_param: AIC79XX_BIOSPARAM, \
can_queue: AHD_MAX_QUEUE,/* max simultaneous cmds */\
this_id: -1, /* scsi id of host adapter */\
sg_tablesize: AHD_NSEG, /* max scatter-gather cmds */\
cmd_per_lun: 2, /* cmds per lun */\
present: 0, /* number of 7xxx's present */\
unchecked_isa_dma: 0, /* no memory DMA restrictions*/\
AIC79XX_TEMPLATE_HIGHMEM_IO \
use_clustering: ENABLE_CLUSTERING
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
#define AIC79XX { \
AIC79XX_TEMPLATE_CORE, \
slave_alloc: ahd_linux_slave_alloc, \
slave_configure: ahd_linux_slave_configure, \
slave_destroy: ahd_linux_slave_destroy \
}
#else
#define AIC79XX { \
AIC79XX_TEMPLATE_CORE, \
select_queue_depths: ahd_linux_select_queue_depth, \
use_new_eh_code: 1 \
}
#endif
#endif /* _AIC79XX_LINUX_HOST_H_ */
/*
* Adaptec AIC79xx device driver for Linux.
*
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#91 $
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#92 $
*
* --------------------------------------------------------------------------
* Copyright (c) 1994-2000 Justin T. Gibbs.
......@@ -549,6 +549,7 @@ static int ahd_linux_next_unit(void);
static void ahd_runq_tasklet(unsigned long data);
static int ahd_linux_halt(struct notifier_block *nb, u_long event, void *buf);
/****************************** Inlines ***************************************/
static __inline void ahd_schedule_completeq(struct ahd_softc *ahd,
struct ahd_cmd *acmd);
static __inline void ahd_schedule_runq(struct ahd_softc *ahd);
......@@ -794,6 +795,531 @@ ahd_linux_map_seg(struct ahd_softc *ahd, struct scb *scb,
return (consumed);
}
/************************ Host template entry points *************************/
static int ahd_linux_detect(Scsi_Host_Template *);
static int ahd_linux_release(struct Scsi_Host *);
static const char *ahd_linux_info(struct Scsi_Host *);
static int ahd_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static int ahd_linux_slave_alloc(Scsi_Device *);
static int ahd_linux_slave_configure(Scsi_Device *);
static void ahd_linux_slave_destroy(Scsi_Device *);
static int ahd_linux_biosparam(struct scsi_device*,
struct block_device*, sector_t, int[]);
#else
static void ahd_linux_select_queue_depth(struct Scsi_Host *host,
Scsi_Device *scsi_devs);
static int ahd_linux_biosparam(Disk *, kdev_t, int[]);
#endif
static int ahd_linux_bus_reset(Scsi_Cmnd *);
static int ahd_linux_dev_reset(Scsi_Cmnd *);
static int ahd_linux_abort(Scsi_Cmnd *);
/*
* Try to detect an Adaptec 79XX controller.
*/
static int
ahd_linux_detect(Scsi_Host_Template *template)
{
struct ahd_softc *ahd;
int found;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
/*
* It is a bug that the upper layer takes
* this lock just prior to calling us.
*/
spin_unlock_irq(&io_request_lock);
#endif
/*
* Sanity checking of Linux SCSI data structures so
* that some of our hacks^H^H^H^H^Hassumptions aren't
* violated.
*/
if (offsetof(struct ahd_cmd_internal, end)
> offsetof(struct scsi_cmnd, host_scribble)) {
printf("ahd_linux_detect: SCSI data structures changed.\n");
printf("ahd_linux_detect: Unable to attach\n");
return (0);
}
#ifdef MODULE
/*
* If we've been passed any parameters, process them now.
*/
if (aic79xx)
aic79xx_setup(aic79xx);
if (dummy_buffer[0] != 'P')
printk(KERN_WARNING
"aic79xx: Please read the file /usr/src/linux/drivers/scsi/README.aic79xx\n"
"aic79xx: to see the proper way to specify options to the aic79xx module\n"
"aic79xx: Specifically, don't use any commas when passing arguments to\n"
"aic79xx: insmod or else it might trash certain memory areas.\n");
#endif
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
template->proc_name = "aic79xx";
#else
template->proc_dir = &proc_scsi_aic79xx;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
/*
* We can only map 16MB per-SG
* so create a sector limit of
* "16MB" in 2K sectors.
*/
template->max_sectors = 8192;
#endif
/*
* Initialize our softc list lock prior to
* probing for any adapters.
*/
ahd_list_lockinit();
#ifdef CONFIG_PCI
ahd_linux_pci_probe(template);
#endif
/*
* Register with the SCSI layer all
* controllers we've found.
*/
found = 0;
TAILQ_FOREACH(ahd, &ahd_tailq, links) {
if (ahd_linux_register_host(ahd, template) == 0)
found++;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_lock_irq(&io_request_lock);
#endif
aic79xx_detect_complete++;
return (found);
}
/*
* Free the passed in Scsi_Host memory structures prior to unloading the
* module.
*/
static int
ahd_linux_release(struct Scsi_Host * host)
{
struct ahd_softc *ahd;
u_long l;
ahd_list_lock(&l);
if (host != NULL) {
/*
* We should be able to just perform
* the free directly, but check our
* list for extra sanity.
*/
ahd = ahd_find_softc(*(struct ahd_softc **)host->hostdata);
if (ahd != NULL) {
u_long s;
ahd_lock(ahd, &s);
ahd_intr_enable(ahd, FALSE);
ahd_unlock(ahd, &s);
ahd_free(ahd);
}
}
ahd_list_unlock(&l);
return (0);
}
/*
* Return a string describing the driver.
*/
static const char *
ahd_linux_info(struct Scsi_Host *host)
{
static char buffer[512];
char ahd_info[256];
char *bp;
struct ahd_softc *ahd;
bp = &buffer[0];
ahd = *(struct ahd_softc **)host->hostdata;
memset(bp, 0, sizeof(buffer));
strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev ");
strcat(bp, AIC79XX_DRIVER_VERSION);
strcat(bp, "\n");
strcat(bp, " <");
strcat(bp, ahd->description);
strcat(bp, ">\n");
strcat(bp, " ");
ahd_controller_info(ahd, ahd_info);
strcat(bp, ahd_info);
strcat(bp, "\n");
return (bp);
}
/*
* Queue an SCB to the controller.
*/
static int
ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
{
struct ahd_softc *ahd;
struct ahd_linux_device *dev;
u_long flags;
ahd = *(struct ahd_softc **)cmd->host->hostdata;
/*
* Save the callback on completion function.
*/
cmd->scsi_done = scsi_done;
ahd_midlayer_entrypoint_lock(ahd, &flags);
/*
* Close the race of a command that was in the process of
* being queued to us just as our simq was frozen. Let
* DV commands through so long as we are only frozen to
* perform DV.
*/
if (ahd->platform_data->qfrozen != 0
&& AHD_DV_CMD(cmd) == 0) {
ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ);
ahd_linux_queue_cmd_complete(ahd, cmd);
ahd_schedule_completeq(ahd, NULL);
ahd_midlayer_entrypoint_unlock(ahd, &flags);
return (0);
}
dev = ahd_linux_get_device(ahd, cmd->channel, cmd->target,
cmd->lun, /*alloc*/TRUE);
if (dev == NULL) {
ahd_midlayer_entrypoint_unlock(ahd, &flags);
printf("aic79xx_linux_queue: Unable to allocate device!\n");
return (-ENOMEM);
}
if (cmd->cmd_len > MAX_CDB_LEN)
return (-EINVAL);
cmd->result = CAM_REQ_INPROG << 16;
TAILQ_INSERT_TAIL(&dev->busyq, (struct ahd_cmd *)cmd, acmd_links.tqe);
if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) {
TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links);
dev->flags |= AHD_DEV_ON_RUN_LIST;
ahd_linux_run_device_queues(ahd);
}
ahd_midlayer_entrypoint_unlock(ahd, &flags);
return (0);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static int
ahd_linux_slave_configure(Scsi_Device *device)
{
struct ahd_softc *ahd;
struct ahd_linux_device *dev;
u_long flags;
ahd = *((struct ahd_softc **)device->host->hostdata);
ahd_midlayer_entrypoint_lock(ahd, &flags);
/*
* Since Linux has attached to the device, configure
* it so we don't free and allocate the device
* structure on every command.
*/
dev = ahd_linux_get_device(ahd, device->channel,
device->id, device->lun,
/*alloc*/TRUE);
if (dev != NULL) {
dev->flags &= ~AHD_DEV_UNCONFIGURED;
dev->scsi_device = device;
}
ahd_linux_device_queue_depth(ahd, dev);
ahd_midlayer_entrypoint_unlock(ahd, &flags);
return (0);
}
static void
ahd_linux_slave_destroy(Scsi_Device *device)
{
struct ahd_softc *ahd;
struct ahd_linux_device *dev;
u_long flags;
ahd = *((struct ahd_softc **)device->host->hostdata);
ahd_midlayer_entrypoint_lock(ahd, &flags);
dev = ahd_linux_get_device(ahd, device->channel,
device->id, device->lun,
/*alloc*/FALSE);
if (dev != NULL)
dev->flags |= AHD_DEV_UNCONFIGURED;
ahd_midlayer_entrypoint_unlock(ahd, &flags);
}
#else
/*
* Sets the queue depth for each SCSI device hanging
* off the input host adapter.
*/
static void
ahd_linux_select_queue_depth(struct Scsi_Host * host,
Scsi_Device * scsi_devs)
{
Scsi_Device *device;
struct ahd_softc *ahd;
u_long flags;
int scbnum;
ahd = *((struct ahd_softc **)host->hostdata);
ahd_midlayer_entrypoint_lock(ahd, &flags);
scbnum = 0;
for (device = scsi_devs; device != NULL; device = device->next) {
if (device->host == host) {
struct ahd_linux_device *dev;
/*
* Since Linux has attached to the device, configure
* it so we don't free and allocate the device
* structure on every command.
*/
dev = ahd_linux_get_device(ahd, device->channel,
device->id, device->lun,
/*alloc*/TRUE);
if (dev != NULL) {
dev->flags &= ~AHD_DEV_UNCONFIGURED;
dev->scsi_device = device;
ahd_linux_device_queue_depth(ahd, dev);
device->queue_depth = dev->openings
+ dev->active;
if ((dev->flags & (AHD_DEV_Q_BASIC
| AHD_DEV_Q_TAGGED)) == 0) {
/*
* We allow the OS to queue 2 untagged
* transactions to us at any time even
* though we can only execute them
* serially on the controller/device.
* This should remove some latency.
*/
device->queue_depth = 2;
}
}
}
}
ahd_midlayer_entrypoint_unlock(ahd, &flags);
}
#endif
/*
* Return the disk geometry for the given SCSI device.
*/
static int
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int geom[])
{
uint8_t *bh;
#else
ahd_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
{
struct scsi_device *sdev = disk->device;
u_long capacity = disk->capacity;
struct buffer_head *bh;
#endif
int heads;
int sectors;
int cylinders;
int ret;
int extended;
struct ahd_softc *ahd;
ahd = *((struct ahd_softc **)sdev->host->hostdata);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
bh = scsi_bios_ptable(bdev);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));
#else
bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);
#endif
if (bh) {
ret = scsi_partsize(bh, capacity,
&geom[2], &geom[0], &geom[1]);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
kfree(bh);
#else
brelse(bh);
#endif
if (ret != -1)
return (ret);
}
heads = 64;
sectors = 32;
cylinders = aic_sector_div(capacity, heads, sectors);
if (aic79xx_extended != 0)
extended = 1;
else
extended = (ahd->flags & AHD_EXTENDED_TRANS_A) != 0;
if (extended && cylinders >= 1024) {
heads = 255;
sectors = 63;
cylinders = aic_sector_div(capacity, heads, sectors);
}
geom[0] = heads;
geom[1] = sectors;
geom[2] = cylinders;
return (0);
}
/*
* Abort the current SCSI command(s).
*/
static int
ahd_linux_abort(Scsi_Cmnd *cmd)
{
struct ahd_softc *ahd;
u_long s;
#if NOTYET
struct ahd_cmd *acmd;
int found;
#endif
ahd = *(struct ahd_softc **)cmd->host->hostdata;
#if NOTYET
int error;
error = ahd_linux_queue_recovery_cmd(cmd, SCB_ABORT);
if (error != 0)
printf("aic79xx_abort returns 0x%x\n", error);
return (error);
#else
ahd_midlayer_entrypoint_lock(ahd, &s);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
printf("%s: Abort called for cmd %p\n", ahd_name(ahd), cmd);
ahd_dump_card_state(ahd);
}
#endif
ahd_midlayer_entrypoint_unlock(ahd, &s);
return (FAILED);
#endif
}
/*
* Attempt to send a target reset message to the device that timed out.
*/
static int
ahd_linux_dev_reset(Scsi_Cmnd *cmd)
{
struct ahd_softc *ahd;
#if NOTYET
struct ahd_cmd *acmd;
u_long s;
int found;
#endif
ahd = *(struct ahd_softc **)cmd->host->hostdata;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
printf("%s: Dev reset called for cmd %p\n",
ahd_name(ahd), cmd);
#endif
#if NOTYET
int error;
error = ahd_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
if (error != 0)
printf("aic79xx_dev_reset returns 0x%x\n", error);
return (error);
#else
return (FAILED);
#endif
}
/*
* Reset the SCSI bus.
*/
static int
ahd_linux_bus_reset(Scsi_Cmnd *cmd)
{
struct ahd_softc *ahd;
struct ahd_cmd *acmd;
u_long s;
int found;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_unlock_irq(&io_request_lock);
#endif
ahd = *(struct ahd_softc **)cmd->host->hostdata;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0);
printf("%s: Bus reset called for cmd %p\n",
ahd_name(ahd), cmd);
#endif
ahd_midlayer_entrypoint_lock(ahd, &s);
found = ahd_reset_channel(ahd, cmd->channel + 'A',
/*initiate reset*/TRUE);
acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
TAILQ_INIT(&ahd->platform_data->completeq);
ahd_midlayer_entrypoint_unlock(ahd, &s);
if (bootverbose)
printf("%s: SCSI bus reset delivered. "
"%d SCBs aborted.\n", ahd_name(ahd), found);
if (acmd != NULL) {
acmd = ahd_linux_run_complete_queue(ahd, acmd);
if (acmd != NULL) {
ahd_midlayer_entrypoint_lock(ahd, &s);
ahd_schedule_completeq(ahd, acmd);
ahd_midlayer_entrypoint_unlock(ahd, &s);
}
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_lock_irq(&io_request_lock);
#endif
return (SUCCESS);
}
Scsi_Host_Template aic79xx_driver_template = {
.proc_info = ahd_linux_proc_info,
.detect = ahd_linux_detect,
.release = ahd_linux_release,
.info = ahd_linux_info,
.queuecommand = ahd_linux_queue,
.eh_abort_handler = ahd_linux_abort,
.eh_device_reset_handler = ahd_linux_dev_reset,
.eh_bus_reset_handler = ahd_linux_bus_reset,
#if defined(__i386__)
.bios_param = ahd_linux_biosparam,
#endif
.can_queue = AHD_MAX_QUEUE,
.this_id = -1,
.sg_tablesize = AHD_NSEG,
.cmd_per_lun = 2,
.use_clustering = ENABLE_CLUSTERING,
#if defined CONFIG_HIGHIO
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
/* Assume RedHat Distribution with its different HIGHIO conventions. */
.can_dma_32 = 1,
.single_sg_okay = 1,
#else
.highmem_io = 1,
#endif
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
.slave_configure = ahd_linux_slave_configure,
.slave_destroy = ahd_linux_slave_destroy,
#else
.select_queue_depths = ahd_linux_select_queue_depth,
.use_new_eh_code = 1,
#endif
};
#define driver_template aic79xx_driver_template
#include "scsi_module.c"
/**************************** Tasklet Handler *********************************/
static void
......@@ -1365,158 +1891,74 @@ aic79xx_setup(char *s)
const char *name;
uint32_t *flag;
} options[] = {
{ "extended", &aic79xx_extended },
{ "no_reset", &aic79xx_no_reset },
{ "verbose", &aic79xx_verbose },
{ "allow_memio", &aic79xx_allow_memio},
#ifdef AHD_DEBUG
{ "debug", &ahd_debug },
#endif
{ "reverse_scan", &aic79xx_reverse_scan },
{ "periodic_otag", &aic79xx_periodic_otag },
{ "pci_parity", &aic79xx_pci_parity },
{ "seltime", &aic79xx_seltime },
{ "tag_info", NULL },
{ "global_tag_depth", NULL},
{ "rd_strm", NULL },
{ "dv", NULL },
{ "slewrate", NULL },
{ "precomp", NULL },
{ "amplitude", NULL },
};
end = strchr(s, '\0');
while ((p = strsep(&s, ",.")) != NULL) {
if (*p == '\0')
continue;
for (i = 0; i < NUM_ELEMENTS(options); i++) {
n = strlen(options[i].name);
if (strncmp(options[i].name, p, n) != 0)
continue;
if (!strncmp(p, "global_tag_depth", n)) {
ahd_linux_setup_tag_info_global(p + n);
} else if (!strncmp(p, "tag_info", n)) {
ahd_linux_setup_tag_info(p + n, end, s);
} else if (strncmp(p, "rd_strm", n) == 0) {
ahd_linux_setup_rd_strm_info(p + n, end, s);
} else if (strncmp(p, "dv", n) == 0) {
ahd_linux_setup_dv(p + n, end, s);
} else if (strncmp(p, "slewrate", n) == 0) {
ahd_linux_setup_iocell_info(p + n, end, s,
AIC79XX_SLEWRATE_INDEX);
} else if (strncmp(p, "precomp", n) == 0) {
ahd_linux_setup_iocell_info(p + n, end, s,
AIC79XX_PRECOMP_INDEX);
} else if (strncmp(p, "amplitude", n) == 0) {
ahd_linux_setup_iocell_info(p + n, end, s,
AIC79XX_AMPLITUDE_INDEX);
} else if (p[n] == ':') {
*(options[i].flag) =
simple_strtoul(p + n + 1, NULL, 0);
} else if (!strncmp(p, "verbose", n)) {
*(options[i].flag) = 1;
} else {
*(options[i].flag) = ~(*(options[i].flag));
}
break;
}
}
return 1;
}
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
__setup("aic79xx=", aic79xx_setup);
#endif
int aic79xx_verbose;
/*
* Try to detect an Adaptec 79XX controller.
*/
int
ahd_linux_detect(Scsi_Host_Template *template)
{
struct ahd_softc *ahd;
int found;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
/*
* It is a bug that the upper layer takes
* this lock just prior to calling us.
*/
spin_unlock_irq(&io_request_lock);
#endif
/*
* Sanity checking of Linux SCSI data structures so
* that some of our hacks^H^H^H^H^Hassumptions aren't
* violated.
*/
if (offsetof(struct ahd_cmd_internal, end)
> offsetof(struct scsi_cmnd, host_scribble)) {
printf("ahd_linux_detect: SCSI data structures changed.\n");
printf("ahd_linux_detect: Unable to attach\n");
return (0);
}
#ifdef MODULE
/*
* If we've been passed any parameters, process them now.
*/
if (aic79xx)
aic79xx_setup(aic79xx);
if (dummy_buffer[0] != 'P')
printk(KERN_WARNING
"aic79xx: Please read the file /usr/src/linux/drivers/scsi/README.aic79xx\n"
"aic79xx: to see the proper way to specify options to the aic79xx module\n"
"aic79xx: Specifically, don't use any commas when passing arguments to\n"
"aic79xx: insmod or else it might trash certain memory areas.\n");
#endif
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
template->proc_name = "aic79xx";
#else
template->proc_dir = &proc_scsi_aic79xx;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
/*
* We can only map 16MB per-SG
* so create a sector limit of
* "16MB" in 2K sectors.
*/
template->max_sectors = 8192;
{ "extended", &aic79xx_extended },
{ "no_reset", &aic79xx_no_reset },
{ "verbose", &aic79xx_verbose },
{ "allow_memio", &aic79xx_allow_memio},
#ifdef AHD_DEBUG
{ "debug", &ahd_debug },
#endif
{ "reverse_scan", &aic79xx_reverse_scan },
{ "periodic_otag", &aic79xx_periodic_otag },
{ "pci_parity", &aic79xx_pci_parity },
{ "seltime", &aic79xx_seltime },
{ "tag_info", NULL },
{ "global_tag_depth", NULL},
{ "rd_strm", NULL },
{ "dv", NULL },
{ "slewrate", NULL },
{ "precomp", NULL },
{ "amplitude", NULL },
};
/*
* Initialize our softc list lock prior to
* probing for any adapters.
*/
ahd_list_lockinit();
end = strchr(s, '\0');
#ifdef CONFIG_PCI
ahd_linux_pci_probe(template);
#endif
while ((p = strsep(&s, ",.")) != NULL) {
if (*p == '\0')
continue;
for (i = 0; i < NUM_ELEMENTS(options); i++) {
n = strlen(options[i].name);
/*
* Register with the SCSI layer all
* controllers we've found.
*/
found = 0;
TAILQ_FOREACH(ahd, &ahd_tailq, links) {
if (strncmp(options[i].name, p, n) != 0)
continue;
if (ahd_linux_register_host(ahd, template) == 0)
found++;
if (!strncmp(p, "global_tag_depth", n)) {
ahd_linux_setup_tag_info_global(p + n);
} else if (!strncmp(p, "tag_info", n)) {
ahd_linux_setup_tag_info(p + n, end, s);
} else if (strncmp(p, "rd_strm", n) == 0) {
ahd_linux_setup_rd_strm_info(p + n, end, s);
} else if (strncmp(p, "dv", n) == 0) {
ahd_linux_setup_dv(p + n, end, s);
} else if (strncmp(p, "slewrate", n) == 0) {
ahd_linux_setup_iocell_info(p + n, end, s,
AIC79XX_SLEWRATE_INDEX);
} else if (strncmp(p, "precomp", n) == 0) {
ahd_linux_setup_iocell_info(p + n, end, s,
AIC79XX_PRECOMP_INDEX);
} else if (strncmp(p, "amplitude", n) == 0) {
ahd_linux_setup_iocell_info(p + n, end, s,
AIC79XX_AMPLITUDE_INDEX);
} else if (p[n] == ':') {
*(options[i].flag) =
simple_strtoul(p + n + 1, NULL, 0);
} else if (!strncmp(p, "verbose", n)) {
*(options[i].flag) = 1;
} else {
*(options[i].flag) = ~(*(options[i].flag));
}
break;
}
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_lock_irq(&io_request_lock);
#endif
aic79xx_detect_complete++;
return (found);
return 1;
}
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
__setup("aic79xx=", aic79xx_setup);
#endif
int aic79xx_verbose;
int
ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template)
{
......@@ -3285,112 +3727,6 @@ ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ)
}
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
int
ahd_linux_slave_alloc(Scsi_Device *device)
{
/*
* Nothing to be done for now.
*/
return (0);
}
int
ahd_linux_slave_configure(Scsi_Device *device)
{
struct ahd_softc *ahd;
struct ahd_linux_device *dev;
u_long flags;
ahd = *((struct ahd_softc **)device->host->hostdata);
ahd_midlayer_entrypoint_lock(ahd, &flags);
/*
* Since Linux has attached to the device, configure
* it so we don't free and allocate the device
* structure on every command.
*/
dev = ahd_linux_get_device(ahd, device->channel,
device->id, device->lun,
/*alloc*/TRUE);
if (dev != NULL) {
dev->flags &= ~AHD_DEV_UNCONFIGURED;
dev->scsi_device = device;
}
ahd_linux_device_queue_depth(ahd, dev);
ahd_midlayer_entrypoint_unlock(ahd, &flags);
return (0);
}
void
ahd_linux_slave_destroy(Scsi_Device *device)
{
struct ahd_softc *ahd;
struct ahd_linux_device *dev;
u_long flags;
ahd = *((struct ahd_softc **)device->host->hostdata);
ahd_midlayer_entrypoint_lock(ahd, &flags);
dev = ahd_linux_get_device(ahd, device->channel,
device->id, device->lun,
/*alloc*/FALSE);
if (dev != NULL)
dev->flags |= AHD_DEV_UNCONFIGURED;
ahd_midlayer_entrypoint_unlock(ahd, &flags);
}
#else
/*
* Sets the queue depth for each SCSI device hanging
* off the input host adapter.
*/
void
ahd_linux_select_queue_depth(struct Scsi_Host * host,
Scsi_Device * scsi_devs)
{
Scsi_Device *device;
struct ahd_softc *ahd;
u_long flags;
int scbnum;
ahd = *((struct ahd_softc **)host->hostdata);
ahd_midlayer_entrypoint_lock(ahd, &flags);
scbnum = 0;
for (device = scsi_devs; device != NULL; device = device->next) {
if (device->host == host) {
struct ahd_linux_device *dev;
/*
* Since Linux has attached to the device, configure
* it so we don't free and allocate the device
* structure on every command.
*/
dev = ahd_linux_get_device(ahd, device->channel,
device->id, device->lun,
/*alloc*/TRUE);
if (dev != NULL) {
dev->flags &= ~AHD_DEV_UNCONFIGURED;
dev->scsi_device = device;
ahd_linux_device_queue_depth(ahd, dev);
device->queue_depth = dev->openings
+ dev->active;
if ((dev->flags & (AHD_DEV_Q_BASIC
| AHD_DEV_Q_TAGGED)) == 0) {
/*
* We allow the OS to queue 2 untagged
* transactions to us at any time even
* though we can only execute them
* serially on the controller/device.
* This should remove some latency.
*/
device->queue_depth = 2;
}
}
}
}
ahd_midlayer_entrypoint_unlock(ahd, &flags);
}
#endif
static u_int
ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
{
......@@ -3462,80 +3798,26 @@ static void
ahd_linux_device_queue_depth(struct ahd_softc *ahd,
struct ahd_linux_device *dev)
{
struct ahd_devinfo devinfo;
u_int tags;
ahd_compile_devinfo(&devinfo,
ahd->our_id,
dev->target->target, dev->lun,
dev->target->channel == 0 ? 'A' : 'B',
ROLE_INITIATOR);
tags = ahd_linux_user_tagdepth(ahd, &devinfo);
if (tags != 0
&& dev->scsi_device != NULL
&& dev->scsi_device->tagged_supported != 0) {
ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED);
printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n",
ahd->platform_data->host->host_no, devinfo.channel,
devinfo.target, devinfo.lun, tags);
} else {
ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE);
}
}
/*
* Queue an SCB to the controller.
*/
int
ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
{
struct ahd_softc *ahd;
struct ahd_linux_device *dev;
u_long flags;
ahd = *(struct ahd_softc **)cmd->host->hostdata;
/*
* Save the callback on completion function.
*/
cmd->scsi_done = scsi_done;
ahd_midlayer_entrypoint_lock(ahd, &flags);
/*
* Close the race of a command that was in the process of
* being queued to us just as our simq was frozen. Let
* DV commands through so long as we are only frozen to
* perform DV.
*/
if (ahd->platform_data->qfrozen != 0
&& AHD_DV_CMD(cmd) == 0) {
ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ);
ahd_linux_queue_cmd_complete(ahd, cmd);
ahd_schedule_completeq(ahd, NULL);
ahd_midlayer_entrypoint_unlock(ahd, &flags);
return (0);
}
dev = ahd_linux_get_device(ahd, cmd->channel, cmd->target,
cmd->lun, /*alloc*/TRUE);
if (dev == NULL) {
ahd_midlayer_entrypoint_unlock(ahd, &flags);
printf("aic79xx_linux_queue: Unable to allocate device!\n");
return (-ENOMEM);
}
if (cmd->cmd_len > MAX_CDB_LEN)
return (-EINVAL);
cmd->result = CAM_REQ_INPROG << 16;
TAILQ_INSERT_TAIL(&dev->busyq, (struct ahd_cmd *)cmd, acmd_links.tqe);
if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) {
TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links);
dev->flags |= AHD_DEV_ON_RUN_LIST;
ahd_linux_run_device_queues(ahd);
struct ahd_devinfo devinfo;
u_int tags;
ahd_compile_devinfo(&devinfo,
ahd->our_id,
dev->target->target, dev->lun,
dev->target->channel == 0 ? 'A' : 'B',
ROLE_INITIATOR);
tags = ahd_linux_user_tagdepth(ahd, &devinfo);
if (tags != 0
&& dev->scsi_device != NULL
&& dev->scsi_device->tagged_supported != 0) {
ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED);
printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n",
ahd->platform_data->host->host_no, devinfo.channel,
devinfo.target, devinfo.lun, tags);
} else {
ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE);
}
ahd_midlayer_entrypoint_unlock(ahd, &flags);
return (0);
}
static void
......@@ -3863,34 +4145,6 @@ ahd_linux_free_device(struct ahd_softc *ahd, struct ahd_linux_device *dev)
ahd_linux_free_target(ahd, targ);
}
/*
* Return a string describing the driver.
*/
const char *
ahd_linux_info(struct Scsi_Host *host)
{
static char buffer[512];
char ahd_info[256];
char *bp;
struct ahd_softc *ahd;
bp = &buffer[0];
ahd = *(struct ahd_softc **)host->hostdata;
memset(bp, 0, sizeof(buffer));
strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev ");
strcat(bp, AIC79XX_DRIVER_VERSION);
strcat(bp, "\n");
strcat(bp, " <");
strcat(bp, ahd->description);
strcat(bp, ">\n");
strcat(bp, " ");
ahd_controller_info(ahd, ahd_info);
strcat(bp, ahd_info);
strcat(bp, "\n");
return (bp);
}
void
ahd_send_async(struct ahd_softc *ahd, char channel,
u_int target, u_int lun, ac_code code, void *arg)
......@@ -4861,218 +5115,6 @@ ahd_linux_dev_timed_unfreeze(u_long arg)
ahd_unlock(ahd, &s);
}
/*
* Abort the current SCSI command(s).
*/
int
ahd_linux_abort(Scsi_Cmnd *cmd)
{
struct ahd_softc *ahd;
u_long s;
#if NOTYET
struct ahd_cmd *acmd;
int found;
#endif
ahd = *(struct ahd_softc **)cmd->host->hostdata;
#if NOTYET
int error;
error = ahd_linux_queue_recovery_cmd(cmd, SCB_ABORT);
if (error != 0)
printf("aic79xx_abort returns 0x%x\n", error);
return (error);
#else
ahd_midlayer_entrypoint_lock(ahd, &s);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
printf("%s: Abort called for cmd %p\n", ahd_name(ahd), cmd);
ahd_dump_card_state(ahd);
}
#endif
ahd_midlayer_entrypoint_unlock(ahd, &s);
return (FAILED);
#endif
}
/*
* Attempt to send a target reset message to the device that timed out.
*/
int
ahd_linux_dev_reset(Scsi_Cmnd *cmd)
{
struct ahd_softc *ahd;
#if NOTYET
struct ahd_cmd *acmd;
u_long s;
int found;
#endif
ahd = *(struct ahd_softc **)cmd->host->hostdata;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
printf("%s: Dev reset called for cmd %p\n",
ahd_name(ahd), cmd);
#endif
#if NOTYET
int error;
error = ahd_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
if (error != 0)
printf("aic79xx_dev_reset returns 0x%x\n", error);
return (error);
#else
return (FAILED);
#endif
}
/*
* Reset the SCSI bus.
*/
int
ahd_linux_bus_reset(Scsi_Cmnd *cmd)
{
struct ahd_softc *ahd;
struct ahd_cmd *acmd;
u_long s;
int found;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_unlock_irq(&io_request_lock);
#endif
ahd = *(struct ahd_softc **)cmd->host->hostdata;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0);
printf("%s: Bus reset called for cmd %p\n",
ahd_name(ahd), cmd);
#endif
ahd_midlayer_entrypoint_lock(ahd, &s);
found = ahd_reset_channel(ahd, cmd->channel + 'A',
/*initiate reset*/TRUE);
acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
TAILQ_INIT(&ahd->platform_data->completeq);
ahd_midlayer_entrypoint_unlock(ahd, &s);
if (bootverbose)
printf("%s: SCSI bus reset delivered. "
"%d SCBs aborted.\n", ahd_name(ahd), found);
if (acmd != NULL) {
acmd = ahd_linux_run_complete_queue(ahd, acmd);
if (acmd != NULL) {
ahd_midlayer_entrypoint_lock(ahd, &s);
ahd_schedule_completeq(ahd, acmd);
ahd_midlayer_entrypoint_unlock(ahd, &s);
}
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_lock_irq(&io_request_lock);
#endif
return (SUCCESS);
}
/*
* Return the disk geometry for the given SCSI device.
*/
int
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int geom[])
#else
ahd_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
#endif
{
int heads;
int sectors;
int cylinders;
int ret;
int extended;
struct ahd_softc *ahd;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
uint8_t *bh;
#else
u_long capacity;
struct buffer_head *bh;
capacity = disk->capacity;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
ahd = *((struct ahd_softc **)sdev->host->hostdata);
#else
ahd = *((struct ahd_softc **)disk->device->host->hostdata);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
bh = scsi_bios_ptable(bdev);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));
#else
bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);
#endif
if (bh) {
ret = scsi_partsize(bh, capacity,
&geom[2], &geom[0], &geom[1]);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
kfree(bh);
#else
brelse(bh);
#endif
if (ret != -1)
return (ret);
}
heads = 64;
sectors = 32;
cylinders = capacity / (heads * sectors);
if (aic79xx_extended != 0)
extended = 1;
else
extended = (ahd->flags & AHD_EXTENDED_TRANS_A) != 0;
if (extended && cylinders >= 1024) {
heads = 255;
sectors = 63;
cylinders = capacity / (heads * sectors);
}
geom[0] = heads;
geom[1] = sectors;
geom[2] = cylinders;
return (0);
}
/*
* Free the passed in Scsi_Host memory structures prior to unloading the
* module.
*/
int
ahd_linux_release(struct Scsi_Host * host)
{
struct ahd_softc *ahd;
u_long l;
ahd_list_lock(&l);
if (host != NULL) {
/*
* We should be able to just perform
* the free directly, but check our
* list for extra sanity.
*/
ahd = ahd_find_softc(*(struct ahd_softc **)host->hostdata);
if (ahd != NULL) {
u_long s;
ahd_lock(ahd, &s);
ahd_intr_enable(ahd, FALSE);
ahd_unlock(ahd, &s);
ahd_free(ahd);
}
}
ahd_list_unlock(&l);
return (0);
}
void
ahd_platform_dump_card_state(struct ahd_softc *ahd)
{
......@@ -5103,9 +5145,3 @@ ahd_platform_dump_card_state(struct ahd_softc *ahd)
}
}
}
#if defined(MODULE) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
static Scsi_Host_Template driver_template = AIC79XX;
Scsi_Host_Template *aic79xx_driver_template = &driver_template;
#include "scsi_module.c"
#endif
......@@ -36,7 +36,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#87 $
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#88 $
*
*/
#ifndef _AIC79XX_LINUX_H_
......@@ -291,7 +291,7 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec)
#include <linux/smp.h>
#endif
#define AIC79XX_DRIVER_VERSION "1.3.0.ALPHA2"
#define AIC79XX_DRIVER_VERSION "1.3.0.ALPHA3"
/**************************** Front End Queues ********************************/
/*
......
......@@ -36,7 +36,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#17 $
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#18 $
*/
#include "aic79xx_osm.h"
......@@ -181,7 +181,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
pci_set_drvdata(pdev, ahd);
if (aic79xx_detect_complete)
ahd_linux_register_host(ahd, aic79xx_driver_template);
ahd_linux_register_host(ahd, &aic79xx_driver_template);
#endif
return (0);
}
......
/*
* Adaptec AIC7xxx device driver host template for Linux.
*
* Copyright (c) 2000-2001 Adaptec Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 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") version 2 as published by the Free
* Software Foundation.
*
* 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 DAMAGES.
*
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_host.h#13 $
*/
#ifndef _AIC7XXX_HOST_H_
#define _AIC7XXX_HOST_H_
int ahc_linux_proc_info(char *, char **, off_t, int, int, int);
int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
int ahc_linux_detect(Scsi_Host_Template *);
int ahc_linux_release(struct Scsi_Host *);
const char *ahc_linux_info(struct Scsi_Host *);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
int ahc_linux_slave_alloc(Scsi_Device *);
int ahc_linux_slave_configure(Scsi_Device *);
void ahc_linux_slave_destroy(Scsi_Device *);
int ahd_linux_biosparam(struct scsi_device*, struct block_device*,
sector_t, int[]);
#else
void ahc_linux_select_queue_depth(struct Scsi_Host *host,
Scsi_Device *scsi_devs);
int ahc_linux_biosparam(Disk *, kdev_t, int[]);
#endif
int ahc_linux_bus_reset(Scsi_Cmnd *);
int ahc_linux_dev_reset(Scsi_Cmnd *);
int ahc_linux_abort(Scsi_Cmnd *);
#if defined(__i386__)
# define AIC7XXX_BIOSPARAM ahc_linux_biosparam
#else
# define AIC7XXX_BIOSPARAM NULL
#endif
#if defined BLK_BOUNCE_HIGH
#define AIC7XXX_TEMPLATE_HIGHMEM_IO \
highmem_io: 1,
#else
#define AIC7XXX_TEMPLATE_HIGHMEM_IO
#endif
/*
* Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
* to do with card config are filled in after the card is detected.
*/
#define AIC7XXX_TEMPLATE_CORE \
proc_info: ahc_linux_proc_info, \
detect: ahc_linux_detect, \
release: ahc_linux_release, \
info: ahc_linux_info, \
queuecommand: ahc_linux_queue, \
eh_abort_handler: ahc_linux_abort, \
eh_device_reset_handler: ahc_linux_dev_reset, \
eh_bus_reset_handler: ahc_linux_bus_reset, \
bios_param: AIC7XXX_BIOSPARAM, \
can_queue: AHC_MAX_QUEUE,/* max simultaneous cmds */\
this_id: -1, /* scsi id of host adapter */\
sg_tablesize: AHC_NSEG, /* max scatter-gather cmds */\
cmd_per_lun: 2, /* cmds per lun */\
present: 0, /* number of 7xxx's present */\
unchecked_isa_dma: 0, /* no memory DMA restrictions*/\
AIC7XXX_TEMPLATE_HIGHMEM_IO \
use_clustering: ENABLE_CLUSTERING
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
#define AIC7XXX { \
AIC7XXX_TEMPLATE_CORE, \
slave_alloc: ahc_linux_slave_alloc, \
slave_configure: ahc_linux_slave_configure, \
slave_destroy: ahc_linux_slave_destroy \
}
#else
#define AIC7XXX { \
AIC7XXX_TEMPLATE_CORE, \
select_queue_depths: ahc_linux_select_queue_depth, \
use_new_eh_code: 1 \
}
#endif
#endif /* _AIC7XXX_HOST_H_ */
/*
* Adaptec AIC7xxx device driver for Linux.
*
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#159 $
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#160 $
*
* Copyright (c) 1994 John Aycock
* The University of Calgary Department of Computer Science.
......@@ -576,12 +576,12 @@ static void ahc_linux_run_device_queue(struct ahc_softc*,
static void ahc_linux_setup_tag_info(char *p, char *end, char *s);
static void ahc_linux_setup_tag_info_global(char *p);
static void ahc_linux_setup_dv(char *p, char *end, char *s);
static int ahc_linux_next_unit(void);
static int ahc_linux_next_unit(void);
static void ahc_runq_tasklet(unsigned long data);
static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf);
static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf);
static void ahc_schedule_completeq(struct ahc_softc *ahc, struct ahc_cmd *acmd);
static void ahc_schedule_completeq(struct ahc_softc *ahc,
struct ahc_cmd *acmd);
/********************************* Inlines ************************************/
static __inline void ahc_schedule_runq(struct ahc_softc *ahc);
static __inline struct ahc_linux_device*
ahc_linux_get_device(struct ahc_softc *ahc, u_int channel,
......@@ -806,6 +806,510 @@ ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
return (consumed);
}
/************************ Host template entry points *************************/
static int ahc_linux_detect(Scsi_Host_Template *);
static int ahc_linux_release(struct Scsi_Host *);
static int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
static const char *ahc_linux_info(struct Scsi_Host *);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static int ahc_linux_slave_alloc(Scsi_Device *);
static int ahc_linux_slave_configure(Scsi_Device *);
static void ahc_linux_slave_destroy(Scsi_Device *);
static int ahd_linux_biosparam(struct scsi_device*,
struct block_device*,
sector_t, int[]);
#else
static void ahc_linux_select_queue_depth(struct Scsi_Host *host,
Scsi_Device *scsi_devs);
static int ahc_linux_biosparam(Disk *, kdev_t, int[]);
#endif
static int ahc_linux_bus_reset(Scsi_Cmnd *);
static int ahc_linux_dev_reset(Scsi_Cmnd *);
static int ahc_linux_abort(Scsi_Cmnd *);
/*
* Try to detect an Adaptec 7XXX controller.
*/
static int
ahc_linux_detect(Scsi_Host_Template *template)
{
struct ahc_softc *ahc;
int found;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
/*
* It is a bug that the upper layer takes
* this lock just prior to calling us.
*/
spin_unlock_irq(&io_request_lock);
#endif
/*
* Sanity checking of Linux SCSI data structures so
* that some of our hacks^H^H^H^H^Hassumptions aren't
* violated.
*/
if (offsetof(struct ahc_cmd_internal, end)
> offsetof(struct scsi_cmnd, host_scribble)) {
printf("ahc_linux_detect: SCSI data structures changed.\n");
printf("ahc_linux_detect: Unable to attach\n");
return (0);
}
#ifdef MODULE
/*
* If we've been passed any parameters, process them now.
*/
if (aic7xxx)
aic7xxx_setup(aic7xxx);
if (dummy_buffer[0] != 'P')
printk(KERN_WARNING
"aic7xxx: Please read the file /usr/src/linux/drivers/scsi/README.aic7xxx\n"
"aic7xxx: to see the proper way to specify options to the aic7xxx module\n"
"aic7xxx: Specifically, don't use any commas when passing arguments to\n"
"aic7xxx: insmod or else it might trash certain memory areas.\n");
#endif
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
template->proc_name = "aic7xxx";
#else
template->proc_dir = &proc_scsi_aic7xxx;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
/*
* We can only map 16MB per-SG
* so create a sector limit of
* "16MB" in 2K sectors.
*/
template->max_sectors = 8192;
#endif
/*
* Initialize our softc list lock prior to
* probing for any adapters.
*/
ahc_list_lockinit();
#ifdef CONFIG_PCI
ahc_linux_pci_probe(template);
#endif
if (aic7xxx_no_probe == 0)
aic7770_linux_probe(template);
/*
* Register with the SCSI layer all
* controllers we've found.
*/
found = 0;
TAILQ_FOREACH(ahc, &ahc_tailq, links) {
if (ahc_linux_register_host(ahc, template) == 0)
found++;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_lock_irq(&io_request_lock);
#endif
aic7xxx_detect_complete++;
return (found);
}
/*
* Free the passed in Scsi_Host memory structures prior to unloading the
* module.
*/
int
ahc_linux_release(struct Scsi_Host * host)
{
struct ahc_softc *ahc;
u_long l;
ahc_list_lock(&l);
if (host != NULL) {
/*
* We should be able to just perform
* the free directly, but check our
* list for extra sanity.
*/
ahc = ahc_find_softc(*(struct ahc_softc **)host->hostdata);
if (ahc != NULL) {
u_long s;
ahc_lock(ahc, &s);
ahc_intr_enable(ahc, FALSE);
ahc_unlock(ahc, &s);
ahc_free(ahc);
}
}
ahc_list_unlock(&l);
return (0);
}
/*
* Return a string describing the driver.
*/
static const char *
ahc_linux_info(struct Scsi_Host *host)
{
static char buffer[512];
char ahc_info[256];
char *bp;
struct ahc_softc *ahc;
bp = &buffer[0];
ahc = *(struct ahc_softc **)host->hostdata;
memset(bp, 0, sizeof(buffer));
strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev ");
strcat(bp, AIC7XXX_DRIVER_VERSION);
strcat(bp, "\n");
strcat(bp, " <");
strcat(bp, ahc->description);
strcat(bp, ">\n");
strcat(bp, " ");
ahc_controller_info(ahc, ahc_info);
strcat(bp, ahc_info);
strcat(bp, "\n");
return (bp);
}
/*
* Queue an SCB to the controller.
*/
static int
ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
{
struct ahc_softc *ahc;
struct ahc_linux_device *dev;
u_long flags;
ahc = *(struct ahc_softc **)cmd->host->hostdata;
/*
* Save the callback on completion function.
*/
cmd->scsi_done = scsi_done;
ahc_midlayer_entrypoint_lock(ahc, &flags);
/*
* Close the race of a command that was in the process of
* being queued to us just as our simq was frozen. Let
* DV commands through so long as we are only frozen to
* perform DV.
*/
if (ahc->platform_data->qfrozen != 0
&& AHC_DV_CMD(cmd) == 0) {
ahc_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ);
ahc_linux_queue_cmd_complete(ahc, cmd);
ahc_schedule_completeq(ahc, NULL);
ahc_midlayer_entrypoint_unlock(ahc, &flags);
return (0);
}
dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target,
cmd->lun, /*alloc*/TRUE);
if (dev == NULL) {
ahc_midlayer_entrypoint_unlock(ahc, &flags);
printf("aic7xxx_linux_queue: Unable to allocate device!\n");
return (-ENOMEM);
}
cmd->result = CAM_REQ_INPROG << 16;
TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe);
if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {
TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links);
dev->flags |= AHC_DEV_ON_RUN_LIST;
ahc_linux_run_device_queues(ahc);
}
ahc_midlayer_entrypoint_unlock(ahc, &flags);
return (0);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static int
ahc_linux_slave_alloc(Scsi_Device *device)
{
/*
* Nothing to be done for now.
*/
return (0);
}
static int
ahc_linux_slave_configure(Scsi_Device *device)
{
struct ahc_softc *ahc;
struct ahc_linux_device *dev;
u_long flags;
ahc = *((struct ahc_softc **)device->host->hostdata);
ahc_midlayer_entrypoint_lock(ahc, &flags);
/*
* Since Linux has attached to the device, configure
* it so we don't free and allocate the device
* structure on every command.
*/
dev = ahc_linux_get_device(ahc, device->channel,
device->id, device->lun,
/*alloc*/TRUE);
if (dev != NULL) {
dev->flags &= ~AHC_DEV_UNCONFIGURED;
dev->scsi_device = device;
}
ahc_linux_device_queue_depth(ahc, dev);
ahc_midlayer_entrypoint_unlock(ahc, &flags);
return (0);
}
static void
ahc_linux_slave_destroy(Scsi_Device *device)
{
struct ahc_softc *ahc;
struct ahc_linux_device *dev;
u_long flags;
ahc = *((struct ahc_softc **)device->host->hostdata);
ahc_midlayer_entrypoint_lock(ahc, &flags);
dev = ahc_linux_get_device(ahc, device->channel,
device->id, device->lun,
/*alloc*/FALSE);
if (dev != NULL)
dev->flags |= AHC_DEV_UNCONFIGURED;
ahc_midlayer_entrypoint_unlock(ahc, &flags);
}
#else
/*
* Sets the queue depth for each SCSI device hanging
* off the input host adapter.
*/
static void
ahc_linux_select_queue_depth(struct Scsi_Host * host,
Scsi_Device * scsi_devs)
{
Scsi_Device *device;
struct ahc_softc *ahc;
u_long flags;
ahc = *((struct ahc_softc **)host->hostdata);
ahc_midlayer_entrypoint_lock(ahc, &flags);
for (device = scsi_devs; device != NULL; device = device->next) {
if (device->host == host) {
struct ahc_linux_device *dev;
/*
* Since Linux has attached to the device, configure
* it so we don't free and allocate the device
* structure on every command.
*/
dev = ahc_linux_get_device(ahc, device->channel,
device->id, device->lun,
/*alloc*/TRUE);
if (dev != NULL) {
dev->flags &= ~AHC_DEV_UNCONFIGURED;
dev->scsi_device = device;
ahc_linux_device_queue_depth(ahc, dev);
device->queue_depth = dev->openings
+ dev->active;
if ((dev->flags & (AHC_DEV_Q_BASIC
| AHC_DEV_Q_TAGGED)) == 0) {
/*
* We allow the OS to queue 2 untagged
* transactions to us at any time even
* though we can only execute them
* serially on the controller/device.
* This should remove some latency.
*/
device->queue_depth = 2;
}
}
}
}
ahc_midlayer_entrypoint_unlock(ahc, &flags);
}
#endif
/*
* Return the disk geometry for the given SCSI device.
*/
static int
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int geom[])
#else
ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
#endif
{
int heads;
int sectors;
int cylinders;
int ret;
int extended;
struct ahc_softc *ahc;
u_int channel;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
uint8_t *bh;
channel = sdev->channel;
#else
u_long capacity;
struct buffer_head *bh;
capacity = disk->capacity;
channel = disk->device->channel;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
ahc = *((struct ahc_softc **)sdev->host->hostdata);
#else
ahc = *((struct ahc_softc **)disk->device->host->hostdata);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
bh = scsi_bios_ptable(bdev);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));
#else
bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);
#endif
if (bh) {
ret = scsi_partsize(bh, capacity,
&geom[2], &geom[0], &geom[1]);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
kfree(bh);
#else
brelse(bh);
#endif
if (ret != -1)
return (ret);
}
heads = 64;
sectors = 32;
cylinders = capacity / (heads * sectors);
if (aic7xxx_extended != 0)
extended = 1;
else if (channel == 0)
extended = (ahc->flags & AHC_EXTENDED_TRANS_A) != 0;
else
extended = (ahc->flags & AHC_EXTENDED_TRANS_B) != 0;
if (extended && cylinders >= 1024) {
heads = 255;
sectors = 63;
cylinders = capacity / (heads * sectors);
}
geom[0] = heads;
geom[1] = sectors;
geom[2] = cylinders;
return (0);
}
/*
* Abort the current SCSI command(s).
*/
static int
ahc_linux_abort(Scsi_Cmnd *cmd)
{
int error;
error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT);
if (error != 0)
printf("aic7xxx_abort returns 0x%x\n", error);
return (error);
}
/*
* Attempt to send a target reset message to the device that timed out.
*/
static int
ahc_linux_dev_reset(Scsi_Cmnd *cmd)
{
int error;
error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
if (error != 0)
printf("aic7xxx_dev_reset returns 0x%x\n", error);
return (error);
}
/*
* Reset the SCSI bus.
*/
static int
ahc_linux_bus_reset(Scsi_Cmnd *cmd)
{
struct ahc_softc *ahc;
struct ahc_cmd *acmd;
u_long s;
int found;
ahc = *(struct ahc_softc **)cmd->host->hostdata;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_unlock_irq(&io_request_lock);
#endif
ahc_midlayer_entrypoint_lock(ahc, &s);
found = ahc_reset_channel(ahc, cmd->channel + 'A',
/*initiate reset*/TRUE);
acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
TAILQ_INIT(&ahc->platform_data->completeq);
ahc_midlayer_entrypoint_unlock(ahc, &s);
if (bootverbose)
printf("%s: SCSI bus reset delivered. "
"%d SCBs aborted.\n", ahc_name(ahc), found);
if (acmd != NULL) {
acmd = ahc_linux_run_complete_queue(ahc, acmd);
if (acmd != NULL) {
ahc_midlayer_entrypoint_lock(ahc, &s);
ahc_schedule_completeq(ahc, acmd);
ahc_midlayer_entrypoint_unlock(ahc, &s);
}
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_lock_irq(&io_request_lock);
#endif
return SUCCESS;
}
Scsi_Host_Template aic7xxx_driver_template = {
.proc_info = ahc_linux_proc_info,
.detect = ahc_linux_detect,
.release = ahc_linux_release,
.info = ahc_linux_info,
.queuecommand = ahc_linux_queue,
.eh_abort_handler = ahc_linux_abort,
.eh_device_reset_handler = ahc_linux_dev_reset,
.eh_bus_reset_handler = ahc_linux_bus_reset,
#if defined(__i386__)
.bios_param = ahc_linux_biosparam,
#endif
.can_queue = AHC_MAX_QUEUE,
.this_id = -1,
.sg_tablesize = AHC_NSEG,
.cmd_per_lun = 2,
.use_clustering = ENABLE_CLUSTERING,
#if defined CONFIG_HIGHIO
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
/* Assume RedHat Distribution with its different HIGHIO conventions. */
.can_dma_32 = 1,
.single_sg_okay = 1,
#else
.highmem_io = 1,
#endif
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
.slave_configure = ahc_linux_slave_configure,
.slave_destroy = ahc_linux_slave_destroy,
#else
.select_queue_depths = ahc_linux_select_queue_depth,
.use_new_eh_code = 1,
#endif
};
#define driver_template aic7xxx_driver_template
#include "scsi_module.c"
/**************************** Tasklet Handler *********************************/
static void
......@@ -1317,93 +1821,6 @@ __setup("aic7xxx=", aic7xxx_setup);
int aic7xxx_verbose;
/*
* Try to detect an Adaptec 7XXX controller.
*/
int
ahc_linux_detect(Scsi_Host_Template *template)
{
struct ahc_softc *ahc;
int found;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
/*
* It is a bug that the upper layer takes
* this lock just prior to calling us.
*/
spin_unlock_irq(&io_request_lock);
#endif
/*
* Sanity checking of Linux SCSI data structures so
* that some of our hacks^H^H^H^H^Hassumptions aren't
* violated.
*/
if (offsetof(struct ahc_cmd_internal, end)
> offsetof(struct scsi_cmnd, host_scribble)) {
printf("ahc_linux_detect: SCSI data structures changed.\n");
printf("ahc_linux_detect: Unable to attach\n");
return (0);
}
#ifdef MODULE
/*
* If we've been passed any parameters, process them now.
*/
if (aic7xxx)
aic7xxx_setup(aic7xxx);
if (dummy_buffer[0] != 'P')
printk(KERN_WARNING
"aic7xxx: Please read the file /usr/src/linux/drivers/scsi/README.aic7xxx\n"
"aic7xxx: to see the proper way to specify options to the aic7xxx module\n"
"aic7xxx: Specifically, don't use any commas when passing arguments to\n"
"aic7xxx: insmod or else it might trash certain memory areas.\n");
#endif
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
template->proc_name = "aic7xxx";
#else
template->proc_dir = &proc_scsi_aic7xxx;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
/*
* We can only map 16MB per-SG
* so create a sector limit of
* "16MB" in 2K sectors.
*/
template->max_sectors = 8192;
#endif
/*
* Initialize our softc list lock prior to
* probing for any adapters.
*/
ahc_list_lockinit();
#ifdef CONFIG_PCI
ahc_linux_pci_probe(template);
#endif
if (aic7xxx_no_probe == 0)
aic7770_linux_probe(template);
/*
* Register with the SCSI layer all
* controllers we've found.
*/
found = 0;
TAILQ_FOREACH(ahc, &ahc_tailq, links) {
if (ahc_linux_register_host(ahc, template) == 0)
found++;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_lock_irq(&io_request_lock);
#endif
aic7xxx_detect_complete++;
return (found);
}
int
ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
{
......@@ -3194,109 +3611,6 @@ ahc_linux_generate_dv_pattern(struct ahc_linux_target *targ)
}
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
int
ahc_linux_slave_alloc(Scsi_Device *device)
{
/*
* Nothing to be done for now.
*/
return (0);
}
int
ahc_linux_slave_configure(Scsi_Device *device)
{
struct ahc_softc *ahc;
struct ahc_linux_device *dev;
u_long flags;
ahc = *((struct ahc_softc **)device->host->hostdata);
ahc_midlayer_entrypoint_lock(ahc, &flags);
/*
* Since Linux has attached to the device, configure
* it so we don't free and allocate the device
* structure on every command.
*/
dev = ahc_linux_get_device(ahc, device->channel,
device->id, device->lun,
/*alloc*/TRUE);
if (dev != NULL) {
dev->flags &= ~AHC_DEV_UNCONFIGURED;
dev->scsi_device = device;
}
ahc_linux_device_queue_depth(ahc, dev);
ahc_midlayer_entrypoint_unlock(ahc, &flags);
return (0);
}
void
ahc_linux_slave_destroy(Scsi_Device *device)
{
struct ahc_softc *ahc;
struct ahc_linux_device *dev;
u_long flags;
ahc = *((struct ahc_softc **)device->host->hostdata);
ahc_midlayer_entrypoint_lock(ahc, &flags);
dev = ahc_linux_get_device(ahc, device->channel,
device->id, device->lun,
/*alloc*/FALSE);
if (dev != NULL)
dev->flags |= AHC_DEV_UNCONFIGURED;
ahc_midlayer_entrypoint_unlock(ahc, &flags);
}
#else
/*
* Sets the queue depth for each SCSI device hanging
* off the input host adapter.
*/
void
ahc_linux_select_queue_depth(struct Scsi_Host * host,
Scsi_Device * scsi_devs)
{
Scsi_Device *device;
struct ahc_softc *ahc;
u_long flags;
ahc = *((struct ahc_softc **)host->hostdata);
ahc_midlayer_entrypoint_lock(ahc, &flags);
for (device = scsi_devs; device != NULL; device = device->next) {
if (device->host == host) {
struct ahc_linux_device *dev;
/*
* Since Linux has attached to the device, configure
* it so we don't free and allocate the device
* structure on every command.
*/
dev = ahc_linux_get_device(ahc, device->channel,
device->id, device->lun,
/*alloc*/TRUE);
if (dev != NULL) {
dev->flags &= ~AHC_DEV_UNCONFIGURED;
dev->scsi_device = device;
ahc_linux_device_queue_depth(ahc, dev);
device->queue_depth = dev->openings
+ dev->active;
if ((dev->flags & (AHC_DEV_Q_BASIC
| AHC_DEV_Q_TAGGED)) == 0) {
/*
* We allow the OS to queue 2 untagged
* transactions to us at any time even
* though we can only execute them
* serially on the controller/device.
* This should remove some latency.
*/
device->queue_depth = 2;
}
}
}
}
ahc_midlayer_entrypoint_unlock(ahc, &flags);
}
#endif
static u_int
ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
{
......@@ -3373,83 +3687,31 @@ ahc_linux_user_dv_setting(struct ahc_softc *ahc)
/*
* Determines the queue depth for a given device.
*/
static void
ahc_linux_device_queue_depth(struct ahc_softc *ahc,
struct ahc_linux_device *dev)
{
struct ahc_devinfo devinfo;
u_int tags;
ahc_compile_devinfo(&devinfo,
dev->target->channel == 0
? ahc->our_id : ahc->our_id_b,
dev->target->target, dev->lun,
dev->target->channel == 0 ? 'A' : 'B',
ROLE_INITIATOR);
tags = ahc_linux_user_tagdepth(ahc, &devinfo);
if (tags != 0
&& dev->scsi_device != NULL
&& dev->scsi_device->tagged_supported != 0) {
ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n",
ahc->platform_data->host->host_no, devinfo.channel,
devinfo.target, devinfo.lun, tags);
} else {
ahc_set_tags(ahc, &devinfo, AHC_QUEUE_NONE);
}
}
/*
* Queue an SCB to the controller.
*/
int
ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
{
struct ahc_softc *ahc;
struct ahc_linux_device *dev;
u_long flags;
ahc = *(struct ahc_softc **)cmd->host->hostdata;
/*
* Save the callback on completion function.
*/
cmd->scsi_done = scsi_done;
ahc_midlayer_entrypoint_lock(ahc, &flags);
static void
ahc_linux_device_queue_depth(struct ahc_softc *ahc,
struct ahc_linux_device *dev)
{
struct ahc_devinfo devinfo;
u_int tags;
/*
* Close the race of a command that was in the process of
* being queued to us just as our simq was frozen. Let
* DV commands through so long as we are only frozen to
* perform DV.
*/
if (ahc->platform_data->qfrozen != 0
&& AHC_DV_CMD(cmd) == 0) {
ahc_compile_devinfo(&devinfo,
dev->target->channel == 0
? ahc->our_id : ahc->our_id_b,
dev->target->target, dev->lun,
dev->target->channel == 0 ? 'A' : 'B',
ROLE_INITIATOR);
tags = ahc_linux_user_tagdepth(ahc, &devinfo);
if (tags != 0
&& dev->scsi_device != NULL
&& dev->scsi_device->tagged_supported != 0) {
ahc_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ);
ahc_linux_queue_cmd_complete(ahc, cmd);
ahc_schedule_completeq(ahc, NULL);
ahc_midlayer_entrypoint_unlock(ahc, &flags);
return (0);
}
dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target,
cmd->lun, /*alloc*/TRUE);
if (dev == NULL) {
ahc_midlayer_entrypoint_unlock(ahc, &flags);
printf("aic7xxx_linux_queue: Unable to allocate device!\n");
return (-ENOMEM);
}
cmd->result = CAM_REQ_INPROG << 16;
TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe);
if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {
TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links);
dev->flags |= AHC_DEV_ON_RUN_LIST;
ahc_linux_run_device_queues(ahc);
ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n",
ahc->platform_data->host->host_no, devinfo.channel,
devinfo.target, devinfo.lun, tags);
} else {
ahc_set_tags(ahc, &devinfo, AHC_QUEUE_NONE);
}
ahc_midlayer_entrypoint_unlock(ahc, &flags);
return (0);
}
static void
......@@ -3843,34 +4105,6 @@ ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
ahc_linux_free_target(ahc, targ);
}
/*
* Return a string describing the driver.
*/
const char *
ahc_linux_info(struct Scsi_Host *host)
{
static char buffer[512];
char ahc_info[256];
char *bp;
struct ahc_softc *ahc;
bp = &buffer[0];
ahc = *(struct ahc_softc **)host->hostdata;
memset(bp, 0, sizeof(buffer));
strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev ");
strcat(bp, AIC7XXX_DRIVER_VERSION);
strcat(bp, "\n");
strcat(bp, " <");
strcat(bp, ahc->description);
strcat(bp, ">\n");
strcat(bp, " ");
ahc_controller_info(ahc, ahc_info);
strcat(bp, ahc_info);
strcat(bp, "\n");
return (bp);
}
void
ahc_send_async(struct ahc_softc *ahc, char channel,
u_int target, u_int lun, ac_code code, void *arg)
......@@ -4852,181 +5086,6 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
return (retval);
}
/*
* Abort the current SCSI command(s).
*/
int
ahc_linux_abort(Scsi_Cmnd *cmd)
{
int error;
error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT);
if (error != 0)
printf("aic7xxx_abort returns 0x%x\n", error);
return (error);
}
/*
* Attempt to send a target reset message to the device that timed out.
*/
int
ahc_linux_dev_reset(Scsi_Cmnd *cmd)
{
int error;
error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
if (error != 0)
printf("aic7xxx_dev_reset returns 0x%x\n", error);
return (error);
}
/*
* Reset the SCSI bus.
*/
int
ahc_linux_bus_reset(Scsi_Cmnd *cmd)
{
struct ahc_softc *ahc;
struct ahc_cmd *acmd;
u_long s;
int found;
ahc = *(struct ahc_softc **)cmd->host->hostdata;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_unlock_irq(&io_request_lock);
#endif
ahc_midlayer_entrypoint_lock(ahc, &s);
found = ahc_reset_channel(ahc, cmd->channel + 'A',
/*initiate reset*/TRUE);
acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
TAILQ_INIT(&ahc->platform_data->completeq);
ahc_midlayer_entrypoint_unlock(ahc, &s);
if (bootverbose)
printf("%s: SCSI bus reset delivered. "
"%d SCBs aborted.\n", ahc_name(ahc), found);
if (acmd != NULL) {
acmd = ahc_linux_run_complete_queue(ahc, acmd);
if (acmd != NULL) {
ahc_midlayer_entrypoint_lock(ahc, &s);
ahc_schedule_completeq(ahc, acmd);
ahc_midlayer_entrypoint_unlock(ahc, &s);
}
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_lock_irq(&io_request_lock);
#endif
return SUCCESS;
}
/*
* Return the disk geometry for the given SCSI device.
*/
int
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int geom[])
#else
ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
#endif
{
int heads;
int sectors;
int cylinders;
int ret;
int extended;
struct ahc_softc *ahc;
u_int channel;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
uint8_t *bh;
channel = sdev->channel;
#else
u_long capacity;
struct buffer_head *bh;
capacity = disk->capacity;
channel = disk->device->channel;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
ahc = *((struct ahc_softc **)sdev->host->hostdata);
#else
ahc = *((struct ahc_softc **)disk->device->host->hostdata);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
bh = scsi_bios_ptable(bdev);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));
#else
bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);
#endif
if (bh) {
ret = scsi_partsize(bh, capacity,
&geom[2], &geom[0], &geom[1]);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
kfree(bh);
#else
brelse(bh);
#endif
if (ret != -1)
return (ret);
}
heads = 64;
sectors = 32;
cylinders = capacity / (heads * sectors);
if (aic7xxx_extended != 0)
extended = 1;
else if (channel == 0)
extended = (ahc->flags & AHC_EXTENDED_TRANS_A) != 0;
else
extended = (ahc->flags & AHC_EXTENDED_TRANS_B) != 0;
if (extended && cylinders >= 1024) {
heads = 255;
sectors = 63;
cylinders = capacity / (heads * sectors);
}
geom[0] = heads;
geom[1] = sectors;
geom[2] = cylinders;
return (0);
}
/*
* Free the passed in Scsi_Host memory structures prior to unloading the
* module.
*/
int
ahc_linux_release(struct Scsi_Host * host)
{
struct ahc_softc *ahc;
u_long l;
ahc_list_lock(&l);
if (host != NULL) {
/*
* We should be able to just perform
* the free directly, but check our
* list for extra sanity.
*/
ahc = ahc_find_softc(*(struct ahc_softc **)host->hostdata);
if (ahc != NULL) {
u_long s;
ahc_lock(ahc, &s);
ahc_intr_enable(ahc, FALSE);
ahc_unlock(ahc, &s);
ahc_free(ahc);
}
}
ahc_list_unlock(&l);
return (0);
}
void
ahc_platform_dump_card_state(struct ahc_softc *ahc)
{
......@@ -5065,9 +5124,3 @@ ahc_platform_dump_card_state(struct ahc_softc *ahc)
}
}
}
#if defined(MODULE) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
static Scsi_Host_Template driver_template = AIC7XXX;
Scsi_Host_Template *aic7xxx_driver_template = &driver_template;
#include "scsi_module.c"
#endif
......@@ -18,7 +18,7 @@
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#107 $
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#108 $
*
* Copyright (c) 2000-2001 Adaptec Inc.
* All rights reserved.
......@@ -55,7 +55,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#107 $
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#108 $
*
*/
#ifndef _AIC7XXX_LINUX_H_
......@@ -306,7 +306,7 @@ ahc_scb_timer_reset(struct scb *scb, u_int usec)
#include <linux/smp.h>
#endif
#define AIC7XXX_DRIVER_VERSION "6.2.22"
#define AIC7XXX_DRIVER_VERSION "6.2.23"
/**************************** Front End Queues ********************************/
/*
......
......@@ -36,7 +36,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#40 $
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#41 $
*/
#include "aic7xxx_osm.h"
......@@ -177,7 +177,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
pci_set_drvdata(pdev, ahc);
if (aic7xxx_detect_complete)
ahc_linux_register_host(ahc, aic7xxx_driver_template);
ahc_linux_register_host(ahc, &aic7xxx_driver_template);
#endif
return (0);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment