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 ====================================================================
= Adaptec Aic7xxx Fast -> Ultra160 Family Manager Set v6.2.10 =
Introduction = README for =
---------------------------- = The Linux Operating System =
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 The following information is available in this file:
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 1. Supported Hardware
2.1.0 or later. 2. Command Line Options
3. Contacting Adaptec
Supported cards/chipsets
---------------------------- 1. Supported Hardware
Adaptec Cards
---------------------------- The following Adaptec SCSI Chips and Host Adapters are supported by
AHA-274x the aic7xxx driver.
AHA-274xT
AHA-274xW Chip MIPS Host Bus MaxSync MaxWidth SCBs Notes
AHA-284x ---------------------------------------------------------------
AHA-284xW aic7770 10 EISA/VL 10MHz 16Bit 4 1
All PCI based cards using any of the chipsets listed under motherboard aic7850 10 PCI/32 10MHz 8Bit 3
chipsets. In general, this means *all* of the Adaptec SCSI controllers aic7855 10 PCI/32 10MHz 8Bit 3
except the ones specifically excluded later on in this document. aic7856 10 PCI/32 10MHz 8Bit 3
aic7859 10 PCI/32 20MHz 8Bit 3
Motherboard Chipsets aic7860 10 PCI/32 20MHz 8Bit 3
---------------------------- aic7870 10 PCI/32 10MHz 16Bit 16
AIC-777x aic7880 10 PCI/32 20MHz 16Bit 16
AIC-785x aic7890 20 PCI/32 40MHz 16Bit 16 3 4 5 6 7 8
AIC-786x aic7891 20 PCI/64 40MHz 16Bit 16 3 4 5 6 7 8
AIC-787x aic7892 20 PCI/64-66 80MHz 16Bit 16 3 4 5 6 7 8
AIC-788x aic7895 15 PCI/32 20MHz 16Bit 16 2 3 4 5
AIC-789x aic7895C 15 PCI/32 20MHz 16Bit 16 2 3 4 5 8
AIC-3860 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
Bus Types aic7899 20 PCI/64-66 80MHz 16Bit 16 2 3 4 5 6 7 8
----------------------------
W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support 1. Multiplexed Twin Channel Device - One controller servicing two
SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s. busses.
U - Ultra SCSI, transfer rates up to 40MB/s. 2. Multi-function Twin Channel Device - Two controllers on one chip.
U2- Ultra 2 SCSI, transfer rates up to 80MB/s. 3. Command Channel Secondary DMA Engine - Allows scatter gather list
U3- Ultra 3 SCSI, transfer rates up to 160MB/s. and SCB prefetch.
D - Differential SCSI. 4. 64 Byte SCB Support - Allows disconnected, unttagged request table
T - Twin Channel SCSI. Up to 14 SCSI devices. for all possible target/lun combinations.
5. Block Move Instruction Support - Doubles the speed of certain
AHA-274x - EISA SCSI controller sequencer operations.
AHA-284x - VLB SCSI controller 6. `Bayonet' style Scatter Gather Engine - Improves S/G prefetch
AHA-29xx - PCI SCSI controller performance.
AHA-39xx - PCI controllers with multiple separate SCSI channels on-board. 7. Queuing Registers - Allows queuing of new transactions without
pausing the sequencer.
Not Supported Devices 8. Multiple Target IDs - Allows the controller to respond to selection
------------------------------ as a target on multiple SCSI IDs.
Adaptec Cards
---------------------------- Controller Chip Host-Bus Int-Connectors Ext-Connectors Notes
AHA-2920 (Only the cards that use the Future Domain chipset are not --------------------------------------------------------------------------
supported, any 2920 cards based on Adaptec AIC chipsets, AHA-274X[A] aic7770 EISA SE-50M SE-HD50F
such as the 2920C, are supported) AHA-274X[A]W aic7770 EISA SE-HD68F SE-HD68F
AAA-13x Raid Adapters SE-50M
AAA-113x Raid Port Card AHA-274X[A]T aic7770 EISA 2 X SE-50M SE-HD50F
AHA-2842 aic7770 VL SE-50M SE-HD50F
Motherboard Chipsets AHA-2940AU aic7860 PCI/32 SE-50M SE-HD50F
---------------------------- AVA-2902I aic7860 PCI/32 SE-50M
AIC-781x AVA-2902E aic7860 PCI/32 SE-50M
AVA-2906 aic7856 PCI/32 SE-50M SE-DB25F
Bus Types APC-7850 aic7850 PCI/32 SE-50M 1
---------------------------- AVA-2940 aic7860 PCI/32 SE-50M
R - Raid Port busses are not supported. AHA-2920B aic7860 PCI/32 SE-50M
AHA-2930B aic7860 PCI/32 SE-50M
The hardware RAID devices sold by Adaptec are *NOT* supported by this AHA-2920C aic7856 PCI/32 SE-50M SE-HD50F
driver (and will people please stop emailing me about them, they are AHA-2930C aic7860 PCI/32 SE-50M
a totally separate beast from the bare SCSI controllers and this driver AHA-2930C aic7860 PCI/32 SE-50M
can not be retrofitted in any sane manner to support the hardware RAID AHA-2910C aic7860 PCI/32 SE-50M
features on those cards - Doug Ledford). 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
People HVD-50M
------------------------------ AHA-3940W aic7870 PCI/32 2 X SE-HD68F SE-HD68F 2
Justin T Gibbs gibbs@plutotech.com AHA-2940UW aic7880 PCI/32 SE-HD68F
(BSD Driver Author) SE-50M SE-HD68F
Dan Eischen deischen@iworks.InterWorks.org AHA-2940U aic7880 PCI/32 SE-50M SE-HD50F
(Original Linux Driver Co-maintainer) AHA-2940D aic7880 PCI/32
Dean Gehnert deang@teleport.com AHA-2940 A/T aic7880 PCI/32
(Original Linux FTP/patch maintainer) AHA-2940D A/T aic7880 PCI/32
Jess Johnson jester@frenzy.com AHA-3940UW aic7880 PCI/32 2 X SE-HD68F SE-HD68F 3
(AIC7xxx FAQ author) AHA-3940UWD aic7880 PCI/32 2 X SE-HD68F 2 X SE-VHD68F 3
Doug Ledford dledford@redhat.com AHA-3940U aic7880 PCI/32 2 X SE-50M SE-HD50F 3
(Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer) AHA-2944UW aic7880 PCI/32 HVD-HD68F HVD-HD68F
HVD-50M
Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original AHA-3944UWD aic7880 PCI/32 2 X HVD-HD68F 2 X HVD-VHD68F 3
author of the driver. John has since retired from the project. Thanks AHA-4944UW aic7880 PCI/32
again for all his work! AHA-2930UW aic7880 PCI/32
AHA-2940UW Pro aic7880 PCI/32 SE-HD68F SE-HD68F 4
Mailing list SE-50M
------------------------------ AHA-2940UW/CN aic7880 PCI/32
There is a mailing list available for users who want to track development AHA-2940UDual aic7895 PCI/32
and converse with other users and developers. This list is for both AHA-2940UWDual aic7895 PCI/32
FreeBSD and Linux support of the AIC7xxx chipsets. AHA-3940UWD aic7895 PCI/32
AHA-3940AUW aic7895 PCI/32
To subscribe to the AIC7xxx mailing list send mail to the list server, AHA-3940AUWD aic7895 PCI/32
with "subscribe AIC7xxx" in the body (no Subject: required): AHA-3940AU aic7895 PCI/32
To: majordomo@FreeBSD.ORG AHA-3944AUWD aic7895 PCI/32 2 X HVD-HD68F 2 X HVD-VHD68F
--- AHA-2940U2B aic7890 PCI/32 LVD-HD68F LVD-HD68F
subscribe AIC7xxx AHA-2940U2 OEM aic7891 PCI/64
AHA-2940U2W aic7890 PCI/32 LVD-HD68F LVD-HD68F
To unsubscribe from the list, send mail to the list server with: SE-HD68F
To: majordomo@FreeBSD.ORG SE-50M
--- AHA-2950U2B aic7891 PCI/64 LVD-HD68F LVD-HD68F
unsubscribe AIC7xxx AHA-2930U2 aic7890 PCI/32 LVD-HD68F SE-HD50F
SE-50M
Send regular messages and replies to: AIC7xxx@FreeBSD.ORG AHA-3950U2B aic7897 PCI/64
AHA-3950U2D aic7897 PCI/64
Boot Command line options AHA-29160 aic7892 PCI/64-66
------------------------------ AHA-29160 CPQ aic7892 PCI/64-66
"aic7xxx=no_reset" - Eliminate the SCSI bus reset during startup. AHA-29160N aic7892 PCI/32 LVD-HD68F SE-HD50F
Some SCSI devices need the initial reset that this option disables SE-50M
in order to work. If you have problems at bootup, please make sure AHA-29160LP aic7892 PCI/64-66
you aren't using this option. AHA-19160 aic7892 PCI/64-66
AHA-29150LP aic7892 PCI/64-66
"aic7xxx=reverse_scan" - Certain PCI motherboards scan for devices at AHA-29130LP aic7892 PCI/64-66
bootup by scanning from the highest numbered PCI device to the AHA-3960D aic7899 PCI/64-66 2 X LVD-HD68F 2 X LVD-VHD68F
lowest numbered PCI device, others do just the opposite and scan LVD-50M
from lowest to highest numbered PCI device. There is no reliable AHA-3960D CPQ aic7899 PCI/64-66 2 X LVD-HD68F 2 X LVD-VHD68F
way to autodetect this ordering. So, we default to the most common LVD-50M
order, which is lowest to highest. Then, in case your motherboard AHA-39160 aic7899 PCI/64-66 2 X LVD-HD68F 2 X LVD-VHD68F
scans from highest to lowest, we have this option. If your BIOS LVD-50M
finds the drives on controller A before controller B but the linux
kernel finds your drives on controller B before A, then you should 1. No BIOS support
use this option. 2. DEC21050 PCI-PCI bridge with multiple controller chips on secondary bus
3. DEC2115X PCI-PCI bridge with multiple controller chips on secondary bus
"aic7xxx=extended" - Force the driver to detect extended drive translation 4. All three SCSI connectors may be used simultaneously without
on your controller. This helps those people who have cards without SCSI "stub" effects.
a SEEPROM make sure that linux and all other operating systems think
the same way about your hard drives. 2. Command Line Options
"aic7xxx=scbram" - Some cards have external SCB RAM that can be used to WARNING: ALTERING OR ADDING THESE DRIVER PARAMETERS
give the card more hardware SCB slots. This allows the driver to use INCORRECTLY CAN RENDER YOUR SYSTEM INOPERABLE.
that SCB RAM. Without this option, the driver won't touch the SCB USE THEM WITH CAUTION.
RAM because it is known to cause problems on a few cards out there
(such as 3985 class cards). Edit the file "modules.conf" in the directory /etc and add/edit a
line containing 'options aic7xxx=[command[,command...]]' where
"aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel 'command' is one or more of the following:
to use the correct IRQ type for your card. This only applies to EISA -----------------------------------------------------------------
based controllers. On these controllers, 0 is for Edge triggered Option: verbose
interrupts, and 1 is for Level triggered interrupts. If you aren't Definition: enable additional informative messages during
sure or don't know which IRQ trigger type your EISA card uses, then driver operation.
let the kernel autodetect the trigger type. Possible Values: This option is a flag
Default Value: disabled
"aic7xxx=verbose" - This option can be used in one of two ways. If you -----------------------------------------------------------------
simply specify aic7xxx=verbose, then the kernel will automatically Option: debug:[value]
pick the default set of verbose messages for you to see. Definition: Enables various levels of debugging information
Alternatively, you can specify the command as Possible Values: 0x0000 = no debugging, 0xffff = full debugging
"aic7xxx=verbose:0xXXXX" where the X entries are replaced with Default Value: 0x0000
hexadecimal digits. This option is a bit field type option. For -----------------------------------------------------------------
a full listing of the available options, search for the Option: no_reset
#define VERBOSE_xxxxxx lines in the aic7xxx.c file. If you want Definition: Do not reset the bus during the initial probe
verbose messages, then it is recommended that you simply use the phase
aic7xxx=verbose variant of this command. Possible Values: This option is a flag
Default Value: disabled
"aic7xxx=pci_parity:x" - This option controls whether or not the driver -----------------------------------------------------------------
enables PCI parity error checking on the PCI bus. By default, this Option: extended
checking is disabled. To enable the checks, simply specify pci_parity Definition: Force extended translation on the controller
with no value afterwords. To reverse the parity from even to odd, Possible Values: This option is a flag
supply any number other than 0 or 255. In short: Default Value: disabled
pci_parity - Even parity checking (even is the normal PCI parity) -----------------------------------------------------------------
pci_parity:x - Where x > 0, Odd parity checking Option: periodic_otag
pci_parity:0 - No check (default) Definition: Send an ordered tag periodically to prevent
NOTE: In order to get Even PCI parity checking, you must use the tag starvation. Needed for some older devices
version of the option that does not include the : and a number at Possible Values: This option is a flag
the end (unless you want to enter exactly 2^32 - 1 as the number). Default Value: disabled
-----------------------------------------------------------------
"aic7xxx=no_probe" - This option will disable the probing for any VLB Option: reverse_scan
based 2842 controllers and any EISA based controllers. This is Definition: Probe the scsi bus in reverse order, starting
needed on certain newer motherboards where the normal EISA I/O ranges with target 15
have been claimed by other PCI devices. Probing on those machines Possible Values: This option is a flag
will often result in the machine crashing or spontaneously rebooting Default Value: disabled
during startup. Examples of machines that need this are the -----------------------------------------------------------------
Dell PowerEdge 6300 machines. Option: global_tag_depth
Definition: Global tag depth for all targets on all busses.
"aic7xxx=seltime:2" - This option controls how long the card waits This option sets the default tag depth which
during a device selection sequence for the device to respond. may be selectively overridden vi the tag_info
The original SCSI spec says that this "should be" 256ms. This option.
is generally not required with modern devices. However, some Possible Values: 1 - 253
very old SCSI I devices need the full 256ms. Most modern devices Default Value: 32
can run fine with only 64ms. The default for this option is -----------------------------------------------------------------
64ms. If you need to change this option, then use the following Option: tag_info:{{value[,value...]}[,{value[,value...]}...]}
table to set the proper value in the example above: Definition: Set the per-target tagged queue depth on a
0 - 256ms per controller basis. Both controllers and targets
1 - 128ms may be ommitted indicating that they should retain
2 - 64ms the default tag depth.
3 - 32ms Examples: tag_info:{{16,32,32,64,8,8,,32,32,32,32,32,32,32,32,32}
On Controller 0
"aic7xxx=panic_on_abort" - This option is for debugging and will cause specifies a tag depth of 16 for target 0
the driver to panic the linux kernel and freeze the system the first specifies a tag depth of 64 for target 3
time the drivers abort or reset routines are called. This is most specifies a tag depth of 8 for targets 4 and 5
helpful when some problem causes infinite reset loops that scroll too leaves target 6 at the default
fast to see. By using this option, you can write down what the errors specifies a tag depth of 32 for targets 1,2,7-15
actually are and send that information to me so it can be fixed. All other targets retain the default depth.
"aic7xxx=dump_card" - This option will print out the *entire* set of tag_info:{{},{32,,32}}
configuration registers on the card during the init sequence. This On Controller 1
is a debugging aid used to see exactly what state the card is in specifies a tag depth of 32 for targets 0 and 2
when we finally finish our initialization routines. If you don't All other targets retain the default depth.
have documentation on the chipsets, this will do you absolutely
no good unless you are simply trying to write all the information Possible Values: 1 - 253
down in order to send it to me. Default Value: 32
-----------------------------------------------------------------
"aic7xxx=dump_sequencer" - This is the same as the above options except Option: seltime:[value]
that instead of dumping the register contents on the card, this Definition: Specifies the selection timeout value
option dumps the contents of the sequencer program RAM. This gives Possible Values: 0 = 256ms, 1 = 128ms, 2 = 64ms, 3 = 32ms
the ability to verify that the instructions downloaded to the Default Value: 0
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. Example: 'options aic7xxx=verbose,no_probe,tag_info:{{},{,,10}},seltime:1"
enables verbose logging, Disable EISA/VLB probing,
"aic7xxx=override_term:0xffffffff" - This option is used to force the and set tag depth on Controller 1/Target 2 to 10 tags.
termination on your SCSI controllers to a particular setting. This
is a bit mask variable that applies for up to 8 aic7xxx SCSI channels. 3. Contacting Adaptec
Each channel gets 4 bits, divided as follows:
bit 3 2 1 0 A Technical Support Identification (TSID) Number is required for
| | | Enable/Disable Single Ended Low Byte Termination Adaptec technical support.
| | En/Disable Single Ended High Byte Termination - The 12-digit TSID can be found on the white barcode-type label
| En/Disable Low Byte LVD Termination included inside the box with your product. The TSID helps us
En/Disable High Byte LVD Termination provide more efficient service by accurately identifying your
product and support status.
The upper 2 bits that deal with LVD termination only apply to Ultra2 Support Options
controllers. Futhermore, due to the current Ultra2 controller - Search the Adaptec Support Knowledgebase (ASK) at
designs, these bits are tied together such that setting either bit http://ask.adaptec.com for articles, troubleshooting tips, and
enables both low and high byte LVD termination. It is not possible frequently asked questions for your product.
to only set high or low byte LVD termination in this manner. This is - For support via Email, submit your question to Adaptec's
an artifact of the BIOS definition on Ultra2 controllers. For other Technical Support Specialists at http://ask.adaptec.com.
controllers, the only important bits are the two lowest bits. Setting
the higher bits on non-Ultra2 controllers has no effect. A few North America
examples of how to use this option: - Visit our Web site at http://www.adaptec.com.
- To speak with a Fibre Channel/RAID/External Storage Technical
Enable low and high byte termination on a non-ultra2 controller that Support Specialist, call 1-321-207-2000,
is the first aic7xxx controller (the correct bits are 0011), Hours: Monday-Friday, 3:00 A.M. to 5:00 P.M., PST.
aic7xxx=override_term:0x3 (Not open on holidays)
- For Technical Support in all other technologies including
Enable all termination on the third aic7xxx controller, high byte SCSI, call 1-408-934-7274,
termination on the second aic7xxx controller, and low and high byte Hours: Monday-Friday, 6:00 A.M. to 5:00 P.M., PST.
SE termination on the first aic7xxx controller (Not open on holidays)
(bits are 1111 0010 0011), - For after hours support, call 1-800-416-8066 ($99/call,
aic7xxx=override_term:0xf23 $149/call on holidays)
- To order Adaptec products including software and cables, call
No attempt has been made to make this option non-cryptic. It really 1-800-442-7274 or 1-408-957-7274. You can also visit our
shouldn't be used except in dire circumstances, and if that happens, online store at http://www.adaptecstore.com
I'm probably going to be telling you what to set this to anyway :)
Europe
"aic7xxx=stpwlev:0xffffffff" - This option is used to control the STPWLEV - Visit our Web site at http://www.adaptec-europe.com.
bit in the DEVCONFIG PCI register. Currently, this is one of the - English and French: To speak with a Technical Support
very few registers that we have absolutely *no* way of detecting Specialist, call one of the following numbers:
what the variable should be. It depends entirely on how the chipset - English: +32-2-352-3470
and external terminators were coupled by the card/motherboard maker. - French: +32-2-352-3460
Further, a chip reset (at power up) always sets this bit to 0. If Hours: Monday-Thursday, 10:00 to 12:30, 13:30 to 17:30 CET
there is no BIOS to run on the chipset/card (such as with a 2910C Friday, 10:00 to 12:30, 13:30 to 16:30 CET
or a motherboard controller with the BIOS totally disabled) then - German: To speak with a Technical Support Specialist,
the variable may not get set properly. Of course, if the proper call +49-89-456-40660
setting was 0, then that's what it would be after the reset, but if Hours: Monday-Thursday, 09:30 to 12:30, 13:30 to 16:30 CET
the proper setting is actually 1.....you get the picture. Now, since Friday, 09:30 to 12:30, 13:30 to 15:00 CET
we can't detect this at all, I've added this option to force the - To order Adaptec products, including accessories and cables:
setting. If you have a BIOS on your controller then you should never - UK: +0800-96-65-26 or fax +0800-731-02-95
need to use this option. However, if you are having lots of SCSI - Other European countries: +32-11-300-379
reset problems and can't seem to get them knocked out, this may help.
Australia and New Zealand
Here's a test to know for certain if you need this option. Make - Visit our Web site at http://www.adaptec.com.au.
a boot floppy that you can use to boot your computer up and that - To speak with a Technical Support Specialist, call
will detect the aic7xxx controller. Next, power down your computer. +612-9416-0698
While it's down, unplug all SCSI cables from your Adaptec SCSI Hours: Monday-Friday, 10:00 A.M. to 4:30 P.M., EAT
controller. Boot the system back up to the Adaptec EZ-SCSI BIOS (Not open on holidays)
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 Japan
made and wait for it to detect the aic7xxx controller. If the kernel - To speak with a Technical Support Specialist, call
finds the controller fine, says scsi : x hosts and then tries to +81-3-5308-6120
detect your devices like normal, up to the point where it fails to Hours: Monday-Friday, 9:00 a.m. to 12:00 p.m., 1:00 p.m. to
mount your root file system and panics, then you're fine. If, on 6:00 p.m. TSC
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 Hong Kong and China
proper termination settings on your controller. If this happens, - To speak with a Technical Support Specialist, call
then you next need to figure out what your settings should be. +852-2869-7200
Hours: Monday-Friday, 10:00 to 17:00.
To find the correct settings, power your machine back down, connect - Fax Technical Support at +852-2869-7100.
back up the SCSI cables, and boot back into your machine like normal.
However, boot with the aic7xxx=verbose:0x39 option. Record the Singapore
initial DEVCONFIG values for each of your aic7xxx controllers as - To speak with a Technical Support Specialist, call
they are listed, and also record what the machine is detecting as +65-245-7470
the proper termination on your controllers. NOTE: the order in Hours: Monday-Friday, 10:00 to 17:00.
which the initial DEVCONFIG values are printed out is not gauranteed - Fax Technical Support at +852-2869-7100
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 (c) 2002 Adaptec, Inc. All Rights Reserved. No part of this
one aic7xxx controller. publication may be reproduced, stored in a retrieval system, or
transmitted in any form or by any means, electronic, mechanical,
Once you have the detected termination settings and the initial photocopying, recording or otherwise, without prior written consent
DEVCONFIG values for each controller, then figure out what the of Adaptec, Inc., 691 South Milpitas Blvd., Milpitas, CA 95035.
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
#
# 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. # 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 config SCSI_AIC7XXX
tristate "Adaptec AIC7xxx Fast -> U160 support" tristate "Adaptec AIC7xxx Fast -> U160 support"
...@@ -104,89 +104,3 @@ config SCSI_AIC79XX ...@@ -104,89 +104,3 @@ config SCSI_AIC79XX
help help
This driver supports all of Adaptec's Ultra 320 PCI-X This driver supports all of Adaptec's Ultra 320 PCI-X
based SCSI controllers. 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. * 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. * Copyright (c) 1994-2000 Justin T. Gibbs.
...@@ -549,6 +549,7 @@ static int ahd_linux_next_unit(void); ...@@ -549,6 +549,7 @@ static int ahd_linux_next_unit(void);
static void ahd_runq_tasklet(unsigned long data); static void ahd_runq_tasklet(unsigned long data);
static int ahd_linux_halt(struct notifier_block *nb, u_long event, void *buf); 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, static __inline void ahd_schedule_completeq(struct ahd_softc *ahd,
struct ahd_cmd *acmd); struct ahd_cmd *acmd);
static __inline void ahd_schedule_runq(struct ahd_softc *ahd); 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, ...@@ -794,6 +795,531 @@ ahd_linux_map_seg(struct ahd_softc *ahd, struct scb *scb,
return (consumed); 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 *********************************/ /**************************** Tasklet Handler *********************************/
static void static void
...@@ -1363,160 +1889,76 @@ aic79xx_setup(char *s) ...@@ -1363,160 +1889,76 @@ aic79xx_setup(char *s)
static struct { static struct {
const char *name; const char *name;
uint32_t *flag; uint32_t *flag;
} options[] = { } options[] = {
{ "extended", &aic79xx_extended }, { "extended", &aic79xx_extended },
{ "no_reset", &aic79xx_no_reset }, { "no_reset", &aic79xx_no_reset },
{ "verbose", &aic79xx_verbose }, { "verbose", &aic79xx_verbose },
{ "allow_memio", &aic79xx_allow_memio}, { "allow_memio", &aic79xx_allow_memio},
#ifdef AHD_DEBUG #ifdef AHD_DEBUG
{ "debug", &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;
#endif #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');
* Initialize our softc list lock prior to
* probing for any adapters.
*/
ahd_list_lockinit();
#ifdef CONFIG_PCI while ((p = strsep(&s, ",.")) != NULL) {
ahd_linux_pci_probe(template); if (*p == '\0')
#endif continue;
for (i = 0; i < NUM_ELEMENTS(options); i++) {
n = strlen(options[i].name);
/* if (strncmp(options[i].name, p, n) != 0)
* Register with the SCSI layer all continue;
* controllers we've found.
*/
found = 0;
TAILQ_FOREACH(ahd, &ahd_tailq, links) {
if (ahd_linux_register_host(ahd, template) == 0) if (!strncmp(p, "global_tag_depth", n)) {
found++; 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));
} }
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) break;
spin_lock_irq(&io_request_lock); }
#endif }
aic79xx_detect_complete++; return 1;
return (found);
} }
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
__setup("aic79xx=", aic79xx_setup);
#endif
int aic79xx_verbose;
int int
ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) 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) ...@@ -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 static u_int
ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
{ {
...@@ -3464,78 +3800,24 @@ ahd_linux_device_queue_depth(struct ahd_softc *ahd, ...@@ -3464,78 +3800,24 @@ ahd_linux_device_queue_depth(struct ahd_softc *ahd,
{ {
struct ahd_devinfo devinfo; struct ahd_devinfo devinfo;
u_int tags; u_int tags;
ahd_compile_devinfo(&devinfo, ahd_compile_devinfo(&devinfo,
ahd->our_id, ahd->our_id,
dev->target->target, dev->lun, dev->target->target, dev->lun,
dev->target->channel == 0 ? 'A' : 'B', dev->target->channel == 0 ? 'A' : 'B',
ROLE_INITIATOR); ROLE_INITIATOR);
tags = ahd_linux_user_tagdepth(ahd, &devinfo); tags = ahd_linux_user_tagdepth(ahd, &devinfo);
if (tags != 0 if (tags != 0
&& dev->scsi_device != NULL && dev->scsi_device != NULL
&& dev->scsi_device->tagged_supported != 0) { && dev->scsi_device->tagged_supported != 0) {
ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED); ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED);
printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n", printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n",
ahd->platform_data->host->host_no, devinfo.channel, ahd->platform_data->host->host_no, devinfo.channel,
devinfo.target, devinfo.lun, tags); devinfo.target, devinfo.lun, tags);
} else { } else {
ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE); 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);
} }
ahd_midlayer_entrypoint_unlock(ahd, &flags);
return (0);
} }
static void static void
...@@ -3863,34 +4145,6 @@ ahd_linux_free_device(struct ahd_softc *ahd, struct ahd_linux_device *dev) ...@@ -3863,34 +4145,6 @@ ahd_linux_free_device(struct ahd_softc *ahd, struct ahd_linux_device *dev)
ahd_linux_free_target(ahd, targ); 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 void
ahd_send_async(struct ahd_softc *ahd, char channel, ahd_send_async(struct ahd_softc *ahd, char channel,
u_int target, u_int lun, ac_code code, void *arg) u_int target, u_int lun, ac_code code, void *arg)
...@@ -4861,218 +5115,6 @@ ahd_linux_dev_timed_unfreeze(u_long arg) ...@@ -4861,218 +5115,6 @@ ahd_linux_dev_timed_unfreeze(u_long arg)
ahd_unlock(ahd, &s); 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 void
ahd_platform_dump_card_state(struct ahd_softc *ahd) ahd_platform_dump_card_state(struct ahd_softc *ahd)
{ {
...@@ -5103,9 +5145,3 @@ 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 @@ ...@@ -36,7 +36,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES. * 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_ #ifndef _AIC79XX_LINUX_H_
...@@ -291,7 +291,7 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec) ...@@ -291,7 +291,7 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec)
#include <linux/smp.h> #include <linux/smp.h>
#endif #endif
#define AIC79XX_DRIVER_VERSION "1.3.0.ALPHA2" #define AIC79XX_DRIVER_VERSION "1.3.0.ALPHA3"
/**************************** Front End Queues ********************************/ /**************************** Front End Queues ********************************/
/* /*
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES. * 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" #include "aic79xx_osm.h"
...@@ -181,7 +181,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -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) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
pci_set_drvdata(pdev, ahd); pci_set_drvdata(pdev, ahd);
if (aic79xx_detect_complete) if (aic79xx_detect_complete)
ahd_linux_register_host(ahd, aic79xx_driver_template); ahd_linux_register_host(ahd, &aic79xx_driver_template);
#endif #endif
return (0); 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. * 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 * Copyright (c) 1994 John Aycock
* The University of Calgary Department of Computer Science. * The University of Calgary Department of Computer Science.
...@@ -579,9 +579,9 @@ static void ahc_linux_setup_dv(char *p, char *end, char *s); ...@@ -579,9 +579,9 @@ 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 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, /********************************* Inlines ************************************/
struct ahc_cmd *acmd);
static __inline void ahc_schedule_runq(struct ahc_softc *ahc); static __inline void ahc_schedule_runq(struct ahc_softc *ahc);
static __inline struct ahc_linux_device* static __inline struct ahc_linux_device*
ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, 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, ...@@ -806,6 +806,510 @@ ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
return (consumed); 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 *********************************/ /**************************** Tasklet Handler *********************************/
static void static void
...@@ -1317,93 +1821,6 @@ __setup("aic7xxx=", aic7xxx_setup); ...@@ -1317,93 +1821,6 @@ __setup("aic7xxx=", aic7xxx_setup);
int aic7xxx_verbose; 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 int
ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) 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) ...@@ -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 static u_int
ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
{ {
...@@ -3367,89 +3681,37 @@ ahc_linux_user_dv_setting(struct ahc_softc *ahc) ...@@ -3367,89 +3681,37 @@ ahc_linux_user_dv_setting(struct ahc_softc *ahc)
dv = (ahc->seep_config->adapter_control & CFENABLEDV); dv = (ahc->seep_config->adapter_control & CFENABLEDV);
ahc_unlock(ahc, &s); ahc_unlock(ahc, &s);
} }
return (dv); return (dv);
} }
/* /*
* Determines the queue depth for a given device. * 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);
/*
* 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 static void
&& AHC_DV_CMD(cmd) == 0) { ahc_linux_device_queue_depth(struct ahc_softc *ahc,
struct ahc_linux_device *dev)
{
struct ahc_devinfo devinfo;
u_int tags;
ahc_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); ahc_compile_devinfo(&devinfo,
ahc_linux_queue_cmd_complete(ahc, cmd); dev->target->channel == 0
ahc_schedule_completeq(ahc, NULL); ? ahc->our_id : ahc->our_id_b,
ahc_midlayer_entrypoint_unlock(ahc, &flags); dev->target->target, dev->lun,
return (0); dev->target->channel == 0 ? 'A' : 'B',
} ROLE_INITIATOR);
dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target, tags = ahc_linux_user_tagdepth(ahc, &devinfo);
cmd->lun, /*alloc*/TRUE); if (tags != 0
if (dev == NULL) { && dev->scsi_device != NULL
ahc_midlayer_entrypoint_unlock(ahc, &flags); && dev->scsi_device->tagged_supported != 0) {
printf("aic7xxx_linux_queue: Unable to allocate device!\n");
return (-ENOMEM); ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
} printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n",
cmd->result = CAM_REQ_INPROG << 16; ahc->platform_data->host->host_no, devinfo.channel,
TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe); devinfo.target, devinfo.lun, tags);
if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { } else {
TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); ahc_set_tags(ahc, &devinfo, AHC_QUEUE_NONE);
dev->flags |= AHC_DEV_ON_RUN_LIST;
ahc_linux_run_device_queues(ahc);
} }
ahc_midlayer_entrypoint_unlock(ahc, &flags);
return (0);
} }
static void static void
...@@ -3843,34 +4105,6 @@ ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) ...@@ -3843,34 +4105,6 @@ ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
ahc_linux_free_target(ahc, targ); 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 void
ahc_send_async(struct ahc_softc *ahc, char channel, ahc_send_async(struct ahc_softc *ahc, char channel,
u_int target, u_int lun, ac_code code, void *arg) 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) ...@@ -4852,181 +5086,6 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
return (retval); 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 void
ahc_platform_dump_card_state(struct ahc_softc *ahc) ahc_platform_dump_card_state(struct ahc_softc *ahc)
{ {
...@@ -5065,9 +5124,3 @@ 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 @@ ...@@ -18,7 +18,7 @@
* along with this program; see the file COPYING. If not, write to * along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * 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. * Copyright (c) 2000-2001 Adaptec Inc.
* All rights reserved. * All rights reserved.
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES. * 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_ #ifndef _AIC7XXX_LINUX_H_
...@@ -306,7 +306,7 @@ ahc_scb_timer_reset(struct scb *scb, u_int usec) ...@@ -306,7 +306,7 @@ ahc_scb_timer_reset(struct scb *scb, u_int usec)
#include <linux/smp.h> #include <linux/smp.h>
#endif #endif
#define AIC7XXX_DRIVER_VERSION "6.2.22" #define AIC7XXX_DRIVER_VERSION "6.2.23"
/**************************** Front End Queues ********************************/ /**************************** Front End Queues ********************************/
/* /*
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES. * 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" #include "aic7xxx_osm.h"
...@@ -177,7 +177,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -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) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
pci_set_drvdata(pdev, ahc); pci_set_drvdata(pdev, ahc);
if (aic7xxx_detect_complete) if (aic7xxx_detect_complete)
ahc_linux_register_host(ahc, aic7xxx_driver_template); ahc_linux_register_host(ahc, &aic7xxx_driver_template);
#endif #endif
return (0); 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