mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-24 06:01:28 +00:00
svn+ssh://yanb123@svn.code.sf.net/p/scst/svn/trunk
........
r5536 | vlnb | 2014-05-22 06:06:46 +0300 (Thu, 22 May 2014) | 3 lines
Version changed to 3.1.0-pre1
........
r5537 | vlnb | 2014-05-22 06:18:27 +0300 (Thu, 22 May 2014) | 3 lines
Web updates
........
r5538 | bvassche | 2014-05-22 10:16:04 +0300 (Thu, 22 May 2014) | 1 line
nightly build: Update kernel versions
........
r5539 | vlnb | 2014-05-23 05:20:35 +0300 (Fri, 23 May 2014) | 9 lines
vdisk_nullio: Add "read_zero" attribute
Add an attribute called "read_zero" to vdisk_nullio devices that
controls whether or not READs from a vdisk_nullio device return
zeroed data buffers.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5543 | bvassche | 2014-05-23 10:33:53 +0300 (Fri, 23 May 2014) | 1 line
RHEL 7 build fixes
........
r5545 | bvassche | 2014-05-23 11:36:36 +0300 (Fri, 23 May 2014) | 1 line
scripts/rebuild-rhel-kernel-rpm: Add RHEL 7 RC support
........
r5547 | vlnb | 2014-05-24 06:10:34 +0300 (Sat, 24 May 2014) | 3 lines
Optimize read_zero functionality
........
r5555 | bvassche | 2014-05-27 14:59:11 +0300 (Tue, 27 May 2014) | 5 lines
qla2x00t: Documentation / source code comment / log messages spelling fix
Change a few occurrences of "conformation" into "confirmation". See also the
QLogic 2500 Series Firmware Interface Specification.
........
r5557 | vlnb | 2014-05-30 03:42:34 +0300 (Fri, 30 May 2014) | 5 lines
Small code reorganization.
No functionality changed
........
r5558 | vlnb | 2014-05-30 06:00:07 +0300 (Fri, 30 May 2014) | 3 lines
Logging fixes
........
r5560 | bvassche | 2014-06-02 18:31:50 +0300 (Mon, 02 Jun 2014) | 1 line
Makefile: Only report which RPMs have been built if "make rpm" is run as a non-privileged user
........
r5561 | bvassche | 2014-06-03 09:04:47 +0300 (Tue, 03 Jun 2014) | 1 line
nightly build: Update kernel versions
........
r5562 | vlnb | 2014-06-04 04:54:21 +0300 (Wed, 04 Jun 2014) | 3 lines
Decrease max WRITE SAME length for better latencies
........
r5563 | vlnb | 2014-06-04 05:16:51 +0300 (Wed, 04 Jun 2014) | 3 lines
Enforce limit on max unmap LBAs
........
r5566 | bvassche | 2014-06-04 18:14:22 +0300 (Wed, 04 Jun 2014) | 1 line
ib_srpt: Fix an error message
........
r5567 | bvassche | 2014-06-04 18:17:59 +0300 (Wed, 04 Jun 2014) | 1 line
ib_srpt: Avoid triggering a SCSI command timeout after login
........
r5568 | bvassche | 2014-06-05 09:34:19 +0300 (Thu, 05 Jun 2014) | 1 line
scst_vdisk: Build fix for kernel versions <= 2.6.32
........
r5569 | bvassche | 2014-06-05 09:46:57 +0300 (Thu, 05 Jun 2014) | 1 line
scst_vdisk: Fix a kernel version < 2.6.38 compiler warning
........
r5570 | vlnb | 2014-06-06 06:20:26 +0300 (Fri, 06 Jun 2014) | 8 lines
scst_lib: Fix a compiler warning triggered by the WRITE SAME implementation
Avoid for release builds that the compiler reports that the variable
'ws_sg_cnt' is not used.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5571 | vlnb | 2014-06-06 06:22:14 +0300 (Fri, 06 Jun 2014) | 7 lines
nullio_exec_read(): Fix kunmap() argument
The argument of kunmap() is of type struct page *. Detected by smatch.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5572 | vlnb | 2014-06-06 06:24:03 +0300 (Fri, 06 Jun 2014) | 11 lines
scst: Leave out FSF mail address
This avoids that the following checkpatch complaint is triggered:
Do not include the paragraph about writing to the Free Software Foundation's
mailing address from the sample GPL notice. The FSF has changed addresses in
the past, and may do so again. Linux already includes a copy of the GPL.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5573 | vlnb | 2014-06-06 06:26:55 +0300 (Fri, 06 Jun 2014) | 10 lines
scst: Make lockdep_assert_held() easier to use
The lockdep_assert_held() macro is a convenient debugging tool.
However, it is inconvenient to surround each invocation of that
macro by an #ifdef/#endif pair. Hence make it easier to use this
macro with older kernel versions.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5574 | vlnb | 2014-06-07 00:59:24 +0300 (Sat, 07 Jun 2014) | 3 lines
Use limits.discard_zeroes_data to set LBPRZ
........
r5575 | bvassche | 2014-06-07 13:46:49 +0300 (Sat, 07 Jun 2014) | 1 line
nightly build: Update kernel versions
........
r5577 | bvassche | 2014-06-10 17:16:14 +0300 (Tue, 10 Jun 2014) | 1 line
ib_srpt: Make the test for IB_EVENT_GID_CHANGE support more robust
........
r5578 | bvassche | 2014-06-10 17:49:59 +0300 (Tue, 10 Jun 2014) | 1 line
ib_srpt: Make IB_EVENT_GID_CHANGE test independent of the OFED detection code
........
r5579 | bvassche | 2014-06-11 13:02:15 +0300 (Wed, 11 Jun 2014) | 1 line
ib_srpt: RHEL 5 build fix
........
r5581 | bvassche | 2014-06-11 18:27:06 +0300 (Wed, 11 Jun 2014) | 1 line
regression tests: Sync with a recent sysfs change
........
r5582 | bvassche | 2014-06-11 18:27:48 +0300 (Wed, 11 Jun 2014) | 1 line
regression tests: Sort hash keys before comparing
........
r5583 | bvassche | 2014-06-11 18:41:01 +0300 (Wed, 11 Jun 2014) | 1 line
nightly build: Update kernel versions
........
r5584 | vlnb | 2014-06-11 22:33:18 +0300 (Wed, 11 Jun 2014) | 8 lines
scst: RHEL 5 build fix
Avoid that building the scst kernel module fails on RHEL 5 due to
a missing kvasprintf() implementation.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5585 | vlnb | 2014-06-11 22:38:10 +0300 (Wed, 11 Jun 2014) | 11 lines
scst: Remove unused variables
Avoid that building scst with W=1 triggers compiler warnings about
variables that are set but not used. See also the documentation of
the gcc compiler flag -Wunused-but-set-variable.
This patch does not change any functionality.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5586 | vlnb | 2014-06-11 22:39:51 +0300 (Wed, 11 Jun 2014) | 9 lines
scst_lib: Introduce additional temporary variables
Make the code slightly easier to read by introducing temporary
variables for the expressions 'tgt_dev->sess' and 'sess->tgt->tgtt'.
This patch does not change any functionality.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5587 | vlnb | 2014-06-11 23:57:03 +0300 (Wed, 11 Jun 2014) | 10 lines
scst: Add support for 64-bit LUNs
The datatype of scsi_device.lun will be changed from u32 into u64
in the near future. Update SCST accordingly. These changes have
been implemented such that these are compatible with 32-bit and
64-bit LUNs.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5588 | vlnb | 2014-06-12 00:00:16 +0300 (Thu, 12 Jun 2014) | 9 lines
scst_local: Support LUN numbers >= 16384
Add support for 32-bit LUN numbers. As soon as the patches that add
64-bit LUN support are upstream this patch will also make 64-bit
LUN support available in scst_local.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5589 | vlnb | 2014-06-12 00:42:08 +0300 (Thu, 12 Jun 2014) | 8 lines
scst: Clean up __scst_resume_activity()
Move all management commands from scst_delayed_mgmt_cmd_list to the
active command list during resume instead of only the first one.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5590 | vlnb | 2014-06-12 01:07:00 +0300 (Thu, 12 Jun 2014) | 9 lines
scst: Introduce scst_lookup_tgt_dev()
This patch does not change any functionality.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
with some improvements
........
r5592 | bvassche | 2014-06-12 11:38:45 +0300 (Thu, 12 Jun 2014) | 7 lines
scst.h: Move definition of swap()
Make sure that the definition of swap() is guarded by
"#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)" only instead
of "#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)" and
"#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)".
........
r5593 | bvassche | 2014-06-12 12:15:50 +0300 (Thu, 12 Jun 2014) | 1 line
nightly build: Update kernel versions
........
r5594 | bvassche | 2014-06-12 14:33:00 +0300 (Thu, 12 Jun 2014) | 1 line
ib_srpt: Set MOFED include path correctly if MOFED has been installed with --add-kernel-support
........
r5595 | bvassche | 2014-06-12 16:38:38 +0300 (Thu, 12 Jun 2014) | 1 line
ib_srpt: Make non-OFED build work again
........
r5596 | vlnb | 2014-06-13 07:52:18 +0300 (Fri, 13 Jun 2014) | 16 lines
scst: Switch from the cpu_*() to the cpumask_*() API
The cpus_*() functions were deprecated via patch "cpumask:
introduce new API, without changing anything" (November 2008,
commit ID 2d3854a37e8b). Hence switch from the cpus_*() API to
the cpumask_*() API.
This patch has the intended side effect of not adding the "[key]"
property to cpumask sysfs attributes that contain the default
cpumask. The current code namely reads uninitialized bits on
systems where nr_cpu_ids < NR_CPUS because cpus_equal() compares
more bits than those that were set by cpumask_copy().
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5597 | vlnb | 2014-06-13 08:03:17 +0300 (Fri, 13 Jun 2014) | 3 lines
Forgotten versions updated
........
r5598 | bvassche | 2014-06-13 09:55:23 +0300 (Fri, 13 Jun 2014) | 1 line
ib_srpt: Make one_target_per_port the default mode
........
r5600 | vlnb | 2014-06-14 01:24:06 +0300 (Sat, 14 Jun 2014) | 9 lines
scst: Avoid that W=1 triggers complaints about unused variables
Avoid that building scst with W=1 triggers compiler warnings about
variables that are set but not used. See also the documentation of
the gcc compiler flag -Wunused-but-set-variable.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5601 | vlnb | 2014-06-14 01:31:42 +0300 (Sat, 14 Jun 2014) | 8 lines
scst_local: Add close_session() callback function
This is useful for triggering the session reassignment code via
the scst_local driver.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5602 | vlnb | 2014-06-14 02:57:26 +0300 (Sat, 14 Jun 2014) | 8 lines
scst_pr_read_reservation(): Initialize returned buffer
Avoid that this function returns an uninitialized buffer to the
initiator if buffer_size < 8. Detected by Coverity.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5603 | vlnb | 2014-06-14 02:58:28 +0300 (Sat, 14 Jun 2014) | 5 lines
scst: Help Coverity recognize that vmalloc(0) returns NULL
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5605 | bvassche | 2014-06-14 20:10:58 +0300 (Sat, 14 Jun 2014) | 1 line
fcst: Remove an unused variable
........
r5606 | bvassche | 2014-06-14 20:17:56 +0300 (Sat, 14 Jun 2014) | 5 lines
fcst: Move exch_done() calls into ft_cmd_done()
This patch ensures that exch_done() gets called if an fcst
callback returns SCST_TGT_RES_FATAL_ERROR.
........
r5607 | bvassche | 2014-06-14 20:18:34 +0300 (Sat, 14 Jun 2014) | 10 lines
fcst: Handle frame send failures properly
Retry sending XFER_RDY, data and response frames if the network
driver reports that sending failed (-ENOMEM) instead of reporting
a kernel warning (WARN_ON(1)). If sending XFER_RDY or data frames
failed for another reason, report this to the initiator as a
write error (ASC = 03; ASCQ = 00 which stands for PERIPHERAL
DEVICE WRITE FAULT). If sending a response frame failed with
another error code than -ENOMEM, do not send a response.
........
r5608 | vlnb | 2014-06-17 03:50:46 +0300 (Tue, 17 Jun 2014) | 10 lines
scst: Make access control group removal behavior configurable
SCST rejects removal of an access control group with one or more
sessions with error code -EBUSY. Make it easy to change this
behavior into forcibly closing sessions when an access control
group is removed.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5609 | bvassche | 2014-06-17 09:37:08 +0300 (Tue, 17 Jun 2014) | 1 line
nightly build: Update kernel versions
........
r5610 | vlnb | 2014-06-19 06:51:48 +0300 (Thu, 19 Jun 2014) | 3 lines
Update for 3.15 kernels
........
r5611 | bvassche | 2014-06-19 10:09:53 +0300 (Thu, 19 Jun 2014) | 1 line
nightly build: Add kernel 3.15 build infrastructure
........
r5612 | bvassche | 2014-06-19 15:48:25 +0300 (Thu, 19 Jun 2014) | 1 line
kernel module installation: Skip "depmod" when building an RPM
........
r5613 | vlnb | 2014-06-20 07:00:41 +0300 (Fri, 20 Jun 2014) | 8 lines
scst: Convert a loop to keep smatch happy
Avoid that smatch reports the following warning:
scst_init_session() info: loop could be replaced with if statement.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5614 | vlnb | 2014-06-20 07:02:00 +0300 (Fri, 20 Jun 2014) | 13 lines
iscsi-scst: Suppress a compiler warning
Avoid that the following compiler warning is reported when compiling
iscsi-scst:
chap.c: In function 'chap_rand':
chap.c:348:5: warning: ignoring return value of 'read', declared with attribute warn_unused_result [-Wunused-result]
(void)read(fd, &r, sizeof(r));
^
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5615 | vlnb | 2014-06-20 07:03:40 +0300 (Fri, 20 Jun 2014) | 5 lines
scst, iscsi-scst: Fix RHEL 5 compilation warnings
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5616 | vlnb | 2014-06-20 07:05:11 +0300 (Fri, 20 Jun 2014) | 10 lines
scst: Exclude certain locking code from static analysis
Loops with locking statements and also lock and unlock
statements guarded by an if-statement trigger false positive
warnings when analyzing the SCST code with smatch and/or sparse.
Hence exclude such code from static analysis.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5617 | vlnb | 2014-06-20 07:09:11 +0300 (Fri, 20 Jun 2014) | 10 lines
scst: Avoid that sparse complains about unreachable code
Remove the code after BUG() statements to avoid that smatch
complains about unreachable code. Hide the spin_unlock() statements
before BUG() statements for static analysis tools to avoid that
sparse complains about locking imbalances.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5618 | vlnb | 2014-06-20 07:10:40 +0300 (Fri, 20 Jun 2014) | 12 lines
Change BUG_ON(1) into BUG()
With CONFIG_BUG=y both BUG() and BUG_ON(1) halt the system. However,
with CONFIG_BUG=n BUG() halts the system but BUG_ON(1) not. To avoid
such subtleties, change BUG_ON(1) into BUG().
See also patch Josh Triplett, "bug: Make BUG() always stop the machine",
7 April 2014 (commit ID a4b5d580e07875f9be29f62a57c67fbbdbb40ba2).
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5619 | bvassche | 2014-06-20 08:56:36 +0300 (Fri, 20 Jun 2014) | 1 line
nightly build: Add kernel version 3.15.1
........
r5620 | vlnb | 2014-06-24 07:45:08 +0300 (Tue, 24 Jun 2014) | 9 lines
scst_vdisk: Split vdisk_exec_inquiry()
Make vdisk_exec_inquiry() easier to read by moving the code
for the implementation of each VPD page into a separate function.
This patch does not change any functionality.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5621 | bvassche | 2014-06-24 16:32:18 +0300 (Tue, 24 Jun 2014) | 1 line
ib_srpt: Complain if another ib_srpt.ko kernel module already exists
........
r5622 | bvassche | 2014-06-24 16:33:23 +0300 (Tue, 24 Jun 2014) | 2 lines
ib_srpt: Set SCSI residual fields in SRP_CMD reply
........
r5624 | bvassche | 2014-06-25 14:50:40 +0300 (Wed, 25 Jun 2014) | 1 line
nightly build: Use http instead of ftp for downloading kernel source code
........
r5625 | vlnb | 2014-06-26 00:38:19 +0300 (Thu, 26 Jun 2014) | 5 lines
scst_debug.h: Make EXTRACHECKS_*_ON() statements visible to Coverity
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5626 | vlnb | 2014-06-27 02:26:25 +0300 (Fri, 27 Jun 2014) | 10 lines
scst_vdisk: Three more put_unaligned_*() conversions
Convert three more *(__be16 *)p = cpu_to_be16(v) statements into
put_unaligned_be16(v, p) since the latter is easier to read. Also
convert one "cmd->dev" into "dev" expression. This patch does not
change any functionality.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5627 | bvassche | 2014-06-27 13:32:02 +0300 (Fri, 27 Jun 2014) | 1 line
nightly build: Update kernel versions
........
r5628 | bvassche | 2014-06-28 22:56:36 +0300 (Sat, 28 Jun 2014) | 1 line
ib_srpt: Remove existing ib_srpt.ko kernel modules before installation
........
r5629 | bvassche | 2014-06-28 22:58:44 +0300 (Sat, 28 Jun 2014) | 6 lines
scst_vdisk: Fix 32-bit build
Avoid 64-bit modulo computations since these result in undefined symbol
errors on 32-bit systems (__moddi3 / __umoddi3). Support sizes >= 2**32
bytes on 32-bit systems.
........
r5630 | bvassche | 2014-06-28 23:00:22 +0300 (Sat, 28 Jun 2014) | 1 line
scst.spec.in: Follow-up for r5628
........
r5631 | bvassche | 2014-06-28 23:15:45 +0300 (Sat, 28 Jun 2014) | 1 line
scst_local: Avoid that session deletion triggers a kernel warning
........
r5647 | bvassche | 2014-06-30 10:18:53 +0300 (Mon, 30 Jun 2014) | 1 line
scst: Build fix for Linux kernel versions 2.6.33 and 2.6.34
........
r5648 | bvassche | 2014-06-30 10:28:18 +0300 (Mon, 30 Jun 2014) | 1 line
scst: Build fix for kernel versions <= 2.6.31
........
r5649 | bvassche | 2014-06-30 11:40:23 +0300 (Mon, 30 Jun 2014) | 6 lines
scst_vdisk: Fix a checkpatch warning
Address the following checkpatch warning:
char * array declaration might be better as static const
........
r5650 | bvassche | 2014-06-30 11:52:06 +0300 (Mon, 30 Jun 2014) | 1 line
nightly build: Correct a kernel version
........
r5651 | bvassche | 2014-06-30 12:18:41 +0300 (Mon, 30 Jun 2014) | 1 line
nightly build: Correct a kernel version
........
r5654 | bvassche | 2014-07-01 09:38:13 +0300 (Tue, 01 Jul 2014) | 6 lines
scst_vdisk: Fix a checkpatch warning
Avoid that checkpatch reports the following warning:
WARNING: static const char * array should probably be static const char * const
........
r5657 | bvassche | 2014-07-01 19:46:12 +0300 (Tue, 01 Jul 2014) | 1 line
nightly build: Update kernel versions
........
r5658 | bvassche | 2014-07-03 11:36:48 +0300 (Thu, 03 Jul 2014) | 1 line
scripts/kernel-functions: Handle 3.x.0 kernel versions correctly
........
r5659 | bvassche | 2014-07-03 11:42:08 +0300 (Thu, 03 Jul 2014) | 1 line
scripts/generate-patched-kernel: Clean up
........
r5661 | bvassche | 2014-07-04 08:39:28 +0300 (Fri, 04 Jul 2014) | 1 line
Make scripts/kernel-functions again compatible with 2.6.x kernels
........
r5662 | bvassche | 2014-07-06 11:02:28 +0300 (Sun, 06 Jul 2014) | 1 line
scripts/run-regression-tests: Add command-line option -4 (disable IPv6)
........
git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@5666 d57e44dd-8a1f-0410-8b47-8ef2f437770f
2234 lines
70 KiB
C
2234 lines
70 KiB
C
/* $Id: isp_pci.c,v 1.186 2009/09/06 00:37:07 mjacob Exp $ */
|
|
/*
|
|
* Copyright (c) 1997-2009 by Matthew Jacob
|
|
* 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.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
*
|
|
* Alternatively, this software may be distributed under the terms of the
|
|
* the GNU Public License ("GPL") with platforms where the prevalant license
|
|
* is the GNU Public License:
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of The Version 2 GNU General Public License as published
|
|
* by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program.
|
|
*
|
|
*
|
|
* Matthew Jacob
|
|
* Feral Software
|
|
* 421 Laurel Avenue
|
|
* Menlo Park, CA 94025
|
|
* USA
|
|
*
|
|
* gplbsd at feral com
|
|
*/
|
|
/*
|
|
* Qlogic ISP Host Adapter PCI specific probe and attach routines
|
|
*/
|
|
#include "isp_linux.h"
|
|
#include <linux/firmware.h>
|
|
|
|
static int isp_pci_mapmem = 0xffffffff;
|
|
#if defined(__sparc__)
|
|
#undef ioremap_nocache
|
|
#define ioremap_nocache ioremap
|
|
#endif
|
|
static int isplinux_pci_init_one(struct Scsi_Host *);
|
|
static uint32_t isp_pci_rd_reg(ispsoftc_t *, int);
|
|
static void isp_pci_wr_reg(ispsoftc_t *, int, uint32_t);
|
|
#if !(defined(ISP_DISABLE_1080_SUPPORT) && defined(ISP_DISABLE_12160_SUPPORT))
|
|
static uint32_t isp_pci_rd_reg_1080(ispsoftc_t *, int);
|
|
static void isp_pci_wr_reg_1080(ispsoftc_t *, int, uint32_t);
|
|
#endif
|
|
#if !(defined(ISP_DISABLE_1020_SUPPORT) && defined(ISP_DISABLE_1080_SUPPORT) && defined(ISP_DISABLE_12160_SUPPORT) && defined(ISP_DISABLE_2100_SUPPORT) && defined(ISP_DISABLE_2200_SUPPORT))
|
|
static int isp_pci_rd_isr(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *);
|
|
#endif
|
|
#if !(defined(ISP_DISABLE_2300_SUPPORT) && defined(ISP_DISABLE_2322_SUPPORT))
|
|
static int isp_pci_rd_isr_2300(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *);
|
|
#endif
|
|
#if !defined(ISP_DISABLE_2400_SUPPORT)
|
|
static uint32_t isp_pci_rd_reg_2400(ispsoftc_t *, int);
|
|
static void isp_pci_wr_reg_2400(ispsoftc_t *, int, uint32_t);
|
|
static int isp_pci_rd_isr_2400(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *);
|
|
#endif
|
|
static int isp_pci_mbxdma(ispsoftc_t *);
|
|
static int isp_pci_dmasetup(ispsoftc_t *, XS_T *, void *);
|
|
static void isp_pci_dmateardown(ispsoftc_t *, XS_T *, uint32_t);
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)
|
|
#define DMA_64BIT_MASK 0xffffffffffffffffULL
|
|
#define DMA_32BIT_MASK 0x00000000ffffffffULL
|
|
#endif
|
|
|
|
#define SIXTEENM_SEG(x) (((u64) (x)) & 0xffffffff00000000ULL)
|
|
#define SAME_SIXTEENM(addr, cnt) (SIXTEENM_SEG(addr) == SIXTEENM_SEG(addr + cnt - 1))
|
|
|
|
#define FOURG_SEG(x) (((u64) (x)) & 0xffffffff00000000ULL)
|
|
#define SAME_4G(addr, cnt) (FOURG_SEG(addr) == FOURG_SEG(addr + cnt - 1))
|
|
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
|
|
#define ISP_IRQ_FLAGS SA_INTERRUPT | SA_SHIRQ
|
|
#else
|
|
#define ISP_IRQ_FLAGS IRQF_SHARED
|
|
#endif
|
|
|
|
static void isp_pci_reset0(ispsoftc_t *);
|
|
static void isp_pci_reset1(ispsoftc_t *);
|
|
static void isp_pci_dumpregs(ispsoftc_t *, const char *);
|
|
static int isplinux_pci_exclude(struct pci_dev *);
|
|
|
|
|
|
#define ISP_1040_RISC_CODE NULL
|
|
#define ISP_1080_RISC_CODE NULL
|
|
#define ISP_12160_RISC_CODE NULL
|
|
#define ISP_2100_RISC_CODE NULL
|
|
#define ISP_2200_RISC_CODE NULL
|
|
#define ISP_2300_RISC_CODE NULL
|
|
#define ISP_2322_RISC_CODE NULL
|
|
#define ISP_2400_RISC_CODE NULL
|
|
#define ISP_2500_RISC_CODE NULL
|
|
|
|
#if defined(DISABLE_FW_LOADER) || !(defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE))
|
|
#ifndef ISP_DISABLE_1020_SUPPORT
|
|
#include "asm_1040.h"
|
|
#undef ISP_1040_RISC_CODE
|
|
#define ISP_1040_RISC_CODE (const uint16_t *) isp_1040_risc_code
|
|
#endif
|
|
#ifndef ISP_DISABLE_1080_SUPPORT
|
|
#include "asm_1080.h"
|
|
#undef ISP_1080_RISC_CODE
|
|
#define ISP_1080_RISC_CODE (const uint16_t *) isp_1080_risc_code
|
|
#endif
|
|
#ifndef ISP_DISABLE_12160_SUPPORT
|
|
#include "asm_12160.h"
|
|
#undef ISP_12160_RISC_CODE
|
|
#define ISP_12160_RISC_CODE (const uint16_t *) isp_12160_risc_code
|
|
#endif
|
|
#ifndef ISP_DISABLE_2100_SUPPORT
|
|
#include "asm_2100.h"
|
|
#undef ISP_2100_RISC_CODE
|
|
#define ISP_2100_RISC_CODE (const uint16_t *) isp_2100_risc_code
|
|
#endif
|
|
#ifndef ISP_DISABLE_2200_SUPPORT
|
|
#include "asm_2200.h"
|
|
#undef ISP_2200_RISC_CODE
|
|
#define ISP_2200_RISC_CODE (const uint16_t *) isp_2200_risc_code
|
|
#endif
|
|
#ifndef ISP_DISABLE_2300_SUPPORT
|
|
#include "asm_2300.h"
|
|
#undef ISP_2300_RISC_CODE
|
|
#define ISP_2300_RISC_CODE (const uint16_t *) isp_2300_risc_code
|
|
#endif
|
|
#ifndef ISP_DISABLE_2322_SUPPORT
|
|
#include "asm_2322.h"
|
|
#undef ISP_2322_RISC_CODE
|
|
#define ISP_2322_RISC_CODE (const uint16_t *) isp_2322_risc_code
|
|
#endif
|
|
#ifndef ISP_DISABLE_2400_SUPPORT
|
|
#define ISP_2400
|
|
#define ISP_2400_MULTI
|
|
#define ISP_2500
|
|
#define ISP_2500_MULTI
|
|
#include "asm_2400.h"
|
|
#include "asm_2500.h"
|
|
#undef ISP_2400_RISC_CODE
|
|
#undef ISP_2500_RISC_CODE
|
|
#define ISP_2400_RISC_CODE (const uint32_t *) isp_2400_risc_code
|
|
#define ISP_2500_RISC_CODE (const uint32_t *) isp_2500_risc_code
|
|
#define ISP_2400_MULTI_RISC_CODE (const uint32_t *) isp_2400_multi_risc_code
|
|
#define ISP_2500_MULTI_RISC_CODE (const uint32_t *) isp_2500_multi_risc_code
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef ISP_DISABLE_1020_SUPPORT
|
|
static struct ispmdvec mdvec = {
|
|
isp_pci_rd_isr,
|
|
isp_pci_rd_reg,
|
|
isp_pci_wr_reg,
|
|
isp_pci_mbxdma,
|
|
isp_pci_dmasetup,
|
|
isp_pci_dmateardown,
|
|
isp_pci_reset0,
|
|
isp_pci_reset1,
|
|
isp_pci_dumpregs,
|
|
ISP_1040_RISC_CODE,
|
|
BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64
|
|
};
|
|
#endif
|
|
|
|
#ifndef ISP_DISABLE_1080_SUPPORT
|
|
static struct ispmdvec mdvec_1080 = {
|
|
isp_pci_rd_isr,
|
|
isp_pci_rd_reg_1080,
|
|
isp_pci_wr_reg_1080,
|
|
isp_pci_mbxdma,
|
|
isp_pci_dmasetup,
|
|
isp_pci_dmateardown,
|
|
isp_pci_reset0,
|
|
isp_pci_reset1,
|
|
isp_pci_dumpregs,
|
|
ISP_1080_RISC_CODE,
|
|
BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_128
|
|
};
|
|
#endif
|
|
|
|
#ifndef ISP_DISABLE_12160_SUPPORT
|
|
static struct ispmdvec mdvec_12160 = {
|
|
isp_pci_rd_isr,
|
|
isp_pci_rd_reg_1080,
|
|
isp_pci_wr_reg_1080,
|
|
isp_pci_mbxdma,
|
|
isp_pci_dmasetup,
|
|
isp_pci_dmateardown,
|
|
isp_pci_reset0,
|
|
isp_pci_reset1,
|
|
isp_pci_dumpregs,
|
|
ISP_12160_RISC_CODE,
|
|
BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_128
|
|
};
|
|
#endif
|
|
|
|
#ifndef ISP_DISABLE_2100_SUPPORT
|
|
static struct ispmdvec mdvec_2100 = {
|
|
isp_pci_rd_isr,
|
|
isp_pci_rd_reg,
|
|
isp_pci_wr_reg,
|
|
isp_pci_mbxdma,
|
|
isp_pci_dmasetup,
|
|
isp_pci_dmateardown,
|
|
isp_pci_reset0,
|
|
isp_pci_reset1,
|
|
isp_pci_dumpregs,
|
|
ISP_2100_RISC_CODE
|
|
};
|
|
#endif
|
|
|
|
#ifndef ISP_DISABLE_2200_SUPPORT
|
|
static struct ispmdvec mdvec_2200 = {
|
|
isp_pci_rd_isr,
|
|
isp_pci_rd_reg,
|
|
isp_pci_wr_reg,
|
|
isp_pci_mbxdma,
|
|
isp_pci_dmasetup,
|
|
isp_pci_dmateardown,
|
|
isp_pci_reset0,
|
|
isp_pci_reset1,
|
|
isp_pci_dumpregs,
|
|
ISP_2200_RISC_CODE
|
|
};
|
|
#endif
|
|
|
|
#ifndef ISP_DISABLE_2300_SUPPORT
|
|
static struct ispmdvec mdvec_2300 = {
|
|
isp_pci_rd_isr_2300,
|
|
isp_pci_rd_reg,
|
|
isp_pci_wr_reg,
|
|
isp_pci_mbxdma,
|
|
isp_pci_dmasetup,
|
|
isp_pci_dmateardown,
|
|
isp_pci_reset0,
|
|
isp_pci_reset1,
|
|
isp_pci_dumpregs,
|
|
ISP_2300_RISC_CODE
|
|
};
|
|
#endif
|
|
#ifndef ISP_DISABLE_2322_SUPPORT
|
|
static struct ispmdvec mdvec_2322 = {
|
|
isp_pci_rd_isr_2300,
|
|
isp_pci_rd_reg,
|
|
isp_pci_wr_reg,
|
|
isp_pci_mbxdma,
|
|
isp_pci_dmasetup,
|
|
isp_pci_dmateardown,
|
|
isp_pci_reset0,
|
|
isp_pci_reset1,
|
|
isp_pci_dumpregs,
|
|
ISP_2322_RISC_CODE
|
|
};
|
|
#endif
|
|
#ifndef ISP_DISABLE_2400_SUPPORT
|
|
static struct ispmdvec mdvec_2400 = {
|
|
isp_pci_rd_isr_2400,
|
|
isp_pci_rd_reg_2400,
|
|
isp_pci_wr_reg_2400,
|
|
isp_pci_mbxdma,
|
|
isp_pci_dmasetup,
|
|
isp_pci_dmateardown,
|
|
isp_pci_reset0,
|
|
isp_pci_reset1,
|
|
NULL,
|
|
ISP_2400_RISC_CODE
|
|
};
|
|
static struct ispmdvec mdvec_2500 = {
|
|
isp_pci_rd_isr_2400,
|
|
isp_pci_rd_reg_2400,
|
|
isp_pci_wr_reg_2400,
|
|
isp_pci_mbxdma,
|
|
isp_pci_dmasetup,
|
|
isp_pci_dmateardown,
|
|
isp_pci_reset0,
|
|
isp_pci_reset1,
|
|
NULL,
|
|
ISP_2500_RISC_CODE
|
|
};
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP1020
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP1020
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP1080
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP10160
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP12160
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP1240
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP1280
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP2100
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP2200
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP2300
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP2312
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP2312 0x2312
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP2322
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP2322 0x2322
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP2422
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP2422 0x2422
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP2432
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP2432 0x2432
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP2532
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP2532 0x2532
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP6312
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP6312 0x6312
|
|
#endif
|
|
|
|
#ifndef PCI_DEVICE_ID_QLOGIC_ISP6322
|
|
#define PCI_DEVICE_ID_QLOGIC_ISP6322 0x6322
|
|
#endif
|
|
|
|
#define PCI_DFLT_LTNCY 0x40
|
|
#define PCI_DFLT_LNSZ 0x10
|
|
#define PCI_CMD_ISP (PCI_COMMAND_MASTER|PCI_COMMAND_INVALIDATE|PCI_COMMAND_PARITY|PCI_COMMAND_SERR)
|
|
|
|
/*
|
|
* Encapsulating softc... Order of elements is important. The tag
|
|
* pci_isp must come first because of multiple structure punning
|
|
* (Scsi_Host == struct isp_pcisoftc == ispsoftc_t).
|
|
*/
|
|
struct isp_pcisoftc {
|
|
ispsoftc_t pci_isp;
|
|
struct pci_dev * pci_dev;
|
|
vm_offset_t port; /* I/O port address */
|
|
vm_offset_t paddr; /* Physical Memory Address */
|
|
void * vaddr; /* Mapped Memory Address */
|
|
vm_offset_t voff;
|
|
vm_offset_t poff[_NREG_BLKS];
|
|
u16 msix_vector[3];
|
|
u8 : 5,
|
|
msix_enabled : 2,
|
|
msi_enabled : 1;
|
|
};
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
|
|
#define pci_enable_msi(x) -ENXIO
|
|
#define pci_enable_msix(x) -ENXIO
|
|
#define pci_disable_msi(x) do { ; } while(0)
|
|
#define pci_disable_msix(x) do { ; } while(0)
|
|
#endif
|
|
|
|
/*
|
|
* Gratefully borrowed from Gerard Roudier's sym53c8xx driver
|
|
*/
|
|
static ISP_INLINE void *
|
|
map_pci_mem(struct isp_pcisoftc *isp_pci, u_long size)
|
|
{
|
|
unsigned long page_base;
|
|
unsigned long map_size;
|
|
u8 *page_remapped;
|
|
|
|
page_base = isp_pci->paddr & PAGE_MASK;
|
|
isp_pci->voff = isp_pci->paddr - page_base;
|
|
map_size = roundup(isp_pci->voff + size, PAGE_SIZE);
|
|
page_remapped = ioremap_nocache(page_base, map_size);
|
|
if (page_remapped) {
|
|
page_remapped += isp_pci->voff;
|
|
}
|
|
return (page_remapped);
|
|
}
|
|
|
|
static ISP_INLINE
|
|
void unmap_pci_mem(struct isp_pcisoftc *isp_pci, unsigned long size)
|
|
{
|
|
if (isp_pci->vaddr) {
|
|
u8 *p = isp_pci->vaddr;
|
|
p += isp_pci->voff;
|
|
iounmap(p);
|
|
}
|
|
}
|
|
|
|
static ISP_INLINE int
|
|
map_isp_mem(struct isp_pcisoftc *isp_pci, u_short cmd, vm_offset_t mem_base)
|
|
{
|
|
if (cmd & PCI_COMMAND_MEMORY) {
|
|
isp_pci->paddr = mem_base;
|
|
isp_pci->paddr &= PCI_BASE_ADDRESS_MEM_MASK;
|
|
isp_pci->vaddr = map_pci_mem(isp_pci, 0xff);
|
|
return (isp_pci->vaddr != (void *) 0);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static ISP_INLINE int
|
|
map_isp_io(struct isp_pcisoftc *isp_pci, u_short cmd, vm_offset_t io_base)
|
|
{
|
|
if ((cmd & PCI_COMMAND_IO) && (io_base & 3) == 1) {
|
|
isp_pci->port = io_base & PCI_BASE_ADDRESS_IO_MASK;
|
|
request_region(isp_pci->port, 0xff, ISP_NAME);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
isplinux_pci_release(struct Scsi_Host *host)
|
|
{
|
|
ispsoftc_t *isp = ISP_HOST2ISP(host);
|
|
struct isp_pcisoftc *isp_pci = (struct isp_pcisoftc *) isp;
|
|
int i;
|
|
|
|
if (host->irq) {
|
|
free_irq(host->irq, isp_pci);
|
|
host->irq = 0;
|
|
}
|
|
if (isp_pci->msix_enabled) {
|
|
if (isp_pci->msix_enabled > 1) {
|
|
free_irq(isp_pci->msix_vector[0], isp_pci);
|
|
free_irq(isp_pci->msix_vector[1], isp_pci);
|
|
free_irq(isp_pci->msix_vector[2], isp_pci);
|
|
}
|
|
pci_disable_msix(isp_pci->pci_dev);
|
|
isp_pci->msix_enabled = 0;
|
|
}
|
|
if (isp_pci->msi_enabled) {
|
|
pci_disable_msi(isp_pci->pci_dev);
|
|
isp_pci->msi_enabled = 0;
|
|
}
|
|
if (isp_pci->vaddr != NULL) {
|
|
unmap_pci_mem(isp_pci, 0xff);
|
|
isp_pci->vaddr = NULL;
|
|
} else if (isp_pci->port) {
|
|
release_region(isp_pci->port, 0xff);
|
|
isp_pci->port = 0;
|
|
}
|
|
if (isp->isp_rquest) {
|
|
pci_free_consistent(isp_pci->pci_dev, RQUEST_QUEUE_LEN(isp) * QENTRY_LEN, isp->isp_rquest, isp->isp_rquest_dma);
|
|
isp->isp_rquest = NULL;
|
|
}
|
|
if (isp->isp_xflist) {
|
|
isp_kfree(isp->isp_xflist, isp->isp_osinfo.mcorig * sizeof (XS_T **));
|
|
isp->isp_xflist = NULL;
|
|
}
|
|
#ifdef ISP_TARGET_MODE
|
|
if (isp->isp_tgtlist) {
|
|
isp_kfree(isp->isp_tgtlist, isp->isp_osinfo.mcorig * sizeof (void **));
|
|
isp->isp_tgtlist = NULL;
|
|
}
|
|
#endif
|
|
if (isp->isp_result) {
|
|
pci_free_consistent(isp_pci->pci_dev, RESULT_QUEUE_LEN(isp) * QENTRY_LEN, isp->isp_result, isp->isp_result_dma);
|
|
isp->isp_result = NULL;
|
|
}
|
|
if (IS_FC(isp)) {
|
|
for (i = 0; i < isp->isp_nchan; i++) {
|
|
fcparam *fcp = FCPARAM(isp, i);
|
|
if (fcp->isp_scratch) {
|
|
pci_free_consistent(isp_pci->pci_dev, ISP_FC_SCRLEN, fcp->isp_scratch, fcp->isp_scdma);
|
|
fcp->isp_scratch = NULL;
|
|
}
|
|
}
|
|
}
|
|
pci_release_regions(isp_pci->pci_dev);
|
|
if (isp->isp_param) {
|
|
isp_kfree(isp->isp_param, isp->isp_osinfo.param_amt);
|
|
isp->isp_param = NULL;
|
|
}
|
|
if (isp->isp_osinfo.storep) {
|
|
isp_kfree(isp->isp_osinfo.storep, isp->isp_osinfo.storep_amt);
|
|
isp->isp_osinfo.storep = NULL;
|
|
}
|
|
pci_disable_device(isp_pci->pci_dev);
|
|
|
|
/*
|
|
* Pull ourselves off the global list
|
|
*/
|
|
for (i = 0; i < MAX_ISP; i++) {
|
|
if (isplist[i] == isp) {
|
|
isplist[i] = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
|
|
/**
|
|
* pci_intx - enables/disables PCI INTx for device dev
|
|
* @pdev: the PCI device to operate on
|
|
* @enable: boolean: whether to enable or disable PCI INTx
|
|
*
|
|
* Enables/disables PCI INTx for device dev
|
|
*/
|
|
static void
|
|
pci_intx(struct pci_dev *pdev, int enable)
|
|
{
|
|
u16 pci_command, new;
|
|
pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
|
|
if (enable) {
|
|
new = pci_command & ~PCI_COMMAND_INTX_DISABLE;
|
|
} else {
|
|
new = pci_command | PCI_COMMAND_INTX_DISABLE;
|
|
}
|
|
if (new != pci_command) {
|
|
pci_write_config_word(pdev, PCI_COMMAND, new);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
isplinux_pci_init_one(struct Scsi_Host *host)
|
|
{
|
|
static char *nomap = "cannot map either memory or I/O space";
|
|
unsigned long io_base, mem_base;
|
|
unsigned int bar, rev;
|
|
u16 cmd;
|
|
struct isp_pcisoftc *isp_pci;
|
|
struct pci_dev *pdev;
|
|
ispsoftc_t *isp;
|
|
const char *fwname = NULL;
|
|
|
|
isp_pci = (struct isp_pcisoftc *) ISP_HOST2ISP(host);
|
|
pdev = isp_pci->pci_dev;
|
|
isp = (ispsoftc_t *) isp_pci;
|
|
if (isp_debug) {
|
|
isp->isp_dblev = isp_debug;
|
|
} else {
|
|
isp->isp_dblev = ISP_LOGCONFIG|ISP_LOGINFO|ISP_LOGWARN|ISP_LOGERR;
|
|
#ifdef ISP_TARGET_MODE
|
|
isp->isp_dblev |= ISP_LOGTINFO;
|
|
#endif
|
|
}
|
|
|
|
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
|
|
pci_read_config_dword(pdev, PCI_CLASS_REVISION, &rev);
|
|
rev &= 0xff;
|
|
|
|
if (pci_request_regions(pdev, ISP_NAME)) {
|
|
return (1);
|
|
}
|
|
|
|
io_base = pci_resource_start(pdev, 0);
|
|
if (pci_resource_flags(pdev, 0) & PCI_BASE_ADDRESS_MEM_TYPE_64) {
|
|
bar = 2;
|
|
} else {
|
|
bar = 1;
|
|
}
|
|
mem_base = pci_resource_start(pdev, bar);
|
|
if (pci_resource_flags(pdev, bar) & PCI_BASE_ADDRESS_MEM_TYPE_64) {
|
|
#if BITS_PER_LONG == 64
|
|
mem_base |= pci_resource_start(pdev, bar+1) << 32;
|
|
#else
|
|
isp_pci_mapmem &= ~(1 << isp->isp_unit);
|
|
#endif
|
|
}
|
|
|
|
isp_pci->poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
|
|
isp_pci->poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF;
|
|
isp_pci->poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF;
|
|
isp_pci->poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF;
|
|
isp_pci->poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
|
|
isp->isp_nchan = 1;
|
|
|
|
switch (pdev->device) {
|
|
case PCI_DEVICE_ID_QLOGIC_ISP1020:
|
|
break;
|
|
case PCI_DEVICE_ID_QLOGIC_ISP12160:
|
|
case PCI_DEVICE_ID_QLOGIC_ISP1240:
|
|
isp->isp_nchan = 2;
|
|
/* FALLTHROUGH */
|
|
case PCI_DEVICE_ID_QLOGIC_ISP1080:
|
|
case PCI_DEVICE_ID_QLOGIC_ISP1280:
|
|
case PCI_DEVICE_ID_QLOGIC_ISP10160:
|
|
isp_pci->poff[DMA_BLOCK >> _BLK_REG_SHFT] = ISP1080_DMA_REGS_OFF;
|
|
break;
|
|
case PCI_DEVICE_ID_QLOGIC_ISP2200:
|
|
case PCI_DEVICE_ID_QLOGIC_ISP2100:
|
|
isp_pci->poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2100_OFF;
|
|
break;
|
|
case PCI_DEVICE_ID_QLOGIC_ISP2300:
|
|
pci_clear_mwi(pdev);
|
|
isp_pci->poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2300_OFF;
|
|
break;
|
|
case PCI_DEVICE_ID_QLOGIC_ISP6312:
|
|
case PCI_DEVICE_ID_QLOGIC_ISP2312:
|
|
case PCI_DEVICE_ID_QLOGIC_ISP2322:
|
|
isp->isp_port = PCI_FUNC(pdev->devfn);
|
|
isp_pci->poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2300_OFF;
|
|
break;
|
|
case PCI_DEVICE_ID_QLOGIC_ISP2422:
|
|
case PCI_DEVICE_ID_QLOGIC_ISP2432:
|
|
case PCI_DEVICE_ID_QLOGIC_ISP2532:
|
|
isp->isp_port = PCI_FUNC(pdev->devfn);
|
|
isp_pci->poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2400_OFF;
|
|
isp->isp_nchan += isp_vports;
|
|
break;
|
|
default:
|
|
isp_prt(isp, ISP_LOGERR, "Device ID 0x%04x is not a known Qlogic Device", pdev->device);
|
|
pci_release_regions(pdev);
|
|
return (1);
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7)
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) {
|
|
struct msix_entry isp_msix[3];
|
|
int reg;
|
|
|
|
isp_msix[0].vector = 0;
|
|
isp_msix[0].entry = 0;
|
|
isp_msix[1].vector = 1;
|
|
isp_msix[1].entry = 1;
|
|
isp_msix[2].vector = 2;
|
|
isp_msix[2].entry = 2;
|
|
|
|
/* enable PCI-INTX */
|
|
pci_intx(pdev, 1);
|
|
|
|
/*
|
|
* enable MSI-X or MSI-X, but no MSI-X for the 2432
|
|
*/
|
|
if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2432 && pci_enable_msix(pdev, isp_msix, 3) == 0) {
|
|
isp_pci->msix_enabled = 1;
|
|
isp_pci->msix_vector[0] = isp_msix[0].vector;
|
|
isp_pci->msix_vector[1] = isp_msix[1].vector;
|
|
isp_pci->msix_vector[2] = isp_msix[2].vector;
|
|
} else if (pci_enable_msi(pdev) == 0) {
|
|
isp_pci->msi_enabled = 1;
|
|
}
|
|
|
|
/*
|
|
* Is this a PCI-X card? If so, set max read byte count.
|
|
*/
|
|
reg = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
|
|
if (reg) {
|
|
uint16_t pxcmd;
|
|
pci_read_config_word(pdev, reg + PCI_X_CMD, &pxcmd);
|
|
pxcmd |= PCI_X_CMD_MAX_READ; /* 4K READ BURST */
|
|
pci_write_config_word(pdev, reg + PCI_X_CMD, pxcmd);
|
|
}
|
|
|
|
/*
|
|
* Is this a PCI Express card? If so, set max read byte count.
|
|
*/
|
|
reg = pci_find_capability(pdev, PCI_CAP_ID_EXP);
|
|
if (reg) {
|
|
uint16_t pectl;
|
|
|
|
reg += 0x8;
|
|
pci_read_config_word(pdev, reg + PCI_EXP_DEVCTL, &pectl);
|
|
pectl &= ~PCI_EXP_DEVCTL_READRQ;
|
|
pectl |= (5 << 12); /* 4K READ BURST */
|
|
pci_write_config_word(pdev, reg + PCI_EXP_DEVCTL, pectl);
|
|
}
|
|
} else
|
|
#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
|
|
if (pci_enable_msi(pdev) == 0) {
|
|
isp_pci->msi_enabled = 1;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Disable the ROM.
|
|
*/
|
|
pci_write_config_dword(pdev, PCI_ROM_ADDRESS, 0);
|
|
|
|
/*
|
|
* Set up stuff...
|
|
*/
|
|
isp_pci->port = 0;
|
|
isp_pci->vaddr = NULL;
|
|
|
|
/*
|
|
* If we prefer to map memory space over I/O, try that first.
|
|
*/
|
|
if (isp_pci_mapmem & (1 << isp->isp_unit)) {
|
|
if (map_isp_mem(isp_pci, cmd, mem_base) == 0) {
|
|
if (map_isp_io(isp_pci, cmd, io_base) == 0) {
|
|
isp_prt(isp, ISP_LOGERR, "%s", nomap);
|
|
pci_release_regions(pdev);
|
|
return (1);
|
|
}
|
|
}
|
|
} else {
|
|
if (map_isp_io(isp_pci, cmd, io_base) == 0) {
|
|
if (map_isp_mem(isp_pci, cmd, mem_base) == 0) {
|
|
isp_prt(isp, ISP_LOGERR, "%s", nomap);
|
|
pci_release_regions(pdev);
|
|
return (1);
|
|
}
|
|
}
|
|
}
|
|
if (isp_pci->vaddr) {
|
|
isp_prt(isp, ISP_LOGCONFIG, "mapped memory 0x%lx at %p", isp_pci->paddr, isp_pci->vaddr);
|
|
host->io_port = isp_pci->paddr;
|
|
} else {
|
|
isp_prt(isp, ISP_LOGCONFIG, "mapped I/O space at 0x%lx", isp_pci->port);
|
|
host->io_port = isp_pci->port;
|
|
}
|
|
host->irq = 0;
|
|
host->max_channel = isp->isp_nchan - 1;
|
|
fwname = NULL;
|
|
isp->isp_revision = rev;
|
|
#ifndef ISP_DISABLE_1020_SUPPORT
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020) {
|
|
isp->isp_mdvec = &mdvec;
|
|
isp->isp_type = ISP_HA_SCSI_UNKNOWN;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL) {
|
|
fwname = "ql1040_fw.bin";
|
|
}
|
|
}
|
|
#endif
|
|
#ifndef ISP_DISABLE_1080_SUPPORT
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1080) {
|
|
isp->isp_mdvec = &mdvec_1080;
|
|
isp->isp_type = ISP_HA_SCSI_1080;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL) {
|
|
fwname = "ql1080_fw.bin";
|
|
}
|
|
}
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1240) {
|
|
isp->isp_mdvec = &mdvec_1080;
|
|
isp->isp_type = ISP_HA_SCSI_1240;
|
|
host->max_channel = 1;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL) {
|
|
fwname = "ql1080_fw.bin";
|
|
}
|
|
}
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1280) {
|
|
isp->isp_mdvec = &mdvec_1080;
|
|
isp->isp_type = ISP_HA_SCSI_1280;
|
|
host->max_channel = 1;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL) {
|
|
fwname = "ql1080_fw.bin";
|
|
}
|
|
}
|
|
#endif
|
|
#ifndef ISP_DISABLE_12160_SUPPORT
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) {
|
|
isp->isp_mdvec = &mdvec_12160;
|
|
isp->isp_type = ISP_HA_SCSI_12160;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL) {
|
|
fwname = "ql12160_fw.bin";
|
|
}
|
|
}
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160) {
|
|
isp->isp_mdvec = &mdvec_12160;
|
|
isp->isp_type = ISP_HA_SCSI_12160;
|
|
host->max_channel = 1;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL) {
|
|
fwname = "ql12160_fw.bin";
|
|
}
|
|
}
|
|
#endif
|
|
#ifndef ISP_DISABLE_2100_SUPPORT
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2100) {
|
|
isp->isp_mdvec = &mdvec_2100;
|
|
isp->isp_type = ISP_HA_FC_2100;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL)
|
|
fwname = "ql2100_fw.bin";
|
|
}
|
|
#endif
|
|
#ifndef ISP_DISABLE_2200_SUPPORT
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2200) {
|
|
isp->isp_mdvec = &mdvec_2200;
|
|
isp->isp_type = ISP_HA_FC_2200;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL)
|
|
fwname = "ql2200_fw.bin";
|
|
}
|
|
#endif
|
|
#ifndef ISP_DISABLE_2300_SUPPORT
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2300) {
|
|
isp->isp_mdvec = &mdvec_2300;
|
|
isp->isp_type = ISP_HA_FC_2300;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL)
|
|
fwname = "ql2300_fw.bin";
|
|
}
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2312) {
|
|
isp->isp_mdvec = &mdvec_2300;
|
|
isp->isp_type = ISP_HA_FC_2312;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL)
|
|
fwname = "ql2300_fw.bin";
|
|
}
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP6312) {
|
|
isp->isp_mdvec = &mdvec_2300;
|
|
isp->isp_type = ISP_HA_FC_2312;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL)
|
|
fwname = "ql2300_fw.bin";
|
|
}
|
|
#endif
|
|
#ifndef ISP_DISABLE_2322_SUPPORT
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2322) {
|
|
isp->isp_mdvec = &mdvec_2322;
|
|
isp->isp_type = ISP_HA_FC_2322;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL)
|
|
fwname = "ql2322_fw.bin";
|
|
}
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP6322) {
|
|
isp->isp_mdvec = &mdvec_2300;
|
|
isp->isp_type = ISP_HA_FC_2322;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL)
|
|
fwname = "ql2322_fw.bin";
|
|
}
|
|
#endif
|
|
#ifndef ISP_DISABLE_2400_SUPPORT
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432) {
|
|
isp->isp_mdvec = &mdvec_2400;
|
|
isp->isp_type = ISP_HA_FC_2400;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL)
|
|
fwname = "ql2400_fw.bin";
|
|
}
|
|
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) {
|
|
isp->isp_mdvec = &mdvec_2500;
|
|
isp->isp_type = ISP_HA_FC_2500;
|
|
if (isp->isp_mdvec->dv_ispfw == NULL)
|
|
fwname = "ql2500_fw.bin";
|
|
}
|
|
#endif
|
|
if (isp_pci->msix_enabled) {
|
|
if (request_irq(isp_pci->msix_vector[0], isplinux_intr, 0, "isp_general", isp_pci)) {
|
|
isp_prt(isp, ISP_LOGWARN, "unable to request MSI-X vector 0");
|
|
pci_disable_msix(pdev);
|
|
isp_pci->msix_enabled = 0;
|
|
} else if (request_irq(isp_pci->msix_vector[1], isplinux_intr, 0, "isp_resp_q", isp_pci)) {
|
|
isp_prt(isp, ISP_LOGWARN, "unable to request MSI-X vector 1");
|
|
free_irq(isp_pci->msix_vector[0], isp_pci);
|
|
pci_disable_msix(pdev);
|
|
isp_pci->msix_enabled = 0;
|
|
} else if (request_irq(isp_pci->msix_vector[2], isplinux_intr, 0, "isp_atio_q", isp_pci)) {
|
|
isp_prt(isp, ISP_LOGWARN, "unable to request MSI-X vector 2");
|
|
free_irq(isp_pci->msix_vector[0], isp_pci);
|
|
free_irq(isp_pci->msix_vector[1], isp_pci);
|
|
pci_disable_msix(pdev);
|
|
isp_pci->msix_enabled = 0;
|
|
} else {
|
|
isp_pci->msix_enabled++;
|
|
}
|
|
}
|
|
if (isp_pci->msix_enabled == 0) {
|
|
if (isp_pci->msi_enabled == 0) {
|
|
if (pci_enable_msi(pdev) == 0) {
|
|
isp_pci->msi_enabled = 1;
|
|
}
|
|
}
|
|
if (request_irq(pdev->irq, isplinux_intr, ISP_IRQ_FLAGS, isp->isp_name, isp_pci)) {
|
|
isp_prt(isp, ISP_LOGERR, "could not snag irq %u (0x%x)", pdev->irq, pdev->irq);
|
|
goto bad;
|
|
}
|
|
host->irq = pdev->irq;
|
|
}
|
|
|
|
/*
|
|
* Get parameter area set up
|
|
*/
|
|
isp->isp_osinfo.storep_amt = sizeof (isp_data) * isp->isp_nchan;
|
|
if (IS_FC(isp)) {
|
|
isp->isp_osinfo.param_amt = sizeof (fcparam) * isp->isp_nchan;
|
|
} else {
|
|
isp->isp_osinfo.param_amt = sizeof (sdparam) * isp->isp_nchan;
|
|
}
|
|
isp->isp_param = isp_kzalloc(isp->isp_osinfo.param_amt, GFP_KERNEL);
|
|
isp->isp_osinfo.storep = isp_kzalloc(isp->isp_osinfo.storep_amt, GFP_KERNEL);
|
|
if (isp->isp_param == NULL || isp->isp_osinfo.storep == NULL) {
|
|
isp_prt(isp, ISP_LOGERR, "unable to allocate data structures");
|
|
goto bad;
|
|
}
|
|
|
|
/*
|
|
* All PCI QLogic cards really can do full 32 bit PCI transactions,
|
|
* at least. But the older cards (1020s) have a 24 bit segment limit
|
|
* where the dma address can't cross a 24 bit boundary. Until we get
|
|
* have segment aware midlayer code, we'll set the DMA mask as if
|
|
* we only could do 24 bit I/O for those cards.
|
|
*
|
|
* We can turn on highmem_io for all of them as we use the PCI dma mapping
|
|
* API.
|
|
*/
|
|
|
|
if (IS_1020(isp)) {
|
|
if (pci_set_dma_mask(pdev, (u64)(0xffffffull))) {
|
|
isp_prt(isp, ISP_LOGERR, "cannot set dma mask");
|
|
goto bad;
|
|
}
|
|
} else if (pci_set_dma_mask(pdev, (u64) (0xffffffffffffffffull))) {
|
|
if (pci_set_dma_mask(pdev, (u64) (0xffffffffull))) {
|
|
isp_prt(isp, ISP_LOGERR, "cannot set dma mask");
|
|
goto bad;
|
|
}
|
|
} else {
|
|
isp->isp_osinfo.is_64bit_dma = 1;
|
|
}
|
|
|
|
#if !defined(DISABLE_FW_LOADER) && (defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE))
|
|
if (fwname) {
|
|
if (request_firmware(&isp->isp_osinfo.fwp, fwname, &pdev->dev) == 0) {
|
|
isp->isp_mdvec->dv_ispfw = isp->isp_osinfo.fwp->data;
|
|
isp_prt(isp, ISP_LOGCONFIG, "using loaded firmware set \"%s\"", fwname);
|
|
/*
|
|
* On little endian machines convert a byte stream of firmware to native 16 or 32 bit format.
|
|
*/
|
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
if (IS_24XX(isp)) {
|
|
uint32_t *ptr = (uint32_t *)isp->isp_osinfo.fwp->data;
|
|
int i;
|
|
for (i = 0; i < isp->isp_osinfo.fwp->size >> 2; i++) {
|
|
ptr[i] = ISP_SWAP32(isp, ptr[i]);
|
|
}
|
|
} else {
|
|
uint16_t *ptr = (uint16_t *)isp->isp_osinfo.fwp->data;
|
|
int i;
|
|
for (i = 0; i < isp->isp_osinfo.fwp->size >> 1; i++) {
|
|
ptr[i] = ISP_SWAP16(isp, ptr[i]);
|
|
}
|
|
}
|
|
#endif
|
|
} else {
|
|
isp_prt(isp, ISP_LOGWARN, "unable to load firmware set \"%s\"", fwname);
|
|
isp->isp_osinfo.fwp = NULL;
|
|
}
|
|
}
|
|
#else
|
|
if (isp_vports) {
|
|
if (IS_25XX(isp)) {
|
|
isp->isp_mdvec->dv_ispfw = ISP_2500_MULTI_RISC_CODE;
|
|
} else if (IS_24XX(isp)) {
|
|
isp->isp_mdvec->dv_ispfw = ISP_2400_MULTI_RISC_CODE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (isplinux_common_init(isp)) {
|
|
isp_prt(isp, ISP_LOGERR, "isplinux_common_init failed");
|
|
goto bad;
|
|
}
|
|
CREATE_ISP_DEV(isp, isp_class);
|
|
return (0);
|
|
bad:
|
|
if (isp->isp_param) {
|
|
isp_kfree(isp->isp_param, isp->isp_osinfo.param_amt);
|
|
isp->isp_param = NULL;
|
|
}
|
|
if (isp->isp_osinfo.storep) {
|
|
isp_kfree(isp->isp_osinfo.storep, isp->isp_osinfo.storep_amt);
|
|
isp->isp_osinfo.storep = NULL;
|
|
}
|
|
#ifdef CONFIG_FW_LOADER
|
|
if (isp->isp_osinfo.fwp) {
|
|
release_firmware(isp->isp_osinfo.fwp);
|
|
isp->isp_osinfo.fwp = NULL;
|
|
}
|
|
#endif
|
|
ISP_DISABLE_INTS(isp);
|
|
if (host->irq) {
|
|
free_irq(host->irq, isp_pci);
|
|
host->irq = 0;
|
|
}
|
|
if (isp_pci->msix_enabled) {
|
|
if (isp_pci->msix_enabled > 1) {
|
|
free_irq(isp_pci->msix_vector[0], isp_pci);
|
|
free_irq(isp_pci->msix_vector[1], isp_pci);
|
|
free_irq(isp_pci->msix_vector[2], isp_pci);
|
|
}
|
|
pci_disable_msix(isp_pci->pci_dev);
|
|
isp_pci->msix_enabled = 0;
|
|
}
|
|
if (isp_pci->msi_enabled) {
|
|
isp_pci->msi_enabled = 0;
|
|
pci_disable_msi(isp_pci->pci_dev);
|
|
}
|
|
if (isp_pci->vaddr != NULL) {
|
|
unmap_pci_mem(isp_pci, 0xff);
|
|
isp_pci->vaddr = NULL;
|
|
} else {
|
|
release_region(isp_pci->port, 0xff);
|
|
isp_pci->port = 0;
|
|
}
|
|
pci_release_regions(pdev);
|
|
return (1);
|
|
}
|
|
|
|
static ISP_INLINE uint32_t
|
|
ispregrd(struct isp_pcisoftc *pcs, vm_offset_t offset)
|
|
{
|
|
uint32_t rv;
|
|
if (pcs->vaddr) {
|
|
u8 *addr = pcs->vaddr;
|
|
rv = readw(addr+offset);
|
|
} else {
|
|
offset += pcs->port;
|
|
rv = inw(offset);
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
static ISP_INLINE void
|
|
ispregwr(struct isp_pcisoftc *pcs, vm_offset_t offset, uint32_t val)
|
|
{
|
|
if (pcs->vaddr) {
|
|
u8 *addr = pcs->vaddr;
|
|
writew(val, addr+offset);
|
|
} else {
|
|
offset += pcs->port;
|
|
outw(val, offset);
|
|
}
|
|
}
|
|
|
|
static ISP_INLINE int
|
|
isp_pci_rd_debounced(struct isp_pcisoftc *pcs, vm_offset_t off, uint16_t *rp)
|
|
{
|
|
uint16_t val0, val1;
|
|
int i = 0;
|
|
do {
|
|
val0 = ispregrd(pcs, off);
|
|
val1 = ispregrd(pcs, off);
|
|
} while (val0 != val1 && ++i < 1000);
|
|
if (val0 != val1) {
|
|
return (1);
|
|
}
|
|
*rp = val0;
|
|
return (0);
|
|
}
|
|
|
|
#define IspVirt2Off(a, x) ((a)->poff[((x) & _BLK_REG_MASK) >> _BLK_REG_SHFT] + ((x) & 0xff))
|
|
|
|
#if !(defined(ISP_DISABLE_1020_SUPPORT) && defined(ISP_DISABLE_1080_SUPPORT) && defined(ISP_DISABLE_12160_SUPPORT) && defined(ISP_DISABLE_2100_SUPPORT) && defined(ISP_DISABLE_2200_SUPPORT))
|
|
static int
|
|
isp_pci_rd_isr(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbp)
|
|
{
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
uint16_t isr, sema;
|
|
|
|
if (IS_2100(isp)) {
|
|
if (isp_pci_rd_debounced(pcs, IspVirt2Off(pcs, BIU_ISR), &isr)) {
|
|
return (0);
|
|
}
|
|
if (isp_pci_rd_debounced(pcs, IspVirt2Off(pcs, BIU_SEMA), &sema)) {
|
|
return (0);
|
|
}
|
|
} else {
|
|
isr = ispregrd(pcs, IspVirt2Off(pcs, BIU_ISR));
|
|
sema = ispregrd(pcs, IspVirt2Off(pcs, BIU_SEMA));
|
|
}
|
|
isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema);
|
|
isr &= INT_PENDING_MASK(isp);
|
|
sema &= BIU_SEMA_LOCK;
|
|
if (isr == 0 && sema == 0) {
|
|
return (0);
|
|
}
|
|
*isrp = isr;
|
|
if ((*semap = sema) != 0) {
|
|
if (IS_2100(isp)) {
|
|
if (isp_pci_rd_debounced(pcs, IspVirt2Off(pcs, OUTMAILBOX0), mbp)) {
|
|
return (0);
|
|
}
|
|
} else {
|
|
*mbp = ispregrd(pcs, IspVirt2Off(pcs, OUTMAILBOX0));
|
|
}
|
|
}
|
|
return (1);
|
|
}
|
|
#endif
|
|
|
|
#if !(defined(ISP_DISABLE_2300_SUPPORT) && defined(ISP_DISABLE_2322_SUPPORT) && defined(ISP_DISABLE_2400_SUPPORT))
|
|
static ISP_INLINE uint32_t
|
|
ispregrd32(struct isp_pcisoftc *pcs, vm_offset_t offset)
|
|
{
|
|
uint32_t rv;
|
|
if (pcs->vaddr) {
|
|
u8 *addr = pcs->vaddr;
|
|
rv = readl(addr+offset);
|
|
} else {
|
|
offset += pcs->port;
|
|
rv = inl(offset);
|
|
}
|
|
return (rv);
|
|
}
|
|
#endif
|
|
|
|
#if !(defined(ISP_DISABLE_2300_SUPPORT) && defined(ISP_DISABLE_2322_SUPPORT))
|
|
static int
|
|
isp_pci_rd_isr_2300(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbox0p)
|
|
{
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
uint32_t hccr;
|
|
uint32_t r2hisr;
|
|
|
|
if ((ispregrd(pcs, IspVirt2Off(pcs, BIU_ISR)) & BIU2100_ISR_RISC_INT) == 0) {
|
|
*isrp = 0;
|
|
return (0);
|
|
}
|
|
|
|
r2hisr = ispregrd32(pcs, IspVirt2Off(pcs, BIU_R2HSTSLO));
|
|
isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr);
|
|
if ((r2hisr & BIU_R2HST_INTR) == 0) {
|
|
*isrp = 0;
|
|
return (0);
|
|
}
|
|
switch (r2hisr & BIU_R2HST_ISTAT_MASK) {
|
|
case ISPR2HST_ROM_MBX_OK:
|
|
case ISPR2HST_ROM_MBX_FAIL:
|
|
case ISPR2HST_MBX_OK:
|
|
case ISPR2HST_MBX_FAIL:
|
|
case ISPR2HST_ASYNC_EVENT:
|
|
*isrp = r2hisr & 0xffff;
|
|
*mbox0p = (r2hisr >> 16);
|
|
*semap = 1;
|
|
return (1);
|
|
case ISPR2HST_RIO_16:
|
|
*isrp = r2hisr & 0xffff;
|
|
*mbox0p = ASYNC_RIO1;
|
|
*semap = 1;
|
|
return (1);
|
|
case ISPR2HST_FPOST:
|
|
*isrp = r2hisr & 0xffff;
|
|
*mbox0p = ASYNC_CMD_CMPLT;
|
|
*semap = 1;
|
|
return (1);
|
|
case ISPR2HST_FPOST_CTIO:
|
|
*isrp = r2hisr & 0xffff;
|
|
*mbox0p = ASYNC_CTIO_DONE;
|
|
*semap = 1;
|
|
return (1);
|
|
case ISPR2HST_RSPQ_UPDATE:
|
|
*isrp = r2hisr & 0xffff;
|
|
*mbox0p = 0;
|
|
*semap = 0;
|
|
return (1);
|
|
default:
|
|
hccr = ISP_READ(isp, HCCR);
|
|
if (hccr & HCCR_PAUSE) {
|
|
ISP_WRITE(isp, HCCR, HCCR_RESET);
|
|
isp_prt(isp, ISP_LOGERR, "RISC paused at interrupt (%x->%x)", hccr, ISP_READ(isp, HCCR));
|
|
} else {
|
|
isp_prt(isp, ISP_LOGERR, "unknown interrerupt 0x%x", r2hisr);
|
|
}
|
|
return (0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if !defined(ISP_DISABLE_2400_SUPPORT)
|
|
static ISP_INLINE void
|
|
ispregwr32(struct isp_pcisoftc *pcs, vm_offset_t offset, uint32_t val)
|
|
{
|
|
if (pcs->vaddr) {
|
|
u8 *addr = pcs->vaddr;
|
|
writel(val, addr+offset);
|
|
} else {
|
|
offset += pcs->port;
|
|
outl(val, offset);
|
|
}
|
|
}
|
|
|
|
static uint32_t
|
|
isp_pci_rd_reg_2400(ispsoftc_t *isp, int regoff)
|
|
{
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
uint32_t rv;
|
|
int block = regoff & _BLK_REG_MASK;
|
|
|
|
switch (block) {
|
|
case BIU_BLOCK:
|
|
break;
|
|
case MBOX_BLOCK:
|
|
return (ispregrd(pcs, IspVirt2Off(pcs, regoff)));
|
|
case SXP_BLOCK:
|
|
isp_prt(isp, ISP_LOGWARN, "SXP_BLOCK read at 0x%x", regoff);
|
|
return (0xffffffff);
|
|
case RISC_BLOCK:
|
|
isp_prt(isp, ISP_LOGWARN, "RISC_BLOCK read at 0x%x", regoff);
|
|
return (0xffffffff);
|
|
case DMA_BLOCK:
|
|
isp_prt(isp, ISP_LOGWARN, "DMA_BLOCK read at 0x%x", regoff);
|
|
return (0xffffffff);
|
|
default:
|
|
isp_prt(isp, ISP_LOGWARN, "unknown block read at 0x%x", regoff);
|
|
return (0xffffffff);
|
|
}
|
|
|
|
|
|
switch (regoff) {
|
|
case BIU2400_FLASH_ADDR:
|
|
case BIU2400_FLASH_DATA:
|
|
case BIU2400_ICR:
|
|
case BIU2400_ISR:
|
|
case BIU2400_CSR:
|
|
case BIU2400_REQINP:
|
|
case BIU2400_REQOUTP:
|
|
case BIU2400_RSPINP:
|
|
case BIU2400_RSPOUTP:
|
|
case BIU2400_PRI_REQINP:
|
|
case BIU2400_PRI_REQOUTP:
|
|
case BIU2400_ATIO_RSPINP:
|
|
case BIU2400_ATIO_RSPOUTP:
|
|
case BIU2400_HCCR:
|
|
case BIU2400_GPIOD:
|
|
case BIU2400_GPIOE:
|
|
case BIU2400_HSEMA:
|
|
rv = ispregrd32(pcs, IspVirt2Off(pcs, regoff));
|
|
break;
|
|
case BIU2400_R2HSTSLO:
|
|
rv = ispregrd32(pcs, IspVirt2Off(pcs, regoff));
|
|
break;
|
|
case BIU2400_R2HSTSHI:
|
|
rv = ispregrd32(pcs, IspVirt2Off(pcs, regoff)) >> 16;
|
|
break;
|
|
default:
|
|
isp_prt(isp, ISP_LOGERR, "isp_pci_rd_reg_2400: unknown offset %x", regoff);
|
|
rv = 0xffffffff;
|
|
break;
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
static void
|
|
isp_pci_wr_reg_2400(ispsoftc_t *isp, int regoff, uint32_t val)
|
|
{
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
int block = regoff & _BLK_REG_MASK;
|
|
volatile int junk;
|
|
|
|
switch (block) {
|
|
case BIU_BLOCK:
|
|
break;
|
|
case MBOX_BLOCK:
|
|
ispregwr(pcs, IspVirt2Off(pcs, regoff), val);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, regoff));
|
|
return;
|
|
case SXP_BLOCK:
|
|
isp_prt(isp, ISP_LOGWARN, "SXP_BLOCK write at 0x%x", regoff);
|
|
return;
|
|
case RISC_BLOCK:
|
|
isp_prt(isp, ISP_LOGWARN, "RISC_BLOCK write at 0x%x", regoff);
|
|
return;
|
|
case DMA_BLOCK:
|
|
isp_prt(isp, ISP_LOGWARN, "DMA_BLOCK write at 0x%x", regoff);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (regoff) {
|
|
case BIU2400_FLASH_ADDR:
|
|
case BIU2400_FLASH_DATA:
|
|
case BIU2400_ICR:
|
|
case BIU2400_ISR:
|
|
case BIU2400_CSR:
|
|
case BIU2400_REQINP:
|
|
case BIU2400_REQOUTP:
|
|
case BIU2400_RSPINP:
|
|
case BIU2400_RSPOUTP:
|
|
case BIU2400_PRI_REQINP:
|
|
case BIU2400_PRI_REQOUTP:
|
|
case BIU2400_ATIO_RSPINP:
|
|
case BIU2400_ATIO_RSPOUTP:
|
|
case BIU2400_HCCR:
|
|
case BIU2400_GPIOD:
|
|
case BIU2400_GPIOE:
|
|
case BIU2400_HSEMA:
|
|
ispregwr32(pcs, IspVirt2Off(pcs, regoff), val);
|
|
junk = ispregrd32(pcs, IspVirt2Off(pcs, regoff));
|
|
break;
|
|
default:
|
|
isp_prt(isp, ISP_LOGERR, "isp_pci_wr_reg_2400: bad offset 0x%x", regoff);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int
|
|
isp_pci_rd_isr_2400(ispsoftc_t *isp, uint32_t *isrp, uint16_t *semap, uint16_t *mbox0p)
|
|
{
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
uint32_t r2hisr;
|
|
volatile int junk;
|
|
|
|
r2hisr = ispregrd32(pcs, IspVirt2Off(pcs, BIU2400_R2HSTSLO));
|
|
isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr);
|
|
if ((r2hisr & BIU2400_R2HST_INTR) == 0) {
|
|
*isrp = 0;
|
|
return (0);
|
|
}
|
|
switch (r2hisr & BIU2400_R2HST_ISTAT_MASK) {
|
|
case ISP2400R2HST_ROM_MBX_OK:
|
|
case ISP2400R2HST_ROM_MBX_FAIL:
|
|
case ISP2400R2HST_MBX_OK:
|
|
case ISP2400R2HST_MBX_FAIL:
|
|
case ISP2400R2HST_ASYNC_EVENT:
|
|
*isrp = r2hisr & 0xffff;
|
|
*mbox0p = (r2hisr >> 16);
|
|
*semap = 1;
|
|
return (1);
|
|
case ISP2400R2HST_RSPQ_UPDATE:
|
|
case ISP2400R2HST_ATIO_RSPQ_UPDATE:
|
|
case ISP2400R2HST_ATIO_RQST_UPDATE:
|
|
*isrp = r2hisr & 0xffff;
|
|
*mbox0p = 0;
|
|
*semap = 0;
|
|
return (1);
|
|
default:
|
|
ispregwr32(pcs, IspVirt2Off(pcs, BIU2400_HCCR), HCCR_2400_CMD_CLEAR_RISC_INT);
|
|
junk = ispregrd32(pcs, IspVirt2Off(pcs, BIU2400_HCCR));
|
|
isp_prt(isp, ISP_LOGERR, "unknown interrupt 0x%x", r2hisr);
|
|
return (0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static uint32_t
|
|
isp_pci_rd_reg(ispsoftc_t *isp, int regoff)
|
|
{
|
|
uint32_t rv, oldconf = 0;
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
volatile int junk;
|
|
|
|
if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
|
|
/*
|
|
* We will assume that someone has paused the RISC processor.
|
|
*/
|
|
oldconf = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
ispregwr(pcs, IspVirt2Off(pcs, BIU_CONF1), oldconf | BIU_PCI_CONF1_SXP);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
}
|
|
rv = ispregrd(pcs, IspVirt2Off(pcs, regoff));
|
|
if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
|
|
ispregwr(pcs, IspVirt2Off(pcs, BIU_CONF1), oldconf);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
static void
|
|
isp_pci_wr_reg(ispsoftc_t *isp, int regoff, uint32_t val)
|
|
{
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
uint32_t oldconf = 0;
|
|
volatile int junk;
|
|
|
|
if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
|
|
/*
|
|
* We will assume that someone has paused the RISC processor.
|
|
*/
|
|
oldconf = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
ispregwr(pcs, IspVirt2Off(pcs, BIU_CONF1), oldconf | BIU_PCI_CONF1_SXP);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
}
|
|
ispregwr(pcs, IspVirt2Off(pcs, regoff), val);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, regoff));
|
|
if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
|
|
ispregwr(pcs, IspVirt2Off(pcs, BIU_CONF1), oldconf);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
}
|
|
}
|
|
|
|
#if !(defined(ISP_DISABLE_1080_SUPPORT) && defined(ISP_DISABLE_12160_SUPPORT))
|
|
static uint32_t
|
|
isp_pci_rd_reg_1080(ispsoftc_t *isp, int regoff)
|
|
{
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
uint32_t rv, oldconf = 0;
|
|
volatile int junk;
|
|
|
|
if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
|
|
uint32_t tmpconf;
|
|
/*
|
|
* We will assume that someone has paused the RISC processor.
|
|
*/
|
|
oldconf = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
tmpconf = oldconf & ~BIU_PCI1080_CONF1_DMA;
|
|
if (IS_1280(isp)) {
|
|
if (regoff & SXP_BANK1_SELECT) {
|
|
tmpconf |= BIU_PCI1080_CONF1_SXP0;
|
|
} else {
|
|
tmpconf |= BIU_PCI1080_CONF1_SXP1;
|
|
}
|
|
} else {
|
|
tmpconf |= BIU_PCI1080_CONF1_SXP0;
|
|
}
|
|
ispregwr(pcs, IspVirt2Off(pcs, BIU_CONF1), tmpconf);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
|
|
oldconf = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
ispregwr(pcs, IspVirt2Off(pcs, BIU_CONF1), oldconf | BIU_PCI1080_CONF1_DMA);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
}
|
|
rv = ispregrd(pcs, IspVirt2Off(pcs, regoff));
|
|
if (oldconf) {
|
|
ispregwr(pcs, IspVirt2Off(pcs, BIU_CONF1), oldconf);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
static void
|
|
isp_pci_wr_reg_1080(ispsoftc_t *isp, int regoff, uint32_t val)
|
|
{
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
uint32_t oldconf = 0;
|
|
volatile int junk;
|
|
|
|
if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
|
|
uint32_t tmpconf;
|
|
/*
|
|
* We will assume that someone has paused the RISC processor.
|
|
*/
|
|
oldconf = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
tmpconf = oldconf & ~BIU_PCI1080_CONF1_DMA;
|
|
if (IS_1280(isp)) {
|
|
if (regoff & SXP_BANK1_SELECT) {
|
|
tmpconf |= BIU_PCI1080_CONF1_SXP0;
|
|
} else {
|
|
tmpconf |= BIU_PCI1080_CONF1_SXP1;
|
|
}
|
|
} else {
|
|
tmpconf |= BIU_PCI1080_CONF1_SXP0;
|
|
}
|
|
ispregwr(pcs, IspVirt2Off(pcs, BIU_CONF1), tmpconf);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
|
|
oldconf = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
ispregwr(pcs, IspVirt2Off(pcs, BIU_CONF1), oldconf | BIU_PCI1080_CONF1_DMA);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
}
|
|
ispregwr(pcs, IspVirt2Off(pcs, regoff), val);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, regoff));
|
|
if (oldconf) {
|
|
ispregwr(pcs, IspVirt2Off(pcs, BIU_CONF1), oldconf);
|
|
junk = ispregrd(pcs, IspVirt2Off(pcs, BIU_CONF1));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* We enter with the IRQs disabled.
|
|
*
|
|
* This makes 2.6 unhappy when we try to allocate memory.
|
|
*
|
|
* The only time we need to allocate memory is when we're
|
|
* setting things up, and in that case the chip isn't really
|
|
* quite active yet.
|
|
*/
|
|
static int
|
|
isp_pci_mbxdma(ispsoftc_t *isp)
|
|
{
|
|
fcparam *fcp;
|
|
int i;
|
|
struct isp_pcisoftc *pcs;
|
|
|
|
if (isp->isp_xflist) {
|
|
return (0);
|
|
}
|
|
isp->isp_osinfo.mcorig = isp->isp_maxcmds;
|
|
|
|
pcs = (struct isp_pcisoftc *) isp;
|
|
|
|
ISP_DROP_LK_SOFTC(isp);
|
|
if (isp->isp_xflist == NULL) {
|
|
size_t amt = isp->isp_osinfo.mcorig * sizeof (XS_T **);
|
|
isp->isp_xflist = isp_kzalloc(amt, GFP_KERNEL);
|
|
if (isp->isp_xflist == NULL) {
|
|
isp_prt(isp, ISP_LOGERR, "unable to allocate xflist array");
|
|
goto bad;
|
|
}
|
|
}
|
|
#ifdef ISP_TARGET_MODE
|
|
if (isp->isp_tgtlist == NULL) {
|
|
size_t amt = isp->isp_osinfo.mcorig * sizeof (void **);
|
|
isp->isp_tgtlist = isp_kzalloc(amt, GFP_KERNEL);
|
|
if (isp->isp_tgtlist == NULL) {
|
|
isp_prt(isp, ISP_LOGERR, "unable to allocate tgtlist array");
|
|
goto bad;
|
|
}
|
|
}
|
|
if (IS_24XX(isp) && isp->isp_atioq == NULL) {
|
|
dma_addr_t busaddr;
|
|
isp->isp_atioq = pci_alloc_consistent(pcs->pci_dev, RESULT_QUEUE_LEN(isp) * QENTRY_LEN, &busaddr);
|
|
if (isp->isp_atioq == NULL) {
|
|
isp_prt(isp, ISP_LOGERR, "unable to allocate atio queue");
|
|
goto bad;
|
|
}
|
|
isp->isp_atioq_dma = busaddr;
|
|
if (isp->isp_atioq_dma & 0x3f) {
|
|
isp_prt(isp, ISP_LOGERR, "ATIO Queue not on 64 byte boundary");
|
|
goto bad;
|
|
}
|
|
memset(isp->isp_atioq, 0, ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)));
|
|
}
|
|
#endif
|
|
if (isp->isp_rquest == NULL) {
|
|
dma_addr_t busaddr;
|
|
isp->isp_rquest = pci_alloc_consistent(pcs->pci_dev, RQUEST_QUEUE_LEN(isp) * QENTRY_LEN, &busaddr);
|
|
if (isp->isp_rquest == NULL) {
|
|
isp_prt(isp, ISP_LOGERR, "unable to allocate request queue");
|
|
goto bad;
|
|
}
|
|
isp->isp_rquest_dma = busaddr;
|
|
if (isp->isp_rquest_dma & 0x3f) {
|
|
isp_prt(isp, ISP_LOGERR, "Request Queue not on 64 byte boundary");
|
|
goto bad;
|
|
}
|
|
memset(isp->isp_rquest, 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)));
|
|
}
|
|
|
|
if (isp->isp_result == NULL) {
|
|
dma_addr_t busaddr;
|
|
isp->isp_result = pci_alloc_consistent(pcs->pci_dev, RESULT_QUEUE_LEN(isp) * QENTRY_LEN, &busaddr);
|
|
if (isp->isp_result == NULL) {
|
|
isp_prt(isp, ISP_LOGERR, "unable to allocate result queue");
|
|
goto bad;
|
|
}
|
|
isp->isp_result_dma = busaddr;
|
|
if (isp->isp_rquest_dma & 0x3f) {
|
|
isp_prt(isp, ISP_LOGERR, "Result Queue not on 64 byte boundary");
|
|
goto bad;
|
|
}
|
|
memset(isp->isp_result, 0, ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)));
|
|
}
|
|
|
|
if (IS_FC(isp)) {
|
|
for (i = 0; i < isp->isp_nchan; i++) {
|
|
fcp = FCPARAM(isp, i);
|
|
if (fcp->isp_scratch == NULL) {
|
|
dma_addr_t busaddr;
|
|
fcp->isp_scratch = pci_alloc_consistent(pcs->pci_dev, ISP_FC_SCRLEN, &busaddr);
|
|
if (fcp->isp_scratch == NULL) {
|
|
isp_prt(isp, ISP_LOGERR, "unable to allocate scratch space");
|
|
goto bad;
|
|
}
|
|
fcp->isp_scdma = busaddr;
|
|
memset(fcp->isp_scratch, 0, ISP_FC_SCRLEN);
|
|
if (fcp->isp_scdma & 0x7) {
|
|
isp_prt(isp, ISP_LOGERR, "scratch space not 8 byte aligned");
|
|
goto bad;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ISP_IGET_LK_SOFTC(isp);
|
|
return (0);
|
|
|
|
bad:
|
|
if (isp->isp_xflist) {
|
|
isp_kfree(isp->isp_xflist, isp->isp_osinfo.mcorig * sizeof (XS_T **));
|
|
isp->isp_xflist = NULL;
|
|
}
|
|
#ifdef ISP_TARGET_MODE
|
|
if (isp->isp_tgtlist) {
|
|
isp_kfree(isp->isp_tgtlist, isp->isp_osinfo.mcorig * sizeof (void **));
|
|
isp->isp_tgtlist = NULL;
|
|
}
|
|
if (isp->isp_atioq) {
|
|
pci_free_consistent(pcs->pci_dev, RESULT_QUEUE_LEN(isp) * QENTRY_LEN, isp->isp_atioq, isp->isp_atioq_dma);
|
|
isp->isp_atioq = NULL;
|
|
isp->isp_atioq_dma = 0;
|
|
}
|
|
#endif
|
|
if (isp->isp_rquest) {
|
|
pci_free_consistent(pcs->pci_dev, RQUEST_QUEUE_LEN(isp) * QENTRY_LEN, isp->isp_rquest, isp->isp_rquest_dma);
|
|
isp->isp_rquest = NULL;
|
|
isp->isp_rquest_dma = 0;
|
|
}
|
|
if (isp->isp_result) {
|
|
pci_free_consistent(pcs->pci_dev, RESULT_QUEUE_LEN(isp) * QENTRY_LEN, isp->isp_result, isp->isp_result_dma);
|
|
isp->isp_result = NULL;
|
|
isp->isp_result_dma = 0;
|
|
}
|
|
if (IS_FC(isp)) {
|
|
for (i = 0; i < isp->isp_nchan; i++) {
|
|
fcp = FCPARAM(isp, i);
|
|
if (fcp->isp_scratch) {
|
|
pci_free_consistent(pcs->pci_dev, ISP_FC_SCRLEN, fcp->isp_scratch, fcp->isp_scdma);
|
|
fcp->isp_scratch = NULL;
|
|
fcp->isp_scdma = 0;
|
|
}
|
|
}
|
|
}
|
|
ISP_IGET_LK_SOFTC(isp);
|
|
return (1);
|
|
}
|
|
|
|
#ifdef ISP_TARGET_MODE
|
|
static int
|
|
isp_pci_dmasetup_tgt(ispsoftc_t *isp, tmd_xact_t *xact, void *fqe)
|
|
{
|
|
struct scatterlist *sg = NULL;
|
|
isp_ddir_t ddir;
|
|
uint32_t nseg;
|
|
int ret;
|
|
|
|
switch (((isphdr_t *)fqe)->rqs_entry_type) {
|
|
case RQSTYPE_CTIO:
|
|
if ((((ct_entry_t *)fqe)->ct_flags & CT_DATAMASK) == CT_DATA_OUT) {
|
|
ddir = ISP_FROM_DEVICE;
|
|
} else if ((((ct_entry_t *)fqe)->ct_flags & CT_DATAMASK) == CT_DATA_IN) {
|
|
ddir = ISP_TO_DEVICE;
|
|
} else {
|
|
ddir = ISP_NOXFR;
|
|
}
|
|
break;
|
|
case RQSTYPE_CTIO2:
|
|
if ((((ct2_entry_t *)fqe)->ct_flags & CT2_DATAMASK) == CT2_DATA_OUT) {
|
|
ddir = ISP_FROM_DEVICE;
|
|
} else if ((((ct2_entry_t *)fqe)->ct_flags & CT2_DATAMASK) == CT2_DATA_IN) {
|
|
ddir = ISP_TO_DEVICE;
|
|
} else {
|
|
ddir = ISP_NOXFR;
|
|
}
|
|
if (ddir != ISP_NOXFR && isp->isp_osinfo.is_64bit_dma) {
|
|
((isphdr_t *)fqe)->rqs_entry_type = RQSTYPE_CTIO3;
|
|
}
|
|
break;
|
|
case RQSTYPE_CTIO7:
|
|
if (((ct7_entry_t *)fqe)->ct_flags & CT7_DATA_OUT) {
|
|
ddir = ISP_FROM_DEVICE;
|
|
} else if (((ct7_entry_t *)fqe)->ct_flags & CT7_DATA_IN) {
|
|
ddir = ISP_TO_DEVICE;
|
|
} else {
|
|
ddir = ISP_NOXFR;
|
|
}
|
|
break;
|
|
default:
|
|
xact->td_error = -EINVAL;
|
|
return (CMD_COMPLETE);
|
|
}
|
|
|
|
if (ddir != ISP_NOXFR) {
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
uint32_t xfcnt;
|
|
|
|
sg = xact->td_data;
|
|
xfcnt = xact->td_xfrlen;
|
|
nseg = 0;
|
|
while (xfcnt > 0) {
|
|
xfcnt -= sg->length;
|
|
sg++;
|
|
nseg++;
|
|
}
|
|
sg = xact->td_data;
|
|
nseg = pci_map_sg(pcs->pci_dev, sg, nseg, ddir == ISP_TO_DEVICE? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
|
|
} else {
|
|
sg = NULL;
|
|
nseg = 0;
|
|
}
|
|
if (isp->isp_osinfo.is_64bit_dma) {
|
|
if (nseg >= ISP_NSEG64_MAX) {
|
|
isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG64_MAX);
|
|
xact->td_error = -EFAULT;
|
|
return (CMD_COMPLETE);
|
|
}
|
|
} else if (nseg >= ISP_NSEG_MAX) {
|
|
isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG_MAX);
|
|
xact->td_error = -EFAULT;
|
|
return (CMD_COMPLETE);
|
|
}
|
|
ret = isp_send_tgt_cmd(isp, fqe, sg, nseg, xact->td_xfrlen, ddir, xact->td_cmd->cd_sense, TMD_SENSELEN);
|
|
if (ret == CMD_QUEUED) {
|
|
int bin;
|
|
if (xact->td_xfrlen <= 1024) {
|
|
bin = 0;
|
|
} else if (xact->td_xfrlen <= 4096) {
|
|
bin = 1;
|
|
} else if (xact->td_xfrlen <= 32768) {
|
|
bin = 2;
|
|
} else if (xact->td_xfrlen <= 65536) {
|
|
bin = 3;
|
|
} else if (xact->td_xfrlen <= 131372) {
|
|
bin = 4;
|
|
} else if (xact->td_xfrlen <= 262144) {
|
|
bin = 5;
|
|
} else if (xact->td_xfrlen <= 524288) {
|
|
bin = 6;
|
|
} else {
|
|
bin = 7;
|
|
}
|
|
isp->isp_osinfo.bins[bin]++;
|
|
}
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
isp_pci_dmasetup(ispsoftc_t *isp, Scsi_Cmnd *Cmnd, void *fqe)
|
|
{
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
|
|
struct scatterlist one_shot;
|
|
#endif
|
|
struct scatterlist *sg = NULL;
|
|
isphdr_t *hp;
|
|
isp_ddir_t ddir;
|
|
uint32_t nseg;
|
|
int ret;
|
|
|
|
hp = fqe;
|
|
switch (hp->rqs_entry_type) {
|
|
#ifdef ISP_TARGET_MODE
|
|
case RQSTYPE_CTIO:
|
|
case RQSTYPE_CTIO2:
|
|
case RQSTYPE_CTIO7:
|
|
return (isp_pci_dmasetup_tgt(isp, (tmd_xact_t *)Cmnd, fqe));
|
|
#endif
|
|
case RQSTYPE_REQUEST:
|
|
if (isp->isp_osinfo.is_64bit_dma) {
|
|
hp->rqs_entry_type = RQSTYPE_A64;
|
|
}
|
|
break;
|
|
case RQSTYPE_T2RQS:
|
|
if (isp->isp_osinfo.is_64bit_dma) {
|
|
hp->rqs_entry_type = RQSTYPE_T3RQS;
|
|
}
|
|
break;
|
|
case RQSTYPE_T7RQS:
|
|
break;
|
|
default:
|
|
isp_prt(isp, ISP_LOGERR, "%s: unknwon type 0x%x", __func__, hp->rqs_entry_type);
|
|
return (CMD_COMPLETE);
|
|
}
|
|
|
|
if (Cmnd->sc_data_direction == SCSI_DATA_NONE) {
|
|
ddir = ISP_NOXFR;
|
|
} else if (Cmnd->sc_data_direction == SCSI_DATA_WRITE) {
|
|
ddir = ISP_TO_DEVICE;
|
|
} else {
|
|
ddir = ISP_FROM_DEVICE;
|
|
}
|
|
|
|
if (ddir != ISP_NOXFR) {
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
|
|
if ((nseg = Cmnd->use_sg) == 0) {
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
nseg = 1;
|
|
sg = &one_shot;
|
|
sg_dma_address(sg) = pci_map_single(pcs->pci_dev, Cmnd->request_buffer, XS_XFRLEN(Cmnd), scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
|
|
sg_dma_len(sg) = XS_XFRLEN(Cmnd);
|
|
QLA_HANDLE(Cmnd) = (DMA_HTYPE_T) sg_dma_address(sg);
|
|
} else {
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
sg = (struct scatterlist *) Cmnd->request_buffer;
|
|
nseg = pci_map_sg(pcs->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
|
|
}
|
|
if (nseg == 0) {
|
|
isp_prt(isp, ISP_LOGWARN, "%s: unable to dma map request", __func__);
|
|
XS_SETERR(Cmnd, HBA_BOTCH);
|
|
return (CMD_COMPLETE);
|
|
}
|
|
#else
|
|
nseg = scsi_dma_map(Cmnd);
|
|
if (nseg <= 0) {
|
|
isp_prt(isp, ISP_LOGWARN, "%s: unable to dma map request", __func__);
|
|
XS_SETERR(Cmnd, HBA_BOTCH);
|
|
return (CMD_COMPLETE);
|
|
}
|
|
sg = scsi_sglist(Cmnd);
|
|
#endif
|
|
} else {
|
|
sg = NULL;
|
|
nseg = 0;
|
|
}
|
|
if (isp->isp_osinfo.is_64bit_dma) {
|
|
if (nseg >= ISP_NSEG64_MAX) {
|
|
isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG64_MAX);
|
|
XS_SETERR(Cmnd, HBA_BOTCH);
|
|
return (CMD_COMPLETE);
|
|
}
|
|
} else if (nseg >= ISP_NSEG_MAX) {
|
|
isp_prt(isp, ISP_LOGERR, "number of segments (%d) exceed maximum we can support (%d)", nseg, ISP_NSEG_MAX);
|
|
XS_SETERR(Cmnd, HBA_BOTCH);
|
|
return (CMD_COMPLETE);
|
|
}
|
|
ret = isp_send_cmd(isp, fqe, sg, nseg, XS_XFRLEN(Cmnd), ddir);
|
|
if (ret == CMD_QUEUED) {
|
|
int bin;
|
|
if (XS_XFRLEN(Cmnd) <= 1024) {
|
|
bin = 0;
|
|
} else if (XS_XFRLEN(Cmnd) <= 4096) {
|
|
bin = 1;
|
|
} else if (XS_XFRLEN(Cmnd) <= 32768) {
|
|
bin = 2;
|
|
} else if (XS_XFRLEN(Cmnd) <= 65536) {
|
|
bin = 3;
|
|
} else if (XS_XFRLEN(Cmnd) <= 131372) {
|
|
bin = 4;
|
|
} else if (XS_XFRLEN(Cmnd) <= 262144) {
|
|
bin = 5;
|
|
} else if (XS_XFRLEN(Cmnd) <= 524288) {
|
|
bin = 6;
|
|
} else {
|
|
bin = 7;
|
|
}
|
|
isp->isp_osinfo.bins[bin]++;
|
|
} else if (ret == CMD_COMPLETE) {
|
|
XS_SETERR(Cmnd, HBA_BOTCH);
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
static void
|
|
isp_pci_dmateardown(ispsoftc_t *isp, Scsi_Cmnd *Cmnd, uint32_t handle)
|
|
{
|
|
#ifdef ISP_TARGET_MODE
|
|
/*
|
|
* The argument passed may not be a Cmnd pointer- this is the
|
|
* safest way to keep the two w/o redoing our internal apis.
|
|
*/
|
|
if (IS_TARGET_HANDLE(handle)) {
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp;
|
|
tmd_xact_t *xact = (tmd_xact_t *) Cmnd;
|
|
tmd_cmd_t *tmd = xact? xact->td_cmd : NULL;
|
|
int nseg = tmd? tmd->cd_nseg : 0;
|
|
if (nseg && xact->td_data) {
|
|
isp_prt(isp, ISP_LOGTDEBUG2, "[%llx]: pci_unmap %d segments at %p for handle 0x%x", tmd->cd_tagval, nseg, xact->td_data, handle);
|
|
pci_unmap_sg(pcs->pci_dev, xact->td_data, nseg, (xact->td_hflags & TDFH_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
|
|
}
|
|
} else
|
|
#endif
|
|
if (Cmnd->sc_data_direction != SCSI_DATA_NONE) {
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp;
|
|
if (Cmnd->use_sg) {
|
|
pci_unmap_sg(pcs->pci_dev, (struct scatterlist *)Cmnd->request_buffer, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
|
|
} else if (XS_XFRLEN(Cmnd)) {
|
|
XS_DMA_ADDR_T dhandle = (XS_DMA_ADDR_T) QLA_HANDLE(Cmnd);
|
|
pci_unmap_single(pcs->pci_dev, dhandle, XS_XFRLEN(Cmnd), scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
|
|
}
|
|
#else
|
|
scsi_dma_unmap(Cmnd);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void
|
|
isp_pci_reset0(ispsoftc_t *isp)
|
|
{
|
|
ISP_DISABLE_INTS(isp);
|
|
isp->mbintsok = 0;
|
|
isp->intsok = 0;
|
|
}
|
|
|
|
static void
|
|
isp_pci_reset1(ispsoftc_t *isp)
|
|
{
|
|
if (!IS_24XX(isp)) {
|
|
isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
|
|
}
|
|
ISP_ENABLE_INTS(isp);
|
|
isp->intsok = 1;
|
|
/*
|
|
* We used to enable mbintsok here.
|
|
* This seemed to nuke 24XX cards in some, but not all cases.
|
|
*/
|
|
}
|
|
|
|
static void
|
|
isp_pci_dumpregs(ispsoftc_t *isp, const char *msg)
|
|
{
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
uint16_t csr;
|
|
|
|
pci_read_config_word(pcs->pci_dev, PCI_COMMAND, &csr);
|
|
printk("%s: ", isp->isp_name);
|
|
if (msg) {
|
|
printk("%s\n", msg);
|
|
}
|
|
if (IS_SCSI(isp)) {
|
|
printk(" biu_conf1=%x", ISP_READ(isp, BIU_CONF1));
|
|
} else {
|
|
printk(" biu_csr=%x", ISP_READ(isp, BIU2100_CSR));
|
|
}
|
|
printk(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR), ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA));
|
|
printk("risc_hccr=%x\n", ISP_READ(isp, HCCR));
|
|
if (IS_SCSI(isp)) {
|
|
ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);
|
|
printk(" cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n", ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS), ISP_READ(isp, CDMA_FIFO_STS));
|
|
printk(" ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n", ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS), ISP_READ(isp, DDMA_FIFO_STS));
|
|
printk(" sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n", ISP_READ(isp, SXP_INTERRUPT), ISP_READ(isp, SXP_GROSS_ERR), ISP_READ(isp, SXP_PINS_CTRL));
|
|
ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);
|
|
}
|
|
printk(" mbox regs: %x %x %x %x %x\n",
|
|
ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1),
|
|
ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3),
|
|
ISP_READ(isp, OUTMAILBOX4));
|
|
printk(" PCI Status Command/Status=%x\n", csr);
|
|
}
|
|
|
|
static char *isp_pci_exclude = NULL;
|
|
static char *isp_pci_include = NULL;
|
|
|
|
static int
|
|
isplinux_pci_exclude(struct pci_dev *dev)
|
|
{
|
|
int checking_for_inclusion;
|
|
char *wrk;
|
|
|
|
if (isp_pci_include && *isp_pci_include) {
|
|
checking_for_inclusion = 1;
|
|
wrk = isp_pci_include;
|
|
} else {
|
|
checking_for_inclusion = 0;
|
|
wrk = isp_pci_exclude;
|
|
}
|
|
while (wrk && *wrk) {
|
|
unsigned int id;
|
|
char *commatok, *p, *q;
|
|
|
|
commatok = strchr(wrk, ',');
|
|
if (commatok) {
|
|
*commatok = 0;
|
|
}
|
|
if (strncmp(wrk, "0x", 2) == 0) {
|
|
q = wrk + 2;
|
|
} else {
|
|
q = wrk;
|
|
}
|
|
id = simple_strtoul(q, &p, 16);
|
|
if (commatok) {
|
|
*commatok = ',';
|
|
}
|
|
if (p != q) {
|
|
/*
|
|
* We have a device id. See if it matches the current device.
|
|
*/
|
|
unsigned int exid = ((dev->bus->number) << 16) | (PCI_SLOT(dev->devfn) << 8) | (PCI_FUNC(dev->devfn));
|
|
if (id == exid) {
|
|
if (checking_for_inclusion) {
|
|
return (0);
|
|
} else {
|
|
printk(KERN_INFO "%s@<%d,%d,%d>: excluding device\n", ISP_NAME, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
|
|
return (1);
|
|
}
|
|
}
|
|
}
|
|
if (commatok) {
|
|
wrk = commatok+1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* We didn't find this device on our list and we were checking
|
|
* the list of devices to *include*, so don't attach this device.
|
|
* Otherwise, we can attach this device.
|
|
*/
|
|
if (checking_for_inclusion) {
|
|
printk(KERN_INFO "%s@<%d,%d,%d>: excluding device\n", ISP_NAME, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
|
|
return (1);
|
|
} else {
|
|
return (0);
|
|
}
|
|
}
|
|
#ifdef MODULE
|
|
module_param(isp_pci_mapmem, int, 0);
|
|
module_param(isp_pci_exclude, charp, 0);
|
|
module_param(isp_pci_include, charp, 0);
|
|
#else
|
|
static int __init isp_exclude(char *str)
|
|
{
|
|
isp_pci_exclude = str;
|
|
return 0;
|
|
}
|
|
__setup("isp_pci_exclude=", isp_exclude);
|
|
|
|
static int __init isp_include(char *str)
|
|
{
|
|
isp_pci_include = str;
|
|
return 0;
|
|
}
|
|
__setup("isp_pci_include=", isp_include);
|
|
#endif
|
|
|
|
static struct pci_device_id isp_pci_tbl[] __devinitdata = {
|
|
#ifndef ISP_DISABLE_1020_SUPPORT
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020) },
|
|
#endif
|
|
#ifndef ISP_DISABLE_1080_SUPPORT
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1080) },
|
|
#endif
|
|
#ifndef ISP_DISABLE_12160_SUPPORT
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP12160) },
|
|
#endif
|
|
#ifndef ISP_DISABLE_2100_SUPPORT
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) },
|
|
#endif
|
|
#ifndef ISP_DISABLE_2200_SUPPORT
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) },
|
|
#endif
|
|
#ifndef ISP_DISABLE_2300_SUPPORT
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2300) },
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2312) },
|
|
#endif
|
|
#ifndef ISP_DISABLE_2322_SUPPORT
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6312) },
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2322) },
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6322) },
|
|
#endif
|
|
#ifndef ISP_DISABLE_2400_SUPPORT
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2422) },
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432) },
|
|
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },
|
|
#endif
|
|
{ 0, 0 }
|
|
};
|
|
MODULE_DEVICE_TABLE(pci, isp_pci_tbl);
|
|
|
|
static int __devinit
|
|
isplinux_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
{
|
|
struct Scsi_Host *host;
|
|
struct scsi_host_template *tmpt = isp_template;
|
|
ispsoftc_t *isp;
|
|
struct isp_pcisoftc *pci_isp;
|
|
int i, ret;
|
|
|
|
if (pdev->subsystem_vendor == PCI_VENDOR_ID_AMI) {
|
|
printk(KERN_INFO "skipping AMI Raid Card that uses QLogic chips\n");
|
|
return (-ENODEV);
|
|
}
|
|
|
|
if (isplinux_pci_exclude(pdev)) {
|
|
printk(KERN_INFO "%s: excluding device\n", pci_name(pdev));
|
|
return (-ENODEV);
|
|
}
|
|
if (pci_enable_device(pdev)) {
|
|
printk(KERN_ERR "%s: cannot enable\n", pci_name(pdev));
|
|
return (-ENODEV);
|
|
}
|
|
pci_set_master(pdev);
|
|
|
|
tmpt->max_sectors = isp_maxsectors;
|
|
|
|
host = scsi_host_alloc(tmpt, sizeof(struct isp_pcisoftc));
|
|
if (host == NULL) {
|
|
pci_disable_device(pdev);
|
|
return (-ENOMEM);
|
|
}
|
|
pci_isp = (struct isp_pcisoftc *) ISP_HOST2ISP(host);
|
|
pci_set_drvdata(pdev, pci_isp);
|
|
pci_isp->pci_dev = pdev;
|
|
isp = (ispsoftc_t *) pci_isp;
|
|
isp->isp_host = host;
|
|
isp->isp_osinfo.device = pdev;
|
|
host->unique_id = isp_unit_seed++;
|
|
sprintf(isp->isp_name, "%s%d", ISP_NAME, isp->isp_unit);
|
|
isp->isp_osinfo.device_id = (pci_domain_nr(pdev->bus) << 16) | ((pdev->bus->number) << 8) | (PCI_SLOT(pdev->devfn) << 3) | (PCI_FUNC(pdev->devfn));
|
|
if (isp_disable & (1 << isp->isp_unit)) {
|
|
printk("%s: disabled at user request\n", isp->isp_name);
|
|
scsi_host_put(host);
|
|
pci_disable_device(pdev);
|
|
return (-ENODEV);
|
|
}
|
|
if (isplinux_pci_init_one(host)) {
|
|
scsi_host_put(host);
|
|
pci_disable_device(pdev);
|
|
return (-ENOMEM);
|
|
}
|
|
ret = scsi_add_host(host, &pdev->dev);
|
|
if (ret) {
|
|
scsi_host_put(host);
|
|
if (pci_isp->msix_enabled) {
|
|
if (pci_isp->msix_enabled > 1) {
|
|
free_irq(pci_isp->msix_vector[0], pci_isp);
|
|
free_irq(pci_isp->msix_vector[1], pci_isp);
|
|
free_irq(pci_isp->msix_vector[2], pci_isp);
|
|
}
|
|
pci_disable_msix(pci_isp->pci_dev);
|
|
pci_isp->msix_enabled = 0;
|
|
}
|
|
if (pci_isp->msi_enabled) {
|
|
pci_isp->msi_enabled = 0;
|
|
pci_disable_msi(pdev);
|
|
}
|
|
pci_disable_device(pdev);
|
|
return (ret);
|
|
}
|
|
for (i = 0; i < MAX_ISP; i++) {
|
|
if (isplist[i] == NULL) {
|
|
isplist[i] = isp;
|
|
break;
|
|
}
|
|
}
|
|
scsi_scan_host(host);
|
|
return (0);
|
|
}
|
|
|
|
static void __devexit
|
|
isplinux_pci_remove(struct pci_dev *pdev)
|
|
{
|
|
struct isp_pcisoftc *pci_isp = pci_get_drvdata(pdev);
|
|
unsigned long flags;
|
|
ispsoftc_t *isp;
|
|
struct Scsi_Host *host;
|
|
|
|
isp = (ispsoftc_t *) pci_isp;
|
|
DESTROY_ISP_DEV(isp);
|
|
host = isp->isp_host;
|
|
scsi_remove_host(host);
|
|
#ifdef ISP_TARGET_MODE
|
|
isp_detach_target(isp);
|
|
#endif
|
|
if (isp->isp_osinfo.thread_task) {
|
|
wake_up(&isp->isp_osinfo.trq);
|
|
kthread_stop(isp->isp_osinfo.thread_task);
|
|
isp->isp_osinfo.thread_task = NULL;
|
|
}
|
|
ISP_LOCKU_SOFTC(isp);
|
|
isp_shutdown(isp);
|
|
isp->dogactive = 0;
|
|
del_timer(&isp->isp_osinfo.timer);
|
|
ISP_DISABLE_INTS(isp);
|
|
ISP_UNLKU_SOFTC(isp);
|
|
isplinux_pci_release(host);
|
|
#ifdef ISP_TARGET_MODE
|
|
isp_deinit_target(isp);
|
|
#endif
|
|
scsi_host_put(host);
|
|
#ifdef CONFIG_FW_LOADER
|
|
if (isp->isp_osinfo.fwp) {
|
|
release_firmware(isp->isp_osinfo.fwp);
|
|
isp->isp_osinfo.fwp = NULL;
|
|
}
|
|
#endif
|
|
pci_set_drvdata(pdev, NULL);
|
|
}
|
|
|
|
static struct pci_driver isplinux_pci_driver = {
|
|
.name = ISP_NAME,
|
|
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
|
|
.driver = {
|
|
.owner = THIS_MODULE,
|
|
},
|
|
#endif
|
|
.id_table = isp_pci_tbl,
|
|
.probe = isplinux_pci_probe,
|
|
.remove = __devexit_p(isplinux_pci_remove),
|
|
};
|
|
|
|
static int __init
|
|
isplinux_pci_init(void)
|
|
{
|
|
int ret;
|
|
|
|
printk(KERN_INFO "Feral Software QLogic SCSI/FC Driver built on %s %s\n", __DATE__, __TIME__);
|
|
ret = alloc_chrdev_region(&isp_dev, 0, MAX_ISP, ISP_NAME);
|
|
if (ret) {
|
|
printk(KERN_ERR "%s: cannot allocate chrdev region\n", __func__);
|
|
return (ret);
|
|
}
|
|
cdev_init(&isp_cdev, &isp_ioctl_operations);
|
|
if (cdev_add(&isp_cdev, isp_dev, MAX_ISP)) {
|
|
printk(KERN_ERR "%s: cannot add cdev\n", __func__);
|
|
kobject_put(&isp_cdev.kobj);
|
|
unregister_chrdev_region(isp_dev, MAX_ISP);
|
|
return (-EIO);
|
|
}
|
|
isp_class = CREATE_ISP_CLASS(THIS_MODULE, ISP_NAME);
|
|
if (IS_ERR(isp_class)) {
|
|
printk(KERN_ERR "%s: unable to add '%s' class\n", ISP_NAME, ISP_NAME);
|
|
cdev_del(&isp_cdev);
|
|
unregister_chrdev_region(isp_dev, MAX_ISP);
|
|
return (PTR_ERR(isp_class));
|
|
}
|
|
ret = pci_register_driver(&isplinux_pci_driver);
|
|
if (ret < 0) {
|
|
printk(KERN_ERR "%s: unable to register driver (return value %d)", __func__, ret);
|
|
DESTROY_ISP_CLASS(isp_class);
|
|
cdev_del(&isp_cdev);
|
|
unregister_chrdev_region(isp_dev, MAX_ISP);
|
|
return (ret);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static void __exit
|
|
isplinux_pci_exit(void)
|
|
{
|
|
pci_unregister_driver(&isplinux_pci_driver);
|
|
DESTROY_ISP_CLASS(isp_class);
|
|
cdev_del(&isp_cdev);
|
|
unregister_chrdev_region(isp_dev, MAX_ISP);
|
|
}
|
|
|
|
module_init(isplinux_pci_init);
|
|
module_exit(isplinux_pci_exit);
|
|
/*
|
|
* vim:ts=4:sw=4:expandtab
|
|
*/
|