Merge git://git.infradead.org/battery-2.6
* git://git.infradead.org/battery-2.6:
git-battery vs git-acpi
Power supply class and drivers: remove non obligatory return statements
pda_power: clean up irq, timer
MAINTAINERS: Add maintainers for power supply subsystem and drivers
Fixed up trivial conflict in drivers/w1/slaves/w1_ds2760.c manually
diff --git a/Documentation/networking/mac80211-injection.txt b/Documentation/networking/mac80211-injection.txt
new file mode 100644
index 0000000..53ef7a0
--- /dev/null
+++ b/Documentation/networking/mac80211-injection.txt
@@ -0,0 +1,59 @@
+How to use packet injection with mac80211
+=========================================
+
+mac80211 now allows arbitrary packets to be injected down any Monitor Mode
+interface from userland. The packet you inject needs to be composed in the
+following format:
+
+ [ radiotap header ]
+ [ ieee80211 header ]
+ [ payload ]
+
+The radiotap format is discussed in
+./Documentation/networking/radiotap-headers.txt.
+
+Despite 13 radiotap argument types are currently defined, most only make sense
+to appear on received packets. Currently three kinds of argument are used by
+the injection code, although it knows to skip any other arguments that are
+present (facilitating replay of captured radiotap headers directly):
+
+ - IEEE80211_RADIOTAP_RATE - u8 arg in 500kbps units (0x02 --> 1Mbps)
+
+ - IEEE80211_RADIOTAP_ANTENNA - u8 arg, 0x00 = ant1, 0x01 = ant2
+
+ - IEEE80211_RADIOTAP_DBM_TX_POWER - u8 arg, dBm
+
+Here is an example valid radiotap header defining these three parameters
+
+ 0x00, 0x00, // <-- radiotap version
+ 0x0b, 0x00, // <- radiotap header length
+ 0x04, 0x0c, 0x00, 0x00, // <-- bitmap
+ 0x6c, // <-- rate
+ 0x0c, //<-- tx power
+ 0x01 //<-- antenna
+
+The ieee80211 header follows immediately afterwards, looking for example like
+this:
+
+ 0x08, 0x01, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x13, 0x22, 0x33, 0x44, 0x55, 0x66,
+ 0x13, 0x22, 0x33, 0x44, 0x55, 0x66,
+ 0x10, 0x86
+
+Then lastly there is the payload.
+
+After composing the packet contents, it is sent by send()-ing it to a logical
+mac80211 interface that is in Monitor mode. Libpcap can also be used,
+(which is easier than doing the work to bind the socket to the right
+interface), along the following lines:
+
+ ppcap = pcap_open_live(szInterfaceName, 800, 1, 20, szErrbuf);
+...
+ r = pcap_inject(ppcap, u8aSendBuffer, nLength);
+
+You can also find sources for a complete inject test applet here:
+
+http://penumbra.warmcat.com/_twk/tiki-index.php?page=packetspammer
+
+Andy Green <andy@warmcat.com>
diff --git a/Documentation/networking/radiotap-headers.txt b/Documentation/networking/radiotap-headers.txt
new file mode 100644
index 0000000..953331c
--- /dev/null
+++ b/Documentation/networking/radiotap-headers.txt
@@ -0,0 +1,152 @@
+How to use radiotap headers
+===========================
+
+Pointer to the radiotap include file
+------------------------------------
+
+Radiotap headers are variable-length and extensible, you can get most of the
+information you need to know on them from:
+
+./include/net/ieee80211_radiotap.h
+
+This document gives an overview and warns on some corner cases.
+
+
+Structure of the header
+-----------------------
+
+There is a fixed portion at the start which contains a u32 bitmap that defines
+if the possible argument associated with that bit is present or not. So if b0
+of the it_present member of ieee80211_radiotap_header is set, it means that
+the header for argument index 0 (IEEE80211_RADIOTAP_TSFT) is present in the
+argument area.
+
+ < 8-byte ieee80211_radiotap_header >
+ [ <possible argument bitmap extensions ... > ]
+ [ <argument> ... ]
+
+At the moment there are only 13 possible argument indexes defined, but in case
+we run out of space in the u32 it_present member, it is defined that b31 set
+indicates that there is another u32 bitmap following (shown as "possible
+argument bitmap extensions..." above), and the start of the arguments is moved
+forward 4 bytes each time.
+
+Note also that the it_len member __le16 is set to the total number of bytes
+covered by the ieee80211_radiotap_header and any arguments following.
+
+
+Requirements for arguments
+--------------------------
+
+After the fixed part of the header, the arguments follow for each argument
+index whose matching bit is set in the it_present member of
+ieee80211_radiotap_header.
+
+ - the arguments are all stored little-endian!
+
+ - the argument payload for a given argument index has a fixed size. So
+ IEEE80211_RADIOTAP_TSFT being present always indicates an 8-byte argument is
+ present. See the comments in ./include/net/ieee80211_radiotap.h for a nice
+ breakdown of all the argument sizes
+
+ - the arguments must be aligned to a boundary of the argument size using
+ padding. So a u16 argument must start on the next u16 boundary if it isn't
+ already on one, a u32 must start on the next u32 boundary and so on.
+
+ - "alignment" is relative to the start of the ieee80211_radiotap_header, ie,
+ the first byte of the radiotap header. The absolute alignment of that first
+ byte isn't defined. So even if the whole radiotap header is starting at, eg,
+ address 0x00000003, still the first byte of the radiotap header is treated as
+ 0 for alignment purposes.
+
+ - the above point that there may be no absolute alignment for multibyte
+ entities in the fixed radiotap header or the argument region means that you
+ have to take special evasive action when trying to access these multibyte
+ entities. Some arches like Blackfin cannot deal with an attempt to
+ dereference, eg, a u16 pointer that is pointing to an odd address. Instead
+ you have to use a kernel API get_unaligned() to dereference the pointer,
+ which will do it bytewise on the arches that require that.
+
+ - The arguments for a given argument index can be a compound of multiple types
+ together. For example IEEE80211_RADIOTAP_CHANNEL has an argument payload
+ consisting of two u16s of total length 4. When this happens, the padding
+ rule is applied dealing with a u16, NOT dealing with a 4-byte single entity.
+
+
+Example valid radiotap header
+-----------------------------
+
+ 0x00, 0x00, // <-- radiotap version + pad byte
+ 0x0b, 0x00, // <- radiotap header length
+ 0x04, 0x0c, 0x00, 0x00, // <-- bitmap
+ 0x6c, // <-- rate (in 500kHz units)
+ 0x0c, //<-- tx power
+ 0x01 //<-- antenna
+
+
+Using the Radiotap Parser
+-------------------------
+
+If you are having to parse a radiotap struct, you can radically simplify the
+job by using the radiotap parser that lives in net/wireless/radiotap.c and has
+its prototypes available in include/net/cfg80211.h. You use it like this:
+
+#include <net/cfg80211.h>
+
+/* buf points to the start of the radiotap header part */
+
+int MyFunction(u8 * buf, int buflen)
+{
+ int pkt_rate_100kHz = 0, antenna = 0, pwr = 0;
+ struct ieee80211_radiotap_iterator iterator;
+ int ret = ieee80211_radiotap_iterator_init(&iterator, buf, buflen);
+
+ while (!ret) {
+
+ ret = ieee80211_radiotap_iterator_next(&iterator);
+
+ if (ret)
+ continue;
+
+ /* see if this argument is something we can use */
+
+ switch (iterator.this_arg_index) {
+ /*
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+ case IEEE80211_RADIOTAP_RATE:
+ /* radiotap "rate" u8 is in
+ * 500kbps units, eg, 0x02=1Mbps
+ */
+ pkt_rate_100kHz = (*iterator.this_arg) * 5;
+ break;
+
+ case IEEE80211_RADIOTAP_ANTENNA:
+ /* radiotap uses 0 for 1st ant */
+ antenna = *iterator.this_arg);
+ break;
+
+ case IEEE80211_RADIOTAP_DBM_TX_POWER:
+ pwr = *iterator.this_arg;
+ break;
+
+ default:
+ break;
+ }
+ } /* while more rt headers */
+
+ if (ret != -ENOENT)
+ return TXRX_DROP;
+
+ /* discard the radiotap header part */
+ buf += iterator.max_length;
+ buflen -= iterator.max_length;
+
+ ...
+
+}
+
+Andy Green <andy@warmcat.com>
diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt
index ce3cb42..cc12b55 100644
--- a/Documentation/scsi/aacraid.txt
+++ b/Documentation/scsi/aacraid.txt
@@ -50,6 +50,9 @@
9005:0285:9005:02be Adaptec 31605 (Marauder160)
9005:0285:9005:02c3 Adaptec 51205 (Voodoo120)
9005:0285:9005:02c4 Adaptec 51605 (Voodoo160)
+ 9005:0285:9005:02ce Adaptec 51245 (Voodoo124)
+ 9005:0285:9005:02cf Adaptec 51645 (Voodoo164)
+ 9005:0285:9005:02d0 Adaptec 52445 (Voodoo244)
1011:0046:9005:0364 Adaptec 5400S (Mustang)
9005:0287:9005:0800 Adaptec Themisto (Jupiter)
9005:0200:9005:0200 Adaptec Themisto (Jupiter)
diff --git a/Documentation/scsi/scsi_fc_transport.txt b/Documentation/scsi/scsi_fc_transport.txt
new file mode 100644
index 0000000..d403e46
--- /dev/null
+++ b/Documentation/scsi/scsi_fc_transport.txt
@@ -0,0 +1,450 @@
+ SCSI FC Tansport
+ =============================================
+
+Date: 4/12/2007
+Kernel Revisions for features:
+ rports : <<TBS>>
+ vports : 2.6.22 (? TBD)
+
+
+Introduction
+============
+This file documents the features and components of the SCSI FC Transport.
+It also provides documents the API between the transport and FC LLDDs.
+The FC transport can be found at:
+ drivers/scsi/scsi_transport_fc.c
+ include/scsi/scsi_transport_fc.h
+ include/scsi/scsi_netlink_fc.h
+
+This file is found at Documentation/scsi/scsi_fc_transport.txt
+
+
+FC Remote Ports (rports)
+========================================================================
+<< To Be Supplied >>
+
+
+FC Virtual Ports (vports)
+========================================================================
+
+Overview:
+-------------------------------
+
+ New FC standards have defined mechanisms which allows for a single physical
+ port to appear on as multiple communication ports. Using the N_Port Id
+ Virtualization (NPIV) mechanism, a point-to-point connection to a Fabric
+ can be assigned more than 1 N_Port_ID. Each N_Port_ID appears as a
+ separate port to other endpoints on the fabric, even though it shares one
+ physical link to the switch for communication. Each N_Port_ID can have a
+ unique view of the fabric based on fabric zoning and array lun-masking
+ (just like a normal non-NPIV adapter). Using the Virtual Fabric (VF)
+ mechanism, adding a fabric header to each frame allows the port to
+ interact with the Fabric Port to join multiple fabrics. The port will
+ obtain an N_Port_ID on each fabric it joins. Each fabric will have its
+ own unique view of endpoints and configuration parameters. NPIV may be
+ used together with VF so that the port can obtain multiple N_Port_IDs
+ on each virtual fabric.
+
+ The FC transport is now recognizing a new object - a vport. A vport is
+ an entity that has a world-wide unique World Wide Port Name (wwpn) and
+ World Wide Node Name (wwnn). The transport also allows for the FC4's to
+ be specified for the vport, with FCP_Initiator being the primary role
+ expected. Once instantiated by one of the above methods, it will have a
+ distinct N_Port_ID and view of fabric endpoints and storage entities.
+ The fc_host associated with the physical adapter will export the ability
+ to create vports. The transport will create the vport object within the
+ Linux device tree, and instruct the fc_host's driver to instantiate the
+ virtual port. Typically, the driver will create a new scsi_host instance
+ on the vport, resulting in a unique <H,C,T,L> namespace for the vport.
+ Thus, whether a FC port is based on a physical port or on a virtual port,
+ each will appear as a unique scsi_host with its own target and lun space.
+
+ Note: At this time, the transport is written to create only NPIV-based
+ vports. However, consideration was given to VF-based vports and it
+ should be a minor change to add support if needed. The remaining
+ discussion will concentrate on NPIV.
+
+ Note: World Wide Name assignment (and uniqueness guarantees) are left
+ up to an administrative entity controling the vport. For example,
+ if vports are to be associated with virtual machines, a XEN mgmt
+ utility would be responsible for creating wwpn/wwnn's for the vport,
+ using it's own naming authority and OUI. (Note: it already does this
+ for virtual MAC addresses).
+
+
+Device Trees and Vport Objects:
+-------------------------------
+
+ Today, the device tree typically contains the scsi_host object,
+ with rports and scsi target objects underneath it. Currently the FC
+ transport creates the vport object and places it under the scsi_host
+ object corresponding to the physical adapter. The LLDD will allocate
+ a new scsi_host for the vport and link it's object under the vport.
+ The remainder of the tree under the vports scsi_host is the same
+ as the non-NPIV case. The transport is written currently to easily
+ allow the parent of the vport to be something other than the scsi_host.
+ This could be used in the future to link the object onto a vm-specific
+ device tree. If the vport's parent is not the physical port's scsi_host,
+ a symbolic link to the vport object will be placed in the physical
+ port's scsi_host.
+
+ Here's what to expect in the device tree :
+ The typical Physical Port's Scsi_Host:
+ /sys/devices/.../host17/
+ and it has the typical decendent tree:
+ /sys/devices/.../host17/rport-17:0-0/target17:0:0/17:0:0:0:
+ and then the vport is created on the Physical Port:
+ /sys/devices/.../host17/vport-17:0-0
+ and the vport's Scsi_Host is then created:
+ /sys/devices/.../host17/vport-17:0-0/host18
+ and then the rest of the tree progresses, such as:
+ /sys/devices/.../host17/vport-17:0-0/host18/rport-18:0-0/target18:0:0/18:0:0:0:
+
+ Here's what to expect in the sysfs tree :
+ scsi_hosts:
+ /sys/class/scsi_host/host17 physical port's scsi_host
+ /sys/class/scsi_host/host18 vport's scsi_host
+ fc_hosts:
+ /sys/class/fc_host/host17 physical port's fc_host
+ /sys/class/fc_host/host18 vport's fc_host
+ fc_vports:
+ /sys/class/fc_vports/vport-17:0-0 the vport's fc_vport
+ fc_rports:
+ /sys/class/fc_remote_ports/rport-17:0-0 rport on the physical port
+ /sys/class/fc_remote_ports/rport-18:0-0 rport on the vport
+
+
+Vport Attributes:
+-------------------------------
+
+ The new fc_vport class object has the following attributes
+
+ node_name: Read_Only
+ The WWNN of the vport
+
+ port_name: Read_Only
+ The WWPN of the vport
+
+ roles: Read_Only
+ Indicates the FC4 roles enabled on the vport.
+
+ symbolic_name: Read_Write
+ A string, appended to the driver's symbolic port name string, which
+ is registered with the switch to identify the vport. For example,
+ a hypervisor could set this string to "Xen Domain 2 VM 5 Vport 2",
+ and this set of identifiers can be seen on switch management screens
+ to identify the port.
+
+ vport_delete: Write_Only
+ When written with a "1", will tear down the vport.
+
+ vport_disable: Write_Only
+ When written with a "1", will transition the vport to a disabled.
+ state. The vport will still be instantiated with the Linux kernel,
+ but it will not be active on the FC link.
+ When written with a "0", will enable the vport.
+
+ vport_last_state: Read_Only
+ Indicates the previous state of the vport. See the section below on
+ "Vport States".
+
+ vport_state: Read_Only
+ Indicates the state of the vport. See the section below on
+ "Vport States".
+
+ vport_type: Read_Only
+ Reflects the FC mechanism used to create the virtual port.
+ Only NPIV is supported currently.
+
+
+ For the fc_host class object, the following attributes are added for vports:
+
+ max_npiv_vports: Read_Only
+ Indicates the maximum number of NPIV-based vports that the
+ driver/adapter can support on the fc_host.
+
+ npiv_vports_inuse: Read_Only
+ Indicates how many NPIV-based vports have been instantiated on the
+ fc_host.
+
+ vport_create: Write_Only
+ A "simple" create interface to instantiate a vport on an fc_host.
+ A "<WWPN>:<WWNN>" string is written to the attribute. The transport
+ then instantiates the vport object and calls the LLDD to create the
+ vport with the role of FCP_Initiator. Each WWN is specified as 16
+ hex characters and may *not* contain any prefixes (e.g. 0x, x, etc).
+
+ vport_delete: Write_Only
+ A "simple" delete interface to teardown a vport. A "<WWPN>:<WWNN>"
+ string is written to the attribute. The transport will locate the
+ vport on the fc_host with the same WWNs and tear it down. Each WWN
+ is specified as 16 hex characters and may *not* contain any prefixes
+ (e.g. 0x, x, etc).
+
+
+Vport States:
+-------------------------------
+
+ Vport instantiation consists of two parts:
+ - Creation with the kernel and LLDD. This means all transport and
+ driver data structures are built up, and device objects created.
+ This is equivalent to a driver "attach" on an adapter, which is
+ independent of the adapter's link state.
+ - Instantiation of the vport on the FC link via ELS traffic, etc.
+ This is equivalent to a "link up" and successfull link initialization.
+ Futher information can be found in the interfaces section below for
+ Vport Creation.
+
+ Once a vport has been instantiated with the kernel/LLDD, a vport state
+ can be reported via the sysfs attribute. The following states exist:
+
+ FC_VPORT_UNKNOWN - Unknown
+ An temporary state, typically set only while the vport is being
+ instantiated with the kernel and LLDD.
+
+ FC_VPORT_ACTIVE - Active
+ The vport has been successfully been created on the FC link.
+ It is fully functional.
+
+ FC_VPORT_DISABLED - Disabled
+ The vport instantiated, but "disabled". The vport is not instantiated
+ on the FC link. This is equivalent to a physical port with the
+ link "down".
+
+ FC_VPORT_LINKDOWN - Linkdown
+ The vport is not operational as the physical link is not operational.
+
+ FC_VPORT_INITIALIZING - Initializing
+ The vport is in the process of instantiating on the FC link.
+ The LLDD will set this state just prior to starting the ELS traffic
+ to create the vport. This state will persist until the vport is
+ successfully created (state becomes FC_VPORT_ACTIVE) or it fails
+ (state is one of the values below). As this state is transitory,
+ it will not be preserved in the "vport_last_state".
+
+ FC_VPORT_NO_FABRIC_SUPP - No Fabric Support
+ The vport is not operational. One of the following conditions were
+ encountered:
+ - The FC topology is not Point-to-Point
+ - The FC port is not connected to an F_Port
+ - The F_Port has indicated that NPIV is not supported.
+
+ FC_VPORT_NO_FABRIC_RSCS - No Fabric Resources
+ The vport is not operational. The Fabric failed FDISC with a status
+ indicating that it does not have sufficient resources to complete
+ the operation.
+
+ FC_VPORT_FABRIC_LOGOUT - Fabric Logout
+ The vport is not operational. The Fabric has LOGO'd the N_Port_ID
+ associated with the vport.
+
+ FC_VPORT_FABRIC_REJ_WWN - Fabric Rejected WWN
+ The vport is not operational. The Fabric failed FDISC with a status
+ indicating that the WWN's are not valid.
+
+ FC_VPORT_FAILED - VPort Failed
+ The vport is not operational. This is a catchall for all other
+ error conditions.
+
+
+ The following state table indicates the different state transitions:
+
+ State Event New State
+ --------------------------------------------------------------------
+ n/a Initialization Unknown
+ Unknown: Link Down Linkdown
+ Link Up & Loop No Fabric Support
+ Link Up & no Fabric No Fabric Support
+ Link Up & FLOGI response No Fabric Support
+ indicates no NPIV support
+ Link Up & FDISC being sent Initializing
+ Disable request Disable
+ Linkdown: Link Up Unknown
+ Initializing: FDISC ACC Active
+ FDISC LS_RJT w/ no resources No Fabric Resources
+ FDISC LS_RJT w/ invalid Fabric Rejected WWN
+ pname or invalid nport_id
+ FDISC LS_RJT failed for Vport Failed
+ other reasons
+ Link Down Linkdown
+ Disable request Disable
+ Disable: Enable request Unknown
+ Active: LOGO received from fabric Fabric Logout
+ Link Down Linkdown
+ Disable request Disable
+ Fabric Logout: Link still up Unknown
+
+ The following 4 error states all have the same transitions:
+ No Fabric Support:
+ No Fabric Resources:
+ Fabric Rejected WWN:
+ Vport Failed:
+ Disable request Disable
+ Link goes down Linkdown
+
+
+Transport <-> LLDD Interfaces :
+-------------------------------
+
+Vport support by LLDD:
+
+ The LLDD indicates support for vports by supplying a vport_create()
+ function in the transport template. The presense of this function will
+ cause the creation of the new attributes on the fc_host. As part of
+ the physical port completing its initialization relative to the
+ transport, it should set the max_npiv_vports attribute to indicate the
+ maximum number of vports the driver and/or adapter supports.
+
+
+Vport Creation:
+
+ The LLDD vport_create() syntax is:
+
+ int vport_create(struct fc_vport *vport, bool disable)
+
+ where:
+ vport: Is the newly allocated vport object
+ disable: If "true", the vport is to be created in a disabled stated.
+ If "false", the vport is to be enabled upon creation.
+
+ When a request is made to create a new vport (via sgio/netlink, or the
+ vport_create fc_host attribute), the transport will validate that the LLDD
+ can support another vport (e.g. max_npiv_vports > npiv_vports_inuse).
+ If not, the create request will be failed. If space remains, the transport
+ will increment the vport count, create the vport object, and then call the
+ LLDD's vport_create() function with the newly allocated vport object.
+
+ As mentioned above, vport creation is divided into two parts:
+ - Creation with the kernel and LLDD. This means all transport and
+ driver data structures are built up, and device objects created.
+ This is equivalent to a driver "attach" on an adapter, which is
+ independent of the adapter's link state.
+ - Instantiation of the vport on the FC link via ELS traffic, etc.
+ This is equivalent to a "link up" and successfull link initialization.
+
+ The LLDD's vport_create() function will not synchronously wait for both
+ parts to be fully completed before returning. It must validate that the
+ infrastructure exists to support NPIV, and complete the first part of
+ vport creation (data structure build up) before returning. We do not
+ hinge vport_create() on the link-side operation mainly because:
+ - The link may be down. It is not a failure if it is. It simply
+ means the vport is in an inoperable state until the link comes up.
+ This is consistent with the link bouncing post vport creation.
+ - The vport may be created in a disabled state.
+ - This is consistent with a model where: the vport equates to a
+ FC adapter. The vport_create is synonymous with driver attachment
+ to the adapter, which is independent of link state.
+
+ Note: special error codes have been defined to delineate infrastructure
+ failure cases for quicker resolution.
+
+ The expected behavior for the LLDD's vport_create() function is:
+ - Validate Infrastructure:
+ - If the driver or adapter cannot support another vport, whether
+ due to improper firmware, (a lie about) max_npiv, or a lack of
+ some other resource - return VPCERR_UNSUPPORTED.
+ - If the driver validates the WWN's against those already active on
+ the adapter and detects an overlap - return VPCERR_BAD_WWN.
+ - If the driver detects the topology is loop, non-fabric, or the
+ FLOGI did not support NPIV - return VPCERR_NO_FABRIC_SUPP.
+ - Allocate data structures. If errors are encountered, such as out
+ of memory conditions, return the respective negative Exxx error code.
+ - If the role is FCP Initiator, the LLDD is to :
+ - Call scsi_host_alloc() to allocate a scsi_host for the vport.
+ - Call scsi_add_host(new_shost, &vport->dev) to start the scsi_host
+ and bind it as a child of the vport device.
+ - Initializes the fc_host attribute values.
+ - Kick of further vport state transitions based on the disable flag and
+ link state - and return success (zero).
+
+ LLDD Implementers Notes:
+ - It is suggested that there be a different fc_function_templates for
+ the physical port and the virtual port. The physical port's template
+ would have the vport_create, vport_delete, and vport_disable functions,
+ while the vports would not.
+ - It is suggested that there be different scsi_host_templates
+ for the physical port and virtual port. Likely, there are driver
+ attributes, embedded into the scsi_host_template, that are applicable
+ for the physical port only (link speed, topology setting, etc). This
+ ensures that the attributes are applicable to the respective scsi_host.
+
+
+Vport Disable/Enable:
+
+ The LLDD vport_disable() syntax is:
+
+ int vport_disable(struct fc_vport *vport, bool disable)
+
+ where:
+ vport: Is vport to to be enabled or disabled
+ disable: If "true", the vport is to be disabled.
+ If "false", the vport is to be enabled.
+
+ When a request is made to change the disabled state on a vport, the
+ transport will validate the request against the existing vport state.
+ If the request is to disable and the vport is already disabled, the
+ request will fail. Similarly, if the request is to enable, and the
+ vport is not in a disabled state, the request will fail. If the request
+ is valid for the vport state, the transport will call the LLDD to
+ change the vport's state.
+
+ Within the LLDD, if a vport is disabled, it remains instantiated with
+ the kernel and LLDD, but it is not active or visible on the FC link in
+ any way. (see Vport Creation and the 2 part instantiation discussion).
+ The vport will remain in this state until it is deleted or re-enabled.
+ When enabling a vport, the LLDD reinstantiates the vport on the FC
+ link - essentially restarting the LLDD statemachine (see Vport States
+ above).
+
+
+Vport Deletion:
+
+ The LLDD vport_delete() syntax is:
+
+ int vport_delete(struct fc_vport *vport)
+
+ where:
+ vport: Is vport to delete
+
+ When a request is made to delete a vport (via sgio/netlink, or via the
+ fc_host or fc_vport vport_delete attributes), the transport will call
+ the LLDD to terminate the vport on the FC link, and teardown all other
+ datastructures and references. If the LLDD completes successfully,
+ the transport will teardown the vport objects and complete the vport
+ removal. If the LLDD delete request fails, the vport object will remain,
+ but will be in an indeterminate state.
+
+ Within the LLDD, the normal code paths for a scsi_host teardown should
+ be followed. E.g. If the vport has a FCP Initiator role, the LLDD
+ will call fc_remove_host() for the vports scsi_host, followed by
+ scsi_remove_host() and scsi_host_put() for the vports scsi_host.
+
+
+Other:
+ fc_host port_type attribute:
+ There is a new fc_host port_type value - FC_PORTTYPE_NPIV. This value
+ must be set on all vport-based fc_hosts. Normally, on a physical port,
+ the port_type attribute would be set to NPORT, NLPORT, etc based on the
+ topology type and existence of the fabric. As this is not applicable to
+ a vport, it makes more sense to report the FC mechanism used to create
+ the vport.
+
+ Driver unload:
+ FC drivers are required to call fc_remove_host() prior to calling
+ scsi_remove_host(). This allows the fc_host to tear down all remote
+ ports prior the scsi_host being torn down. The fc_remove_host() call
+ was updated to remove all vports for the fc_host as well.
+
+
+Credits
+=======
+The following people have contributed to this document:
+
+
+
+
+
+
+James Smart
+james.smart@emulex.com
+
diff --git a/MAINTAINERS b/MAINTAINERS
index f57f6e0..3914269 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2330,6 +2330,12 @@
T: git kernel.org:/pub/scm/linux/kernel/git/jbenc/mac80211.git
S: Maintained
+MACVLAN DRIVER
+P: Patrick McHardy
+M: kaber@trash.net
+L: netdev@vger.kernel.org
+S: Maintained
+
MARVELL YUKON / SYSKONNECT DRIVER
P: Mirko Lindner
M: mlindner@syskonnect.de
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 470db6e..a031d99 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -176,7 +176,7 @@
return;
cascade_irq = irq_of_parse_and_map(cascade, 0);
- if (cascade == NO_IRQ) {
+ if (cascade_irq == NO_IRQ) {
printk(KERN_ERR "mpic: failed to map cascade interrupt");
return;
}
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 68441e0..143ed8e 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -19,7 +19,7 @@
AFLAGS += -m31
UTS_MACHINE := s390
STACK_SIZE := 8192
-CHECKFLAGS += -D__s390__
+CHECKFLAGS += -D__s390__ -msize-long
else
LDFLAGS := -m elf64_s390
MODFLAGS += -fpic -D__PIC__
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 9a13b24..8b8f136 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -295,8 +295,8 @@
static struct subsys_attribute sys_ipl_device_attr =
__ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
-static ssize_t ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
{
unsigned int size = IPL_PARMBLOCK_SIZE;
@@ -317,8 +317,8 @@
.read = &ipl_parameter_read,
};
-static ssize_t ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+static ssize_t ipl_scp_data_read(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
{
unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len;
void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data;
@@ -337,7 +337,7 @@
.mode = S_IRUGO,
},
.size = PAGE_SIZE,
- .read = &ipl_scp_data_read,
+ .read = ipl_scp_data_read,
};
/* FCP ipl device attributes */
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 07090e9..3d1a1e2 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -12,9 +12,7 @@
#
# Cryptographic API Configuration
#
-menu "Cryptographic options"
-
-config CRYPTO
+menuconfig CRYPTO
bool "Cryptographic API"
help
This option provides the core Cryptographic API.
@@ -473,5 +471,3 @@
source "drivers/crypto/Kconfig"
endif # if CRYPTO
-
-endmenu
diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c
index 9348ddd..1c166b4 100644
--- a/crypto/ablkcipher.c
+++ b/crypto/ablkcipher.c
@@ -19,16 +19,41 @@
#include <linux/module.h>
#include <linux/seq_file.h>
+static int setkey_unaligned(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen)
+{
+ struct ablkcipher_alg *cipher = crypto_ablkcipher_alg(tfm);
+ unsigned long alignmask = crypto_ablkcipher_alignmask(tfm);
+ int ret;
+ u8 *buffer, *alignbuffer;
+ unsigned long absize;
+
+ absize = keylen + alignmask;
+ buffer = kmalloc(absize, GFP_ATOMIC);
+ if (!buffer)
+ return -ENOMEM;
+
+ alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ memcpy(alignbuffer, key, keylen);
+ ret = cipher->setkey(tfm, alignbuffer, keylen);
+ memset(alignbuffer, 0, absize);
+ kfree(buffer);
+ return ret;
+}
+
static int setkey(struct crypto_ablkcipher *tfm, const u8 *key,
unsigned int keylen)
{
struct ablkcipher_alg *cipher = crypto_ablkcipher_alg(tfm);
+ unsigned long alignmask = crypto_ablkcipher_alignmask(tfm);
if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) {
crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
return -EINVAL;
}
+ if ((unsigned long)key & alignmask)
+ return setkey_unaligned(tfm, key, keylen);
+
return cipher->setkey(tfm, key, keylen);
}
@@ -66,8 +91,10 @@
seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize);
seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize);
seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize);
- seq_printf(m, "qlen : %u\n", ablkcipher->queue->qlen);
- seq_printf(m, "max qlen : %u\n", ablkcipher->queue->max_qlen);
+ if (ablkcipher->queue) {
+ seq_printf(m, "qlen : %u\n", ablkcipher->queue->qlen);
+ seq_printf(m, "max qlen : %u\n", ablkcipher->queue->max_qlen);
+ }
}
const struct crypto_type crypto_ablkcipher_type = {
diff --git a/crypto/algapi.c b/crypto/algapi.c
index f137a432..38aa9e99 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -34,7 +34,7 @@
if (alg) {
if (crypto_is_larval(alg)) {
struct crypto_larval *larval = (void *)alg;
- complete(&larval->completion);
+ complete_all(&larval->completion);
}
crypto_mod_put(alg);
}
@@ -164,7 +164,7 @@
continue;
larval->adult = alg;
- complete(&larval->completion);
+ complete_all(&larval->completion);
continue;
}
diff --git a/crypto/api.c b/crypto/api.c
index 33734fd..4ccc5af 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -144,7 +144,7 @@
down_write(&crypto_alg_sem);
list_del(&alg->cra_list);
up_write(&crypto_alg_sem);
- complete(&larval->completion);
+ complete_all(&larval->completion);
crypto_alg_put(alg);
}
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index 8edf40c..40a3dcf 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -336,16 +336,41 @@
return blkcipher_walk_next(desc, walk);
}
+static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+{
+ struct blkcipher_alg *cipher = &tfm->__crt_alg->cra_blkcipher;
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+ int ret;
+ u8 *buffer, *alignbuffer;
+ unsigned long absize;
+
+ absize = keylen + alignmask;
+ buffer = kmalloc(absize, GFP_ATOMIC);
+ if (!buffer)
+ return -ENOMEM;
+
+ alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ memcpy(alignbuffer, key, keylen);
+ ret = cipher->setkey(tfm, alignbuffer, keylen);
+ memset(alignbuffer, 0, absize);
+ kfree(buffer);
+ return ret;
+}
+
static int setkey(struct crypto_tfm *tfm, const u8 *key,
unsigned int keylen)
{
struct blkcipher_alg *cipher = &tfm->__crt_alg->cra_blkcipher;
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) {
tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
}
+ if ((unsigned long)key & alignmask)
+ return setkey_unaligned(tfm, key, keylen);
+
return cipher->setkey(tfm, key, keylen);
}
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 333aab2f..0b2650c 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -20,16 +20,43 @@
#include <linux/string.h>
#include "internal.h"
+static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+{
+ struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+ int ret;
+ u8 *buffer, *alignbuffer;
+ unsigned long absize;
+
+ absize = keylen + alignmask;
+ buffer = kmalloc(absize, GFP_ATOMIC);
+ if (!buffer)
+ return -ENOMEM;
+
+ alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ memcpy(alignbuffer, key, keylen);
+ ret = cia->cia_setkey(tfm, alignbuffer, keylen);
+ memset(alignbuffer, 0, absize);
+ kfree(buffer);
+ return ret;
+
+}
+
static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
{
struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
-
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+
tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) {
tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
- } else
- return cia->cia_setkey(tfm, key, keylen);
+ }
+
+ if ((unsigned long)key & alignmask)
+ return setkey_unaligned(tfm, key, keylen);
+
+ return cia->cia_setkey(tfm, key, keylen);
}
static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *,
diff --git a/crypto/hash.c b/crypto/hash.c
index 4ccd22d..4d75ca7 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -22,6 +22,42 @@
return alg->cra_ctxsize;
}
+static int hash_setkey_unaligned(struct crypto_hash *crt, const u8 *key,
+ unsigned int keylen)
+{
+ struct crypto_tfm *tfm = crypto_hash_tfm(crt);
+ struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
+ unsigned long alignmask = crypto_hash_alignmask(crt);
+ int ret;
+ u8 *buffer, *alignbuffer;
+ unsigned long absize;
+
+ absize = keylen + alignmask;
+ buffer = kmalloc(absize, GFP_ATOMIC);
+ if (!buffer)
+ return -ENOMEM;
+
+ alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ memcpy(alignbuffer, key, keylen);
+ ret = alg->setkey(crt, alignbuffer, keylen);
+ memset(alignbuffer, 0, absize);
+ kfree(buffer);
+ return ret;
+}
+
+static int hash_setkey(struct crypto_hash *crt, const u8 *key,
+ unsigned int keylen)
+{
+ struct crypto_tfm *tfm = crypto_hash_tfm(crt);
+ struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
+ unsigned long alignmask = crypto_hash_alignmask(crt);
+
+ if ((unsigned long)key & alignmask)
+ return hash_setkey_unaligned(crt, key, keylen);
+
+ return alg->setkey(crt, key, keylen);
+}
+
static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
{
struct hash_tfm *crt = &tfm->crt_hash;
@@ -34,7 +70,7 @@
crt->update = alg->update;
crt->final = alg->final;
crt->digest = alg->digest;
- crt->setkey = alg->setkey;
+ crt->setkey = hash_setkey;
crt->digestsize = alg->digestsize;
return 0;
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 90961a8..4aca7dd 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -555,7 +555,6 @@
{
struct scsi_cmnd *cmd;
ctlr_info_t *ctlr;
- u64bit addr64;
ErrorInfo_struct *ei;
ei = cp->err_info;
@@ -569,20 +568,7 @@
cmd = (struct scsi_cmnd *) cp->scsi_cmd;
ctlr = hba[cp->ctlr];
- /* undo the DMA mappings */
-
- if (cmd->use_sg) {
- pci_unmap_sg(ctlr->pdev,
- cmd->request_buffer, cmd->use_sg,
- cmd->sc_data_direction);
- }
- else if (cmd->request_bufflen) {
- addr64.val32.lower = cp->SG[0].Addr.lower;
- addr64.val32.upper = cp->SG[0].Addr.upper;
- pci_unmap_single(ctlr->pdev, (dma_addr_t) addr64.val,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
cmd->result = (DID_OK << 16); /* host byte */
cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
@@ -597,7 +583,7 @@
ei->SenseLen > SCSI_SENSE_BUFFERSIZE ?
SCSI_SENSE_BUFFERSIZE :
ei->SenseLen);
- cmd->resid = ei->ResidualCnt;
+ scsi_set_resid(cmd, ei->ResidualCnt);
if(ei->CommandStatus != 0)
{ /* an error has occurred */
@@ -1204,46 +1190,29 @@
CommandList_struct *cp,
struct scsi_cmnd *cmd)
{
- unsigned int use_sg, nsegs=0, len;
- struct scatterlist *scatter = (struct scatterlist *) cmd->request_buffer;
+ unsigned int len;
+ struct scatterlist *sg;
__u64 addr64;
+ int use_sg, i;
- /* is it just one virtual address? */
- if (!cmd->use_sg) {
- if (cmd->request_bufflen) { /* anything to xfer? */
+ BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES);
- addr64 = (__u64) pci_map_single(pdev,
- cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
-
- cp->SG[0].Addr.lower =
- (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
- cp->SG[0].Addr.upper =
- (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
- cp->SG[0].Len = cmd->request_bufflen;
- nsegs=1;
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg) { /* not too many addrs? */
+ scsi_for_each_sg(cmd, sg, use_sg, i) {
+ addr64 = (__u64) sg_dma_address(sg);
+ len = sg_dma_len(sg);
+ cp->SG[i].Addr.lower =
+ (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[i].Addr.upper =
+ (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[i].Len = len;
+ cp->SG[i].Ext = 0; // we are not chaining
}
- } /* else, must be a list of virtual addresses.... */
- else if (cmd->use_sg <= MAXSGENTRIES) { /* not too many addrs? */
+ }
- use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg,
- cmd->sc_data_direction);
-
- for (nsegs=0; nsegs < use_sg; nsegs++) {
- addr64 = (__u64) sg_dma_address(&scatter[nsegs]);
- len = sg_dma_len(&scatter[nsegs]);
- cp->SG[nsegs].Addr.lower =
- (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
- cp->SG[nsegs].Addr.upper =
- (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
- cp->SG[nsegs].Len = len;
- cp->SG[nsegs].Ext = 0; // we are not chaining
- }
- } else BUG();
-
- cp->Header.SGList = (__u8) nsegs; /* no. SGs contig in this cmd */
- cp->Header.SGTotal = (__u16) nsegs; /* total sgs in this cmd list */
+ cp->Header.SGList = (__u8) use_sg; /* no. SGs contig in this cmd */
+ cp->Header.SGTotal = (__u16) use_sg; /* total sgs in this cmd list */
return;
}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index fcde9ba..1c77e14 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -560,7 +560,7 @@
will be called i2c-versatile.
config I2C_ACORN
- bool "Acorn IOC/IOMD I2C bus support"
+ tristate "Acorn IOC/IOMD I2C bus support"
depends on ARCH_ACORN
default y
select I2C_ALGOBIT
diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c
index 09bd7f4..7c2be35 100644
--- a/drivers/i2c/busses/i2c-acorn.c
+++ b/drivers/i2c/busses/i2c-acorn.c
@@ -94,4 +94,4 @@
return i2c_bit_add_bus(&ioc_ops);
}
-__initcall(i2c_ioc_init);
+module_init(i2c_ioc_init);
diff --git a/drivers/i2c/chips/ds1682.c b/drivers/i2c/chips/ds1682.c
index 25fd467..5879f0f 100644
--- a/drivers/i2c/chips/ds1682.c
+++ b/drivers/i2c/chips/ds1682.c
@@ -140,8 +140,8 @@
/*
* User data attribute
*/
-static ssize_t ds1682_eeprom_read(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+static ssize_t ds1682_eeprom_read(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
{
struct i2c_client *client = kobj_to_i2c_client(kobj);
int rc;
@@ -163,8 +163,8 @@
return count;
}
-static ssize_t ds1682_eeprom_write(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+static ssize_t ds1682_eeprom_write(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
{
struct i2c_client *client = kobj_to_i2c_client(kobj);
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index 444a0b8..c89b5f4 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -18,10 +18,10 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/scatterlist.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <asm/ecard.h>
-#include <asm/io.h>
#define ICS_IDENT_OFFSET 0x2280
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index c4d3d41..51a1206 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -283,7 +283,7 @@
memcpy(buf, \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(class->td_kv), \
len); \
- while ((buf + len - 1) == '\0') \
+ while (buf[len - 1] == '\0') \
len--; \
buf[len++] = '\n'; \
buf[len] = '\0'; \
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index e0c385a..e882cb9 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -1509,69 +1509,6 @@
}
}
-static void sbp2_prep_command_orb_no_sg(struct sbp2_command_orb *orb,
- struct sbp2_fwhost_info *hi,
- struct sbp2_command_info *cmd,
- struct scatterlist *sgpnt,
- u32 orb_direction,
- unsigned int scsi_request_bufflen,
- void *scsi_request_buffer,
- enum dma_data_direction dma_dir)
-{
- cmd->dma_dir = dma_dir;
- cmd->dma_size = scsi_request_bufflen;
- cmd->dma_type = CMD_DMA_SINGLE;
- cmd->cmd_dma = dma_map_single(hi->host->device.parent,
- scsi_request_buffer,
- cmd->dma_size, cmd->dma_dir);
- orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
- orb->misc |= ORB_SET_DIRECTION(orb_direction);
-
- /* handle case where we get a command w/o s/g enabled
- * (but check for transfers larger than 64K) */
- if (scsi_request_bufflen <= SBP2_MAX_SG_ELEMENT_LENGTH) {
-
- orb->data_descriptor_lo = cmd->cmd_dma;
- orb->misc |= ORB_SET_DATA_SIZE(scsi_request_bufflen);
-
- } else {
- /* The buffer is too large. Turn this into page tables. */
-
- struct sbp2_unrestricted_page_table *sg_element =
- &cmd->scatter_gather_element[0];
- u32 sg_count, sg_len;
- dma_addr_t sg_addr;
-
- orb->data_descriptor_lo = cmd->sge_dma;
- orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
-
- /* fill out our SBP-2 page tables; split up the large buffer */
- sg_count = 0;
- sg_len = scsi_request_bufflen;
- sg_addr = cmd->cmd_dma;
- while (sg_len) {
- sg_element[sg_count].segment_base_lo = sg_addr;
- if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) {
- sg_element[sg_count].length_segment_base_hi =
- PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH);
- sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH;
- sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH;
- } else {
- sg_element[sg_count].length_segment_base_hi =
- PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len);
- sg_len = 0;
- }
- sg_count++;
- }
-
- orb->misc |= ORB_SET_DATA_SIZE(sg_count);
-
- sbp2util_cpu_to_be32_buffer(sg_element,
- (sizeof(struct sbp2_unrestricted_page_table)) *
- sg_count);
- }
-}
-
static void sbp2_create_command_orb(struct sbp2_lu *lu,
struct sbp2_command_info *cmd,
unchar *scsi_cmd,
@@ -1615,13 +1552,9 @@
orb->data_descriptor_hi = 0x0;
orb->data_descriptor_lo = 0x0;
orb->misc |= ORB_SET_DIRECTION(1);
- } else if (scsi_use_sg)
+ } else
sbp2_prep_command_orb_sg(orb, hi, cmd, scsi_use_sg, sgpnt,
orb_direction, dma_dir);
- else
- sbp2_prep_command_orb_no_sg(orb, hi, cmd, sgpnt, orb_direction,
- scsi_request_bufflen,
- scsi_request_buffer, dma_dir);
sbp2util_cpu_to_be32_buffer(orb, sizeof(*orb));
@@ -1710,15 +1643,15 @@
void (*done)(struct scsi_cmnd *))
{
unchar *scsi_cmd = (unchar *)SCpnt->cmnd;
- unsigned int request_bufflen = SCpnt->request_bufflen;
+ unsigned int request_bufflen = scsi_bufflen(SCpnt);
struct sbp2_command_info *cmd;
cmd = sbp2util_allocate_command_orb(lu, SCpnt, done);
if (!cmd)
return -EIO;
- sbp2_create_command_orb(lu, cmd, scsi_cmd, SCpnt->use_sg,
- request_bufflen, SCpnt->request_buffer,
+ sbp2_create_command_orb(lu, cmd, scsi_cmd, scsi_sg_count(SCpnt),
+ request_bufflen, scsi_sglist(SCpnt),
SCpnt->sc_data_direction);
sbp2_link_orb_command(lu, cmd);
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index dd221ed..effdee2 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -134,19 +134,9 @@
{
struct iscsi_iser_conn *iser_conn = ctask->conn->dd_data;
struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
- struct scsi_cmnd *sc = ctask->sc;
iser_ctask->command_sent = 0;
iser_ctask->iser_conn = iser_conn;
-
- if (sc->sc_data_direction == DMA_TO_DEVICE) {
- BUG_ON(ctask->total_length == 0);
-
- debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
- ctask->itt, ctask->total_length, ctask->imm_count,
- ctask->unsol_count);
- }
-
iser_ctask_rdma_init(iser_ctask);
}
@@ -219,6 +209,14 @@
struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
int error = 0;
+ if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) {
+ BUG_ON(scsi_bufflen(ctask->sc) == 0);
+
+ debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
+ ctask->itt, scsi_bufflen(ctask->sc),
+ ctask->imm_count, ctask->unsol_count);
+ }
+
debug_scsi("ctask deq [cid %d itt 0x%x]\n",
conn->id, ctask->itt);
@@ -375,7 +373,8 @@
static struct iscsi_cls_session *
iscsi_iser_session_create(struct iscsi_transport *iscsit,
struct scsi_transport_template *scsit,
- uint32_t initial_cmdsn, uint32_t *hostno)
+ uint16_t cmds_max, uint16_t qdepth,
+ uint32_t initial_cmdsn, uint32_t *hostno)
{
struct iscsi_cls_session *cls_session;
struct iscsi_session *session;
@@ -386,7 +385,13 @@
struct iscsi_iser_cmd_task *iser_ctask;
struct iser_desc *desc;
+ /*
+ * we do not support setting can_queue cmd_per_lun from userspace yet
+ * because we preallocate so many resources
+ */
cls_session = iscsi_session_setup(iscsit, scsit,
+ ISCSI_DEF_XMIT_CMDS_MAX,
+ ISCSI_MAX_CMD_PER_LUN,
sizeof(struct iscsi_iser_cmd_task),
sizeof(struct iser_desc),
initial_cmdsn, &hn);
@@ -545,7 +550,7 @@
static struct scsi_host_template iscsi_iser_sht = {
.name = "iSCSI Initiator over iSER, v." DRV_VER,
.queuecommand = iscsi_queuecommand,
- .can_queue = ISCSI_XMIT_CMDS_MAX - 1,
+ .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1,
.sg_tablesize = ISCSI_ISER_SG_TABLESIZE,
.max_sectors = 1024,
.cmd_per_lun = ISCSI_MAX_CMD_PER_LUN,
@@ -574,8 +579,12 @@
ISCSI_EXP_STATSN |
ISCSI_PERSISTENT_PORT |
ISCSI_PERSISTENT_ADDRESS |
- ISCSI_TARGET_NAME |
- ISCSI_TPGT,
+ ISCSI_TARGET_NAME | ISCSI_TPGT |
+ ISCSI_USERNAME | ISCSI_PASSWORD |
+ ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
+ .host_param_mask = ISCSI_HOST_HWADDRESS |
+ ISCSI_HOST_NETDEV_NAME |
+ ISCSI_HOST_INITIATOR_NAME,
.host_template = &iscsi_iser_sht,
.conndata_size = sizeof(struct iscsi_conn),
.max_lun = ISCSI_ISER_MAX_LUN,
@@ -592,6 +601,9 @@
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_iser_conn_start,
.stop_conn = iscsi_conn_stop,
+ /* iscsi host params */
+ .get_host_param = iscsi_host_get_param,
+ .set_host_param = iscsi_host_set_param,
/* IO */
.send_pdu = iscsi_conn_send_pdu,
.get_stats = iscsi_iser_conn_get_stats,
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 8960196..e235370 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -98,7 +98,7 @@
#define ISER_MAX_TX_MISC_PDUS 6 /* NOOP_OUT(2), TEXT(1), *
* SCSI_TMFUNC(2), LOGOUT(1) */
-#define ISER_QP_MAX_RECV_DTOS (ISCSI_XMIT_CMDS_MAX + \
+#define ISER_QP_MAX_RECV_DTOS (ISCSI_DEF_XMIT_CMDS_MAX + \
ISER_MAX_RX_MISC_PDUS + \
ISER_MAX_TX_MISC_PDUS)
@@ -110,7 +110,7 @@
#define ISER_INFLIGHT_DATAOUTS 8
-#define ISER_QP_MAX_REQ_DTOS (ISCSI_XMIT_CMDS_MAX * \
+#define ISER_QP_MAX_REQ_DTOS (ISCSI_DEF_XMIT_CMDS_MAX * \
(1 + ISER_INFLIGHT_DATAOUTS) + \
ISER_MAX_TX_MISC_PDUS + \
ISER_MAX_RX_MISC_PDUS)
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 3651072..9ea5b9a 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -351,18 +351,12 @@
else
data_buf = &iser_ctask->data[ISER_DIR_OUT];
- if (sc->use_sg) { /* using a scatter list */
- data_buf->buf = sc->request_buffer;
- data_buf->size = sc->use_sg;
- } else if (sc->request_bufflen) {
- /* using a single buffer - convert it into one entry SG */
- sg_init_one(&data_buf->sg_single,
- sc->request_buffer, sc->request_bufflen);
- data_buf->buf = &data_buf->sg_single;
- data_buf->size = 1;
+ if (scsi_sg_count(sc)) { /* using a scatter list */
+ data_buf->buf = scsi_sglist(sc);
+ data_buf->size = scsi_sg_count(sc);
}
- data_buf->data_len = sc->request_bufflen;
+ data_buf->data_len = scsi_bufflen(sc);
if (hdr->flags & ISCSI_FLAG_CMD_READ) {
err = iser_prepare_read_cmd(ctask, edtl);
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 3702e23..2044de1 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -155,8 +155,8 @@
params.max_pages_per_fmr = ISCSI_ISER_SG_TABLESIZE + 1;
/* make the pool size twice the max number of SCSI commands *
* the ML is expected to queue, watermark for unmap at 50% */
- params.pool_size = ISCSI_XMIT_CMDS_MAX * 2;
- params.dirty_watermark = ISCSI_XMIT_CMDS_MAX;
+ params.pool_size = ISCSI_DEF_XMIT_CMDS_MAX * 2;
+ params.dirty_watermark = ISCSI_DEF_XMIT_CMDS_MAX;
params.cache = 0;
params.flush_function = NULL;
params.access = (IB_ACCESS_LOCAL_WRITE |
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 39bf057..f01ca18 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -455,10 +455,7 @@
struct srp_target_port *target,
struct srp_request *req)
{
- struct scatterlist *scat;
- int nents;
-
- if (!scmnd->request_buffer ||
+ if (!scsi_sglist(scmnd) ||
(scmnd->sc_data_direction != DMA_TO_DEVICE &&
scmnd->sc_data_direction != DMA_FROM_DEVICE))
return;
@@ -468,20 +465,8 @@
req->fmr = NULL;
}
- /*
- * This handling of non-SG commands can be killed when the
- * SCSI midlayer no longer generates non-SG commands.
- */
- if (likely(scmnd->use_sg)) {
- nents = scmnd->use_sg;
- scat = scmnd->request_buffer;
- } else {
- nents = 1;
- scat = &req->fake_sg;
- }
-
- ib_dma_unmap_sg(target->srp_host->dev->dev, scat, nents,
- scmnd->sc_data_direction);
+ ib_dma_unmap_sg(target->srp_host->dev->dev, scsi_sglist(scmnd),
+ scsi_sg_count(scmnd), scmnd->sc_data_direction);
}
static void srp_remove_req(struct srp_target_port *target, struct srp_request *req)
@@ -595,6 +580,7 @@
int ret;
struct srp_device *dev = target->srp_host->dev;
struct ib_device *ibdev = dev->dev;
+ struct scatterlist *sg;
if (!dev->fmr_pool)
return -ENODEV;
@@ -604,16 +590,16 @@
return -EINVAL;
len = page_cnt = 0;
- for (i = 0; i < sg_cnt; ++i) {
- unsigned int dma_len = ib_sg_dma_len(ibdev, &scat[i]);
+ scsi_for_each_sg(req->scmnd, sg, sg_cnt, i) {
+ unsigned int dma_len = ib_sg_dma_len(ibdev, sg);
- if (ib_sg_dma_address(ibdev, &scat[i]) & ~dev->fmr_page_mask) {
+ if (ib_sg_dma_address(ibdev, sg) & ~dev->fmr_page_mask) {
if (i > 0)
return -EINVAL;
else
++page_cnt;
}
- if ((ib_sg_dma_address(ibdev, &scat[i]) + dma_len) &
+ if ((ib_sg_dma_address(ibdev, sg) + dma_len) &
~dev->fmr_page_mask) {
if (i < sg_cnt - 1)
return -EINVAL;
@@ -633,12 +619,12 @@
return -ENOMEM;
page_cnt = 0;
- for (i = 0; i < sg_cnt; ++i) {
- unsigned int dma_len = ib_sg_dma_len(ibdev, &scat[i]);
+ scsi_for_each_sg(req->scmnd, sg, sg_cnt, i) {
+ unsigned int dma_len = ib_sg_dma_len(ibdev, sg);
for (j = 0; j < dma_len; j += dev->fmr_page_size)
dma_pages[page_cnt++] =
- (ib_sg_dma_address(ibdev, &scat[i]) &
+ (ib_sg_dma_address(ibdev, sg) &
dev->fmr_page_mask) + j;
}
@@ -673,7 +659,7 @@
struct srp_device *dev;
struct ib_device *ibdev;
- if (!scmnd->request_buffer || scmnd->sc_data_direction == DMA_NONE)
+ if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE)
return sizeof (struct srp_cmd);
if (scmnd->sc_data_direction != DMA_FROM_DEVICE &&
@@ -683,18 +669,8 @@
return -EINVAL;
}
- /*
- * This handling of non-SG commands can be killed when the
- * SCSI midlayer no longer generates non-SG commands.
- */
- if (likely(scmnd->use_sg)) {
- nents = scmnd->use_sg;
- scat = scmnd->request_buffer;
- } else {
- nents = 1;
- scat = &req->fake_sg;
- sg_init_one(scat, scmnd->request_buffer, scmnd->request_bufflen);
- }
+ nents = scsi_sg_count(scmnd);
+ scat = scsi_sglist(scmnd);
dev = target->srp_host->dev;
ibdev = dev->dev;
@@ -724,6 +700,7 @@
* descriptor.
*/
struct srp_indirect_buf *buf = (void *) cmd->add_data;
+ struct scatterlist *sg;
u32 datalen = 0;
int i;
@@ -732,11 +709,11 @@
sizeof (struct srp_indirect_buf) +
count * sizeof (struct srp_direct_buf);
- for (i = 0; i < count; ++i) {
- unsigned int dma_len = ib_sg_dma_len(ibdev, &scat[i]);
+ scsi_for_each_sg(scmnd, sg, count, i) {
+ unsigned int dma_len = ib_sg_dma_len(ibdev, sg);
buf->desc_list[i].va =
- cpu_to_be64(ib_sg_dma_address(ibdev, &scat[i]));
+ cpu_to_be64(ib_sg_dma_address(ibdev, sg));
buf->desc_list[i].key =
cpu_to_be32(dev->mr->rkey);
buf->desc_list[i].len = cpu_to_be32(dma_len);
@@ -802,9 +779,9 @@
}
if (rsp->flags & (SRP_RSP_FLAG_DOOVER | SRP_RSP_FLAG_DOUNDER))
- scmnd->resid = be32_to_cpu(rsp->data_out_res_cnt);
+ scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt));
else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER))
- scmnd->resid = be32_to_cpu(rsp->data_in_res_cnt);
+ scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt));
if (!req->tsk_mgmt) {
scmnd->host_scribble = (void *) -1L;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 1d53c7b..e3573e7 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -106,11 +106,6 @@
struct srp_iu *cmd;
struct srp_iu *tsk_mgmt;
struct ib_pool_fmr *fmr;
- /*
- * Fake scatterlist used when scmnd->use_sg==0. Can be killed
- * when the SCSI midlayer no longer generates non-SG commands.
- */
- struct scatterlist fake_sg;
struct completion done;
short index;
u8 cmd_done;
diff --git a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h
deleted file mode 100644
index bb2bf5a..0000000
--- a/drivers/message/fusion/linux_compat.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/* drivers/message/fusion/linux_compat.h */
-
-#ifndef FUSION_LINUX_COMPAT_H
-#define FUSION_LINUX_COMPAT_H
-
-#include <linux/version.h>
-#include <scsi/scsi_device.h>
-
-#endif /* _LINUX_COMPAT_H */
diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h
index 75223bf..6a92e3d 100644
--- a/drivers/message/fusion/lsi/mpi.h
+++ b/drivers/message/fusion/lsi/mpi.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2006 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Logic Corporation.
*
*
* Name: mpi.h
* Title: MPI Message independent structures and definitions
* Creation Date: July 27, 2000
*
- * mpi.h Version: 01.05.12
+ * mpi.h Version: 01.05.13
*
* Version History
* ---------------
@@ -78,6 +78,7 @@
* 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target.
* 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT.
* 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT.
+ * 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -108,7 +109,7 @@
/* Note: The major versions of 0xe0 through 0xff are reserved */
/* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT (0x0E)
+#define MPI_HEADER_VERSION_UNIT (0x10)
#define MPI_HEADER_VERSION_DEV (0x00)
#define MPI_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI_HEADER_VERSION_UNIT_SHIFT (8)
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
index 0e4c8e7..eda7697 100644
--- a/drivers/message/fusion/lsi/mpi_cnfg.h
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2006 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Logic Corporation.
*
*
* Name: mpi_cnfg.h
* Title: MPI Config message, structures, and Pages
* Creation Date: July 27, 2000
*
- * mpi_cnfg.h Version: 01.05.13
+ * mpi_cnfg.h Version: 01.05.15
*
* Version History
* ---------------
@@ -293,6 +293,21 @@
* Added more AccessStatus values for SAS Device Page 0.
* Added bit for SATA Asynchronous Notification Support in
* Flags field of SAS Device Page 0.
+ * 02-28-07 01.05.14 Added ExtFlags field to Manufacturing Page 4.
+ * Added Disable SMART Polling for CapabilitiesFlags of
+ * IOC Page 6.
+ * Added Disable SMART Polling to DeviceSettings of BIOS
+ * Page 1.
+ * Added Multi-Port Domain bit for DiscoveryStatus field
+ * of SAS IO Unit Page.
+ * Added Multi-Port Domain Illegal flag for SAS IO Unit
+ * Page 1 AdditionalControlFlags field.
+ * 05-24-07 01.05.15 Added Hide Physical Disks with Non-Integrated RAID
+ * Metadata bit to Manufacturing Page 4 ExtFlags field.
+ * Added Internal Connector to End Device Present bit to
+ * Expander Page 0 Flags field.
+ * Fixed define for
+ * MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED.
* --------------------------------------------------------------------------
*/
@@ -639,7 +654,7 @@
U8 InfoSize1; /* 0Bh */
U8 InquirySize; /* 0Ch */
U8 Flags; /* 0Dh */
- U16 Reserved2; /* 0Eh */
+ U16 ExtFlags; /* 0Eh */
U8 InquiryData[56]; /* 10h */
U32 ISVolumeSettings; /* 48h */
U32 IMEVolumeSettings; /* 4Ch */
@@ -658,7 +673,7 @@
} CONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4,
ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t;
-#define MPI_MANUFACTURING4_PAGEVERSION (0x04)
+#define MPI_MANUFACTURING4_PAGEVERSION (0x05)
/* defines for the Flags field */
#define MPI_MANPAGE4_FORCE_BAD_BLOCK_TABLE (0x80)
@@ -670,6 +685,12 @@
#define MPI_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x02)
#define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01)
+/* defines for the ExtFlags field */
+#define MPI_MANPAGE4_EXTFLAGS_HIDE_NON_IR_METADATA (0x0008)
+#define MPI_MANPAGE4_EXTFLAGS_SAS_CACHE_DISABLE (0x0004)
+#define MPI_MANPAGE4_EXTFLAGS_SATA_CACHE_DISABLE (0x0002)
+#define MPI_MANPAGE4_EXTFLAGS_LEGACY_MODE (0x0001)
+
#ifndef MPI_MANPAGE5_NUM_FORCEWWID
#define MPI_MANPAGE5_NUM_FORCEWWID (1)
@@ -781,7 +802,7 @@
} CONFIG_PAGE_MANUFACTURING_9, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_9,
ManufacturingPage9_t, MPI_POINTER pManufacturingPage9_t;
-#define MPI_MANUFACTURING6_PAGEVERSION (0x00)
+#define MPI_MANUFACTURING9_PAGEVERSION (0x00)
typedef struct _CONFIG_PAGE_MANUFACTURING_10
@@ -1138,6 +1159,8 @@
/* IOC Page 6 Capabilities Flags */
+#define MPI_IOCPAGE6_CAP_FLAGS_DISABLE_SMART_POLLING (0x00000008)
+
#define MPI_IOCPAGE6_CAP_FLAGS_MASK_METADATA_SIZE (0x00000006)
#define MPI_IOCPAGE6_CAP_FLAGS_64MB_METADATA_SIZE (0x00000000)
#define MPI_IOCPAGE6_CAP_FLAGS_512MB_METADATA_SIZE (0x00000002)
@@ -1208,6 +1231,7 @@
#define MPI_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008)
/* values for the DeviceSettings field */
+#define MPI_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING (0x00000010)
#define MPI_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008)
#define MPI_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004)
#define MPI_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002)
@@ -2281,11 +2305,11 @@
typedef struct _CONFIG_PAGE_RAID_VOL_1
{
CONFIG_PAGE_HEADER Header; /* 00h */
- U8 VolumeID; /* 01h */
- U8 VolumeBus; /* 02h */
- U8 VolumeIOC; /* 03h */
- U8 Reserved0; /* 04h */
- U8 GUID[24]; /* 05h */
+ U8 VolumeID; /* 04h */
+ U8 VolumeBus; /* 05h */
+ U8 VolumeIOC; /* 06h */
+ U8 Reserved0; /* 07h */
+ U8 GUID[24]; /* 08h */
U8 Name[32]; /* 20h */
U64 WWID; /* 40h */
U32 Reserved1; /* 48h */
@@ -2340,7 +2364,7 @@
} RAID_PHYS_DISK0_STATUS, MPI_POINTER PTR_RAID_PHYS_DISK0_STATUS,
RaidPhysDiskStatus_t, MPI_POINTER pRaidPhysDiskStatus_t;
-/* RAID Volume 2 IM Physical Disk DiskStatus flags */
+/* RAID Physical Disk PhysDiskStatus flags */
#define MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x01)
#define MPI_PHYSDISK0_STATUS_FLAG_QUIESCED (0x02)
@@ -2544,6 +2568,7 @@
#define MPI_SAS_IOUNIT0_DS_TABLE_LINK (0x00000400)
#define MPI_SAS_IOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800)
#define MPI_SAS_IOUNIT0_DS_MAX_SATA_TARGETS (0x00001000)
+#define MPI_SAS_IOUNIT0_DS_MULTI_PORT_DOMAIN (0x00002000)
typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA
@@ -2607,6 +2632,7 @@
#define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001)
/* values for SAS IO Unit Page 1 AdditionalControlFlags */
+#define MPI_SAS_IOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080)
#define MPI_SAS_IOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040)
#define MPI_SAS_IOUNIT1_ACONTROL_HIDE_NONZERO_ATTACHED_PHY_IDENT (0x0020)
#define MPI_SAS_IOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010)
@@ -2734,6 +2760,7 @@
#define MPI_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800)
/* values for SAS Expander Page 0 Flags field */
+#define MPI_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x04)
#define MPI_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x02)
#define MPI_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x01)
@@ -2774,7 +2801,7 @@
/* see mpi_sas.h for values for SAS Expander Page 1 AttachedDeviceInfo values */
/* values for SAS Expander Page 1 DiscoveryInfo field */
-#define MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY DISABLED (0x04)
+#define MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04)
#define MPI_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02)
#define MPI_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01)
@@ -2895,11 +2922,11 @@
U8 AttachedPhyIdentifier; /* 16h */
U8 Reserved2; /* 17h */
U32 AttachedDeviceInfo; /* 18h */
- U8 ProgrammedLinkRate; /* 20h */
- U8 HwLinkRate; /* 21h */
- U8 ChangeCount; /* 22h */
- U8 Flags; /* 23h */
- U32 PhyInfo; /* 24h */
+ U8 ProgrammedLinkRate; /* 1Ch */
+ U8 HwLinkRate; /* 1Dh */
+ U8 ChangeCount; /* 1Eh */
+ U8 Flags; /* 1Fh */
+ U32 PhyInfo; /* 20h */
} CONFIG_PAGE_SAS_PHY_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_0,
SasPhyPage0_t, MPI_POINTER pSasPhyPage0_t;
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
index ddc7ae0..a1f4790 100644
--- a/drivers/message/fusion/lsi/mpi_history.txt
+++ b/drivers/message/fusion/lsi/mpi_history.txt
@@ -3,28 +3,28 @@
MPI Header File Change History
==============================
- Copyright (c) 2000-2006 LSI Logic Corporation.
+ Copyright (c) 2000-2007 LSI Logic Corporation.
---------------------------------------
- Header Set Release Version: 01.05.14
- Header Set Release Date: 10-11-06
+ Header Set Release Version: 01.05.16
+ Header Set Release Date: 05-24-07
---------------------------------------
Filename Current version Prior version
---------- --------------- -------------
- mpi.h 01.05.12 01.05.11
- mpi_ioc.h 01.05.12 01.05.11
- mpi_cnfg.h 01.05.13 01.05.12
- mpi_init.h 01.05.08 01.05.07
+ mpi.h 01.05.13 01.05.12
+ mpi_ioc.h 01.05.14 01.05.13
+ mpi_cnfg.h 01.05.15 01.05.14
+ mpi_init.h 01.05.09 01.05.09
mpi_targ.h 01.05.06 01.05.06
mpi_fc.h 01.05.01 01.05.01
mpi_lan.h 01.05.01 01.05.01
- mpi_raid.h 01.05.02 01.05.02
+ mpi_raid.h 01.05.03 01.05.03
mpi_tool.h 01.05.03 01.05.03
mpi_inb.h 01.05.01 01.05.01
- mpi_sas.h 01.05.04 01.05.03
+ mpi_sas.h 01.05.04 01.05.04
mpi_type.h 01.05.02 01.05.02
- mpi_history.txt 01.05.14 01.05.13
+ mpi_history.txt 01.05.14 01.05.14
* Date Version Description
@@ -95,6 +95,7 @@
* 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target.
* 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT.
* 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT.
+ * 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
mpi_ioc.h
@@ -191,6 +192,13 @@
* data structure.
* Added new ImageType values for FWDownload and FWUpload
* requests.
+ * 02-28-07 01.05.13 Added MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT for SAS
+ * Broadcast Event Data (replacing _RESERVED2).
+ * For Discovery Error Event Data DiscoveryStatus field,
+ * replaced _MULTPL_PATHS with _UNSUPPORTED_DEVICE and
+ * added _MULTI_PORT_DOMAIN.
+ * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request.
+ * Added Common Boot Block type to FWUpload Request.
* --------------------------------------------------------------------------
mpi_cnfg.h
@@ -473,6 +481,21 @@
* Added more AccessStatus values for SAS Device Page 0.
* Added bit for SATA Asynchronous Notification Support in
* Flags field of SAS Device Page 0.
+ * 02-28-07 01.05.14 Added ExtFlags field to Manufacturing Page 4.
+ * Added Disable SMART Polling for CapabilitiesFlags of
+ * IOC Page 6.
+ * Added Disable SMART Polling to DeviceSettings of BIOS
+ * Page 1.
+ * Added Multi-Port Domain bit for DiscoveryStatus field
+ * of SAS IO Unit Page.
+ * Added Multi-Port Domain Illegal flag for SAS IO Unit
+ * Page 1 AdditionalControlFlags field.
+ * 05-24-07 01.05.15 Added Hide Physical Disks with Non-Integrated RAID
+ * Metadata bit to Manufacturing Page 4 ExtFlags field.
+ * Added Internal Connector to End Device Present bit to
+ * Expander Page 0 Flags field.
+ * Fixed define for
+ * MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED.
* --------------------------------------------------------------------------
mpi_init.h
@@ -517,6 +540,8 @@
* unique in the first 32 characters.
* 03-27-06 01.05.07 Added Task Management type of Clear ACA.
* 10-11-06 01.05.08 Shortened define for Task Management type of Clear ACA.
+ * 02-28-07 01.05.09 Defined two new MsgFlags bits for SCSI Task Management
+ * Request: Do Not Send Task IU and Soft Reset Option.
* --------------------------------------------------------------------------
mpi_targ.h
@@ -571,7 +596,7 @@
* 11-02-00 01.01.01 Original release for post 1.0 work
* 12-04-00 01.01.02 Added messages for Common Transport Send and
* Primitive Send.
- * 01-09-01 01.01.03 Modified some of the new flags to have an MPI prefix
+ * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix
* and modified the FcPrimitiveSend flags.
* 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger
* field.
@@ -634,6 +659,8 @@
* 08-19-04 01.05.01 Original release for MPI v1.5.
* 01-15-05 01.05.02 Added defines for the two new RAID Actions for
* _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
+ * 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and
+ * associated defines.
* --------------------------------------------------------------------------
mpi_tool.h
@@ -682,7 +709,22 @@
mpi_history.txt Parts list history
-Filename 01.05.13 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09
+Filename 01.05.15 01.05.15
+---------- -------- --------
+mpi.h 01.05.12 01.05.13
+mpi_ioc.h 01.05.13 01.05.14
+mpi_cnfg.h 01.05.14 01.05.15
+mpi_init.h 01.05.09 01.05.09
+mpi_targ.h 01.05.06 01.05.06
+mpi_fc.h 01.05.01 01.05.01
+mpi_lan.h 01.05.01 01.05.01
+mpi_raid.h 01.05.03 01.05.03
+mpi_tool.h 01.05.03 01.05.03
+mpi_inb.h 01.05.01 01.05.01
+mpi_sas.h 01.05.04 01.05.04
+mpi_type.h 01.05.02 01.05.02
+
+Filename 01.05.14 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09
---------- -------- -------- -------- -------- -------- --------
mpi.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08 01.05.07
mpi_ioc.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.09 01.05.08
diff --git a/drivers/message/fusion/lsi/mpi_inb.h b/drivers/message/fusion/lsi/mpi_inb.h
deleted file mode 100644
index ff16730..0000000
--- a/drivers/message/fusion/lsi/mpi_inb.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (c) 2003-2004 LSI Logic Corporation.
- *
- *
- * Name: mpi_inb.h
- * Title: MPI Inband structures and definitions
- * Creation Date: September 30, 2003
- *
- * mpi_inb.h Version: 01.05.01
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 05-11-04 01.03.01 Original release.
- * 08-19-04 01.05.01 Original release for MPI v1.5.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI_INB_H
-#define MPI_INB_H
-
-/******************************************************************************
-*
-* I n b a n d M e s s a g e s
-*
-*******************************************************************************/
-
-
-/****************************************************************************/
-/* Inband Buffer Post Request */
-/****************************************************************************/
-
-typedef struct _MSG_INBAND_BUFFER_POST_REQUEST
-{
- U8 Reserved1; /* 00h */
- U8 BufferCount; /* 01h */
- U8 ChainOffset; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U32 Reserved4; /* 0Ch */
- SGE_TRANS_SIMPLE_UNION SGL; /* 10h */
-} MSG_INBAND_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_INBAND_BUFFER_POST_REQUEST,
- MpiInbandBufferPostRequest_t , MPI_POINTER pMpiInbandBufferPostRequest_t;
-
-
-typedef struct _WWN_FC_FORMAT
-{
- U64 NodeName; /* 00h */
- U64 PortName; /* 08h */
-} WWN_FC_FORMAT, MPI_POINTER PTR_WWN_FC_FORMAT,
- WwnFcFormat_t, MPI_POINTER pWwnFcFormat_t;
-
-typedef struct _WWN_SAS_FORMAT
-{
- U64 WorldWideID; /* 00h */
- U32 Reserved1; /* 08h */
- U32 Reserved2; /* 0Ch */
-} WWN_SAS_FORMAT, MPI_POINTER PTR_WWN_SAS_FORMAT,
- WwnSasFormat_t, MPI_POINTER pWwnSasFormat_t;
-
-typedef union _WWN_INBAND_FORMAT
-{
- WWN_FC_FORMAT Fc;
- WWN_SAS_FORMAT Sas;
-} WWN_INBAND_FORMAT, MPI_POINTER PTR_WWN_INBAND_FORMAT,
- WwnInbandFormat, MPI_POINTER pWwnInbandFormat;
-
-
-/* Inband Buffer Post reply message */
-
-typedef struct _MSG_INBAND_BUFFER_POST_REPLY
-{
- U16 Reserved1; /* 00h */
- U8 MsgLength; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U16 Reserved4; /* 0Ch */
- U16 IOCStatus; /* 0Eh */
- U32 IOCLogInfo; /* 10h */
- U32 TransferLength; /* 14h */
- U32 TransactionContext; /* 18h */
- WWN_INBAND_FORMAT Wwn; /* 1Ch */
- U32 IOCIdentifier[4]; /* 2Ch */
-} MSG_INBAND_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_INBAND_BUFFER_POST_REPLY,
- MpiInbandBufferPostReply_t, MPI_POINTER pMpiInbandBufferPostReply_t;
-
-
-/****************************************************************************/
-/* Inband Send Request */
-/****************************************************************************/
-
-typedef struct _MSG_INBAND_SEND_REQUEST
-{
- U16 Reserved1; /* 00h */
- U8 ChainOffset; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U32 Reserved4; /* 0Ch */
- WWN_INBAND_FORMAT Wwn; /* 10h */
- U32 Reserved5; /* 20h */
- SGE_IO_UNION SGL; /* 24h */
-} MSG_INBAND_SEND_REQUEST, MPI_POINTER PTR_MSG_INBAND_SEND_REQUEST,
- MpiInbandSendRequest_t , MPI_POINTER pMpiInbandSendRequest_t;
-
-
-/* Inband Send reply message */
-
-typedef struct _MSG_INBAND_SEND_REPLY
-{
- U16 Reserved1; /* 00h */
- U8 MsgLength; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U16 Reserved4; /* 0Ch */
- U16 IOCStatus; /* 0Eh */
- U32 IOCLogInfo; /* 10h */
- U32 ResponseLength; /* 14h */
-} MSG_INBAND_SEND_REPLY, MPI_POINTER PTR_MSG_INBAND_SEND_REPLY,
- MpiInbandSendReply_t, MPI_POINTER pMpiInbandSendReply_t;
-
-
-/****************************************************************************/
-/* Inband Response Request */
-/****************************************************************************/
-
-typedef struct _MSG_INBAND_RSP_REQUEST
-{
- U16 Reserved1; /* 00h */
- U8 ChainOffset; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U32 Reserved4; /* 0Ch */
- WWN_INBAND_FORMAT Wwn; /* 10h */
- U32 IOCIdentifier[4]; /* 20h */
- U32 ResponseLength; /* 30h */
- SGE_IO_UNION SGL; /* 34h */
-} MSG_INBAND_RSP_REQUEST, MPI_POINTER PTR_MSG_INBAND_RSP_REQUEST,
- MpiInbandRspRequest_t , MPI_POINTER pMpiInbandRspRequest_t;
-
-
-/* Inband Response reply message */
-
-typedef struct _MSG_INBAND_RSP_REPLY
-{
- U16 Reserved1; /* 00h */
- U8 MsgLength; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U16 Reserved4; /* 0Ch */
- U16 IOCStatus; /* 0Eh */
- U32 IOCLogInfo; /* 10h */
-} MSG_INBAND_RSP_REPLY, MPI_POINTER PTR_MSG_INBAND_RSP_REPLY,
- MpiInbandRspReply_t, MPI_POINTER pMpiInbandRspReply_t;
-
-
-/****************************************************************************/
-/* Inband Abort Request */
-/****************************************************************************/
-
-typedef struct _MSG_INBAND_ABORT_REQUEST
-{
- U8 Reserved1; /* 00h */
- U8 AbortType; /* 01h */
- U8 ChainOffset; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U32 Reserved4; /* 0Ch */
- U32 ContextToAbort; /* 10h */
-} MSG_INBAND_ABORT_REQUEST, MPI_POINTER PTR_MSG_INBAND_ABORT_REQUEST,
- MpiInbandAbortRequest_t , MPI_POINTER pMpiInbandAbortRequest_t;
-
-#define MPI_INBAND_ABORT_TYPE_ALL_BUFFERS (0x00)
-#define MPI_INBAND_ABORT_TYPE_EXACT_BUFFER (0x01)
-#define MPI_INBAND_ABORT_TYPE_SEND_REQUEST (0x02)
-#define MPI_INBAND_ABORT_TYPE_RESPONSE_REQUEST (0x03)
-
-
-/* Inband Abort reply message */
-
-typedef struct _MSG_INBAND_ABORT_REPLY
-{
- U8 Reserved1; /* 00h */
- U8 AbortType; /* 01h */
- U8 MsgLength; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U16 Reserved4; /* 0Ch */
- U16 IOCStatus; /* 0Eh */
- U32 IOCLogInfo; /* 10h */
-} MSG_INBAND_ABORT_REPLY, MPI_POINTER PTR_MSG_INBAND_ABORT_REPLY,
- MpiInbandAbortReply_t, MPI_POINTER pMpiInbandAbortReply_t;
-
-
-#endif
-
diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h
index ec9dff2..3a02615 100644
--- a/drivers/message/fusion/lsi/mpi_init.h
+++ b/drivers/message/fusion/lsi/mpi_init.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2006 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Logic Corporation.
*
*
* Name: mpi_init.h
* Title: MPI initiator mode messages and structures
* Creation Date: June 8, 2000
*
- * mpi_init.h Version: 01.05.08
+ * mpi_init.h Version: 01.05.09
*
* Version History
* ---------------
@@ -54,6 +54,8 @@
* unique in the first 32 characters.
* 03-27-06 01.05.07 Added Task Management type of Clear ACA.
* 10-11-06 01.05.08 Shortened define for Task Management type of Clear ACA.
+ * 02-28-07 01.05.09 Defined two new MsgFlags bits for SCSI Task Management
+ * Request: Do Not Send Task IU and Soft Reset Option.
* --------------------------------------------------------------------------
*/
@@ -432,10 +434,14 @@
#define MPI_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08)
/* MsgFlags bits */
+#define MPI_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01)
+
#define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00)
#define MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION (0x02)
#define MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION (0x04)
+#define MPI_SCSITASKMGMT_MSGFLAGS_SOFT_RESET_OPTION (0x08)
+
/* SCSI Task Management Reply */
typedef struct _MSG_SCSI_TASK_MGMT_REPLY
{
diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h
index 6c33e33..b1893d1 100644
--- a/drivers/message/fusion/lsi/mpi_ioc.h
+++ b/drivers/message/fusion/lsi/mpi_ioc.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2006 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Logic Corporation.
*
*
* Name: mpi_ioc.h
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: August 11, 2000
*
- * mpi_ioc.h Version: 01.05.12
+ * mpi_ioc.h Version: 01.05.14
*
* Version History
* ---------------
@@ -106,6 +106,13 @@
* data structure.
* Added new ImageType values for FWDownload and FWUpload
* requests.
+ * 02-28-07 01.05.13 Added MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT for SAS
+ * Broadcast Event Data (replacing _RESERVED2).
+ * For Discovery Error Event Data DiscoveryStatus field,
+ * replaced _MULTPL_PATHS with _UNSUPPORTED_DEVICE and
+ * added _MULTI_PORT_DOMAIN.
+ * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request.
+ * Added Common Boot Block type to FWUpload Request.
* --------------------------------------------------------------------------
*/
@@ -792,7 +799,7 @@
#define MPI_EVENT_PRIMITIVE_CHANGE (0x01)
#define MPI_EVENT_PRIMITIVE_EXPANDER (0x03)
-#define MPI_EVENT_PRIMITIVE_RESERVED2 (0x04)
+#define MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04)
#define MPI_EVENT_PRIMITIVE_RESERVED3 (0x05)
#define MPI_EVENT_PRIMITIVE_RESERVED4 (0x06)
#define MPI_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07)
@@ -857,8 +864,9 @@
#define MPI_EVENT_DSCVRY_ERR_DS_SMP_CRC_ERROR (0x00000100)
#define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_SUBTRACTIVE (0x00000200)
#define MPI_EVENT_DSCVRY_ERR_DS_TABLE_TO_TABLE (0x00000400)
-#define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_PATHS (0x00000800)
+#define MPI_EVENT_DSCVRY_ERR_DS_UNSUPPORTED_DEVICE (0x00000800)
#define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000)
+#define MPI_EVENT_DSCVRY_ERR_DS_MULTI_PORT_DOMAIN (0x00002000)
/* SAS SMP Error Event data */
@@ -990,6 +998,7 @@
#define MPI_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07)
#define MPI_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08)
#define MPI_FW_DOWNLOAD_ITYPE_MEGARAID (0x09)
+#define MPI_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
typedef struct _FWDownloadTCSGE
@@ -1038,17 +1047,18 @@
} MSG_FW_UPLOAD, MPI_POINTER PTR_MSG_FW_UPLOAD,
FWUpload_t, MPI_POINTER pFWUpload_t;
-#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM (0x00)
-#define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01)
-#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02)
-#define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03)
-#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER (0x04)
-#define MPI_FW_UPLOAD_ITYPE_FW_BACKUP (0x05)
-#define MPI_FW_UPLOAD_ITYPE_MANUFACTURING (0x06)
-#define MPI_FW_UPLOAD_ITYPE_CONFIG_1 (0x07)
-#define MPI_FW_UPLOAD_ITYPE_CONFIG_2 (0x08)
-#define MPI_FW_UPLOAD_ITYPE_MEGARAID (0x09)
-#define MPI_FW_UPLOAD_ITYPE_COMPLETE (0x0A)
+#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM (0x00)
+#define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01)
+#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02)
+#define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03)
+#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER (0x04)
+#define MPI_FW_UPLOAD_ITYPE_FW_BACKUP (0x05)
+#define MPI_FW_UPLOAD_ITYPE_MANUFACTURING (0x06)
+#define MPI_FW_UPLOAD_ITYPE_CONFIG_1 (0x07)
+#define MPI_FW_UPLOAD_ITYPE_CONFIG_2 (0x08)
+#define MPI_FW_UPLOAD_ITYPE_MEGARAID (0x09)
+#define MPI_FW_UPLOAD_ITYPE_COMPLETE (0x0A)
+#define MPI_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
typedef struct _FWUploadTCSGE
{
diff --git a/drivers/message/fusion/lsi/mpi_raid.h b/drivers/message/fusion/lsi/mpi_raid.h
index 802255d..32819b1 100644
--- a/drivers/message/fusion/lsi/mpi_raid.h
+++ b/drivers/message/fusion/lsi/mpi_raid.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2001-2005 LSI Logic Corporation.
+ * Copyright (c) 2001-2007 LSI Logic Corporation.
*
*
* Name: mpi_raid.h
* Title: MPI RAID message and structures
* Creation Date: February 27, 2001
*
- * mpi_raid.h Version: 01.05.02
+ * mpi_raid.h Version: 01.05.03
*
* Version History
* ---------------
@@ -32,6 +32,8 @@
* 08-19-04 01.05.01 Original release for MPI v1.5.
* 01-15-05 01.05.02 Added defines for the two new RAID Actions for
* _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
+ * 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and
+ * associated defines.
* --------------------------------------------------------------------------
*/
@@ -90,6 +92,7 @@
#define MPI_RAID_ACTION_INACTIVATE_VOLUME (0x12)
#define MPI_RAID_ACTION_SET_RESYNC_RATE (0x13)
#define MPI_RAID_ACTION_SET_DATA_SCRUB_RATE (0x14)
+#define MPI_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15)
/* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */
#define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC (0x00000001)
@@ -111,6 +114,10 @@
/* ActionDataWord defines for use with MPI_RAID_ACTION_SET_DATA_SCRUB_RATE action */
#define MPI_RAID_ACTION_ADATA_DATA_SCRUB_RATE_MASK (0x000000FF)
+/* ActionDataWord defines for use with MPI_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */
+#define MPI_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x00000001)
+#define MPI_RAID_ACTION_ADATA_MASK_FW_UPDATE_TIMEOUT (0x0000FF00)
+#define MPI_RAID_ACTION_ADATA_SHIFT_FW_UPDATE_TIMEOUT (8)
/* RAID Action reply message */
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 5021d1a..5a10c87 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -6,7 +6,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -64,6 +64,7 @@
#endif
#include "mptbase.h"
+#include "lsi/mpi_log_fc.h"
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#define my_NAME "Fusion MPT base driver"
@@ -6349,14 +6350,37 @@
static void
mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
{
- static char *subcl_str[8] = {
- "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
- "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
- };
- u8 subcl = (log_info >> 24) & 0x7;
+ char *desc = "unknown";
- printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
- ioc->name, log_info, subcl_str[subcl]);
+ switch (log_info & 0xFF000000) {
+ case MPI_IOCLOGINFO_FC_INIT_BASE:
+ desc = "FCP Initiator";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_BASE:
+ desc = "FCP Target";
+ break;
+ case MPI_IOCLOGINFO_FC_LAN_BASE:
+ desc = "LAN";
+ break;
+ case MPI_IOCLOGINFO_FC_MSG_BASE:
+ desc = "MPI Message Layer";
+ break;
+ case MPI_IOCLOGINFO_FC_LINK_BASE:
+ desc = "FC Link";
+ break;
+ case MPI_IOCLOGINFO_FC_CTX_BASE:
+ desc = "Context Manager";
+ break;
+ case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
+ desc = "Invalid Field Offset";
+ break;
+ case MPI_IOCLOGINFO_FC_STATE_CHANGE:
+ desc = "State Change Info";
+ break;
+ }
+
+ printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
+ ioc->name, log_info, desc, (log_info & 0xFFFFFF));
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 165f81d..05eb6e5 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -6,7 +6,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -75,8 +75,8 @@
#define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.04"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.04"
+#define MPT_LINUX_VERSION_COMMON "3.04.05"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.05"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 9d0f304..58e6c31 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -5,7 +5,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
index f7e72c5..180b3c1 100644
--- a/drivers/message/fusion/mptctl.h
+++ b/drivers/message/fusion/mptctl.h
@@ -6,7 +6,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index 0caaf64..b766445 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -4,7 +4,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -43,7 +43,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#include "linux_compat.h" /* linux-2.6 tweaks */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index 7dd34bd..7e8a90c 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -5,7 +5,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 2000-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h
index fe438bf..8d08c2b 100644
--- a/drivers/message/fusion/mptlan.h
+++ b/drivers/message/fusion/mptlan.h
@@ -5,7 +5,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 2000-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 1d2d03f..9e5424e 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -4,7 +4,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
* Copyright (c) 2005-2007 Dell
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 3bd94f1..d356173 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -4,7 +4,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -44,7 +44,6 @@
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#include "linux_compat.h" /* linux-2.6 tweaks */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -260,30 +259,13 @@
/* Map the data portion, if any.
* sges_left = 0 if no data transfer.
*/
- if ( (sges_left = SCpnt->use_sg) ) {
- sges_left = pci_map_sg(ioc->pcidev,
- (struct scatterlist *) SCpnt->request_buffer,
- SCpnt->use_sg,
- SCpnt->sc_data_direction);
- if (sges_left == 0)
- return FAILED;
- } else if (SCpnt->request_bufflen) {
- SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
- SCpnt->request_buffer,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
- ioc->name, SCpnt, SCpnt->request_bufflen));
- mptscsih_add_sge((char *) &pReq->SGL,
- 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
- SCpnt->SCp.dma_handle);
-
- return SUCCESS;
- }
+ sges_left = scsi_dma_map(SCpnt);
+ if (sges_left < 0)
+ return FAILED;
/* Handle the SG case.
*/
- sg = (struct scatterlist *) SCpnt->request_buffer;
+ sg = scsi_sglist(SCpnt);
sg_done = 0;
sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
chainSge = NULL;
@@ -465,7 +447,12 @@
MPT_FRAME_HDR *mf;
SEPRequest_t *SEPMsg;
- if (ioc->bus_type == FC)
+ if (ioc->bus_type != SAS)
+ return;
+
+ /* Not supported for hidden raid components
+ */
+ if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
return;
if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
@@ -662,7 +649,7 @@
scsi_state = pScsiReply->SCSIState;
scsi_status = pScsiReply->SCSIStatus;
xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
- sc->resid = sc->request_bufflen - xfer_cnt;
+ scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
/*
@@ -767,7 +754,7 @@
break;
case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
- sc->resid = sc->request_bufflen - xfer_cnt;
+ scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
sc->result=DID_SOFT_ERROR << 16;
else /* Sufficient data transfer occurred */
@@ -816,7 +803,7 @@
break;
case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
- sc->resid=0;
+ scsi_set_resid(sc, 0);
case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
sc->result = (DID_OK << 16) | scsi_status;
@@ -899,23 +886,18 @@
scsi_state, scsi_status, log_info));
dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d "
- "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
- sc->device->host->host_no, sc->device->channel, sc->device->id,
- sc->device->lun, sc->resid, sc->request_bufflen,
- xfer_cnt));
+ "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
+ sc->device->host->host_no,
+ sc->device->channel, sc->device->id,
+ sc->device->lun, scsi_get_resid(sc),
+ scsi_bufflen(sc), xfer_cnt));
}
#endif
} /* end of address reply case */
/* Unmap the DMA buffers, if any. */
- if (sc->use_sg) {
- pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
- sc->use_sg, sc->sc_data_direction);
- } else if (sc->request_bufflen) {
- pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
- sc->request_bufflen, sc->sc_data_direction);
- }
+ scsi_dma_unmap(sc);
sc->scsi_done(sc); /* Issue the command callback */
@@ -970,17 +952,8 @@
/* Set status, free OS resources (SG DMA buffers)
* Do OS callback
*/
- if (SCpnt->use_sg) {
- pci_unmap_sg(ioc->pcidev,
- (struct scatterlist *) SCpnt->request_buffer,
- SCpnt->use_sg,
- SCpnt->sc_data_direction);
- } else if (SCpnt->request_bufflen) {
- pci_unmap_single(ioc->pcidev,
- SCpnt->SCp.dma_handle,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- }
+ scsi_dma_unmap(SCpnt);
+
SCpnt->result = DID_RESET << 16;
SCpnt->host_scribble = NULL;
@@ -1023,14 +996,19 @@
mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
if (mf == NULL)
continue;
+ /* If the device is a hidden raid component, then its
+ * expected that the mf->function will be RAID_SCSI_IO
+ */
+ if (vdevice->vtarget->tflags &
+ MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
+ MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
+ continue;
+
int_to_scsilun(vdevice->lun, &lun);
if ((mf->Bus != vdevice->vtarget->channel) ||
(mf->TargetID != vdevice->vtarget->id) ||
memcmp(lun.scsi_lun, mf->LUN, 8))
continue;
- dsprintk(( "search_running: found (sc=%p, mf = %p) "
- "channel %d id %d, lun %d \n", hd->ScsiLookup[ii],
- mf, mf->Bus, mf->TargetID, vdevice->lun));
/* Cleanup
*/
@@ -1039,19 +1017,12 @@
mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
if ((unsigned char *)mf != sc->host_scribble)
continue;
- if (sc->use_sg) {
- pci_unmap_sg(hd->ioc->pcidev,
- (struct scatterlist *) sc->request_buffer,
- sc->use_sg,
- sc->sc_data_direction);
- } else if (sc->request_bufflen) {
- pci_unmap_single(hd->ioc->pcidev,
- sc->SCp.dma_handle,
- sc->request_bufflen,
- sc->sc_data_direction);
- }
+ scsi_dma_unmap(sc);
sc->host_scribble = NULL;
sc->result = DID_NO_CONNECT << 16;
+ dsprintk(( "search_running: found (sc=%p, mf = %p) "
+ "channel %d id %d, lun %d \n", sc, mf,
+ vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun));
sc->scsi_done(sc);
}
}
@@ -1380,10 +1351,10 @@
* will be no data transfer! GRRRRR...
*/
if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
- datalen = SCpnt->request_bufflen;
+ datalen = scsi_bufflen(SCpnt);
scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
- datalen = SCpnt->request_bufflen;
+ datalen = scsi_bufflen(SCpnt);
scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
} else {
datalen = 0;
@@ -1768,20 +1739,45 @@
u32 ctx2abort;
int scpnt_idx;
int retval;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
ulong sn = SCpnt->serial_number;
+ MPT_ADAPTER *ioc;
/* If we can't locate our host adapter structure, return FAILED status.
*/
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
SCpnt->result = DID_RESET << 16;
SCpnt->scsi_done(SCpnt);
- dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
- "Can't locate host! (sc=%p)\n",
- SCpnt));
+ dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: Can't locate "
+ "host! (sc=%p)\n", SCpnt));
return FAILED;
}
+ ioc = hd->ioc;
+ printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
+ ioc->name, SCpnt);
+ scsi_print_command(SCpnt);
+
+ vdevice = SCpnt->device->hostdata;
+ if (!vdevice || !vdevice->vtarget) {
+ dtmprintk((MYIOC_s_DEBUG_FMT "task abort: device has been "
+ "deleted (sc=%p)\n", ioc->name, SCpnt));
+ SCpnt->result = DID_NO_CONNECT << 16;
+ SCpnt->scsi_done(SCpnt);
+ retval = 0;
+ goto out;
+ }
+
+ /* Task aborts are not supported for hidden raid components.
+ */
+ if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
+ dtmprintk((MYIOC_s_DEBUG_FMT "task abort: hidden raid "
+ "component (sc=%p)\n", ioc->name, SCpnt));
+ SCpnt->result = DID_RESET << 16;
+ retval = FAILED;
+ goto out;
+ }
+
/* Find this command
*/
if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
@@ -1790,21 +1786,20 @@
*/
SCpnt->result = DID_RESET << 16;
dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
- "Command not in the active list! (sc=%p)\n",
- hd->ioc->name, SCpnt));
- return SUCCESS;
+ "Command not in the active list! (sc=%p)\n", ioc->name,
+ SCpnt));
+ retval = 0;
+ goto out;
}
- if (hd->resetPending)
- return FAILED;
+ if (hd->resetPending) {
+ retval = FAILED;
+ goto out;
+ }
if (hd->timeouts < -1)
hd->timeouts++;
- printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
- hd->ioc->name, SCpnt);
- scsi_print_command(SCpnt);
-
/* Most important! Set TaskMsgContext to SCpnt's MsgContext!
* (the IO to be ABORT'd)
*
@@ -1817,18 +1812,17 @@
hd->abortSCpnt = SCpnt;
- vdev = SCpnt->device->hostdata;
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
- vdev->vtarget->channel, vdev->vtarget->id, vdev->lun,
- ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
+ vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
+ ctx2abort, mptscsih_get_tm_timeout(ioc));
if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
SCpnt->serial_number == sn)
retval = FAILED;
- printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
- hd->ioc->name,
- ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
+ out:
+ printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
+ ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
if (retval == 0)
return SUCCESS;
@@ -1850,32 +1844,47 @@
{
MPT_SCSI_HOST *hd;
int retval;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
+ MPT_ADAPTER *ioc;
/* If we can't locate our host adapter structure, return FAILED status.
*/
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
- "Can't locate host! (sc=%p)\n",
- SCpnt));
+ dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: Can't "
+ "locate host! (sc=%p)\n", SCpnt));
return FAILED;
}
- if (hd->resetPending)
- return FAILED;
-
- printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
- hd->ioc->name, SCpnt);
+ ioc = hd->ioc;
+ printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
+ ioc->name, SCpnt);
scsi_print_command(SCpnt);
- vdev = SCpnt->device->hostdata;
- retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
- vdev->vtarget->channel, vdev->vtarget->id,
- 0, 0, mptscsih_get_tm_timeout(hd->ioc));
+ if (hd->resetPending) {
+ retval = FAILED;
+ goto out;
+ }
- printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
- hd->ioc->name,
- ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
+ vdevice = SCpnt->device->hostdata;
+ if (!vdevice || !vdevice->vtarget) {
+ retval = 0;
+ goto out;
+ }
+
+ /* Target reset to hidden raid component is not supported
+ */
+ if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
+ retval = FAILED;
+ goto out;
+ }
+
+ retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+ vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
+ mptscsih_get_tm_timeout(ioc));
+
+ out:
+ printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
+ ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
if (retval == 0)
return SUCCESS;
@@ -1899,18 +1908,19 @@
MPT_SCSI_HOST *hd;
int retval;
VirtDevice *vdev;
+ MPT_ADAPTER *ioc;
/* If we can't locate our host adapter structure, return FAILED status.
*/
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
- "Can't locate host! (sc=%p)\n",
- SCpnt ) );
+ dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: Can't "
+ "locate host! (sc=%p)\n", SCpnt ));
return FAILED;
}
- printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
- hd->ioc->name, SCpnt);
+ ioc = hd->ioc;
+ printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
+ ioc->name, SCpnt);
scsi_print_command(SCpnt);
if (hd->timeouts < -1)
@@ -1918,11 +1928,10 @@
vdev = SCpnt->device->hostdata;
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
- vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
+ vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
- printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
- hd->ioc->name,
- ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
+ printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
+ ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
if (retval == 0)
return SUCCESS;
@@ -1943,37 +1952,38 @@
mptscsih_host_reset(struct scsi_cmnd *SCpnt)
{
MPT_SCSI_HOST * hd;
- int status = SUCCESS;
+ int retval;
+ MPT_ADAPTER *ioc;
/* If we can't locate the host to reset, then we failed. */
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
- "Can't locate host! (sc=%p)\n",
- SCpnt ) );
+ dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: Can't "
+ "locate host! (sc=%p)\n", SCpnt));
return FAILED;
}
- printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
- hd->ioc->name, SCpnt);
+ ioc = hd->ioc;
+ printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
+ ioc->name, SCpnt);
/* If our attempts to reset the host failed, then return a failed
* status. The host will be taken off line by the SCSI mid-layer.
*/
- if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
- status = FAILED;
+ if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
+ retval = FAILED;
} else {
/* Make sure TM pending is cleared and TM state is set to
* NONE.
*/
+ retval = 0;
hd->tmPending = 0;
hd->tmState = TM_STATE_NONE;
}
- dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
- "Status = %s\n",
- (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
+ printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
+ ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
- return status;
+ return retval;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -3150,6 +3160,16 @@
{
INTERNAL_CMD iocmd;
+ /* Ignore hidden raid components, this is handled when the command
+ * is sent to the volume
+ */
+ if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
+ return;
+
+ if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
+ !vdevice->configured_lun)
+ return;
+
/* Following parameters will not change
* in this routine.
*/
@@ -3164,9 +3184,7 @@
iocmd.id = vdevice->vtarget->id;
iocmd.lun = vdevice->lun;
- if ((vdevice->vtarget->type == TYPE_DISK) &&
- (vdevice->configured_lun))
- mptscsih_do_cmd(hd, &iocmd);
+ mptscsih_do_cmd(hd, &iocmd);
}
EXPORT_SYMBOL(mptscsih_remove);
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index 843c01a..8eccdfe 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -6,7 +6,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 37bf653..6b3e0c0 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -4,7 +4,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -44,7 +44,6 @@
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#include "linux_compat.h" /* linux-2.6 tweaks */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c
index b9df143..611adc3 100644
--- a/drivers/message/i2o/device.c
+++ b/drivers/message/i2o/device.c
@@ -485,7 +485,7 @@
u8 *resblk; /* 8 bytes for header */
int rc;
- resblk = kmalloc(buflen + 8, GFP_KERNEL | GFP_ATOMIC);
+ resblk = kmalloc(buflen + 8, GFP_KERNEL);
if (!resblk)
return -ENOMEM;
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
index 1045c8a..aa6fb94 100644
--- a/drivers/message/i2o/i2o_scsi.c
+++ b/drivers/message/i2o/i2o_scsi.c
@@ -377,12 +377,8 @@
osm_err("SCSI error %08x\n", error);
dev = &c->pdev->dev;
- if (cmd->use_sg)
- dma_unmap_sg(dev, cmd->request_buffer, cmd->use_sg,
- cmd->sc_data_direction);
- else if (cmd->SCp.dma_handle)
- dma_unmap_single(dev, cmd->SCp.dma_handle, cmd->request_bufflen,
- cmd->sc_data_direction);
+
+ scsi_dma_unmap(cmd);
cmd->scsi_done(cmd);
@@ -664,21 +660,15 @@
if (sgl_offset != SGL_OFFSET_0) {
/* write size of data addressed by SGL */
- *mptr++ = cpu_to_le32(SCpnt->request_bufflen);
+ *mptr++ = cpu_to_le32(scsi_bufflen(SCpnt));
/* Now fill in the SGList and command */
- if (SCpnt->use_sg) {
- if (!i2o_dma_map_sg(c, SCpnt->request_buffer,
- SCpnt->use_sg,
+
+ if (scsi_sg_count(SCpnt)) {
+ if (!i2o_dma_map_sg(c, scsi_sglist(SCpnt),
+ scsi_sg_count(SCpnt),
SCpnt->sc_data_direction, &mptr))
goto nomem;
- } else {
- SCpnt->SCp.dma_handle =
- i2o_dma_map_single(c, SCpnt->request_buffer,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction, &mptr);
- if (dma_mapping_error(SCpnt->SCp.dma_handle))
- goto nomem;
}
}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index ba314ad..d17d64e 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -82,6 +82,16 @@
To compile this driver as a module, choose M here: the module
will be called bonding.
+config MACVLAN
+ tristate "MAC-VLAN support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ ---help---
+ This allows one to create virtual interfaces that map packets to
+ or from specific MAC addresses to a particular interface.
+
+ To compile this driver as a module, choose M here: the module
+ will be called macvlan.
+
config EQUALIZER
tristate "EQL (serial line load balancing) support"
---help---
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index a2241e6..c26b867 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -128,6 +128,7 @@
obj-$(CONFIG_DUMMY) += dummy.o
obj-$(CONFIG_IFB) += ifb.o
+obj-$(CONFIG_MACVLAN) += macvlan.o
obj-$(CONFIG_DE600) += de600.o
obj-$(CONFIG_DE620) += de620.o
obj-$(CONFIG_LANCE) += lance.o
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index d19874b..1d88236 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -459,7 +459,7 @@
struct ei_device *ei_local = netdev_priv(dev);
int ret;
- dev_dbg(ax->dev, "%s: open\n", dev->name);
+ dev_dbg(&ax->dev->dev, "%s: open\n", dev->name);
ret = request_irq(dev->irq, ax_ei_interrupt, 0, dev->name, dev);
if (ret)
@@ -492,7 +492,7 @@
struct ax_device *ax = to_ax_dev(dev);
struct ei_device *ei_local = netdev_priv(dev);
- dev_dbg(ax->dev, "%s: close\n", dev->name);
+ dev_dbg(&ax->dev->dev, "%s: close\n", dev->name);
/* turn the phy off */
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 4e5e1cb..d23861c 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -6218,7 +6218,7 @@
struct bnx2 *bp = netdev_priv(dev);
if (CHIP_NUM(bp) == CHIP_NUM_5709)
- return (ethtool_op_set_tx_hw_csum(dev, data));
+ return (ethtool_op_set_tx_ipv6_csum(dev, data));
else
return (ethtool_op_set_tx_csum(dev, data));
}
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
new file mode 100644
index 0000000..dc74d00
--- /dev/null
+++ b/drivers/net/macvlan.c
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 2007 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * The code this is based on carried the following copyright notice:
+ * ---
+ * (C) Copyright 2001-2006
+ * Alex Zeffertt, Cambridge Broadband Ltd, ajz@cambridgebroadband.com
+ * Re-worked by Ben Greear <greearb@candelatech.com>
+ * ---
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_arp.h>
+#include <linux/if_link.h>
+#include <linux/if_macvlan.h>
+#include <net/rtnetlink.h>
+
+#define MACVLAN_HASH_SIZE (1 << BITS_PER_BYTE)
+
+struct macvlan_port {
+ struct net_device *dev;
+ struct hlist_head vlan_hash[MACVLAN_HASH_SIZE];
+ struct list_head vlans;
+};
+
+struct macvlan_dev {
+ struct net_device *dev;
+ struct list_head list;
+ struct hlist_node hlist;
+ struct macvlan_port *port;
+ struct net_device *lowerdev;
+};
+
+
+static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
+ const unsigned char *addr)
+{
+ struct macvlan_dev *vlan;
+ struct hlist_node *n;
+
+ hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[addr[5]], hlist) {
+ if (!compare_ether_addr(vlan->dev->dev_addr, addr))
+ return vlan;
+ }
+ return NULL;
+}
+
+static void macvlan_broadcast(struct sk_buff *skb,
+ const struct macvlan_port *port)
+{
+ const struct ethhdr *eth = eth_hdr(skb);
+ const struct macvlan_dev *vlan;
+ struct hlist_node *n;
+ struct net_device *dev;
+ struct sk_buff *nskb;
+ unsigned int i;
+
+ for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
+ hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) {
+ dev = vlan->dev;
+ if (unlikely(!(dev->flags & IFF_UP)))
+ continue;
+
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (nskb == NULL) {
+ dev->stats.rx_errors++;
+ dev->stats.rx_dropped++;
+ continue;
+ }
+
+ dev->stats.rx_bytes += skb->len + ETH_HLEN;
+ dev->stats.rx_packets++;
+ dev->stats.multicast++;
+ dev->last_rx = jiffies;
+
+ nskb->dev = dev;
+ if (!compare_ether_addr(eth->h_dest, dev->broadcast))
+ nskb->pkt_type = PACKET_BROADCAST;
+ else
+ nskb->pkt_type = PACKET_MULTICAST;
+
+ netif_rx(nskb);
+ }
+ }
+}
+
+/* called under rcu_read_lock() from netif_receive_skb */
+static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
+{
+ const struct ethhdr *eth = eth_hdr(skb);
+ const struct macvlan_port *port;
+ const struct macvlan_dev *vlan;
+ struct net_device *dev;
+
+ port = rcu_dereference(skb->dev->macvlan_port);
+ if (port == NULL)
+ return skb;
+
+ if (is_multicast_ether_addr(eth->h_dest)) {
+ macvlan_broadcast(skb, port);
+ return skb;
+ }
+
+ vlan = macvlan_hash_lookup(port, eth->h_dest);
+ if (vlan == NULL)
+ return skb;
+
+ dev = vlan->dev;
+ if (unlikely(!(dev->flags & IFF_UP))) {
+ kfree_skb(skb);
+ return NULL;
+ }
+
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (skb == NULL) {
+ dev->stats.rx_errors++;
+ dev->stats.rx_dropped++;
+ return NULL;
+ }
+
+ dev->stats.rx_bytes += skb->len + ETH_HLEN;
+ dev->stats.rx_packets++;
+ dev->last_rx = jiffies;
+
+ skb->dev = dev;
+ skb->pkt_type = PACKET_HOST;
+
+ netif_rx(skb);
+ return NULL;
+}
+
+static int macvlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ const struct macvlan_dev *vlan = netdev_priv(dev);
+ unsigned int len = skb->len;
+ int ret;
+
+ skb->dev = vlan->lowerdev;
+ ret = dev_queue_xmit(skb);
+
+ if (likely(ret == NET_XMIT_SUCCESS)) {
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += len;
+ } else {
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
+ }
+ return NETDEV_TX_OK;
+}
+
+static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, void *daddr, void *saddr,
+ unsigned len)
+{
+ const struct macvlan_dev *vlan = netdev_priv(dev);
+ struct net_device *lowerdev = vlan->lowerdev;
+
+ return lowerdev->hard_header(skb, lowerdev, type, daddr,
+ saddr ? : dev->dev_addr, len);
+}
+
+static int macvlan_open(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct macvlan_port *port = vlan->port;
+ struct net_device *lowerdev = vlan->lowerdev;
+ int err;
+
+ err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN);
+ if (err < 0)
+ return err;
+ if (dev->flags & IFF_ALLMULTI)
+ dev_set_allmulti(lowerdev, 1);
+
+ hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[dev->dev_addr[5]]);
+ return 0;
+}
+
+static int macvlan_stop(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct net_device *lowerdev = vlan->lowerdev;
+
+ dev_mc_unsync(lowerdev, dev);
+ if (dev->flags & IFF_ALLMULTI)
+ dev_set_allmulti(lowerdev, -1);
+
+ dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
+
+ hlist_del_rcu(&vlan->hlist);
+ synchronize_rcu();
+ return 0;
+}
+
+static void macvlan_change_rx_flags(struct net_device *dev, int change)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct net_device *lowerdev = vlan->lowerdev;
+
+ if (change & IFF_ALLMULTI)
+ dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1);
+}
+
+static void macvlan_set_multicast_list(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+
+ dev_mc_sync(vlan->lowerdev, dev);
+}
+
+static int macvlan_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+
+ if (new_mtu < 68 || vlan->lowerdev->mtu < new_mtu)
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+/*
+ * macvlan network devices have devices nesting below it and are a special
+ * "super class" of normal network devices; split their locks off into a
+ * separate class since they always nest.
+ */
+static struct lock_class_key macvlan_netdev_xmit_lock_key;
+
+#define MACVLAN_FEATURES \
+ (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
+ NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
+ NETIF_F_TSO_ECN | NETIF_F_TSO6)
+
+#define MACVLAN_STATE_MASK \
+ ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
+
+static int macvlan_init(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ const struct net_device *lowerdev = vlan->lowerdev;
+
+ dev->state = (dev->state & ~MACVLAN_STATE_MASK) |
+ (lowerdev->state & MACVLAN_STATE_MASK);
+ dev->features = lowerdev->features & MACVLAN_FEATURES;
+ dev->iflink = lowerdev->ifindex;
+
+ lockdep_set_class(&dev->_xmit_lock, &macvlan_netdev_xmit_lock_key);
+ return 0;
+}
+
+static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ snprintf(drvinfo->driver, 32, "macvlan");
+ snprintf(drvinfo->version, 32, "0.1");
+}
+
+static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev)
+{
+ const struct macvlan_dev *vlan = netdev_priv(dev);
+ struct net_device *lowerdev = vlan->lowerdev;
+
+ if (lowerdev->ethtool_ops->get_rx_csum == NULL)
+ return 0;
+ return lowerdev->ethtool_ops->get_rx_csum(lowerdev);
+}
+
+static const struct ethtool_ops macvlan_ethtool_ops = {
+ .get_link = ethtool_op_get_link,
+ .get_rx_csum = macvlan_ethtool_get_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_tso = ethtool_op_get_tso,
+ .get_ufo = ethtool_op_get_ufo,
+ .get_sg = ethtool_op_get_sg,
+ .get_drvinfo = macvlan_ethtool_get_drvinfo,
+};
+
+static void macvlan_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+
+ dev->init = macvlan_init;
+ dev->open = macvlan_open;
+ dev->stop = macvlan_stop;
+ dev->change_mtu = macvlan_change_mtu;
+ dev->change_rx_flags = macvlan_change_rx_flags;
+ dev->set_multicast_list = macvlan_set_multicast_list;
+ dev->hard_header = macvlan_hard_header;
+ dev->hard_start_xmit = macvlan_hard_start_xmit;
+ dev->destructor = free_netdev;
+ dev->ethtool_ops = &macvlan_ethtool_ops;
+ dev->tx_queue_len = 0;
+}
+
+static int macvlan_port_create(struct net_device *dev)
+{
+ struct macvlan_port *port;
+ unsigned int i;
+
+ if (dev->type != ARPHRD_ETHER || dev->flags & IFF_LOOPBACK)
+ return -EINVAL;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (port == NULL)
+ return -ENOMEM;
+
+ port->dev = dev;
+ INIT_LIST_HEAD(&port->vlans);
+ for (i = 0; i < MACVLAN_HASH_SIZE; i++)
+ INIT_HLIST_HEAD(&port->vlan_hash[i]);
+ rcu_assign_pointer(dev->macvlan_port, port);
+ return 0;
+}
+
+static void macvlan_port_destroy(struct net_device *dev)
+{
+ struct macvlan_port *port = dev->macvlan_port;
+
+ rcu_assign_pointer(dev->macvlan_port, NULL);
+ synchronize_rcu();
+ kfree(port);
+}
+
+static void macvlan_transfer_operstate(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ const struct net_device *lowerdev = vlan->lowerdev;
+
+ if (lowerdev->operstate == IF_OPER_DORMANT)
+ netif_dormant_on(dev);
+ else
+ netif_dormant_off(dev);
+
+ if (netif_carrier_ok(lowerdev)) {
+ if (!netif_carrier_ok(dev))
+ netif_carrier_on(dev);
+ } else {
+ if (netif_carrier_ok(lowerdev))
+ netif_carrier_off(dev);
+ }
+}
+
+static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+ if (tb[IFLA_ADDRESS]) {
+ if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+ return -EINVAL;
+ if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+ return -EADDRNOTAVAIL;
+ }
+ return 0;
+}
+
+static int macvlan_newlink(struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct macvlan_port *port;
+ struct net_device *lowerdev;
+ int err;
+
+ if (!tb[IFLA_LINK])
+ return -EINVAL;
+
+ lowerdev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK]));
+ if (lowerdev == NULL)
+ return -ENODEV;
+
+ if (!tb[IFLA_MTU])
+ dev->mtu = lowerdev->mtu;
+ else if (dev->mtu > lowerdev->mtu)
+ return -EINVAL;
+
+ if (!tb[IFLA_ADDRESS])
+ random_ether_addr(dev->dev_addr);
+
+ if (lowerdev->macvlan_port == NULL) {
+ err = macvlan_port_create(lowerdev);
+ if (err < 0)
+ return err;
+ }
+ port = lowerdev->macvlan_port;
+
+ vlan->lowerdev = lowerdev;
+ vlan->dev = dev;
+ vlan->port = port;
+
+ err = register_netdevice(dev);
+ if (err < 0)
+ return err;
+
+ list_add_tail(&vlan->list, &port->vlans);
+ macvlan_transfer_operstate(dev);
+ return 0;
+}
+
+static void macvlan_dellink(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct macvlan_port *port = vlan->port;
+
+ list_del(&vlan->list);
+ unregister_netdevice(dev);
+
+ if (list_empty(&port->vlans))
+ macvlan_port_destroy(dev);
+}
+
+static struct rtnl_link_ops macvlan_link_ops __read_mostly = {
+ .kind = "macvlan",
+ .priv_size = sizeof(struct macvlan_dev),
+ .setup = macvlan_setup,
+ .validate = macvlan_validate,
+ .newlink = macvlan_newlink,
+ .dellink = macvlan_dellink,
+};
+
+static int macvlan_device_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+ struct macvlan_dev *vlan, *next;
+ struct macvlan_port *port;
+
+ port = dev->macvlan_port;
+ if (port == NULL)
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case NETDEV_CHANGE:
+ list_for_each_entry(vlan, &port->vlans, list)
+ macvlan_transfer_operstate(vlan->dev);
+ break;
+ case NETDEV_FEAT_CHANGE:
+ list_for_each_entry(vlan, &port->vlans, list) {
+ vlan->dev->features = dev->features & MACVLAN_FEATURES;
+ netdev_features_change(vlan->dev);
+ }
+ break;
+ case NETDEV_UNREGISTER:
+ list_for_each_entry_safe(vlan, next, &port->vlans, list)
+ macvlan_dellink(vlan->dev);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block macvlan_notifier_block __read_mostly = {
+ .notifier_call = macvlan_device_event,
+};
+
+static int __init macvlan_init_module(void)
+{
+ int err;
+
+ register_netdevice_notifier(&macvlan_notifier_block);
+ macvlan_handle_frame_hook = macvlan_handle_frame;
+
+ err = rtnl_link_register(&macvlan_link_ops);
+ if (err < 0)
+ goto err1;
+ return 0;
+err1:
+ macvlan_handle_frame_hook = macvlan_handle_frame;
+ unregister_netdevice_notifier(&macvlan_notifier_block);
+ return err;
+}
+
+static void __exit macvlan_cleanup_module(void)
+{
+ rtnl_link_unregister(&macvlan_link_ops);
+ macvlan_handle_frame_hook = NULL;
+ unregister_netdevice_notifier(&macvlan_notifier_block);
+}
+
+module_init(macvlan_init_module);
+module_exit(macvlan_cleanup_module);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("Driver for MAC address based VLANs");
+MODULE_ALIAS_RTNL_LINK("macvlan");
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 32e4037..5ee1476 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -8318,7 +8318,7 @@
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
- ethtool_op_set_tx_hw_csum(dev, data);
+ ethtool_op_set_tx_ipv6_csum(dev, data);
else
ethtool_op_set_tx_csum(dev, data);
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 7dcd138..f87d769 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1274,7 +1274,7 @@
if (pdev->vendor == 0x1282 && pdev->device == 0x9100)
{
/* Read Chip revision */
- if (pdev->revision < 0x02000030)
+ if (pdev->revision < 0x30)
{
printk(KERN_ERR PFX "skipping early DM9100 with Crc bug (use dmfe)\n");
return -ENODEV;
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 740a219..ca24299 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -15,7 +15,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <asm/unaligned.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -26,6 +25,7 @@
#include <linux/usb.h>
#include <linux/workqueue.h>
#include <net/ieee80211.h>
+#include <asm/unaligned.h>
#include "zd_def.h"
#include "zd_netdev.h"
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index ab9c3e5..3f6e176 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -16,6 +16,7 @@
config PDA_POWER
tristate "Generic PDA/phone power driver"
+ depends on !S390
help
Say Y here to enable generic power driver for PDAs and phones with
one or two external power supplies (AC/USB) connected to main and
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 821cde65..a1db959 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -815,9 +815,7 @@
struct zfcp_unit *
zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
{
- struct zfcp_unit *unit, *tmp_unit;
- unsigned int scsi_lun;
- int found;
+ struct zfcp_unit *unit;
/*
* check that there is no unit with this FCP_LUN already in list
@@ -863,22 +861,10 @@
}
zfcp_unit_get(unit);
+ unit->scsi_lun = scsilun_to_int((struct scsi_lun *)&unit->fcp_lun);
- scsi_lun = 0;
- found = 0;
write_lock_irq(&zfcp_data.config_lock);
- list_for_each_entry(tmp_unit, &port->unit_list_head, list) {
- if (tmp_unit->scsi_lun != scsi_lun) {
- found = 1;
- break;
- }
- scsi_lun++;
- }
- unit->scsi_lun = scsi_lun;
- if (found)
- list_add_tail(&unit->list, &tmp_unit->list);
- else
- list_add_tail(&unit->list, &port->unit_list_head);
+ list_add_tail(&unit->list, &port->unit_list_head);
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status);
write_unlock_irq(&zfcp_data.config_lock);
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index aef66bc..4e7cb6d 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -1986,6 +1986,10 @@
failed_openfcp:
zfcp_close_fsf(erp_action->adapter);
failed_qdio:
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
+ ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
+ ZFCP_STATUS_ADAPTER_XPORT_OK,
+ &erp_action->adapter->status);
out:
return retval;
}
@@ -2167,6 +2171,9 @@
sleep *= 2;
}
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
+ &adapter->status);
+
if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
&adapter->status)) {
ZFCP_LOG_INFO("error: exchange of configuration data for "
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index eb766c3..76c0909 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -1306,22 +1306,26 @@
wake_up(&tw_dev->ioctl_wqueue);
}
} else {
+ struct scsi_cmnd *cmd;
+
+ cmd = tw_dev->srb[request_id];
+
twa_scsiop_execute_scsi_complete(tw_dev, request_id);
/* If no error command was a success */
if (error == 0) {
- tw_dev->srb[request_id]->result = (DID_OK << 16);
+ cmd->result = (DID_OK << 16);
}
/* If error, command failed */
if (error == 1) {
/* Ask for a host reset */
- tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+ cmd->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
}
/* Report residual bytes for single sgl */
- if ((tw_dev->srb[request_id]->use_sg <= 1) && (full_command_packet->command.newcommand.status == 0)) {
- if (full_command_packet->command.newcommand.sg_list[0].length < tw_dev->srb[request_id]->request_bufflen)
- tw_dev->srb[request_id]->resid = tw_dev->srb[request_id]->request_bufflen - full_command_packet->command.newcommand.sg_list[0].length;
+ if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) {
+ if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id]))
+ scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length);
}
/* Now complete the io */
@@ -1384,53 +1388,21 @@
{
int use_sg;
struct scsi_cmnd *cmd = tw_dev->srb[request_id];
- struct pci_dev *pdev = tw_dev->tw_pci_dev;
- int retval = 0;
- if (cmd->use_sg == 0)
- goto out;
-
- use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
-
- if (use_sg == 0) {
+ use_sg = scsi_dma_map(cmd);
+ if (!use_sg)
+ return 0;
+ else if (use_sg < 0) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list");
- goto out;
+ return 0;
}
cmd->SCp.phase = TW_PHASE_SGLIST;
cmd->SCp.have_data_in = use_sg;
- retval = use_sg;
-out:
- return retval;
+
+ return use_sg;
} /* End twa_map_scsi_sg_data() */
-/* This function will perform a pci-dma map for a single buffer */
-static dma_addr_t twa_map_scsi_single_data(TW_Device_Extension *tw_dev, int request_id)
-{
- dma_addr_t mapping;
- struct scsi_cmnd *cmd = tw_dev->srb[request_id];
- struct pci_dev *pdev = tw_dev->tw_pci_dev;
- dma_addr_t retval = 0;
-
- if (cmd->request_bufflen == 0) {
- retval = 0;
- goto out;
- }
-
- mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, DMA_BIDIRECTIONAL);
-
- if (mapping == 0) {
- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Failed to map page");
- goto out;
- }
-
- cmd->SCp.phase = TW_PHASE_SINGLE;
- cmd->SCp.have_data_in = mapping;
- retval = mapping;
-out:
- return retval;
-} /* End twa_map_scsi_single_data() */
-
/* This function will poll for a response interrupt of a request */
static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
{
@@ -1815,15 +1787,13 @@
u32 num_sectors = 0x0;
int i, sg_count;
struct scsi_cmnd *srb = NULL;
- struct scatterlist *sglist = NULL;
- dma_addr_t buffaddr = 0x0;
+ struct scatterlist *sglist = NULL, *sg;
int retval = 1;
if (tw_dev->srb[request_id]) {
- if (tw_dev->srb[request_id]->request_buffer) {
- sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
- }
srb = tw_dev->srb[request_id];
+ if (scsi_sglist(srb))
+ sglist = scsi_sglist(srb);
}
/* Initialize command packet */
@@ -1856,32 +1826,12 @@
if (!sglistarg) {
/* Map sglist from scsi layer to cmd packet */
- if (tw_dev->srb[request_id]->use_sg == 0) {
- if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) {
- command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
- command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH);
- if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL)
- memcpy(tw_dev->generic_buffer_virt[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
- } else {
- buffaddr = twa_map_scsi_single_data(tw_dev, request_id);
- if (buffaddr == 0)
- goto out;
- command_packet->sg_list[0].address = TW_CPU_TO_SGL(buffaddr);
- command_packet->sg_list[0].length = cpu_to_le32(tw_dev->srb[request_id]->request_bufflen);
- }
- command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), 1));
-
- if (command_packet->sg_list[0].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address during execute scsi");
- goto out;
- }
- }
-
- if (tw_dev->srb[request_id]->use_sg > 0) {
- if ((tw_dev->srb[request_id]->use_sg == 1) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
- if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL) {
- struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+ if (scsi_sg_count(srb)) {
+ if ((scsi_sg_count(srb) == 1) &&
+ (scsi_bufflen(srb) < TW_MIN_SGL_LENGTH)) {
+ if (srb->sc_data_direction == DMA_TO_DEVICE || srb->sc_data_direction == DMA_BIDIRECTIONAL) {
+ struct scatterlist *sg = scsi_sglist(srb);
char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
memcpy(tw_dev->generic_buffer_virt[request_id], buf, sg->length);
kunmap_atomic(buf - sg->offset, KM_IRQ0);
@@ -1893,16 +1843,16 @@
if (sg_count == 0)
goto out;
- for (i = 0; i < sg_count; i++) {
- command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(&sglist[i]));
- command_packet->sg_list[i].length = cpu_to_le32(sg_dma_len(&sglist[i]));
+ scsi_for_each_sg(srb, sg, sg_count, i) {
+ command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(sg));
+ command_packet->sg_list[i].length = cpu_to_le32(sg_dma_len(sg));
if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
goto out;
}
}
}
- command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), tw_dev->srb[request_id]->use_sg));
+ command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id])));
}
} else {
/* Internal cdb post */
@@ -1932,7 +1882,7 @@
/* Update SG statistics */
if (srb) {
- tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+ tw_dev->sgl_entries = scsi_sg_count(tw_dev->srb[request_id]);
if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
tw_dev->max_sgl_entries = tw_dev->sgl_entries;
}
@@ -1951,16 +1901,13 @@
/* This function completes an execute scsi operation */
static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id)
{
- if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH &&
- (tw_dev->srb[request_id]->sc_data_direction == DMA_FROM_DEVICE ||
- tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL)) {
- if (tw_dev->srb[request_id]->use_sg == 0) {
- memcpy(tw_dev->srb[request_id]->request_buffer,
- tw_dev->generic_buffer_virt[request_id],
- tw_dev->srb[request_id]->request_bufflen);
- }
- if (tw_dev->srb[request_id]->use_sg == 1) {
- struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+ struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+
+ if (scsi_bufflen(cmd) < TW_MIN_SGL_LENGTH &&
+ (cmd->sc_data_direction == DMA_FROM_DEVICE ||
+ cmd->sc_data_direction == DMA_BIDIRECTIONAL)) {
+ if (scsi_sg_count(cmd) == 1) {
+ struct scatterlist *sg = scsi_sglist(tw_dev->srb[request_id]);
char *buf;
unsigned long flags = 0;
local_irq_save(flags);
@@ -2017,16 +1964,8 @@
static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
{
struct scsi_cmnd *cmd = tw_dev->srb[request_id];
- struct pci_dev *pdev = tw_dev->tw_pci_dev;
- switch(cmd->SCp.phase) {
- case TW_PHASE_SINGLE:
- pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
- break;
- case TW_PHASE_SGLIST:
- pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
- break;
- }
+ scsi_dma_unmap(cmd);
} /* End twa_unmap_scsi_data() */
/* scsi_host_template initializer */
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 656bdb1..c7995fc 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -1273,57 +1273,24 @@
int use_sg;
dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
-
- if (cmd->use_sg == 0)
- return 0;
- use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
-
- if (use_sg == 0) {
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg < 0) {
printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
return 0;
}
cmd->SCp.phase = TW_PHASE_SGLIST;
cmd->SCp.have_data_in = use_sg;
-
+
return use_sg;
} /* End tw_map_scsi_sg_data() */
-static u32 tw_map_scsi_single_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
- dma_addr_t mapping;
-
- dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
-
- if (cmd->request_bufflen == 0)
- return 0;
-
- mapping = pci_map_page(pdev, virt_to_page(cmd->request_buffer), offset_in_page(cmd->request_buffer), cmd->request_bufflen, DMA_BIDIRECTIONAL);
-
- if (mapping == 0) {
- printk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n");
- return 0;
- }
-
- cmd->SCp.phase = TW_PHASE_SINGLE;
- cmd->SCp.have_data_in = mapping;
-
- return mapping;
-} /* End tw_map_scsi_single_data() */
-
static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
{
dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
- switch(cmd->SCp.phase) {
- case TW_PHASE_SINGLE:
- pci_unmap_page(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
- break;
- case TW_PHASE_SGLIST:
- pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
- break;
- }
+ scsi_dma_unmap(cmd);
} /* End tw_unmap_scsi_data() */
/* This function will reset a device extension */
@@ -1499,27 +1466,16 @@
void *buf;
unsigned int transfer_len;
unsigned long flags = 0;
+ struct scatterlist *sg = scsi_sglist(cmd);
- if (cmd->use_sg) {
- struct scatterlist *sg =
- (struct scatterlist *)cmd->request_buffer;
- local_irq_save(flags);
- buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- transfer_len = min(sg->length, len);
- } else {
- buf = cmd->request_buffer;
- transfer_len = min(cmd->request_bufflen, len);
- }
+ local_irq_save(flags);
+ buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ transfer_len = min(sg->length, len);
memcpy(buf, data, transfer_len);
-
- if (cmd->use_sg) {
- struct scatterlist *sg;
- sg = (struct scatterlist *)cmd->request_buffer;
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
- local_irq_restore(flags);
- }
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ local_irq_restore(flags);
}
/* This function is called by the isr to complete an inquiry command */
@@ -1764,19 +1720,20 @@
{
TW_Command *command_packet;
unsigned long command_que_value;
- u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
+ u32 lba = 0x0, num_sectors = 0x0;
int i, use_sg;
struct scsi_cmnd *srb;
- struct scatterlist *sglist;
+ struct scatterlist *sglist, *sg;
dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write()\n");
- if (tw_dev->srb[request_id]->request_buffer == NULL) {
+ srb = tw_dev->srb[request_id];
+
+ sglist = scsi_sglist(srb);
+ if (!sglist) {
printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Request buffer NULL.\n");
return 1;
}
- sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
- srb = tw_dev->srb[request_id];
/* Initialize command packet */
command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
@@ -1819,33 +1776,18 @@
command_packet->byte8.io.lba = lba;
command_packet->byte6.block_count = num_sectors;
- /* Do this if there are no sg list entries */
- if (tw_dev->srb[request_id]->use_sg == 0) {
- dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
- buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
- if (buffaddr == 0)
- return 1;
+ use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+ if (!use_sg)
+ return 1;
- command_packet->byte8.io.sgl[0].address = buffaddr;
- command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+ scsi_for_each_sg(tw_dev->srb[request_id], sg, use_sg, i) {
+ command_packet->byte8.io.sgl[i].address = sg_dma_address(sg);
+ command_packet->byte8.io.sgl[i].length = sg_dma_len(sg);
command_packet->size+=2;
}
- /* Do this if we have multiple sg list entries */
- if (tw_dev->srb[request_id]->use_sg > 0) {
- use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
- if (use_sg == 0)
- return 1;
-
- for (i=0;i<use_sg; i++) {
- command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
- command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
- command_packet->size+=2;
- }
- }
-
/* Update SG statistics */
- tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+ tw_dev->sgl_entries = scsi_sg_count(tw_dev->srb[request_id]);
if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
tw_dev->max_sgl_entries = tw_dev->sgl_entries;
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index cb02656..71ff3fb 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -267,8 +267,6 @@
offset = max_offset;
}
if(XFERP < min_xferp) {
- printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n",
- XFERP, min_xferp);
XFERP = min_xferp;
}
return (offset & 0x0f) | (XFERP & 0x07)<<4;
@@ -585,16 +583,8 @@
struct NCR_700_command_slot *slot)
{
if(SCp->sc_data_direction != DMA_NONE &&
- SCp->sc_data_direction != DMA_BIDIRECTIONAL) {
- if(SCp->use_sg) {
- dma_unmap_sg(hostdata->dev, SCp->request_buffer,
- SCp->use_sg, SCp->sc_data_direction);
- } else {
- dma_unmap_single(hostdata->dev, slot->dma_handle,
- SCp->request_bufflen,
- SCp->sc_data_direction);
- }
- }
+ SCp->sc_data_direction != DMA_BIDIRECTIONAL)
+ scsi_dma_unmap(SCp);
}
STATIC inline void
@@ -661,7 +651,6 @@
{
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)host->hostdata[0];
- __u32 dcntl_extra = 0;
__u8 min_period;
__u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
@@ -686,13 +675,14 @@
burst_disable = BURST_DISABLE;
break;
}
- dcntl_extra = COMPAT_700_MODE;
+ hostdata->dcntl_extra |= COMPAT_700_MODE;
- NCR_700_writeb(dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(hostdata->dcntl_extra, host, DCNTL_REG);
NCR_700_writeb(burst_length | hostdata->dmode_extra,
host, DMODE_710_REG);
- NCR_700_writeb(burst_disable | (hostdata->differential ?
- DIFF : 0), host, CTEST7_REG);
+ NCR_700_writeb(burst_disable | hostdata->ctest7_extra |
+ (hostdata->differential ? DIFF : 0),
+ host, CTEST7_REG);
NCR_700_writeb(BTB_TIMER_DISABLE, host, CTEST0_REG);
NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY | PARITY
| AUTO_ATN, host, SCNTL0_REG);
@@ -727,13 +717,13 @@
* of spec: sync divider 2, async divider 3 */
DEBUG(("53c700: sync 2 async 3\n"));
NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG);
- NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG);
hostdata->sync_clock = hostdata->clock/2;
} else if(hostdata->clock > 50 && hostdata->clock <= 75) {
/* sync divider 1.5, async divider 3 */
DEBUG(("53c700: sync 1.5 async 3\n"));
NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG);
- NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG);
hostdata->sync_clock = hostdata->clock*2;
hostdata->sync_clock /= 3;
@@ -741,18 +731,18 @@
/* sync divider 1, async divider 2 */
DEBUG(("53c700: sync 1 async 2\n"));
NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
- NCR_700_writeb(ASYNC_DIV_2_0 | dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(ASYNC_DIV_2_0 | hostdata->dcntl_extra, host, DCNTL_REG);
hostdata->sync_clock = hostdata->clock;
} else if(hostdata->clock > 25 && hostdata->clock <=37) {
/* sync divider 1, async divider 1.5 */
DEBUG(("53c700: sync 1 async 1.5\n"));
NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
- NCR_700_writeb(ASYNC_DIV_1_5 | dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(ASYNC_DIV_1_5 | hostdata->dcntl_extra, host, DCNTL_REG);
hostdata->sync_clock = hostdata->clock;
} else {
DEBUG(("53c700: sync 1 async 1\n"));
NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
- NCR_700_writeb(ASYNC_DIV_1_0 | dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(ASYNC_DIV_1_0 | hostdata->dcntl_extra, host, DCNTL_REG);
/* sync divider 1, async divider 1 */
hostdata->sync_clock = hostdata->clock;
}
@@ -1263,14 +1253,13 @@
host->host_no, pun, lun, NCR_700_condition[i],
NCR_700_phase[j], dsp - hostdata->pScript);
if(SCp != NULL) {
- scsi_print_command(SCp);
+ struct scatterlist *sg;
- if(SCp->use_sg) {
- for(i = 0; i < SCp->use_sg + 1; i++) {
- printk(KERN_INFO " SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, ((struct scatterlist *)SCp->request_buffer)[i].length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr);
- }
+ scsi_print_command(SCp);
+ scsi_for_each_sg(SCp, sg, scsi_sg_count(SCp) + 1, i) {
+ printk(KERN_INFO " SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, sg->length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr);
}
- }
+ }
NCR_700_internal_bus_reset(host);
} else if((dsps & 0xfffff000) == A_DEBUG_INTERRUPT) {
printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %08x[%04x], continuing\n",
@@ -1844,8 +1833,8 @@
}
/* sanity check: some of the commands generated by the mid-layer
* have an eccentric idea of their sc_data_direction */
- if(!SCp->use_sg && !SCp->request_bufflen
- && SCp->sc_data_direction != DMA_NONE) {
+ if(!scsi_sg_count(SCp) && !scsi_bufflen(SCp) &&
+ SCp->sc_data_direction != DMA_NONE) {
#ifdef NCR_700_DEBUG
printk("53c700: Command");
scsi_print_command(SCp);
@@ -1887,31 +1876,15 @@
int i;
int sg_count;
dma_addr_t vPtr = 0;
+ struct scatterlist *sg;
__u32 count = 0;
- if(SCp->use_sg) {
- sg_count = dma_map_sg(hostdata->dev,
- SCp->request_buffer, SCp->use_sg,
- direction);
- } else {
- vPtr = dma_map_single(hostdata->dev,
- SCp->request_buffer,
- SCp->request_bufflen,
- direction);
- count = SCp->request_bufflen;
- slot->dma_handle = vPtr;
- sg_count = 1;
- }
-
+ sg_count = scsi_dma_map(SCp);
+ BUG_ON(sg_count < 0);
- for(i = 0; i < sg_count; i++) {
-
- if(SCp->use_sg) {
- struct scatterlist *sg = SCp->request_buffer;
-
- vPtr = sg_dma_address(&sg[i]);
- count = sg_dma_len(&sg[i]);
- }
+ scsi_for_each_sg(SCp, sg, sg_count, i) {
+ vPtr = sg_dma_address(sg);
+ count = sg_dma_len(sg);
slot->SG[i].ins = bS_to_host(move_ins | count);
DEBUG((" scatter block %d: move %d[%08x] from 0x%lx\n",
diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
index 841e1bb..e06bdfe 100644
--- a/drivers/scsi/53c700.h
+++ b/drivers/scsi/53c700.h
@@ -177,6 +177,7 @@
__u8 state;
#define NCR_700_FLAG_AUTOSENSE 0x01
__u8 flags;
+ __u8 pad1[2]; /* Needed for m68k where min alignment is 2 bytes */
int tag;
__u32 resume_offset;
struct scsi_cmnd *cmnd;
@@ -196,6 +197,8 @@
void __iomem *base; /* the base for the port (copied to host) */
struct device *dev;
__u32 dmode_extra; /* adjustable bus settings */
+ __u32 dcntl_extra; /* adjustable bus settings */
+ __u32 ctest7_extra; /* adjustable bus settings */
__u32 differential:1; /* if we are differential */
#ifdef CONFIG_53C700_LE_ON_BE
/* This option is for HP only. Set it if your chip is wired for
@@ -352,6 +355,7 @@
#define SEL_TIMEOUT_DISABLE 0x10 /* 710 only */
#define DFP 0x08
#define EVP 0x04
+#define CTEST7_TT1 0x02
#define DIFF 0x01
#define CTEST6_REG 0x1A
#define TEMP_REG 0x1C
@@ -385,6 +389,7 @@
#define SOFTWARE_RESET 0x01
#define COMPAT_700_MODE 0x01
#define SCRPTS_16BITS 0x20
+#define EA_710 0x20
#define ASYNC_DIV_2_0 0x00
#define ASYNC_DIV_1_5 0x40
#define ASYNC_DIV_1_0 0x80
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
deleted file mode 100644
index 93b41f4..0000000
--- a/drivers/scsi/53c7xx.c
+++ /dev/null
@@ -1,6102 +0,0 @@
-/*
- * 53c710 driver. Modified from Drew Eckhardts driver
- * for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
- * Check out PERM_OPTIONS and EXPECTED_CLOCK, which may be defined in the
- * relevant machine specific file (eg. mvme16x.[ch], amiga7xx.[ch]).
- * There are also currently some defines at the top of 53c7xx.scr.
- * The chip type is #defined in script_asm.pl, as well as the Makefile.
- * Host scsi ID expected to be 7 - see NCR53c7x0_init().
- *
- * I have removed the PCI code and some of the 53c8xx specific code -
- * simply to make this file smaller and easier to manage.
- *
- * MVME16x issues:
- * Problems trying to read any chip registers in NCR53c7x0_init(), as they
- * may never have been set by 16xBug (eg. If kernel has come in over tftp).
- */
-
-/*
- * Adapted for Linux/m68k Amiga platforms for the A4000T/A4091 and
- * WarpEngine SCSI controllers.
- * By Alan Hourihane <alanh@fairlite.demon.co.uk>
- * Thanks to Richard Hirst for making it possible with the MVME additions
- */
-
-/*
- * 53c710 rev 0 doesn't support add with carry. Rev 1 and 2 does. To
- * overcome this problem you can define FORCE_DSA_ALIGNMENT, which ensures
- * that the DSA address is always xxxxxx00. If disconnection is not allowed,
- * then the script only ever tries to add small (< 256) positive offsets to
- * DSA, so lack of carry isn't a problem. FORCE_DSA_ALIGNMENT can, of course,
- * be defined for all chip revisions at a small cost in memory usage.
- */
-
-#define FORCE_DSA_ALIGNMENT
-
-/*
- * Selection timer does not always work on the 53c710, depending on the
- * timing at the last disconnect, if this is a problem for you, try
- * using validids as detailed below.
- *
- * Options for the NCR7xx driver
- *
- * noasync:0 - disables sync and asynchronous negotiation
- * nosync:0 - disables synchronous negotiation (does async)
- * nodisconnect:0 - disables disconnection
- * validids:0x?? - Bitmask field that disallows certain ID's.
- * - e.g. 0x03 allows ID 0,1
- * - 0x1F allows ID 0,1,2,3,4
- * opthi:n - replace top word of options with 'n'
- * optlo:n - replace bottom word of options with 'n'
- * - ALWAYS SPECIFY opthi THEN optlo <<<<<<<<<<
- */
-
-/*
- * PERM_OPTIONS are driver options which will be enabled for all NCR boards
- * in the system at driver initialization time.
- *
- * Don't THINK about touching these in PERM_OPTIONS :
- * OPTION_MEMORY_MAPPED
- * 680x0 doesn't have an IO map!
- *
- * OPTION_DEBUG_TEST1
- * Test 1 does bus mastering and interrupt tests, which will help weed
- * out brain damaged main boards.
- *
- * Other PERM_OPTIONS settings are listed below. Note the actual options
- * required are set in the relevant file (mvme16x.c, amiga7xx.c, etc):
- *
- * OPTION_NO_ASYNC
- * Don't negotiate for asynchronous transfers on the first command
- * when OPTION_ALWAYS_SYNCHRONOUS is set. Useful for dain bramaged
- * devices which do something bad rather than sending a MESSAGE
- * REJECT back to us like they should if they can't cope.
- *
- * OPTION_SYNCHRONOUS
- * Enable support for synchronous transfers. Target negotiated
- * synchronous transfers will be responded to. To initiate
- * a synchronous transfer request, call
- *
- * request_synchronous (hostno, target)
- *
- * from within KGDB.
- *
- * OPTION_ALWAYS_SYNCHRONOUS
- * Negotiate for synchronous transfers with every target after
- * driver initialization or a SCSI bus reset. This is a bit dangerous,
- * since there are some dain bramaged SCSI devices which will accept
- * SDTR messages but keep talking asynchronously.
- *
- * OPTION_DISCONNECT
- * Enable support for disconnect/reconnect. To change the
- * default setting on a given host adapter, call
- *
- * request_disconnect (hostno, allow)
- *
- * where allow is non-zero to allow, 0 to disallow.
- *
- * If you really want to run 10MHz FAST SCSI-II transfers, you should
- * know that the NCR driver currently ignores parity information. Most
- * systems do 5MHz SCSI fine. I've seen a lot that have problems faster
- * than 8MHz. To play it safe, we only request 5MHz transfers.
- *
- * If you'd rather get 10MHz transfers, edit sdtr_message and change
- * the fourth byte from 50 to 25.
- */
-
-/*
- * Sponsored by
- * iX Multiuser Multitasking Magazine
- * Hannover, Germany
- * hm@ix.de
- *
- * Copyright 1993, 1994, 1995 Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@PoohSticks.ORG
- * +1 (303) 786-7975
- *
- * TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
- *
- * For more information, please consult
- *
- * NCR53C810
- * SCSI I/O Processor
- * Programmer's Guide
- *
- * NCR 53C810
- * PCI-SCSI I/O Processor
- * Data Manual
- *
- * NCR 53C810/53C820
- * PCI-SCSI I/O Processor Design In Guide
- *
- * For literature on Symbios Logic Inc. formerly NCR, SCSI,
- * and Communication products please call (800) 334-5454 or
- * (719) 536-3300.
- *
- * PCI BIOS Specification Revision
- * PCI Local Bus Specification
- * PCI System Design Guide
- *
- * PCI Special Interest Group
- * M/S HF3-15A
- * 5200 N.E. Elam Young Parkway
- * Hillsboro, Oregon 97124-6497
- * +1 (503) 696-2000
- * +1 (800) 433-5177
- */
-
-/*
- * Design issues :
- * The cumulative latency needed to propagate a read/write request
- * through the file system, buffer cache, driver stacks, SCSI host, and
- * SCSI device is ultimately the limiting factor in throughput once we
- * have a sufficiently fast host adapter.
- *
- * So, to maximize performance we want to keep the ratio of latency to data
- * transfer time to a minimum by
- * 1. Minimizing the total number of commands sent (typical command latency
- * including drive and bus mastering host overhead is as high as 4.5ms)
- * to transfer a given amount of data.
- *
- * This is accomplished by placing no arbitrary limit on the number
- * of scatter/gather buffers supported, since we can transfer 1K
- * per scatter/gather buffer without Eric's cluster patches,
- * 4K with.
- *
- * 2. Minimizing the number of fatal interrupts serviced, since
- * fatal interrupts halt the SCSI I/O processor. Basically,
- * this means offloading the practical maximum amount of processing
- * to the SCSI chip.
- *
- * On the NCR53c810/820/720, this is accomplished by using
- * interrupt-on-the-fly signals when commands complete,
- * and only handling fatal errors and SDTR / WDTR messages
- * in the host code.
- *
- * On the NCR53c710, interrupts are generated as on the NCR53c8x0,
- * only the lack of a interrupt-on-the-fly facility complicates
- * things. Also, SCSI ID registers and commands are
- * bit fielded rather than binary encoded.
- *
- * On the NCR53c700 and NCR53c700-66, operations that are done via
- * indirect, table mode on the more advanced chips must be
- * replaced by calls through a jump table which
- * acts as a surrogate for the DSA. Unfortunately, this
- * will mean that we must service an interrupt for each
- * disconnect/reconnect.
- *
- * 3. Eliminating latency by pipelining operations at the different levels.
- *
- * This driver allows a configurable number of commands to be enqueued
- * for each target/lun combination (experimentally, I have discovered
- * that two seems to work best) and will ultimately allow for
- * SCSI-II tagged queuing.
- *
- *
- * Architecture :
- * This driver is built around a Linux queue of commands waiting to
- * be executed, and a shared Linux/NCR array of commands to start. Commands
- * are transferred to the array by the run_process_issue_queue() function
- * which is called whenever a command completes.
- *
- * As commands are completed, the interrupt routine is triggered,
- * looks for commands in the linked list of completed commands with
- * valid status, removes these commands from a list of running commands,
- * calls the done routine, and flags their target/luns as not busy.
- *
- * Due to limitations in the intelligence of the NCR chips, certain
- * concessions are made. In many cases, it is easier to dynamically
- * generate/fix-up code rather than calculate on the NCR at run time.
- * So, code is generated or fixed up for
- *
- * - Handling data transfers, using a variable number of MOVE instructions
- * interspersed with CALL MSG_IN, WHEN MSGIN instructions.
- *
- * The DATAIN and DATAOUT routines are separate, so that an incorrect
- * direction can be trapped, and space isn't wasted.
- *
- * It may turn out that we're better off using some sort
- * of table indirect instruction in a loop with a variable
- * sized table on the NCR53c710 and newer chips.
- *
- * - Checking for reselection (NCR53c710 and better)
- *
- * - Handling the details of SCSI context switches (NCR53c710 and better),
- * such as reprogramming appropriate synchronous parameters,
- * removing the dsa structure from the NCR's queue of outstanding
- * commands, etc.
- *
- */
-
-#include <linux/module.h>
-
-
-#include <linux/types.h>
-#include <asm/setup.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/time.h>
-#include <linux/blkdev.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <asm/pgtable.h>
-
-#ifdef CONFIG_AMIGA
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/irq.h>
-
-#define BIG_ENDIAN
-#define NO_IO_SPACE
-#endif
-
-#ifdef CONFIG_MVME16x
-#include <asm/mvme16xhw.h>
-
-#define BIG_ENDIAN
-#define NO_IO_SPACE
-#define VALID_IDS
-#endif
-
-#ifdef CONFIG_BVME6000
-#include <asm/bvme6000hw.h>
-
-#define BIG_ENDIAN
-#define NO_IO_SPACE
-#define VALID_IDS
-#endif
-
-#include "scsi.h"
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_transport_spi.h>
-#include "53c7xx.h"
-#include <linux/stat.h>
-#include <linux/stddef.h>
-
-#ifdef NO_IO_SPACE
-/*
- * The following make the definitions in 53c7xx.h (write8, etc) smaller,
- * we don't have separate i/o space anyway.
- */
-#undef inb
-#undef outb
-#undef inw
-#undef outw
-#undef inl
-#undef outl
-#define inb(x) 1
-#define inw(x) 1
-#define inl(x) 1
-#define outb(x,y) 1
-#define outw(x,y) 1
-#define outl(x,y) 1
-#endif
-
-static int check_address (unsigned long addr, int size);
-static void dump_events (struct Scsi_Host *host, int count);
-static Scsi_Cmnd * return_outstanding_commands (struct Scsi_Host *host,
- int free, int issue);
-static void hard_reset (struct Scsi_Host *host);
-static void ncr_scsi_reset (struct Scsi_Host *host);
-static void print_lots (struct Scsi_Host *host);
-static void set_synchronous (struct Scsi_Host *host, int target, int sxfer,
- int scntl3, int now_connected);
-static int datapath_residual (struct Scsi_Host *host);
-static const char * sbcl_to_phase (int sbcl);
-static void print_progress (Scsi_Cmnd *cmd);
-static void print_queues (struct Scsi_Host *host);
-static void process_issue_queue (unsigned long flags);
-static int shutdown (struct Scsi_Host *host);
-static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
-static int disable (struct Scsi_Host *host);
-static int NCR53c7xx_run_tests (struct Scsi_Host *host);
-static irqreturn_t NCR53c7x0_intr(int irq, void *dev_id);
-static void NCR53c7x0_intfly (struct Scsi_Host *host);
-static int ncr_halt (struct Scsi_Host *host);
-static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
- *cmd);
-static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
-static void print_dsa (struct Scsi_Host *host, u32 *dsa,
- const char *prefix);
-static int print_insn (struct Scsi_Host *host, const u32 *insn,
- const char *prefix, int kernel);
-
-static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd);
-static void NCR53c7x0_init_fixup (struct Scsi_Host *host);
-static int NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
- NCR53c7x0_cmd *cmd);
-static void NCR53c7x0_soft_reset (struct Scsi_Host *host);
-
-/* Size of event list (per host adapter) */
-static int track_events = 0;
-static struct Scsi_Host *first_host = NULL; /* Head of list of NCR boards */
-static struct scsi_host_template *the_template = NULL;
-
-/* NCR53c710 script handling code */
-
-#include "53c7xx_d.h"
-#ifdef A_int_debug_sync
-#define DEBUG_SYNC_INTR A_int_debug_sync
-#endif
-int NCR53c7xx_script_len = sizeof (SCRIPT);
-int NCR53c7xx_dsa_len = A_dsa_end + Ent_dsa_zero - Ent_dsa_code_template;
-#ifdef FORCE_DSA_ALIGNMENT
-int CmdPageStart = (0 - Ent_dsa_zero - sizeof(struct NCR53c7x0_cmd)) & 0xff;
-#endif
-
-static char *setup_strings[] =
- {"","","","","","","",""};
-
-#define MAX_SETUP_STRINGS ARRAY_SIZE(setup_strings)
-#define SETUP_BUFFER_SIZE 200
-static char setup_buffer[SETUP_BUFFER_SIZE];
-static char setup_used[MAX_SETUP_STRINGS];
-
-void ncr53c7xx_setup (char *str, int *ints)
-{
- int i;
- char *p1, *p2;
-
- p1 = setup_buffer;
- *p1 = '\0';
- if (str)
- strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
- setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
- p1 = setup_buffer;
- i = 0;
- while (*p1 && (i < MAX_SETUP_STRINGS)) {
- p2 = strchr(p1, ',');
- if (p2) {
- *p2 = '\0';
- if (p1 != p2)
- setup_strings[i] = p1;
- p1 = p2 + 1;
- i++;
- }
- else {
- setup_strings[i] = p1;
- break;
- }
- }
- for (i=0; i<MAX_SETUP_STRINGS; i++)
- setup_used[i] = 0;
-}
-
-
-/* check_setup_strings() returns index if key found, 0 if not
- */
-
-static int check_setup_strings(char *key, int *flags, int *val, char *buf)
-{
-int x;
-char *cp;
-
- for (x=0; x<MAX_SETUP_STRINGS; x++) {
- if (setup_used[x])
- continue;
- if (!strncmp(setup_strings[x], key, strlen(key)))
- break;
- if (!strncmp(setup_strings[x], "next", strlen("next")))
- return 0;
- }
- if (x == MAX_SETUP_STRINGS)
- return 0;
- setup_used[x] = 1;
- cp = setup_strings[x] + strlen(key);
- *val = -1;
- if (*cp != ':')
- return ++x;
- cp++;
- if ((*cp >= '0') && (*cp <= '9')) {
- *val = simple_strtoul(cp,NULL,0);
- }
- return ++x;
-}
-
-
-
-/*
- * KNOWN BUGS :
- * - There is some sort of conflict when the PPP driver is compiled with
- * support for 16 channels?
- *
- * - On systems which predate the 1.3.x initialization order change,
- * the NCR driver will cause Cannot get free page messages to appear.
- * These are harmless, but I don't know of an easy way to avoid them.
- *
- * - With OPTION_DISCONNECT, on two systems under unknown circumstances,
- * we get a PHASE MISMATCH with DSA set to zero (suggests that we
- * are occurring somewhere in the reselection code) where
- * DSP=some value DCMD|DBC=same value.
- *
- * Closer inspection suggests that we may be trying to execute
- * some portion of the DSA?
- * scsi0 : handling residual transfer (+ 0 bytes from DMA FIFO)
- * scsi0 : handling residual transfer (+ 0 bytes from DMA FIFO)
- * scsi0 : no current command : unexpected phase MSGIN.
- * DSP=0x1c46cc, DCMD|DBC=0x1c46ac, DSA=0x0
- * DSPS=0x0, TEMP=0x1c3e70, DMODE=0x80
- * scsi0 : DSP->
- * 001c46cc : 0x001c46cc 0x00000000
- * 001c46d4 : 0x001c5ea0 0x000011f8
- *
- * Changed the print code in the phase_mismatch handler so
- * that we call print_lots to try to diagnose this.
- *
- */
-
-/*
- * Possible future direction of architecture for max performance :
- *
- * We're using a single start array for the NCR chip. This is
- * sub-optimal, because we cannot add a command which would conflict with
- * an executing command to this start queue, and therefore must insert the
- * next command for a given I/T/L combination after the first has completed;
- * incurring our interrupt latency between SCSI commands.
- *
- * To allow further pipelining of the NCR and host CPU operation, we want
- * to set things up so that immediately on termination of a command destined
- * for a given LUN, we get that LUN busy again.
- *
- * To do this, we need to add a 32 bit pointer to which is jumped to
- * on completion of a command. If no new command is available, this
- * would point to the usual DSA issue queue select routine.
- *
- * If one were, it would point to a per-NCR53c7x0_cmd select routine
- * which starts execution immediately, inserting the command at the head
- * of the start queue if the NCR chip is selected or reselected.
- *
- * We would change so that we keep a list of outstanding commands
- * for each unit, rather than a single running_list. We'd insert
- * a new command into the right running list; if the NCR didn't
- * have something running for that yet, we'd put it in the
- * start queue as well. Some magic needs to happen to handle the
- * race condition between the first command terminating before the
- * new one is written.
- *
- * Potential for profiling :
- * Call do_gettimeofday(struct timeval *tv) to get 800ns resolution.
- */
-
-
-/*
- * TODO :
- * 1. To support WIDE transfers, not much needs to happen. We
- * should do CHMOVE instructions instead of MOVEs when
- * we have scatter/gather segments of uneven length. When
- * we do this, we need to handle the case where we disconnect
- * between segments.
- *
- * 2. Currently, when Icky things happen we do a FATAL(). Instead,
- * we want to do an integrity check on the parts of the NCR hostdata
- * structure which were initialized at boot time; FATAL() if that
- * fails, and otherwise try to recover. Keep track of how many
- * times this has happened within a single SCSI command; if it
- * gets excessive, then FATAL().
- *
- * 3. Parity checking is currently disabled, and a few things should
- * happen here now that we support synchronous SCSI transfers :
- * 1. On soft-reset, we shoould set the EPC (Enable Parity Checking)
- * and AAP (Assert SATN/ on parity error) bits in SCNTL0.
- *
- * 2. We should enable the parity interrupt in the SIEN0 register.
- *
- * 3. intr_phase_mismatch() needs to believe that message out is
- * always an "acceptable" phase to have a mismatch in. If
- * the old phase was MSG_IN, we should send a MESSAGE PARITY
- * error. If the old phase was something else, we should send
- * a INITIATOR_DETECTED_ERROR message. Note that this could
- * cause a RESTORE POINTERS message; so we should handle that
- * correctly first. Instead, we should probably do an
- * initiator_abort.
- *
- * 4. MPEE bit of CTEST4 should be set so we get interrupted if
- * we detect an error.
- *
- *
- * 5. The initial code has been tested on the NCR53c810. I don't
- * have access to NCR53c700, 700-66 (Forex boards), NCR53c710
- * (NCR Pentium systems), NCR53c720, NCR53c820, or NCR53c825 boards to
- * finish development on those platforms.
- *
- * NCR53c820/825/720 - need to add wide transfer support, including WDTR
- * negotiation, programming of wide transfer capabilities
- * on reselection and table indirect selection.
- *
- * NCR53c710 - need to add fatal interrupt or GEN code for
- * command completion signaling. Need to modify all
- * SDID, SCID, etc. registers, and table indirect select code
- * since these use bit fielded (ie 1<<target) instead of
- * binary encoded target ids. Need to accommodate
- * different register mappings, probably scan through
- * the SCRIPT code and change the non SFBR register operand
- * of all MOVE instructions.
- *
- * It is rather worse than this actually, the 710 corrupts
- * both TEMP and DSA when you do a MOVE MEMORY. This
- * screws you up all over the place. MOVE MEMORY 4 with a
- * destination of DSA seems to work OK, which helps some.
- * Richard Hirst richard@sleepie.demon.co.uk
- *
- * NCR53c700/700-66 - need to add code to refix addresses on
- * every nexus change, eliminate all table indirect code,
- * very messy.
- *
- * 6. The NCR53c7x0 series is very popular on other platforms that
- * could be running Linux - ie, some high performance AMIGA SCSI
- * boards use it.
- *
- * So, I should include #ifdef'd code so that it is
- * compatible with these systems.
- *
- * Specifically, the little Endian assumptions I made in my
- * bit fields need to change, and if the NCR doesn't see memory
- * the right way, we need to provide options to reverse words
- * when the scripts are relocated.
- *
- * 7. Use vremap() to access memory mapped boards.
- */
-
-/*
- * Allow for simultaneous existence of multiple SCSI scripts so we
- * can have a single driver binary for all of the family.
- *
- * - one for NCR53c700 and NCR53c700-66 chips (not yet supported)
- * - one for rest (only the NCR53c810, 815, 820, and 825 are currently
- * supported)
- *
- * So that we only need two SCSI scripts, we need to modify things so
- * that we fixup register accesses in READ/WRITE instructions, and
- * we'll also have to accommodate the bit vs. binary encoding of IDs
- * with the 7xx chips.
- */
-
-#define ROUNDUP(adr,type) \
- ((void *) (((long) (adr) + sizeof(type) - 1) & ~(sizeof(type) - 1)))
-
-
-/*
- * Function: issue_to_cmd
- *
- * Purpose: convert jump instruction in issue array to NCR53c7x0_cmd
- * structure pointer.
- *
- * Inputs; issue - pointer to start of NOP or JUMP instruction
- * in issue array.
- *
- * Returns: pointer to command on success; 0 if opcode is NOP.
- */
-
-static inline struct NCR53c7x0_cmd *
-issue_to_cmd (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
- u32 *issue)
-{
- return (issue[0] != hostdata->NOP_insn) ?
- /*
- * If the IF TRUE bit is set, it's a JUMP instruction. The
- * operand is a bus pointer to the dsa_begin routine for this DSA. The
- * dsa field of the NCR53c7x0_cmd structure starts with the
- * DSA code template. By converting to a virtual address,
- * subtracting the code template size, and offset of the
- * dsa field, we end up with a pointer to the start of the
- * structure (alternatively, we could use the
- * dsa_cmnd field, an anachronism from when we weren't
- * sure what the relationship between the NCR structures
- * and host structures were going to be.
- */
- (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (issue[1]) -
- (hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template) -
- offsetof(struct NCR53c7x0_cmd, dsa))
- /* If the IF TRUE bit is not set, it's a NOP */
- : NULL;
-}
-
-
-/*
- * FIXME: we should junk these, in favor of synchronous_want and
- * wide_want in the NCR53c7x0_hostdata structure.
- */
-
-/* Template for "preferred" synchronous transfer parameters. */
-
-static const unsigned char sdtr_message[] = {
-#ifdef CONFIG_SCSI_NCR53C7xx_FAST
- EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 25 /* *4ns */, 8 /* off */
-#else
- EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 50 /* *4ns */, 8 /* off */
-#endif
-};
-
-/* Template to request asynchronous transfers */
-
-static const unsigned char async_message[] = {
- EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 0, 0 /* asynchronous */
-};
-
-/* Template for "preferred" WIDE transfer parameters */
-
-static const unsigned char wdtr_message[] = {
- EXTENDED_MESSAGE, 2 /* length */, EXTENDED_WDTR, 1 /* 2^1 bytes */
-};
-
-#if 0
-/*
- * Function : struct Scsi_Host *find_host (int host)
- *
- * Purpose : KGDB support function which translates a host number
- * to a host structure.
- *
- * Inputs : host - number of SCSI host
- *
- * Returns : NULL on failure, pointer to host structure on success.
- */
-
-static struct Scsi_Host *
-find_host (int host) {
- struct Scsi_Host *h;
- for (h = first_host; h && h->host_no != host; h = h->next);
- if (!h) {
- printk (KERN_ALERT "scsi%d not found\n", host);
- return NULL;
- } else if (h->hostt != the_template) {
- printk (KERN_ALERT "scsi%d is not a NCR board\n", host);
- return NULL;
- }
- return h;
-}
-
-#if 0
-/*
- * Function : request_synchronous (int host, int target)
- *
- * Purpose : KGDB interface which will allow us to negotiate for
- * synchronous transfers. This ill be replaced with a more
- * integrated function; perhaps a new entry in the scsi_host
- * structure, accessible via an ioctl() or perhaps /proc/scsi.
- *
- * Inputs : host - number of SCSI host; target - number of target.
- *
- * Returns : 0 when negotiation has been setup for next SCSI command,
- * -1 on failure.
- */
-
-static int
-request_synchronous (int host, int target) {
- struct Scsi_Host *h;
- struct NCR53c7x0_hostdata *hostdata;
- unsigned long flags;
- if (target < 0) {
- printk (KERN_ALERT "target %d is bogus\n", target);
- return -1;
- }
- if (!(h = find_host (host)))
- return -1;
- else if (h->this_id == target) {
- printk (KERN_ALERT "target %d is host ID\n", target);
- return -1;
- }
- else if (target >= h->max_id) {
- printk (KERN_ALERT "target %d exceeds maximum of %d\n", target,
- h->max_id);
- return -1;
- }
- hostdata = (struct NCR53c7x0_hostdata *)h->hostdata[0];
-
- local_irq_save(flags);
- if (hostdata->initiate_sdtr & (1 << target)) {
- local_irq_restore(flags);
- printk (KERN_ALERT "target %d already doing SDTR\n", target);
- return -1;
- }
- hostdata->initiate_sdtr |= (1 << target);
- local_irq_restore(flags);
- return 0;
-}
-#endif
-
-/*
- * Function : request_disconnect (int host, int on_or_off)
- *
- * Purpose : KGDB support function, tells us to allow or disallow
- * disconnections.
- *
- * Inputs : host - number of SCSI host; on_or_off - non-zero to allow,
- * zero to disallow.
- *
- * Returns : 0 on success, * -1 on failure.
- */
-
-static int
-request_disconnect (int host, int on_or_off) {
- struct Scsi_Host *h;
- struct NCR53c7x0_hostdata *hostdata;
- if (!(h = find_host (host)))
- return -1;
- hostdata = (struct NCR53c7x0_hostdata *) h->hostdata[0];
- if (on_or_off)
- hostdata->options |= OPTION_DISCONNECT;
- else
- hostdata->options &= ~OPTION_DISCONNECT;
- return 0;
-}
-#endif
-
-/*
- * Function : static void NCR53c7x0_driver_init (struct Scsi_Host *host)
- *
- * Purpose : Initialize internal structures, as required on startup, or
- * after a SCSI bus reset.
- *
- * Inputs : host - pointer to this host adapter's structure
- */
-
-static void
-NCR53c7x0_driver_init (struct Scsi_Host *host) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- int i, j;
- u32 *ncrcurrent;
-
- for (i = 0; i < 16; ++i) {
- hostdata->request_sense[i] = 0;
- for (j = 0; j < 8; ++j)
- hostdata->busy[i][j] = 0;
- set_synchronous (host, i, /* sxfer */ 0, hostdata->saved_scntl3, 0);
- }
- hostdata->issue_queue = NULL;
- hostdata->running_list = hostdata->finished_queue =
- hostdata->ncrcurrent = NULL;
- for (i = 0, ncrcurrent = (u32 *) hostdata->schedule;
- i < host->can_queue; ++i, ncrcurrent += 2) {
- ncrcurrent[0] = hostdata->NOP_insn;
- ncrcurrent[1] = 0xdeadbeef;
- }
- ncrcurrent[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
- ncrcurrent[1] = (u32) virt_to_bus (hostdata->script) +
- hostdata->E_wait_reselect;
- hostdata->reconnect_dsa_head = 0;
- hostdata->addr_reconnect_dsa_head = (u32)
- virt_to_bus((void *) &(hostdata->reconnect_dsa_head));
- hostdata->expecting_iid = 0;
- hostdata->expecting_sto = 0;
- if (hostdata->options & OPTION_ALWAYS_SYNCHRONOUS)
- hostdata->initiate_sdtr = 0xffff;
- else
- hostdata->initiate_sdtr = 0;
- hostdata->talked_to = 0;
- hostdata->idle = 1;
-}
-
-/*
- * Function : static int clock_to_ccf_710 (int clock)
- *
- * Purpose : Return the clock conversion factor for a given SCSI clock.
- *
- * Inputs : clock - SCSI clock expressed in Hz.
- *
- * Returns : ccf on success, -1 on failure.
- */
-
-static int
-clock_to_ccf_710 (int clock) {
- if (clock <= 16666666)
- return -1;
- if (clock <= 25000000)
- return 2; /* Divide by 1.0 */
- else if (clock <= 37500000)
- return 1; /* Divide by 1.5 */
- else if (clock <= 50000000)
- return 0; /* Divide by 2.0 */
- else if (clock <= 66000000)
- return 3; /* Divide by 3.0 */
- else
- return -1;
-}
-
-/*
- * Function : static int NCR53c7x0_init (struct Scsi_Host *host)
- *
- * Purpose : initialize the internal structures for a given SCSI host
- *
- * Inputs : host - pointer to this host adapter's structure
- *
- * Preconditions : when this function is called, the chip_type
- * field of the hostdata structure MUST have been set.
- *
- * Returns : 0 on success, -1 on failure.
- */
-
-int
-NCR53c7x0_init (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- int i, ccf;
- unsigned char revision;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- /*
- * There are some things which we need to know about in order to provide
- * a semblance of support. Print 'em if they aren't what we expect,
- * otherwise don't add to the noise.
- *
- * -1 means we don't know what to expect.
- */
- int val, flags;
- char buf[32];
- int expected_id = -1;
- int expected_clock = -1;
- int uninitialized = 0;
-#ifdef NO_IO_SPACE
- int expected_mapping = OPTION_MEMORY_MAPPED;
-#else
- int expected_mapping = OPTION_IO_MAPPED;
-#endif
- for (i=0;i<7;i++)
- hostdata->valid_ids[i] = 1; /* Default all ID's to scan */
-
- /* Parse commandline flags */
- if (check_setup_strings("noasync",&flags,&val,buf))
- {
- hostdata->options |= OPTION_NO_ASYNC;
- hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
- }
-
- if (check_setup_strings("nosync",&flags,&val,buf))
- {
- hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
- }
-
- if (check_setup_strings("nodisconnect",&flags,&val,buf))
- hostdata->options &= ~OPTION_DISCONNECT;
-
- if (check_setup_strings("validids",&flags,&val,buf))
- {
- for (i=0;i<7;i++)
- hostdata->valid_ids[i] = val & (1<<i);
- }
-
- if ((i = check_setup_strings("next",&flags,&val,buf)))
- {
- while (i)
- setup_used[--i] = 1;
- }
-
- if (check_setup_strings("opthi",&flags,&val,buf))
- hostdata->options = (long long)val << 32;
- if (check_setup_strings("optlo",&flags,&val,buf))
- hostdata->options |= val;
-
- NCR53c7x0_local_setup(host);
- switch (hostdata->chip) {
- case 710:
- case 770:
- hostdata->dstat_sir_intr = NCR53c7x0_dstat_sir_intr;
- hostdata->init_save_regs = NULL;
- hostdata->dsa_fixup = NCR53c7xx_dsa_fixup;
- hostdata->init_fixup = NCR53c7x0_init_fixup;
- hostdata->soft_reset = NCR53c7x0_soft_reset;
- hostdata->run_tests = NCR53c7xx_run_tests;
- expected_clock = hostdata->scsi_clock;
- expected_id = 7;
- break;
- default:
- printk ("scsi%d : chip type of %d is not supported yet, detaching.\n",
- host->host_no, hostdata->chip);
- scsi_unregister (host);
- return -1;
- }
-
- /* Assign constants accessed by NCR */
- hostdata->NCR53c7xx_zero = 0;
- hostdata->NCR53c7xx_msg_reject = MESSAGE_REJECT;
- hostdata->NCR53c7xx_msg_abort = ABORT;
- hostdata->NCR53c7xx_msg_nop = NOP;
- hostdata->NOP_insn = (DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24;
- if (expected_mapping == -1 ||
- (hostdata->options & (OPTION_MEMORY_MAPPED)) !=
- (expected_mapping & OPTION_MEMORY_MAPPED))
- printk ("scsi%d : using %s mapped access\n", host->host_no,
- (hostdata->options & OPTION_MEMORY_MAPPED) ? "memory" :
- "io");
-
- hostdata->dmode = (hostdata->chip == 700 || hostdata->chip == 70066) ?
- DMODE_REG_00 : DMODE_REG_10;
- hostdata->istat = ((hostdata->chip / 100) == 8) ?
- ISTAT_REG_800 : ISTAT_REG_700;
-
-/* We have to assume that this may be the first access to the chip, so
- * we must set EA in DCNTL. */
-
- NCR53c7x0_write8 (DCNTL_REG, DCNTL_10_EA|DCNTL_10_COM);
-
-
-/* Only the ISTAT register is readable when the NCR is running, so make
- sure it's halted. */
- ncr_halt(host);
-
-/*
- * XXX - the NCR53c700 uses bitfielded registers for SCID, SDID, etc,
- * as does the 710 with one bit per SCSI ID. Conversely, the NCR
- * uses a normal, 3 bit binary representation of these values.
- *
- * Get the rest of the NCR documentation, and FIND OUT where the change
- * was.
- */
-
-#if 0
- /* May not be able to do this - chip my not have been set up yet */
- tmp = hostdata->this_id_mask = NCR53c7x0_read8(SCID_REG);
- for (host->this_id = 0; tmp != 1; tmp >>=1, ++host->this_id);
-#else
- host->this_id = 7;
-#endif
-
-/*
- * Note : we should never encounter a board setup for ID0. So,
- * if we see ID0, assume that it was uninitialized and set it
- * to the industry standard 7.
- */
- if (!host->this_id) {
- printk("scsi%d : initiator ID was %d, changing to 7\n",
- host->host_no, host->this_id);
- host->this_id = 7;
- hostdata->this_id_mask = 1 << 7;
- uninitialized = 1;
- };
-
- if (expected_id == -1 || host->this_id != expected_id)
- printk("scsi%d : using initiator ID %d\n", host->host_no,
- host->this_id);
-
- /*
- * Save important registers to allow a soft reset.
- */
-
- /*
- * CTEST7 controls cache snooping, burst mode, and support for
- * external differential drivers. This isn't currently used - the
- * default value may not be optimal anyway.
- * Even worse, it may never have been set up since reset.
- */
- hostdata->saved_ctest7 = NCR53c7x0_read8(CTEST7_REG) & CTEST7_SAVE;
- revision = (NCR53c7x0_read8(CTEST8_REG) & 0xF0) >> 4;
- switch (revision) {
- case 1: revision = 0; break;
- case 2: revision = 1; break;
- case 4: revision = 2; break;
- case 8: revision = 3; break;
- default: revision = 255; break;
- }
- printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
-
- if ((revision == 0 || revision == 255) && (hostdata->options & (OPTION_SYNCHRONOUS|OPTION_DISCONNECT|OPTION_ALWAYS_SYNCHRONOUS)))
- {
- printk ("scsi%d: Disabling sync working and disconnect/reselect\n",
- host->host_no);
- hostdata->options &= ~(OPTION_SYNCHRONOUS|OPTION_DISCONNECT|OPTION_ALWAYS_SYNCHRONOUS);
- }
-
- /*
- * On NCR53c700 series chips, DCNTL controls the SCSI clock divisor,
- * on 800 series chips, it allows for a totem-pole IRQ driver.
- * NOTE saved_dcntl currently overwritten in init function.
- * The value read here may be garbage anyway, MVME16x board at least
- * does not initialise chip if kernel arrived via tftp.
- */
-
- hostdata->saved_dcntl = NCR53c7x0_read8(DCNTL_REG);
-
- /*
- * DMODE controls DMA burst length, and on 700 series chips,
- * 286 mode and bus width
- * NOTE: On MVME16x, chip may have been reset, so this could be a
- * power-on/reset default value.
- */
- hostdata->saved_dmode = NCR53c7x0_read8(hostdata->dmode);
-
- /*
- * Now that burst length and enabled/disabled status is known,
- * clue the user in on it.
- */
-
- ccf = clock_to_ccf_710 (expected_clock);
-
- for (i = 0; i < 16; ++i)
- hostdata->cmd_allocated[i] = 0;
-
- if (hostdata->init_save_regs)
- hostdata->init_save_regs (host);
- if (hostdata->init_fixup)
- hostdata->init_fixup (host);
-
- if (!the_template) {
- the_template = host->hostt;
- first_host = host;
- }
-
- /*
- * Linux SCSI drivers have always been plagued with initialization
- * problems - some didn't work with the BIOS disabled since they expected
- * initialization from it, some didn't work when the networking code
- * was enabled and registers got scrambled, etc.
- *
- * To avoid problems like this, in the future, we will do a soft
- * reset on the SCSI chip, taking it back to a sane state.
- */
-
- hostdata->soft_reset (host);
-
-#if 1
- hostdata->debug_count_limit = -1;
-#else
- hostdata->debug_count_limit = 1;
-#endif
- hostdata->intrs = -1;
- hostdata->resets = -1;
- memcpy ((void *) hostdata->synchronous_want, (void *) sdtr_message,
- sizeof (hostdata->synchronous_want));
-
- NCR53c7x0_driver_init (host);
-
- if (request_irq(host->irq, NCR53c7x0_intr, IRQF_SHARED, "53c7xx", host))
- {
- printk("scsi%d : IRQ%d not free, detaching\n",
- host->host_no, host->irq);
- goto err_unregister;
- }
-
- if ((hostdata->run_tests && hostdata->run_tests(host) == -1) ||
- (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
- /* XXX Should disable interrupts, etc. here */
- goto err_free_irq;
- } else {
- if (host->io_port) {
- host->n_io_port = 128;
- if (!request_region (host->io_port, host->n_io_port, "ncr53c7xx"))
- goto err_free_irq;
- }
- }
-
- if (NCR53c7x0_read8 (SBCL_REG) & SBCL_BSY) {
- printk ("scsi%d : bus wedge, doing SCSI reset\n", host->host_no);
- hard_reset (host);
- }
- return 0;
-
- err_free_irq:
- free_irq(host->irq, NCR53c7x0_intr);
- err_unregister:
- scsi_unregister(host);
- return -1;
-}
-
-/*
- * Function : int ncr53c7xx_init(struct scsi_host_template *tpnt, int board, int chip,
- * unsigned long base, int io_port, int irq, int dma, long long options,
- * int clock);
- *
- * Purpose : initializes a NCR53c7,8x0 based on base addresses,
- * IRQ, and DMA channel.
- *
- * Inputs : tpnt - Template for this SCSI adapter, board - board level
- * product, chip - 710
- *
- * Returns : 0 on success, -1 on failure.
- *
- */
-
-int
-ncr53c7xx_init (struct scsi_host_template *tpnt, int board, int chip,
- unsigned long base, int io_port, int irq, int dma,
- long long options, int clock)
-{
- struct Scsi_Host *instance;
- struct NCR53c7x0_hostdata *hostdata;
- char chip_str[80];
- int script_len = 0, dsa_len = 0, size = 0, max_cmd_size = 0,
- schedule_size = 0, ok = 0;
- void *tmp;
- unsigned long page;
-
- switch (chip) {
- case 710:
- case 770:
- schedule_size = (tpnt->can_queue + 1) * 8 /* JUMP instruction size */;
- script_len = NCR53c7xx_script_len;
- dsa_len = NCR53c7xx_dsa_len;
- options |= OPTION_INTFLY;
- sprintf (chip_str, "NCR53c%d", chip);
- break;
- default:
- printk("scsi-ncr53c7xx : unsupported SCSI chip %d\n", chip);
- return -1;
- }
-
- printk("scsi-ncr53c7xx : %s at memory 0x%lx, io 0x%x, irq %d",
- chip_str, base, io_port, irq);
- if (dma == DMA_NONE)
- printk("\n");
- else
- printk(", dma %d\n", dma);
-
- if (options & OPTION_DEBUG_PROBE_ONLY) {
- printk ("scsi-ncr53c7xx : probe only enabled, aborting initialization\n");
- return -1;
- }
-
- max_cmd_size = sizeof(struct NCR53c7x0_cmd) + dsa_len +
- /* Size of dynamic part of command structure : */
- 2 * /* Worst case : we don't know if we need DATA IN or DATA out */
- ( 2 * /* Current instructions per scatter/gather segment */
- tpnt->sg_tablesize +
- 3 /* Current startup / termination required per phase */
- ) *
- 8 /* Each instruction is eight bytes */;
-
- /* Allocate fixed part of hostdata, dynamic part to hold appropriate
- SCSI SCRIPT(tm) plus a single, maximum-sized NCR53c7x0_cmd structure.
-
- We need a NCR53c7x0_cmd structure for scan_scsis() when we are
- not loaded as a module, and when we're loaded as a module, we
- can't use a non-dynamically allocated structure because modules
- are vmalloc()'d, which can allow structures to cross page
- boundaries and breaks our physical/virtual address assumptions
- for DMA.
-
- So, we stick it past the end of our hostdata structure.
-
- ASSUMPTION :
- Regardless of how many simultaneous SCSI commands we allow,
- the probe code only executes a _single_ instruction at a time,
- so we only need one here, and don't need to allocate NCR53c7x0_cmd
- structures for each target until we are no longer in scan_scsis
- and kmalloc() has become functional (memory_init() happens
- after all device driver initialization).
- */
-
- size = sizeof(struct NCR53c7x0_hostdata) + script_len +
- /* Note that alignment will be guaranteed, since we put the command
- allocated at probe time after the fixed-up SCSI script, which
- consists of 32 bit words, aligned on a 32 bit boundary. But
- on a 64bit machine we need 8 byte alignment for hostdata->free, so
- we add in another 4 bytes to take care of potential misalignment
- */
- (sizeof(void *) - sizeof(u32)) + max_cmd_size + schedule_size;
-
- page = __get_free_pages(GFP_ATOMIC,1);
- if(page==0)
- {
- printk(KERN_ERR "53c7xx: out of memory.\n");
- return -ENOMEM;
- }
-#ifdef FORCE_DSA_ALIGNMENT
- /*
- * 53c710 rev.0 doesn't have an add-with-carry instruction.
- * Ensure we allocate enough memory to force DSA alignment.
- */
- size += 256;
-#endif
- /* Size should be < 8K, so we can fit it in two pages. */
- if (size > 8192) {
- printk(KERN_ERR "53c7xx: hostdata > 8K\n");
- return -1;
- }
-
- instance = scsi_register (tpnt, 4);
- if (!instance)
- {
- free_page(page);
- return -1;
- }
- instance->hostdata[0] = page;
- memset((void *)instance->hostdata[0], 0, 8192);
- cache_push(virt_to_phys((void *)(instance->hostdata[0])), 8192);
- cache_clear(virt_to_phys((void *)(instance->hostdata[0])), 8192);
- kernel_set_cachemode((void *)instance->hostdata[0], 8192, IOMAP_NOCACHE_SER);
-
- /* FIXME : if we ever support an ISA NCR53c7xx based board, we
- need to check if the chip is running in a 16 bit mode, and if so
- unregister it if it is past the 16M (0x1000000) mark */
-
- hostdata = (struct NCR53c7x0_hostdata *)instance->hostdata[0];
- hostdata->size = size;
- hostdata->script_count = script_len / sizeof(u32);
- hostdata->board = board;
- hostdata->chip = chip;
-
- /*
- * Being memory mapped is more desirable, since
- *
- * - Memory accesses may be faster.
- *
- * - The destination and source address spaces are the same for
- * all instructions, meaning we don't have to twiddle dmode or
- * any other registers.
- *
- * So, we try for memory mapped, and if we don't get it,
- * we go for port mapped, and that failing we tell the user
- * it can't work.
- */
-
- if (base) {
- instance->base = base;
- /* Check for forced I/O mapping */
- if (!(options & OPTION_IO_MAPPED)) {
- options |= OPTION_MEMORY_MAPPED;
- ok = 1;
- }
- } else {
- options &= ~OPTION_MEMORY_MAPPED;
- }
-
- if (io_port) {
- instance->io_port = io_port;
- options |= OPTION_IO_MAPPED;
- ok = 1;
- } else {
- options &= ~OPTION_IO_MAPPED;
- }
-
- if (!ok) {
- printk ("scsi%d : not initializing, no I/O or memory mapping known \n",
- instance->host_no);
- scsi_unregister (instance);
- return -1;
- }
- instance->irq = irq;
- instance->dma_channel = dma;
-
- hostdata->options = options;
- hostdata->dsa_len = dsa_len;
- hostdata->max_cmd_size = max_cmd_size;
- hostdata->num_cmds = 1;
- hostdata->scsi_clock = clock;
- /* Initialize single command */
- tmp = (hostdata->script + hostdata->script_count);
-#ifdef FORCE_DSA_ALIGNMENT
- {
- void *t = ROUNDUP(tmp, void *);
- if (((u32)t & 0xff) > CmdPageStart)
- t = (void *)((u32)t + 255);
- t = (void *)(((u32)t & ~0xff) + CmdPageStart);
- hostdata->free = t;
-#if 0
- printk ("scsi: Registered size increased by 256 to %d\n", size);
- printk ("scsi: CmdPageStart = 0x%02x\n", CmdPageStart);
- printk ("scsi: tmp = 0x%08x, hostdata->free set to 0x%08x\n",
- (u32)tmp, (u32)t);
-#endif
- }
-#else
- hostdata->free = ROUNDUP(tmp, void *);
-#endif
- hostdata->free->real = tmp;
- hostdata->free->size = max_cmd_size;
- hostdata->free->free = NULL;
- hostdata->free->next = NULL;
- hostdata->extra_allocate = 0;
-
- /* Allocate command start code space */
- hostdata->schedule = (chip == 700 || chip == 70066) ?
- NULL : (u32 *) ((char *)hostdata->free + max_cmd_size);
-
-/*
- * For diagnostic purposes, we don't really care how fast things blaze.
- * For profiling, we want to access the 800ns resolution system clock,
- * using a 'C' call on the host processor.
- *
- * Therefore, there's no need for the NCR chip to directly manipulate
- * this data, and we should put it wherever is most convenient for
- * Linux.
- */
- if (track_events)
- hostdata->events = (struct NCR53c7x0_event *) (track_events ?
- vmalloc (sizeof (struct NCR53c7x0_event) * track_events) : NULL);
- else
- hostdata->events = NULL;
-
- if (hostdata->events) {
- memset ((void *) hostdata->events, 0, sizeof(struct NCR53c7x0_event) *
- track_events);
- hostdata->event_size = track_events;
- hostdata->event_index = 0;
- } else
- hostdata->event_size = 0;
-
- return NCR53c7x0_init(instance);
-}
-
-
-/*
- * Function : static void NCR53c7x0_init_fixup (struct Scsi_Host *host)
- *
- * Purpose : copy and fixup the SCSI SCRIPTS(tm) code for this device.
- *
- * Inputs : host - pointer to this host adapter's structure
- *
- */
-
-static void
-NCR53c7x0_init_fixup (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned char tmp;
- int i, ncr_to_memory, memory_to_ncr;
- u32 base;
- NCR53c7x0_local_setup(host);
-
-
- /* XXX - NOTE : this code MUST be made endian aware */
- /* Copy code into buffer that was allocated at detection time. */
- memcpy ((void *) hostdata->script, (void *) SCRIPT,
- sizeof(SCRIPT));
- /* Fixup labels */
- for (i = 0; i < PATCHES; ++i)
- hostdata->script[LABELPATCHES[i]] +=
- virt_to_bus(hostdata->script);
- /* Fixup addresses of constants that used to be EXTERNAL */
-
- patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_abort,
- virt_to_bus(&(hostdata->NCR53c7xx_msg_abort)));
- patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_reject,
- virt_to_bus(&(hostdata->NCR53c7xx_msg_reject)));
- patch_abs_32 (hostdata->script, 0, NCR53c7xx_zero,
- virt_to_bus(&(hostdata->NCR53c7xx_zero)));
- patch_abs_32 (hostdata->script, 0, NCR53c7xx_sink,
- virt_to_bus(&(hostdata->NCR53c7xx_sink)));
- patch_abs_32 (hostdata->script, 0, NOP_insn,
- virt_to_bus(&(hostdata->NOP_insn)));
- patch_abs_32 (hostdata->script, 0, schedule,
- virt_to_bus((void *) hostdata->schedule));
-
- /* Fixup references to external variables: */
- for (i = 0; i < EXTERNAL_PATCHES_LEN; ++i)
- hostdata->script[EXTERNAL_PATCHES[i].offset] +=
- virt_to_bus(EXTERNAL_PATCHES[i].address);
-
- /*
- * Fixup absolutes set at boot-time.
- *
- * All non-code absolute variables suffixed with "dsa_" and "int_"
- * are constants, and need no fixup provided the assembler has done
- * it for us (I don't know what the "real" NCR assembler does in
- * this case, my assembler does the right magic).
- */
-
- patch_abs_rwri_data (hostdata->script, 0, dsa_save_data_pointer,
- Ent_dsa_code_save_data_pointer - Ent_dsa_zero);
- patch_abs_rwri_data (hostdata->script, 0, dsa_restore_pointers,
- Ent_dsa_code_restore_pointers - Ent_dsa_zero);
- patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect,
- Ent_dsa_code_check_reselect - Ent_dsa_zero);
-
- /*
- * Just for the hell of it, preserve the settings of
- * Burst Length and Enable Read Line bits from the DMODE
- * register. Make sure SCRIPTS start automagically.
- */
-
-#if defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
- /* We know better what we want than 16xBug does! */
- tmp = DMODE_10_BL_8 | DMODE_10_FC2;
-#else
- tmp = NCR53c7x0_read8(DMODE_REG_10);
- tmp &= (DMODE_BL_MASK | DMODE_10_FC2 | DMODE_10_FC1 | DMODE_710_PD |
- DMODE_710_UO);
-#endif
-
- if (!(hostdata->options & OPTION_MEMORY_MAPPED)) {
- base = (u32) host->io_port;
- memory_to_ncr = tmp|DMODE_800_DIOM;
- ncr_to_memory = tmp|DMODE_800_SIOM;
- } else {
- base = virt_to_bus((void *)host->base);
- memory_to_ncr = ncr_to_memory = tmp;
- }
-
- /* SCRATCHB_REG_10 == SCRATCHA_REG_800, as it happens */
- patch_abs_32 (hostdata->script, 0, addr_scratch, base + SCRATCHA_REG_800);
- patch_abs_32 (hostdata->script, 0, addr_temp, base + TEMP_REG);
- patch_abs_32 (hostdata->script, 0, addr_dsa, base + DSA_REG);
-
- /*
- * I needed some variables in the script to be accessible to
- * both the NCR chip and the host processor. For these variables,
- * I made the arbitrary decision to store them directly in the
- * hostdata structure rather than in the RELATIVE area of the
- * SCRIPTS.
- */
-
-
- patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_memory, tmp);
- patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_ncr, memory_to_ncr);
- patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_memory, ncr_to_memory);
-
- patch_abs_32 (hostdata->script, 0, msg_buf,
- virt_to_bus((void *)&(hostdata->msg_buf)));
- patch_abs_32 (hostdata->script, 0, reconnect_dsa_head,
- virt_to_bus((void *)&(hostdata->reconnect_dsa_head)));
- patch_abs_32 (hostdata->script, 0, addr_reconnect_dsa_head,
- virt_to_bus((void *)&(hostdata->addr_reconnect_dsa_head)));
- patch_abs_32 (hostdata->script, 0, reselected_identify,
- virt_to_bus((void *)&(hostdata->reselected_identify)));
-/* reselected_tag is currently unused */
-#if 0
- patch_abs_32 (hostdata->script, 0, reselected_tag,
- virt_to_bus((void *)&(hostdata->reselected_tag)));
-#endif
-
- patch_abs_32 (hostdata->script, 0, test_dest,
- virt_to_bus((void*)&hostdata->test_dest));
- patch_abs_32 (hostdata->script, 0, test_src,
- virt_to_bus(&hostdata->test_source));
- patch_abs_32 (hostdata->script, 0, saved_dsa,
- virt_to_bus((void *)&hostdata->saved2_dsa));
- patch_abs_32 (hostdata->script, 0, emulfly,
- virt_to_bus((void *)&hostdata->emulated_intfly));
-
- patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect,
- (unsigned char)(Ent_dsa_code_check_reselect - Ent_dsa_zero));
-
-/* These are for event logging; the ncr_event enum contains the
- actual interrupt numbers. */
-#ifdef A_int_EVENT_SELECT
- patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT, (u32) EVENT_SELECT);
-#endif
-#ifdef A_int_EVENT_DISCONNECT
- patch_abs_32 (hostdata->script, 0, int_EVENT_DISCONNECT, (u32) EVENT_DISCONNECT);
-#endif
-#ifdef A_int_EVENT_RESELECT
- patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT, (u32) EVENT_RESELECT);
-#endif
-#ifdef A_int_EVENT_COMPLETE
- patch_abs_32 (hostdata->script, 0, int_EVENT_COMPLETE, (u32) EVENT_COMPLETE);
-#endif
-#ifdef A_int_EVENT_IDLE
- patch_abs_32 (hostdata->script, 0, int_EVENT_IDLE, (u32) EVENT_IDLE);
-#endif
-#ifdef A_int_EVENT_SELECT_FAILED
- patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT_FAILED,
- (u32) EVENT_SELECT_FAILED);
-#endif
-#ifdef A_int_EVENT_BEFORE_SELECT
- patch_abs_32 (hostdata->script, 0, int_EVENT_BEFORE_SELECT,
- (u32) EVENT_BEFORE_SELECT);
-#endif
-#ifdef A_int_EVENT_RESELECT_FAILED
- patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT_FAILED,
- (u32) EVENT_RESELECT_FAILED);
-#endif
-
- /*
- * Make sure the NCR and Linux code agree on the location of
- * certain fields.
- */
-
- hostdata->E_accept_message = Ent_accept_message;
- hostdata->E_command_complete = Ent_command_complete;
- hostdata->E_cmdout_cmdout = Ent_cmdout_cmdout;
- hostdata->E_data_transfer = Ent_data_transfer;
- hostdata->E_debug_break = Ent_debug_break;
- hostdata->E_dsa_code_template = Ent_dsa_code_template;
- hostdata->E_dsa_code_template_end = Ent_dsa_code_template_end;
- hostdata->E_end_data_transfer = Ent_end_data_transfer;
- hostdata->E_initiator_abort = Ent_initiator_abort;
- hostdata->E_msg_in = Ent_msg_in;
- hostdata->E_other_transfer = Ent_other_transfer;
- hostdata->E_other_in = Ent_other_in;
- hostdata->E_other_out = Ent_other_out;
- hostdata->E_reject_message = Ent_reject_message;
- hostdata->E_respond_message = Ent_respond_message;
- hostdata->E_select = Ent_select;
- hostdata->E_select_msgout = Ent_select_msgout;
- hostdata->E_target_abort = Ent_target_abort;
-#ifdef Ent_test_0
- hostdata->E_test_0 = Ent_test_0;
-#endif
- hostdata->E_test_1 = Ent_test_1;
- hostdata->E_test_2 = Ent_test_2;
-#ifdef Ent_test_3
- hostdata->E_test_3 = Ent_test_3;
-#endif
- hostdata->E_wait_reselect = Ent_wait_reselect;
- hostdata->E_dsa_code_begin = Ent_dsa_code_begin;
-
- hostdata->dsa_cmdout = A_dsa_cmdout;
- hostdata->dsa_cmnd = A_dsa_cmnd;
- hostdata->dsa_datain = A_dsa_datain;
- hostdata->dsa_dataout = A_dsa_dataout;
- hostdata->dsa_end = A_dsa_end;
- hostdata->dsa_msgin = A_dsa_msgin;
- hostdata->dsa_msgout = A_dsa_msgout;
- hostdata->dsa_msgout_other = A_dsa_msgout_other;
- hostdata->dsa_next = A_dsa_next;
- hostdata->dsa_select = A_dsa_select;
- hostdata->dsa_start = Ent_dsa_code_template - Ent_dsa_zero;
- hostdata->dsa_status = A_dsa_status;
- hostdata->dsa_jump_dest = Ent_dsa_code_fix_jump - Ent_dsa_zero +
- 8 /* destination operand */;
-
- /* sanity check */
- if (A_dsa_fields_start != Ent_dsa_code_template_end -
- Ent_dsa_zero)
- printk("scsi%d : NCR dsa_fields start is %d not %d\n",
- host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end -
- Ent_dsa_zero);
-
- printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
- virt_to_bus(hostdata->script), hostdata->script);
-}
-
-/*
- * Function : static int NCR53c7xx_run_tests (struct Scsi_Host *host)
- *
- * Purpose : run various verification tests on the NCR chip,
- * including interrupt generation, and proper bus mastering
- * operation.
- *
- * Inputs : host - a properly initialized Scsi_Host structure
- *
- * Preconditions : the NCR chip must be in a halted state.
- *
- * Returns : 0 if all tests were successful, -1 on error.
- *
- */
-
-static int
-NCR53c7xx_run_tests (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned long timeout;
- u32 start;
- int failed, i;
- unsigned long flags;
- NCR53c7x0_local_setup(host);
-
- /* The NCR chip _must_ be idle to run the test scripts */
-
- local_irq_save(flags);
- if (!hostdata->idle) {
- printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
- local_irq_restore(flags);
- return -1;
- }
-
- /*
- * Check for functional interrupts, this could work as an
- * autoprobe routine.
- */
-
- if ((hostdata->options & OPTION_DEBUG_TEST1) &&
- hostdata->state != STATE_DISABLED) {
- hostdata->idle = 0;
- hostdata->test_running = 1;
- hostdata->test_completed = -1;
- hostdata->test_dest = 0;
- hostdata->test_source = 0xdeadbeef;
- start = virt_to_bus (hostdata->script) + hostdata->E_test_1;
- hostdata->state = STATE_RUNNING;
- printk ("scsi%d : test 1", host->host_no);
- NCR53c7x0_write32 (DSP_REG, start);
- if (hostdata->options & OPTION_DEBUG_TRACE)
- NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM |
- DCNTL_STD);
- printk (" started\n");
- local_irq_restore(flags);
-
- /*
- * This is currently a .5 second timeout, since (in theory) no slow
- * board will take that long. In practice, we've seen one
- * pentium which occassionally fails with this, but works with
- * 10 times as much?
- */
-
- timeout = jiffies + 5 * HZ / 10;
- while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
- barrier();
-
- failed = 1;
- if (hostdata->test_completed == -1)
- printk ("scsi%d : driver test 1 timed out%s\n",host->host_no ,
- (hostdata->test_dest == 0xdeadbeef) ?
- " due to lost interrupt.\n"
- " Please verify that the correct IRQ is being used for your board,\n"
- : "");
- else if (hostdata->test_completed != 1)
- printk ("scsi%d : test 1 bad interrupt value (%d)\n",
- host->host_no, hostdata->test_completed);
- else
- failed = (hostdata->test_dest != 0xdeadbeef);
-
- if (hostdata->test_dest != 0xdeadbeef) {
- printk ("scsi%d : driver test 1 read 0x%x instead of 0xdeadbeef indicating a\n"
- " probable cache invalidation problem. Please configure caching\n"
- " as write-through or disabled\n",
- host->host_no, hostdata->test_dest);
- }
-
- if (failed) {
- printk ("scsi%d : DSP = 0x%p (script at 0x%p, start at 0x%x)\n",
- host->host_no, bus_to_virt(NCR53c7x0_read32(DSP_REG)),
- hostdata->script, start);
- printk ("scsi%d : DSPS = 0x%x\n", host->host_no,
- NCR53c7x0_read32(DSPS_REG));
- local_irq_restore(flags);
- return -1;
- }
- hostdata->test_running = 0;
- }
-
- if ((hostdata->options & OPTION_DEBUG_TEST2) &&
- hostdata->state != STATE_DISABLED) {
- u32 dsa[48];
- unsigned char identify = IDENTIFY(0, 0);
- unsigned char cmd[6];
- unsigned char data[36];
- unsigned char status = 0xff;
- unsigned char msg = 0xff;
-
- cmd[0] = INQUIRY;
- cmd[1] = cmd[2] = cmd[3] = cmd[5] = 0;
- cmd[4] = sizeof(data);
-
- dsa[2] = 1;
- dsa[3] = virt_to_bus(&identify);
- dsa[4] = 6;
- dsa[5] = virt_to_bus(&cmd);
- dsa[6] = sizeof(data);
- dsa[7] = virt_to_bus(&data);
- dsa[8] = 1;
- dsa[9] = virt_to_bus(&status);
- dsa[10] = 1;
- dsa[11] = virt_to_bus(&msg);
-
- for (i = 0; i < 6; ++i) {
-#ifdef VALID_IDS
- if (!hostdata->valid_ids[i])
- continue;
-#endif
- local_irq_disable();
- if (!hostdata->idle) {
- printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
- local_irq_restore(flags);
- return -1;
- }
-
- /* 710: bit mapped scsi ID, async */
- dsa[0] = (1 << i) << 16;
- hostdata->idle = 0;
- hostdata->test_running = 2;
- hostdata->test_completed = -1;
- start = virt_to_bus(hostdata->script) + hostdata->E_test_2;
- hostdata->state = STATE_RUNNING;
- NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa));
- NCR53c7x0_write32 (DSP_REG, start);
- if (hostdata->options & OPTION_DEBUG_TRACE)
- NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
- DCNTL_SSM | DCNTL_STD);
- local_irq_restore(flags);
-
- timeout = jiffies + 5 * HZ; /* arbitrary */
- while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
- barrier();
-
- NCR53c7x0_write32 (DSA_REG, 0);
-
- if (hostdata->test_completed == 2) {
- data[35] = 0;
- printk ("scsi%d : test 2 INQUIRY to target %d, lun 0 : %s\n",
- host->host_no, i, data + 8);
- printk ("scsi%d : status ", host->host_no);
- scsi_print_status (status);
- printk ("\nscsi%d : message ", host->host_no);
- spi_print_msg(&msg);
- printk ("\n");
- } else if (hostdata->test_completed == 3) {
- printk("scsi%d : test 2 no connection with target %d\n",
- host->host_no, i);
- if (!hostdata->idle) {
- printk("scsi%d : not idle\n", host->host_no);
- local_irq_restore(flags);
- return -1;
- }
- } else if (hostdata->test_completed == -1) {
- printk ("scsi%d : test 2 timed out\n", host->host_no);
- local_irq_restore(flags);
- return -1;
- }
- hostdata->test_running = 0;
- }
- }
-
- local_irq_restore(flags);
- return 0;
-}
-
-/*
- * Function : static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : copy the NCR53c8xx dsa structure into cmd's dsa buffer,
- * performing all necessary relocation.
- *
- * Inputs : cmd, a NCR53c7x0_cmd structure with a dsa area large
- * enough to hold the NCR53c8xx dsa.
- */
-
-static void
-NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
- Scsi_Cmnd *c = cmd->cmd;
- struct Scsi_Host *host = c->device->host;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- int i;
-
- memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
- hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
-
- /*
- * Note : within the NCR 'C' code, dsa points to the _start_
- * of the DSA structure, and _not_ the offset of dsa_zero within
- * that structure used to facilitate shorter signed offsets
- * for the 8 bit ALU.
- *
- * The implications of this are that
- *
- * - 32 bit A_dsa_* absolute values require an additional
- * dsa_zero added to their value to be correct, since they are
- * relative to dsa_zero which is in essentially a separate
- * space from the code symbols.
- *
- * - All other symbols require no special treatment.
- */
-
- patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_lun, c->device->lun);
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_addr_next, virt_to_bus(&cmd->dsa_next_addr));
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_next, virt_to_bus(cmd->dsa) + Ent_dsa_zero -
- Ent_dsa_code_template + A_dsa_next);
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->device->id].script));
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->device->id].sscf_710));
- patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_target, 1 << c->device->id);
- /* XXX - new pointer stuff */
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_addr_saved_pointer, virt_to_bus(&cmd->saved_data_pointer));
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_addr_saved_residual, virt_to_bus(&cmd->saved_residual));
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_addr_residual, virt_to_bus(&cmd->residual));
-
- /* XXX - new start stuff */
-
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
-}
-
-/*
- * Function : run_process_issue_queue (void)
- *
- * Purpose : insure that the coroutine is running and will process our
- * request. process_issue_queue_running is checked/set here (in an
- * inline function) rather than in process_issue_queue itself to reduce
- * the chances of stack overflow.
- *
- */
-
-static volatile int process_issue_queue_running = 0;
-
-static __inline__ void
-run_process_issue_queue(void) {
- unsigned long flags;
- local_irq_save(flags);
- if (!process_issue_queue_running) {
- process_issue_queue_running = 1;
- process_issue_queue(flags);
- /*
- * process_issue_queue_running is cleared in process_issue_queue
- * once it can't do more work, and process_issue_queue exits with
- * interrupts disabled.
- */
- }
- local_irq_restore(flags);
-}
-
-/*
- * Function : static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int
- * result)
- *
- * Purpose : mark SCSI command as finished, OR'ing the host portion
- * of the result word into the result field of the corresponding
- * Scsi_Cmnd structure, and removing it from the internal queues.
- *
- * Inputs : cmd - command, result - entire result field
- *
- * Preconditions : the NCR chip should be in a halted state when
- * abnormal_finished is run, since it modifies structures which
- * the NCR expects to have exclusive access to.
- */
-
-static void
-abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
- Scsi_Cmnd *c = cmd->cmd;
- struct Scsi_Host *host = c->device->host;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned long flags;
- int left, found;
- volatile struct NCR53c7x0_cmd * linux_search;
- volatile struct NCR53c7x0_cmd * volatile *linux_prev;
- volatile u32 *ncr_prev, *ncrcurrent, ncr_search;
-
-#if 0
- printk ("scsi%d: abnormal finished\n", host->host_no);
-#endif
-
- local_irq_save(flags);
- found = 0;
- /*
- * Traverse the NCR issue array until we find a match or run out
- * of instructions. Instructions in the NCR issue array are
- * either JUMP or NOP instructions, which are 2 words in length.
- */
-
-
- for (found = 0, left = host->can_queue, ncrcurrent = hostdata->schedule;
- left > 0; --left, ncrcurrent += 2)
- {
- if (issue_to_cmd (host, hostdata, (u32 *) ncrcurrent) == cmd)
- {
- ncrcurrent[0] = hostdata->NOP_insn;
- ncrcurrent[1] = 0xdeadbeef;
- ++found;
- break;
- }
- }
-
- /*
- * Traverse the NCR reconnect list of DSA structures until we find
- * a pointer to this dsa or have found too many command structures.
- * We let prev point at the next field of the previous element or
- * head of the list, so we don't do anything different for removing
- * the head element.
- */
-
- for (left = host->can_queue,
- ncr_search = hostdata->reconnect_dsa_head,
- ncr_prev = &hostdata->reconnect_dsa_head;
- left >= 0 && ncr_search &&
- ((char*)bus_to_virt(ncr_search) + hostdata->dsa_start)
- != (char *) cmd->dsa;
- ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) +
- hostdata->dsa_next), ncr_search = *ncr_prev, --left);
-
- if (left < 0)
- printk("scsi%d: loop detected in ncr reconncect list\n",
- host->host_no);
- else if (ncr_search) {
- if (found)
- printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n",
- host->host_no, c->pid);
- else {
- volatile u32 * next = (u32 *)
- ((char *)bus_to_virt(ncr_search) + hostdata->dsa_next);
- *ncr_prev = *next;
-/* If we're at the tail end of the issue queue, update that pointer too. */
- found = 1;
- }
- }
-
- /*
- * Traverse the host running list until we find this command or discover
- * we have too many elements, pointing linux_prev at the next field of the
- * linux_previous element or head of the list, search at this element.
- */
-
- for (left = host->can_queue, linux_search = hostdata->running_list,
- linux_prev = &hostdata->running_list;
- left >= 0 && linux_search && linux_search != cmd;
- linux_prev = &(linux_search->next),
- linux_search = linux_search->next, --left);
-
- if (left < 0)
- printk ("scsi%d: loop detected in host running list for scsi pid %ld\n",
- host->host_no, c->pid);
- else if (linux_search) {
- *linux_prev = linux_search->next;
- --hostdata->busy[c->device->id][c->device->lun];
- }
-
- /* Return the NCR command structure to the free list */
- cmd->next = hostdata->free;
- hostdata->free = cmd;
- c->host_scribble = NULL;
-
- /* And return */
- c->result = result;
- c->scsi_done(c);
-
- local_irq_restore(flags);
- run_process_issue_queue();
-}
-
-/*
- * Function : static void intr_break (struct Scsi_Host *host,
- * struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : Handler for breakpoint interrupts from a SCSI script
- *
- * Inputs : host - pointer to this host adapter's structure,
- * cmd - pointer to the command (if any) dsa was pointing
- * to.
- *
- */
-
-static void
-intr_break (struct Scsi_Host *host, struct
- NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_break *bp;
-#if 0
- Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
-#endif
- u32 *dsp;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned long flags;
- NCR53c7x0_local_setup(host);
-
- /*
- * Find the break point corresponding to this address, and
- * dump the appropriate debugging information to standard
- * output.
- */
- local_irq_save(flags);
- dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
- for (bp = hostdata->breakpoints; bp && bp->address != dsp;
- bp = bp->next);
- if (!bp)
- panic("scsi%d : break point interrupt from %p with no breakpoint!",
- host->host_no, dsp);
-
- /*
- * Configure the NCR chip for manual start mode, so that we can
- * point the DSP register at the instruction that follows the
- * INT int_debug_break instruction.
- */
-
- NCR53c7x0_write8 (hostdata->dmode,
- NCR53c7x0_read8(hostdata->dmode)|DMODE_MAN);
-
- /*
- * And update the DSP register, using the size of the old
- * instruction in bytes.
- */
-
- local_irq_restore(flags);
-}
-/*
- * Function : static void print_synchronous (const char *prefix,
- * const unsigned char *msg)
- *
- * Purpose : print a pretty, user and machine parsable representation
- * of a SDTR message, including the "real" parameters, data
- * clock so we can tell transfer rate at a glance.
- *
- * Inputs ; prefix - text to prepend, msg - SDTR message (5 bytes)
- */
-
-static void
-print_synchronous (const char *prefix, const unsigned char *msg) {
- if (msg[4]) {
- int Hz = 1000000000 / (msg[3] * 4);
- int integer = Hz / 1000000;
- int fraction = (Hz - (integer * 1000000)) / 10000;
- printk ("%speriod %dns offset %d %d.%02dMHz %s SCSI%s\n",
- prefix, (int) msg[3] * 4, (int) msg[4], integer, fraction,
- (((msg[3] * 4) < 200) ? "FAST" : "synchronous"),
- (((msg[3] * 4) < 200) ? "-II" : ""));
- } else
- printk ("%sasynchronous SCSI\n", prefix);
-}
-
-/*
- * Function : static void set_synchronous (struct Scsi_Host *host,
- * int target, int sxfer, int scntl3, int now_connected)
- *
- * Purpose : reprogram transfers between the selected SCSI initiator and
- * target with the given register values; in the indirect
- * select operand, reselection script, and chip registers.
- *
- * Inputs : host - NCR53c7,8xx SCSI host, target - number SCSI target id,
- * sxfer and scntl3 - NCR registers. now_connected - if non-zero,
- * we should reprogram the registers now too.
- *
- * NOTE: For 53c710, scntl3 is actually used for SCF bits from
- * SBCL, as we don't have a SCNTL3.
- */
-
-static void
-set_synchronous (struct Scsi_Host *host, int target, int sxfer, int scntl3,
- int now_connected) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- u32 *script;
- NCR53c7x0_local_setup(host);
-
- /* These are eight bit registers */
- sxfer &= 0xff;
- scntl3 &= 0xff;
-
- hostdata->sync[target].sxfer_sanity = sxfer;
- hostdata->sync[target].scntl3_sanity = scntl3;
-
-/*
- * HARD CODED : synchronous script is EIGHT words long. This
- * must agree with 53c7.8xx.h
- */
-
- if ((hostdata->chip != 700) && (hostdata->chip != 70066)) {
- hostdata->sync[target].select_indirect = (1 << target) << 16 |
- (sxfer << 8);
- hostdata->sync[target].sscf_710 = scntl3;
-
- script = (u32 *) hostdata->sync[target].script;
-
- /* XXX - add NCR53c7x0 code to reprogram SCF bits if we want to */
- script[0] = ((DCMD_TYPE_RWRI | DCMD_RWRI_OPC_MODIFY |
- DCMD_RWRI_OP_MOVE) << 24) |
- (SBCL_REG << 16) | (scntl3 << 8);
- script[1] = 0;
- script += 2;
-
- script[0] = ((DCMD_TYPE_RWRI | DCMD_RWRI_OPC_MODIFY |
- DCMD_RWRI_OP_MOVE) << 24) |
- (SXFER_REG << 16) | (sxfer << 8);
- script[1] = 0;
- script += 2;
-
-#ifdef DEBUG_SYNC_INTR
- if (hostdata->options & OPTION_DEBUG_DISCONNECT) {
- script[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_INT) << 24) | DBC_TCI_TRUE;
- script[1] = DEBUG_SYNC_INTR;
- script += 2;
- }
-#endif
-
- script[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_RETURN) << 24) | DBC_TCI_TRUE;
- script[1] = 0;
- script += 2;
- }
-
- if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS)
- printk ("scsi%d : target %d sync parameters are sxfer=0x%x, scntl3=0x%x\n",
- host->host_no, target, sxfer, scntl3);
-
- if (now_connected) {
- NCR53c7x0_write8(SBCL_REG, scntl3);
- NCR53c7x0_write8(SXFER_REG, sxfer);
- }
-}
-
-
-/*
- * Function : static int asynchronous (struct Scsi_Host *host, int target)
- *
- * Purpose : reprogram between the selected SCSI Host adapter and target
- * (assumed to be currently connected) for asynchronous transfers.
- *
- * Inputs : host - SCSI host structure, target - numeric target ID.
- *
- * Preconditions : the NCR chip should be in one of the halted states
- */
-
-static void
-asynchronous (struct Scsi_Host *host, int target) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- NCR53c7x0_local_setup(host);
- set_synchronous (host, target, /* no offset */ 0, hostdata->saved_scntl3,
- 1);
- printk ("scsi%d : setting target %d to asynchronous SCSI\n",
- host->host_no, target);
-}
-
-/*
- * XXX - do we want to go out of our way (ie, add extra code to selection
- * in the NCR53c710/NCR53c720 script) to reprogram the synchronous
- * conversion bits, or can we be content in just setting the
- * sxfer bits? I chose to do so [richard@sleepie.demon.co.uk]
- */
-
-/* Table for NCR53c8xx synchronous values */
-
-/* This table is also correct for 710, allowing that scf=4 is equivalent
- * of SSCF=0 (ie use DCNTL, divide by 3) for a 50.01-66.00MHz clock.
- * For any other clock values, we cannot use entries with SCF values of
- * 4. I guess that for a 66MHz clock, the slowest it will set is 2MHz,
- * and for a 50MHz clock, the slowest will be 2.27Mhz. Should check
- * that a device doesn't try and negotiate sync below these limits!
- */
-
-static const struct {
- int div; /* Total clock divisor * 10 */
- unsigned char scf; /* */
- unsigned char tp; /* 4 + tp = xferp divisor */
-} syncs[] = {
-/* div scf tp div scf tp div scf tp */
- { 40, 1, 0}, { 50, 1, 1}, { 60, 1, 2},
- { 70, 1, 3}, { 75, 2, 1}, { 80, 1, 4},
- { 90, 1, 5}, { 100, 1, 6}, { 105, 2, 3},
- { 110, 1, 7}, { 120, 2, 4}, { 135, 2, 5},
- { 140, 3, 3}, { 150, 2, 6}, { 160, 3, 4},
- { 165, 2, 7}, { 180, 3, 5}, { 200, 3, 6},
- { 210, 4, 3}, { 220, 3, 7}, { 240, 4, 4},
- { 270, 4, 5}, { 300, 4, 6}, { 330, 4, 7}
-};
-
-/*
- * Function : static void synchronous (struct Scsi_Host *host, int target,
- * char *msg)
- *
- * Purpose : reprogram transfers between the selected SCSI initiator and
- * target for synchronous SCSI transfers such that the synchronous
- * offset is less than that requested and period at least as long
- * as that requested. Also modify *msg such that it contains
- * an appropriate response.
- *
- * Inputs : host - NCR53c7,8xx SCSI host, target - number SCSI target id,
- * msg - synchronous transfer request.
- */
-
-
-static void
-synchronous (struct Scsi_Host *host, int target, char *msg) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- int desire, divisor, i, limit;
- unsigned char scntl3, sxfer;
-/* The diagnostic message fits on one line, even with max. width integers */
- char buf[80];
-
-/* Desired transfer clock in Hz */
- desire = 1000000000L / (msg[3] * 4);
-/* Scale the available SCSI clock by 10 so we get tenths */
- divisor = (hostdata->scsi_clock * 10) / desire;
-
-/* NCR chips can handle at most an offset of 8 */
- if (msg[4] > 8)
- msg[4] = 8;
-
- if (hostdata->options & OPTION_DEBUG_SDTR)
- printk("scsi%d : optimal synchronous divisor of %d.%01d\n",
- host->host_no, divisor / 10, divisor % 10);
-
- limit = ARRAY_SIZE(syncs) - 1;
- for (i = 0; (i < limit) && (divisor > syncs[i].div); ++i);
-
- if (hostdata->options & OPTION_DEBUG_SDTR)
- printk("scsi%d : selected synchronous divisor of %d.%01d\n",
- host->host_no, syncs[i].div / 10, syncs[i].div % 10);
-
- msg[3] = ((1000000000L / hostdata->scsi_clock) * syncs[i].div / 10 / 4);
-
- if (hostdata->options & OPTION_DEBUG_SDTR)
- printk("scsi%d : selected synchronous period of %dns\n", host->host_no,
- msg[3] * 4);
-
- scntl3 = syncs[i].scf;
- sxfer = (msg[4] << SXFER_MO_SHIFT) | (syncs[i].tp << 4);
- if (hostdata->options & OPTION_DEBUG_SDTR)
- printk ("scsi%d : sxfer=0x%x scntl3=0x%x\n",
- host->host_no, (int) sxfer, (int) scntl3);
- set_synchronous (host, target, sxfer, scntl3, 1);
- sprintf (buf, "scsi%d : setting target %d to ", host->host_no, target);
- print_synchronous (buf, msg);
-}
-
-/*
- * Function : static int NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host,
- * struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : Handler for INT generated instructions for the
- * NCR53c810/820 SCSI SCRIPT
- *
- * Inputs : host - pointer to this host adapter's structure,
- * cmd - pointer to the command (if any) dsa was pointing
- * to.
- *
- */
-
-static int
-NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
- NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- int print;
- Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- u32 dsps,*dsp; /* Argument of the INT instruction */
-
- NCR53c7x0_local_setup(host);
- dsps = NCR53c7x0_read32(DSPS_REG);
- dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
-
- /* RGH 150597: Frig. Commands which fail with Check Condition are
- * Flagged as successful - hack dsps to indicate check condition */
-#if 0
- /* RGH 200597: Need to disable for BVME6000, as it gets Check Conditions
- * and then dies. Seems to handle Check Condition at startup, but
- * not mid kernel build. */
- if (dsps == A_int_norm_emulateintfly && cmd && cmd->result == 2)
- dsps = A_int_err_check_condition;
-#endif
-
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
-
- switch (dsps) {
- case A_int_msg_1:
- print = 1;
- switch (hostdata->msg_buf[0]) {
- /*
- * Unless we've initiated synchronous negotiation, I don't
- * think that this should happen.
- */
- case MESSAGE_REJECT:
- hostdata->dsp = hostdata->script + hostdata->E_accept_message /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- if (cmd && (cmd->flags & CMD_FLAG_SDTR)) {
- printk ("scsi%d : target %d rejected SDTR\n", host->host_no,
- c->device->id);
- cmd->flags &= ~CMD_FLAG_SDTR;
- asynchronous (host, c->device->id);
- print = 0;
- }
- break;
- case INITIATE_RECOVERY:
- printk ("scsi%d : extended contingent allegiance not supported yet, rejecting\n",
- host->host_no);
- /* Fall through to default */
- hostdata->dsp = hostdata->script + hostdata->E_reject_message /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- break;
- default:
- printk ("scsi%d : unsupported message, rejecting\n",
- host->host_no);
- hostdata->dsp = hostdata->script + hostdata->E_reject_message /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- }
- if (print) {
- printk ("scsi%d : received message", host->host_no);
- if (c)
- printk (" from target %d lun %d ", c->device->id, c->device->lun);
- spi_print_msg((unsigned char *) hostdata->msg_buf);
- printk("\n");
- }
-
- return SPECIFIC_INT_NOTHING;
-
-
- case A_int_msg_sdtr:
-/*
- * At this point, hostdata->msg_buf contains
- * 0 EXTENDED MESSAGE
- * 1 length
- * 2 SDTR
- * 3 period * 4ns
- * 4 offset
- */
-
- if (cmd) {
- char buf[80];
- sprintf (buf, "scsi%d : target %d %s ", host->host_no, c->device->id,
- (cmd->flags & CMD_FLAG_SDTR) ? "accepting" : "requesting");
- print_synchronous (buf, (unsigned char *) hostdata->msg_buf);
-
- /*
- * Initiator initiated, won't happen unless synchronous
- * transfers are enabled. If we get a SDTR message in
- * response to our SDTR, we should program our parameters
- * such that
- * offset <= requested offset
- * period >= requested period
- */
- if (cmd->flags & CMD_FLAG_SDTR) {
- cmd->flags &= ~CMD_FLAG_SDTR;
- if (hostdata->msg_buf[4])
- synchronous (host, c->device->id, (unsigned char *)
- hostdata->msg_buf);
- else
- asynchronous (host, c->device->id);
- hostdata->dsp = hostdata->script + hostdata->E_accept_message /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- return SPECIFIC_INT_NOTHING;
- } else {
- if (hostdata->options & OPTION_SYNCHRONOUS) {
- cmd->flags |= CMD_FLAG_DID_SDTR;
- synchronous (host, c->device->id, (unsigned char *)
- hostdata->msg_buf);
- } else {
- hostdata->msg_buf[4] = 0; /* 0 offset = async */
- asynchronous (host, c->device->id);
- }
- patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
- patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32)
- virt_to_bus ((void *)&hostdata->msg_buf));
- hostdata->dsp = hostdata->script +
- hostdata->E_respond_message / sizeof(u32);
- hostdata->dsp_changed = 1;
- }
- return SPECIFIC_INT_NOTHING;
- }
- /* Fall through to abort if we couldn't find a cmd, and
- therefore a dsa structure to twiddle */
- case A_int_msg_wdtr:
- hostdata->dsp = hostdata->script + hostdata->E_reject_message /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- return SPECIFIC_INT_NOTHING;
- case A_int_err_unexpected_phase:
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : unexpected phase\n", host->host_no);
- return SPECIFIC_INT_ABORT;
- case A_int_err_selected:
- if ((hostdata->chip / 100) == 8)
- printk ("scsi%d : selected by target %d\n", host->host_no,
- (int) NCR53c7x0_read8(SDID_REG_800) &7);
- else
- printk ("scsi%d : selected by target LCRC=0x%02x\n", host->host_no,
- (int) NCR53c7x0_read8(LCRC_REG_10));
- hostdata->dsp = hostdata->script + hostdata->E_target_abort /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- return SPECIFIC_INT_NOTHING;
- case A_int_err_unexpected_reselect:
- if ((hostdata->chip / 100) == 8)
- printk ("scsi%d : unexpected reselect by target %d lun %d\n",
- host->host_no, (int) NCR53c7x0_read8(SDID_REG_800) & 7,
- hostdata->reselected_identify & 7);
- else
- printk ("scsi%d : unexpected reselect LCRC=0x%02x\n", host->host_no,
- (int) NCR53c7x0_read8(LCRC_REG_10));
- hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- return SPECIFIC_INT_NOTHING;
-/*
- * Since contingent allegiance conditions are cleared by the next
- * command issued to a target, we must issue a REQUEST SENSE
- * command after receiving a CHECK CONDITION status, before
- * another command is issued.
- *
- * Since this NCR53c7x0_cmd will be freed after use, we don't
- * care if we step on the various fields, so modify a few things.
- */
- case A_int_err_check_condition:
-#if 0
- if (hostdata->options & OPTION_DEBUG_INTR)
-#endif
- printk ("scsi%d : CHECK CONDITION\n", host->host_no);
- if (!c) {
- printk("scsi%d : CHECK CONDITION with no SCSI command\n",
- host->host_no);
- return SPECIFIC_INT_PANIC;
- }
-
- /*
- * FIXME : this uses the normal one-byte selection message.
- * We may want to renegotiate for synchronous & WIDE transfers
- * since these could be the crux of our problem.
- *
- hostdata->NOP_insn* FIXME : once SCSI-II tagged queuing is implemented, we'll
- * have to set this up so that the rest of the DSA
- * agrees with this being an untagged queue'd command.
- */
-
- patch_dsa_32 (cmd->dsa, dsa_msgout, 0, 1);
-
- /*
- * Modify the table indirect for COMMAND OUT phase, since
- * Request Sense is a six byte command.
- */
-
- patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
-
- /*
- * The CDB is now mirrored in our local non-cached
- * structure, but keep the old structure up to date as well,
- * just in case anyone looks at it.
- */
-
- /*
- * XXX Need to worry about data buffer alignment/cache state
- * XXX here, but currently never get A_int_err_check_condition,
- * XXX so ignore problem for now.
- */
- cmd->cmnd[0] = c->cmnd[0] = REQUEST_SENSE;
- cmd->cmnd[0] = c->cmnd[1] &= 0xe0; /* Zero all but LUN */
- cmd->cmnd[0] = c->cmnd[2] = 0;
- cmd->cmnd[0] = c->cmnd[3] = 0;
- cmd->cmnd[0] = c->cmnd[4] = sizeof(c->sense_buffer);
- cmd->cmnd[0] = c->cmnd[5] = 0;
-
- /*
- * Disable dataout phase, and program datain to transfer to the
- * sense buffer, and add a jump to other_transfer after the
- * command so overflow/underrun conditions are detected.
- */
-
- patch_dsa_32 (cmd->dsa, dsa_dataout, 0,
- virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
- patch_dsa_32 (cmd->dsa, dsa_datain, 0,
- virt_to_bus(cmd->data_transfer_start));
- cmd->data_transfer_start[0] = (((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I |
- DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer);
- cmd->data_transfer_start[1] = (u32) virt_to_bus(c->sense_buffer);
-
- cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP)
- << 24) | DBC_TCI_TRUE;
- cmd->data_transfer_start[3] = (u32) virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
-
- /*
- * Currently, this command is flagged as completed, ie
- * it has valid status and message data. Reflag it as
- * incomplete. Q - need to do something so that original
- * status, etc are used.
- */
-
- cmd->result = cmd->cmd->result = 0xffff;
-
- /*
- * Restart command as a REQUEST SENSE.
- */
- hostdata->dsp = (u32 *) hostdata->script + hostdata->E_select /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- return SPECIFIC_INT_NOTHING;
- case A_int_debug_break:
- return SPECIFIC_INT_BREAK;
- case A_int_norm_aborted:
- hostdata->dsp = (u32 *) hostdata->schedule;
- hostdata->dsp_changed = 1;
- if (cmd)
- abnormal_finished (cmd, DID_ERROR << 16);
- return SPECIFIC_INT_NOTHING;
- case A_int_norm_emulateintfly:
- NCR53c7x0_intfly(host);
- return SPECIFIC_INT_NOTHING;
- case A_int_test_1:
- case A_int_test_2:
- hostdata->idle = 1;
- hostdata->test_completed = (dsps - A_int_test_1) / 0x00010000 + 1;
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk("scsi%d : test%d complete\n", host->host_no,
- hostdata->test_completed);
- return SPECIFIC_INT_NOTHING;
-#ifdef A_int_debug_reselected_ok
- case A_int_debug_reselected_ok:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT)) {
- /*
- * Note - this dsa is not based on location relative to
- * the command structure, but to location relative to the
- * DSA register
- */
- u32 *dsa;
- dsa = (u32 *) bus_to_virt (NCR53c7x0_read32(DSA_REG));
-
- printk("scsi%d : reselected_ok (DSA = 0x%x (virt 0x%p)\n",
- host->host_no, NCR53c7x0_read32(DSA_REG), dsa);
- printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
- host->host_no, cmd->saved_data_pointer,
- bus_to_virt(cmd->saved_data_pointer));
- print_insn (host, hostdata->script + Ent_reselected_ok /
- sizeof(u32), "", 1);
- if ((hostdata->chip / 100) == 8)
- printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
- host->host_no, NCR53c7x0_read8(SXFER_REG),
- NCR53c7x0_read8(SCNTL3_REG_800));
- else
- printk ("scsi%d : sxfer=0x%x, cannot read SBCL\n",
- host->host_no, NCR53c7x0_read8(SXFER_REG));
- if (c) {
- print_insn (host, (u32 *)
- hostdata->sync[c->device->id].script, "", 1);
- print_insn (host, (u32 *)
- hostdata->sync[c->device->id].script + 2, "", 1);
- }
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_reselect_check
- case A_int_debug_reselect_check:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- u32 *dsa;
-#if 0
- u32 *code;
-#endif
- /*
- * Note - this dsa is not based on location relative to
- * the command structure, but to location relative to the
- * DSA register
- */
- dsa = bus_to_virt (NCR53c7x0_read32(DSA_REG));
- printk("scsi%d : reselected_check_next (DSA = 0x%lx (virt 0x%p))\n",
- host->host_no, virt_to_bus(dsa), dsa);
- if (dsa) {
- printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
- host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer));
-#if 0
- printk("scsi%d : template code :\n", host->host_no);
- for (code = dsa + (Ent_dsa_code_check_reselect - Ent_dsa_zero)
- / sizeof(u32); code < (dsa + Ent_dsa_zero / sizeof(u32));
- code += print_insn (host, code, "", 1));
-#endif
- }
- print_insn (host, hostdata->script + Ent_reselected_ok /
- sizeof(u32), "", 1);
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_dsa_schedule
- case A_int_debug_dsa_schedule:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- u32 *dsa;
- /*
- * Note - this dsa is not based on location relative to
- * the command structure, but to location relative to the
- * DSA register
- */
- dsa = (u32 *) bus_to_virt (NCR53c7x0_read32(DSA_REG));
- printk("scsi%d : dsa_schedule (old DSA = 0x%lx (virt 0x%p))\n",
- host->host_no, virt_to_bus(dsa), dsa);
- if (dsa)
- printk("scsi%d : resume address is 0x%x (virt 0x%p)\n"
- " (temp was 0x%x (virt 0x%p))\n",
- host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer),
- NCR53c7x0_read32 (TEMP_REG),
- bus_to_virt (NCR53c7x0_read32(TEMP_REG)));
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_scheduled
- case A_int_debug_scheduled:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- printk("scsi%d : new I/O 0x%x (virt 0x%p) scheduled\n",
- host->host_no, NCR53c7x0_read32(DSA_REG),
- bus_to_virt(NCR53c7x0_read32(DSA_REG)));
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_idle
- case A_int_debug_idle:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- printk("scsi%d : idle\n", host->host_no);
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_cmd
- case A_int_debug_cmd:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- printk("scsi%d : command sent\n");
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_dsa_loaded
- case A_int_debug_dsa_loaded:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- printk("scsi%d : DSA loaded with 0x%x (virt 0x%p)\n", host->host_no,
- NCR53c7x0_read32(DSA_REG),
- bus_to_virt(NCR53c7x0_read32(DSA_REG)));
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_reselected
- case A_int_debug_reselected:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT)) {
- if ((hostdata->chip / 100) == 8)
- printk("scsi%d : reselected by target %d lun %d\n",
- host->host_no, (int) NCR53c7x0_read8(SDID_REG_800) & ~0x80,
- (int) hostdata->reselected_identify & 7);
- else
- printk("scsi%d : reselected by LCRC=0x%02x lun %d\n",
- host->host_no, (int) NCR53c7x0_read8(LCRC_REG_10),
- (int) hostdata->reselected_identify & 7);
- print_queues(host);
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_disconnect_msg
- case A_int_debug_disconnect_msg:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- if (c)
- printk("scsi%d : target %d lun %d disconnecting\n",
- host->host_no, c->device->id, c->device->lun);
- else
- printk("scsi%d : unknown target disconnecting\n",
- host->host_no);
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_disconnected
- case A_int_debug_disconnected:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT)) {
- printk ("scsi%d : disconnected, new queues are\n",
- host->host_no);
- print_queues(host);
-#if 0
- /* Not valid on ncr53c710! */
- printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
- host->host_no, NCR53c7x0_read8(SXFER_REG),
- NCR53c7x0_read8(SCNTL3_REG_800));
-#endif
- if (c) {
- print_insn (host, (u32 *)
- hostdata->sync[c->device->id].script, "", 1);
- print_insn (host, (u32 *)
- hostdata->sync[c->device->id].script + 2, "", 1);
- }
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_panic
- case A_int_debug_panic:
- printk("scsi%d : int_debug_panic received\n", host->host_no);
- print_lots (host);
- return SPECIFIC_INT_PANIC;
-#endif
-#ifdef A_int_debug_saved
- case A_int_debug_saved:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT)) {
- printk ("scsi%d : saved data pointer 0x%x (virt 0x%p)\n",
- host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer));
- print_progress (c);
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_restored
- case A_int_debug_restored:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT)) {
- if (cmd) {
- int size;
- printk ("scsi%d : restored data pointer 0x%x (virt 0x%p)\n",
- host->host_no, cmd->saved_data_pointer, bus_to_virt (
- cmd->saved_data_pointer));
- size = print_insn (host, (u32 *)
- bus_to_virt(cmd->saved_data_pointer), "", 1);
- size = print_insn (host, (u32 *)
- bus_to_virt(cmd->saved_data_pointer) + size, "", 1);
- print_progress (c);
- }
-#if 0
- printk ("scsi%d : datapath residual %d\n",
- host->host_no, datapath_residual (host)) ;
-#endif
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_sync
- case A_int_debug_sync:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT|OPTION_DEBUG_SDTR)) {
- unsigned char sxfer = NCR53c7x0_read8 (SXFER_REG), scntl3;
- if ((hostdata->chip / 100) == 8) {
- scntl3 = NCR53c7x0_read8 (SCNTL3_REG_800);
- if (c) {
- if (sxfer != hostdata->sync[c->device->id].sxfer_sanity ||
- scntl3 != hostdata->sync[c->device->id].scntl3_sanity) {
- printk ("scsi%d : sync sanity check failed sxfer=0x%x, scntl3=0x%x",
- host->host_no, sxfer, scntl3);
- NCR53c7x0_write8 (SXFER_REG, sxfer);
- NCR53c7x0_write8 (SCNTL3_REG_800, scntl3);
- }
- } else
- printk ("scsi%d : unknown command sxfer=0x%x, scntl3=0x%x\n",
- host->host_no, (int) sxfer, (int) scntl3);
- } else {
- if (c) {
- if (sxfer != hostdata->sync[c->device->id].sxfer_sanity) {
- printk ("scsi%d : sync sanity check failed sxfer=0x%x",
- host->host_no, sxfer);
- NCR53c7x0_write8 (SXFER_REG, sxfer);
- NCR53c7x0_write8 (SBCL_REG,
- hostdata->sync[c->device->id].sscf_710);
- }
- } else
- printk ("scsi%d : unknown command sxfer=0x%x\n",
- host->host_no, (int) sxfer);
- }
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_datain
- case A_int_debug_datain:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT|OPTION_DEBUG_SDTR)) {
- int size;
- if ((hostdata->chip / 100) == 8)
- printk ("scsi%d : In do_datain (%s) sxfer=0x%x, scntl3=0x%x\n"
- " datapath residual=%d\n",
- host->host_no, sbcl_to_phase (NCR53c7x0_read8 (SBCL_REG)),
- (int) NCR53c7x0_read8(SXFER_REG),
- (int) NCR53c7x0_read8(SCNTL3_REG_800),
- datapath_residual (host)) ;
- else
- printk ("scsi%d : In do_datain (%s) sxfer=0x%x\n"
- " datapath residual=%d\n",
- host->host_no, sbcl_to_phase (NCR53c7x0_read8 (SBCL_REG)),
- (int) NCR53c7x0_read8(SXFER_REG),
- datapath_residual (host)) ;
- print_insn (host, dsp, "", 1);
- size = print_insn (host, (u32 *) bus_to_virt(dsp[1]), "", 1);
- print_insn (host, (u32 *) bus_to_virt(dsp[1]) + size, "", 1);
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_check_dsa
- case A_int_debug_check_dsa:
- if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
- int sdid;
- int tmp;
- char *where;
- if (hostdata->chip / 100 == 8)
- sdid = NCR53c7x0_read8 (SDID_REG_800) & 15;
- else {
- tmp = NCR53c7x0_read8 (SDID_REG_700);
- if (!tmp)
- panic ("SDID_REG_700 = 0");
- tmp >>= 1;
- sdid = 0;
- while (tmp) {
- tmp >>= 1;
- sdid++;
- }
- }
- where = dsp - NCR53c7x0_insn_size(NCR53c7x0_read8
- (DCMD_REG)) == hostdata->script +
- Ent_select_check_dsa / sizeof(u32) ?
- "selection" : "reselection";
- if (c && sdid != c->device->id) {
- printk ("scsi%d : SDID target %d != DSA target %d at %s\n",
- host->host_no, sdid, c->device->id, where);
- print_lots(host);
- dump_events (host, 20);
- return SPECIFIC_INT_PANIC;
- }
- }
- return SPECIFIC_INT_RESTART;
-#endif
- default:
- if ((dsps & 0xff000000) == 0x03000000) {
- printk ("scsi%d : misc debug interrupt 0x%x\n",
- host->host_no, dsps);
- return SPECIFIC_INT_RESTART;
- } else if ((dsps & 0xff000000) == 0x05000000) {
- if (hostdata->events) {
- struct NCR53c7x0_event *event;
- ++hostdata->event_index;
- if (hostdata->event_index >= hostdata->event_size)
- hostdata->event_index = 0;
- event = (struct NCR53c7x0_event *) hostdata->events +
- hostdata->event_index;
- event->event = (enum ncr_event) dsps;
- event->dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
- if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
- if (hostdata->chip / 100 == 8)
- event->target = NCR53c7x0_read8(SSID_REG_800);
- else {
- unsigned char tmp, sdid;
- tmp = NCR53c7x0_read8 (SDID_REG_700);
- if (!tmp)
- panic ("SDID_REG_700 = 0");
- tmp >>= 1;
- sdid = 0;
- while (tmp) {
- tmp >>= 1;
- sdid++;
- }
- event->target = sdid;
- }
- }
- else
- event->target = 255;
-
- if (event->event == EVENT_RESELECT)
- event->lun = hostdata->reselected_identify & 0xf;
- else if (c)
- event->lun = c->device->lun;
- else
- event->lun = 255;
- do_gettimeofday(&(event->time));
- if (c) {
- event->pid = c->pid;
- memcpy ((void *) event->cmnd, (void *) c->cmnd,
- sizeof (event->cmnd));
- } else {
- event->pid = -1;
- }
- }
- return SPECIFIC_INT_RESTART;
- }
-
- printk ("scsi%d : unknown user interrupt 0x%x\n",
- host->host_no, (unsigned) dsps);
- return SPECIFIC_INT_PANIC;
- }
-}
-
-/*
- * XXX - the stock NCR assembler won't output the scriptu.h file,
- * which undefine's all #define'd CPP symbols from the script.h
- * file, which will create problems if you use multiple scripts
- * with the same symbol names.
- *
- * If you insist on using NCR's assembler, you could generate
- * scriptu.h from script.h using something like
- *
- * grep #define script.h | \
- * sed 's/#define[ ][ ]*\([_a-zA-Z][_a-zA-Z0-9]*\).*$/#undefine \1/' \
- * > scriptu.h
- */
-
-#include "53c7xx_u.h"
-
-/* XXX - add alternate script handling code here */
-
-
-/*
- * Function : static void NCR537xx_soft_reset (struct Scsi_Host *host)
- *
- * Purpose : perform a soft reset of the NCR53c7xx chip
- *
- * Inputs : host - pointer to this host adapter's structure
- *
- * Preconditions : NCR53c7x0_init must have been called for this
- * host.
- *
- */
-
-static void
-NCR53c7x0_soft_reset (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- unsigned long flags;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- NCR53c7x0_local_setup(host);
-
- local_irq_save(flags);
-
- /* Disable scsi chip and s/w level 7 ints */
-
-#ifdef CONFIG_MVME16x
- if (MACH_IS_MVME16x)
- {
- volatile unsigned long v;
-
- v = *(volatile unsigned long *)0xfff4006c;
- v &= ~0x8000;
- *(volatile unsigned long *)0xfff4006c = v;
- v = *(volatile unsigned long *)0xfff4202c;
- v &= ~0x10;
- *(volatile unsigned long *)0xfff4202c = v;
- }
-#endif
- /* Anything specific for your hardware? */
-
- /*
- * Do a soft reset of the chip so that everything is
- * reinitialized to the power-on state.
- *
- * Basically follow the procedure outlined in the NCR53c700
- * data manual under Chapter Six, How to Use, Steps Necessary to
- * Start SCRIPTS, with the exception of actually starting the
- * script and setting up the synchronous transfer gunk.
- */
-
- /* Should we reset the scsi bus here??????????????????? */
-
- NCR53c7x0_write8(ISTAT_REG_700, ISTAT_10_SRST);
- NCR53c7x0_write8(ISTAT_REG_700, 0);
-
- /*
- * saved_dcntl is set up in NCR53c7x0_init() before it is overwritten
- * here. We should have some better way of working out the CF bit
- * setting..
- */
-
- hostdata->saved_dcntl = DCNTL_10_EA|DCNTL_10_COM;
- if (hostdata->scsi_clock > 50000000)
- hostdata->saved_dcntl |= DCNTL_700_CF_3;
- else
- if (hostdata->scsi_clock > 37500000)
- hostdata->saved_dcntl |= DCNTL_700_CF_2;
-#if 0
- else
- /* Any clocks less than 37.5MHz? */
-#endif
-
- if (hostdata->options & OPTION_DEBUG_TRACE)
- NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM);
- else
- NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl);
- /* Following disables snooping - snooping is not required, as non-
- * cached pages are used for shared data, and appropriate use is
- * made of cache_push/cache_clear. Indeed, for 68060
- * enabling snooping causes disk corruption of ext2fs free block
- * bitmaps and the like. If you have a 68060 with snooping hardwared
- * on, then you need to enable CONFIG_060_WRITETHROUGH.
- */
- NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD);
- /* Actually burst of eight, according to my 53c710 databook */
- NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2);
- NCR53c7x0_write8(SCID_REG, 1 << host->this_id);
- NCR53c7x0_write8(SBCL_REG, 0);
- NCR53c7x0_write8(SCNTL1_REG, SCNTL1_ESR_700);
- NCR53c7x0_write8(SCNTL0_REG, ((hostdata->options & OPTION_PARITY) ?
- SCNTL0_EPC : 0) | SCNTL0_EPG_700 | SCNTL0_ARB1 | SCNTL0_ARB2);
-
- /*
- * Enable all interrupts, except parity which we only want when
- * the user requests it.
- */
-
- NCR53c7x0_write8(DIEN_REG, DIEN_700_BF |
- DIEN_ABRT | DIEN_SSI | DIEN_SIR | DIEN_700_OPC);
-
- NCR53c7x0_write8(SIEN_REG_700, ((hostdata->options & OPTION_PARITY) ?
- SIEN_PAR : 0) | SIEN_700_STO | SIEN_RST | SIEN_UDC |
- SIEN_SGE | SIEN_MA);
-
-#ifdef CONFIG_MVME16x
- if (MACH_IS_MVME16x)
- {
- volatile unsigned long v;
-
- /* Enable scsi chip and s/w level 7 ints */
- v = *(volatile unsigned long *)0xfff40080;
- v = (v & ~(0xf << 28)) | (4 << 28);
- *(volatile unsigned long *)0xfff40080 = v;
- v = *(volatile unsigned long *)0xfff4006c;
- v |= 0x8000;
- *(volatile unsigned long *)0xfff4006c = v;
- v = *(volatile unsigned long *)0xfff4202c;
- v = (v & ~0xff) | 0x10 | 4;
- *(volatile unsigned long *)0xfff4202c = v;
- }
-#endif
- /* Anything needed for your hardware? */
- local_irq_restore(flags);
-}
-
-
-/*
- * Function static struct NCR53c7x0_cmd *allocate_cmd (Scsi_Cmnd *cmd)
- *
- * Purpose : Return the first free NCR53c7x0_cmd structure (which are
- * reused in a LIFO manner to minimize cache thrashing).
- *
- * Side effects : If we haven't yet scheduled allocation of NCR53c7x0_cmd
- * structures for this device, do so. Attempt to complete all scheduled
- * allocations using get_zeroed_page(), putting NCR53c7x0_cmd structures on
- * the free list. Teach programmers not to drink and hack.
- *
- * Inputs : cmd - SCSI command
- *
- * Returns : NCR53c7x0_cmd structure allocated on behalf of cmd;
- * NULL on failure.
- */
-
-static void
-my_free_page (void *addr, int dummy)
-{
- /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
- * XXX may be invalid (CONFIG_060_WRITETHROUGH)
- */
- kernel_set_cachemode((void *)addr, 4096, IOMAP_FULL_CACHING);
- free_page ((u32)addr);
-}
-
-static struct NCR53c7x0_cmd *
-allocate_cmd (Scsi_Cmnd *cmd) {
- struct Scsi_Host *host = cmd->device->host;
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) host->hostdata[0];
- u32 real; /* Real address */
- int size; /* Size of *tmp */
- struct NCR53c7x0_cmd *tmp;
- unsigned long flags;
-
- if (hostdata->options & OPTION_DEBUG_ALLOCATION)
- printk ("scsi%d : num_cmds = %d, can_queue = %d\n"
- " target = %d, lun = %d, %s\n",
- host->host_no, hostdata->num_cmds, host->can_queue,
- cmd->device->id, cmd->device->lun, (hostdata->cmd_allocated[cmd->device->id] &
- (1 << cmd->device->lun)) ? "already allocated" : "not allocated");
-
-/*
- * If we have not yet reserved commands for this I_T_L nexus, and
- * the device exists (as indicated by permanent Scsi_Cmnd structures
- * being allocated under 1.3.x, or being outside of scan_scsis in
- * 1.2.x), do so now.
- */
- if (!(hostdata->cmd_allocated[cmd->device->id] & (1 << cmd->device->lun)) &&
- cmd->device && cmd->device->has_cmdblocks) {
- if ((hostdata->extra_allocate + hostdata->num_cmds) < host->can_queue)
- hostdata->extra_allocate += host->cmd_per_lun;
- hostdata->cmd_allocated[cmd->device->id] |= (1 << cmd->device->lun);
- }
-
- for (; hostdata->extra_allocate > 0 ; --hostdata->extra_allocate,
- ++hostdata->num_cmds) {
- /* historically, kmalloc has returned unaligned addresses; pad so we
- have enough room to ROUNDUP */
- size = hostdata->max_cmd_size + sizeof (void *);
-#ifdef FORCE_DSA_ALIGNMENT
- /*
- * 53c710 rev.0 doesn't have an add-with-carry instruction.
- * Ensure we allocate enough memory to force alignment.
- */
- size += 256;
-#endif
-/* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
-
- if (size > 4096) {
- printk (KERN_ERR "53c7xx: allocate_cmd size > 4K\n");
- return NULL;
- }
- real = get_zeroed_page(GFP_ATOMIC);
- if (real == 0)
- return NULL;
- cache_push(virt_to_phys((void *)real), 4096);
- cache_clear(virt_to_phys((void *)real), 4096);
- kernel_set_cachemode((void *)real, 4096, IOMAP_NOCACHE_SER);
- tmp = ROUNDUP(real, void *);
-#ifdef FORCE_DSA_ALIGNMENT
- {
- if (((u32)tmp & 0xff) > CmdPageStart)
- tmp = (struct NCR53c7x0_cmd *)((u32)tmp + 255);
- tmp = (struct NCR53c7x0_cmd *)(((u32)tmp & ~0xff) + CmdPageStart);
-#if 0
- printk ("scsi: size = %d, real = 0x%08x, tmp set to 0x%08x\n",
- size, real, (u32)tmp);
-#endif
- }
-#endif
- tmp->real = (void *)real;
- tmp->size = size;
- tmp->free = ((void (*)(void *, int)) my_free_page);
- local_irq_save(flags);
- tmp->next = hostdata->free;
- hostdata->free = tmp;
- local_irq_restore(flags);
- }
- local_irq_save(flags);
- tmp = (struct NCR53c7x0_cmd *) hostdata->free;
- if (tmp) {
- hostdata->free = tmp->next;
- }
- local_irq_restore(flags);
- if (!tmp)
- printk ("scsi%d : can't allocate command for target %d lun %d\n",
- host->host_no, cmd->device->id, cmd->device->lun);
- return tmp;
-}
-
-/*
- * Function static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd)
- *
- *
- * Purpose : allocate a NCR53c7x0_cmd structure, initialize it based on the
- * Scsi_Cmnd structure passed in cmd, including dsa and Linux field
- * initialization, and dsa code relocation.
- *
- * Inputs : cmd - SCSI command
- *
- * Returns : NCR53c7x0_cmd structure corresponding to cmd,
- * NULL on failure.
- */
-static struct NCR53c7x0_cmd *
-create_cmd (Scsi_Cmnd *cmd) {
- NCR53c7x0_local_declare();
- struct Scsi_Host *host = cmd->device->host;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- struct NCR53c7x0_cmd *tmp; /* NCR53c7x0_cmd structure for this command */
- int datain, /* Number of instructions per phase */
- dataout;
- int data_transfer_instructions, /* Count of dynamic instructions */
- i; /* Counter */
- u32 *cmd_datain, /* Address of datain/dataout code */
- *cmd_dataout; /* Incremented as we assemble */
-#ifdef notyet
- unsigned char *msgptr; /* Current byte in select message */
- int msglen; /* Length of whole select message */
-#endif
- unsigned long flags;
- u32 exp_select_indirect; /* Used in sanity check */
- NCR53c7x0_local_setup(cmd->device->host);
-
- if (!(tmp = allocate_cmd (cmd)))
- return NULL;
-
- /*
- * Copy CDB and initialised result fields from Scsi_Cmnd to NCR53c7x0_cmd.
- * We do this because NCR53c7x0_cmd may have a special cache mode
- * selected to cope with lack of bus snooping, etc.
- */
-
- memcpy(tmp->cmnd, cmd->cmnd, 12);
- tmp->result = cmd->result;
-
- /*
- * Decide whether we need to generate commands for DATA IN,
- * DATA OUT, neither, or both based on the SCSI command
- */
-
- switch (cmd->cmnd[0]) {
- /* These commands do DATA IN */
- case INQUIRY:
- case MODE_SENSE:
- case READ_6:
- case READ_10:
- case READ_CAPACITY:
- case REQUEST_SENSE:
- case READ_BLOCK_LIMITS:
- case READ_TOC:
- datain = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
- dataout = 0;
- break;
- /* These commands do DATA OUT */
- case MODE_SELECT:
- case WRITE_6:
- case WRITE_10:
-#if 0
- printk("scsi%d : command is ", host->host_no);
- __scsi_print_command(cmd->cmnd);
-#endif
-#if 0
- printk ("scsi%d : %d scatter/gather segments\n", host->host_no,
- cmd->use_sg);
-#endif
- datain = 0;
- dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
-#if 0
- hostdata->options |= OPTION_DEBUG_INTR;
-#endif
- break;
- /*
- * These commands do no data transfer, we should force an
- * interrupt if a data phase is attempted on them.
- */
- case TEST_UNIT_READY:
- case ALLOW_MEDIUM_REMOVAL:
- case START_STOP:
- datain = dataout = 0;
- break;
- /*
- * We don't know about these commands, so generate code to handle
- * both DATA IN and DATA OUT phases. More efficient to identify them
- * and add them to the above cases.
- */
- default:
- printk("scsi%d : datain+dataout for command ", host->host_no);
- __scsi_print_command(cmd->cmnd);
- datain = dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
- }
-
- /*
- * New code : so that active pointers work correctly regardless
- * of where the saved data pointer is at, we want to immediately
- * enter the dynamic code after selection, and on a non-data
- * phase perform a CALL to the non-data phase handler, with
- * returns back to this address.
- *
- * If a phase mismatch is encountered in the middle of a
- * Block MOVE instruction, we want to _leave_ that instruction
- * unchanged as the current case is, modify a temporary buffer,
- * and point the active pointer (TEMP) at that.
- *
- * Furthermore, we want to implement a saved data pointer,
- * set by the SAVE_DATA_POINTERs message.
- *
- * So, the data transfer segments will change to
- * CALL data_transfer, WHEN NOT data phase
- * MOVE x, x, WHEN data phase
- * ( repeat )
- * JUMP other_transfer
- */
-
- data_transfer_instructions = datain + dataout;
-
- /*
- * When we perform a request sense, we overwrite various things,
- * including the data transfer code. Make sure we have enough
- * space to do that.
- */
-
- if (data_transfer_instructions < 2)
- data_transfer_instructions = 2;
-
-
- /*
- * The saved data pointer is set up so that a RESTORE POINTERS message
- * will start the data transfer over at the beginning.
- */
-
- tmp->saved_data_pointer = virt_to_bus (hostdata->script) +
- hostdata->E_data_transfer;
-
- /*
- * Initialize Linux specific fields.
- */
-
- tmp->cmd = cmd;
- tmp->next = NULL;
- tmp->flags = 0;
- tmp->dsa_next_addr = virt_to_bus(tmp->dsa) + hostdata->dsa_next -
- hostdata->dsa_start;
- tmp->dsa_addr = virt_to_bus(tmp->dsa) - hostdata->dsa_start;
-
- /*
- * Calculate addresses of dynamic code to fill in DSA
- */
-
- tmp->data_transfer_start = tmp->dsa + (hostdata->dsa_end -
- hostdata->dsa_start) / sizeof(u32);
- tmp->data_transfer_end = tmp->data_transfer_start +
- 2 * data_transfer_instructions;
-
- cmd_datain = datain ? tmp->data_transfer_start : NULL;
- cmd_dataout = dataout ? (datain ? cmd_datain + 2 * datain : tmp->
- data_transfer_start) : NULL;
-
- /*
- * Fill in the NCR53c7x0_cmd structure as follows
- * dsa, with fixed up DSA code
- * datain code
- * dataout code
- */
-
- /* Copy template code into dsa and perform all necessary fixups */
- if (hostdata->dsa_fixup)
- hostdata->dsa_fixup(tmp);
-
- patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
- /*
- * XXX is this giving 53c710 access to the Scsi_Cmnd in some way?
- * Do we need to change it for caching reasons?
- */
- patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
-
- if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) {
-
- exp_select_indirect = ((1 << cmd->device->id) << 16) |
- (hostdata->sync[cmd->device->id].sxfer_sanity << 8);
-
- if (hostdata->sync[cmd->device->id].select_indirect !=
- exp_select_indirect) {
- printk ("scsi%d : sanity check failed select_indirect=0x%x\n",
- host->host_no, hostdata->sync[cmd->device->id].select_indirect);
- FATAL(host);
-
- }
- }
-
- patch_dsa_32(tmp->dsa, dsa_select, 0,
- hostdata->sync[cmd->device->id].select_indirect);
-
- /*
- * Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
- * different commands; although it should be trivial to do them
- * both at the same time.
- */
- if (hostdata->initiate_wdtr & (1 << cmd->device->id)) {
- memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
- sizeof(wdtr_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
- local_irq_save(flags);
- hostdata->initiate_wdtr &= ~(1 << cmd->device->id);
- local_irq_restore(flags);
- } else if (hostdata->initiate_sdtr & (1 << cmd->device->id)) {
- memcpy ((void *) (tmp->select + 1), (void *) sdtr_message,
- sizeof(sdtr_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
- tmp->flags |= CMD_FLAG_SDTR;
- local_irq_save(flags);
- hostdata->initiate_sdtr &= ~(1 << cmd->device->id);
- local_irq_restore(flags);
-
- }
-#if 1
- else if (!(hostdata->talked_to & (1 << cmd->device->id)) &&
- !(hostdata->options & OPTION_NO_ASYNC)) {
-
- memcpy ((void *) (tmp->select + 1), (void *) async_message,
- sizeof(async_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(async_message));
- tmp->flags |= CMD_FLAG_SDTR;
- }
-#endif
- else
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
-
- hostdata->talked_to |= (1 << cmd->device->id);
- tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ?
- IDENTIFY (1, cmd->device->lun) : IDENTIFY (0, cmd->device->lun);
- patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
- patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
- patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(tmp->cmnd));
- patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ?
- virt_to_bus (cmd_dataout)
- : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
- patch_dsa_32(tmp->dsa, dsa_datain, 0, cmd_datain ?
- virt_to_bus (cmd_datain)
- : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
- /*
- * XXX - need to make endian aware, should use separate variables
- * for both status and message bytes.
- */
- patch_dsa_32(tmp->dsa, dsa_msgin, 0, 1);
-/*
- * FIXME : these only works for little endian. We probably want to
- * provide message and status fields in the NCR53c7x0_cmd
- * structure, and assign them to cmd->result when we're done.
- */
-#ifdef BIG_ENDIAN
- patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&tmp->result) + 2);
- patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
- patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&tmp->result) + 3);
-#else
- patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&tmp->result) + 1);
- patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
- patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&tmp->result));
-#endif
- patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
- patch_dsa_32(tmp->dsa, dsa_msgout_other, 1,
- virt_to_bus(&(hostdata->NCR53c7xx_msg_nop)));
-
- /*
- * Generate code for zero or more of the DATA IN, DATA OUT phases
- * in the format
- *
- * CALL data_transfer, WHEN NOT phase
- * MOVE first buffer length, first buffer address, WHEN phase
- * ...
- * MOVE last buffer length, last buffer address, WHEN phase
- * JUMP other_transfer
- */
-
-/*
- * See if we're getting to data transfer by generating an unconditional
- * interrupt.
- */
-#if 0
- if (datain) {
- cmd_datain[0] = 0x98080000;
- cmd_datain[1] = 0x03ffd00d;
- cmd_datain += 2;
- }
-#endif
-
-/*
- * XXX - I'm undecided whether all of this nonsense is faster
- * in the long run, or whether I should just go and implement a loop
- * on the NCR chip using table indirect mode?
- *
- * In any case, this is how it _must_ be done for 53c700/700-66 chips,
- * so this stays even when we come up with something better.
- *
- * When we're limited to 1 simultaneous command, no overlapping processing,
- * we're seeing 630K/sec, with 7% CPU usage on a slow Syquest 45M
- * drive.
- *
- * Not bad, not good. We'll see.
- */
-
- tmp->bounce.len = 0; /* Assume aligned buffer */
-
- for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4,
- cmd_dataout += 4, ++i) {
- u32 vbuf = cmd->use_sg
- ? (u32)page_address(((struct scatterlist *)cmd->request_buffer)[i].page)+
- ((struct scatterlist *)cmd->request_buffer)[i].offset
- : (u32)(cmd->request_buffer);
- u32 bbuf = virt_to_bus((void *)vbuf);
- u32 count = cmd->use_sg ?
- ((struct scatterlist *)cmd->request_buffer)[i].length :
- cmd->request_bufflen;
-
- /*
- * If we have buffers which are not aligned with 16 byte cache
- * lines, then we just hope nothing accesses the other parts of
- * those cache lines while the transfer is in progress. That would
- * fill the cache, and subsequent reads of the dma data would pick
- * up the wrong thing.
- * XXX We need a bounce buffer to handle that correctly.
- */
-
- if (((bbuf & 15) || (count & 15)) && (datain || dataout))
- {
- /* Bounce buffer needed */
- if (cmd->use_sg)
- printk ("53c7xx: Non-aligned buffer with use_sg\n");
- else if (datain && dataout)
- printk ("53c7xx: Non-aligned buffer with datain && dataout\n");
- else if (count > 256)
- printk ("53c7xx: Non-aligned transfer > 256 bytes\n");
- else
- {
- if (datain)
- {
- tmp->bounce.len = count;
- tmp->bounce.addr = vbuf;
- bbuf = virt_to_bus(tmp->bounce.buf);
- tmp->bounce.buf[0] = 0xff;
- tmp->bounce.buf[1] = 0xfe;
- tmp->bounce.buf[2] = 0xfd;
- tmp->bounce.buf[3] = 0xfc;
- }
- if (dataout)
- {
- memcpy ((void *)tmp->bounce.buf, (void *)vbuf, count);
- bbuf = virt_to_bus(tmp->bounce.buf);
- }
- }
- }
-
- if (datain) {
- cache_clear(virt_to_phys((void *)vbuf), count);
- /* CALL other_in, WHEN NOT DATA_IN */
- cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
- DCMD_TCI_IO) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd_datain[1] = virt_to_bus (hostdata->script) +
- hostdata->E_other_in;
- /* MOVE count, buf, WHEN DATA_IN */
- cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO)
- << 24) | count;
- cmd_datain[3] = bbuf;
-#if 0
- print_insn (host, cmd_datain, "dynamic ", 1);
- print_insn (host, cmd_datain + 2, "dynamic ", 1);
-#endif
- }
- if (dataout) {
- cache_push(virt_to_phys((void *)vbuf), count);
- /* CALL other_out, WHEN NOT DATA_OUT */
- cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd_dataout[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_out;
- /* MOVE count, buf, WHEN DATA+OUT */
- cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24)
- | count;
- cmd_dataout[3] = bbuf;
-#if 0
- print_insn (host, cmd_dataout, "dynamic ", 1);
- print_insn (host, cmd_dataout + 2, "dynamic ", 1);
-#endif
- }
- }
-
- /*
- * Install JUMP instructions after the data transfer routines to return
- * control to the do_other_transfer routines.
- */
-
-
- if (datain) {
- cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
- cmd_datain[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
-#if 0
- print_insn (host, cmd_datain, "dynamic jump ", 1);
-#endif
- cmd_datain += 2;
- }
-#if 0
- if (datain) {
- cmd_datain[0] = 0x98080000;
- cmd_datain[1] = 0x03ffdeed;
- cmd_datain += 2;
- }
-#endif
- if (dataout) {
- cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
- cmd_dataout[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
-#if 0
- print_insn (host, cmd_dataout, "dynamic jump ", 1);
-#endif
- cmd_dataout += 2;
- }
-
- return tmp;
-}
-
-/*
- * Function : int NCR53c7xx_queue_command (Scsi_Cmnd *cmd,
- * void (*done)(Scsi_Cmnd *))
- *
- * Purpose : enqueues a SCSI command
- *
- * Inputs : cmd - SCSI command, done - function called on completion, with
- * a pointer to the command descriptor.
- *
- * Returns : 0
- *
- * Side effects :
- * cmd is added to the per instance driver issue_queue, with major
- * twiddling done to the host specific fields of cmd. If the
- * process_issue_queue coroutine isn't running, it is restarted.
- *
- * NOTE : we use the host_scribble field of the Scsi_Cmnd structure to
- * hold our own data, and pervert the ptr field of the SCp field
- * to create a linked list.
- */
-
-int
-NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
- struct Scsi_Host *host = cmd->device->host;
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) host->hostdata[0];
- unsigned long flags;
- Scsi_Cmnd *tmp;
-
- cmd->scsi_done = done;
- cmd->host_scribble = NULL;
- cmd->SCp.ptr = NULL;
- cmd->SCp.buffer = NULL;
-
-#ifdef VALID_IDS
- /* Ignore commands on invalid IDs */
- if (!hostdata->valid_ids[cmd->device->id]) {
- printk("scsi%d : ignoring target %d lun %d\n", host->host_no,
- cmd->device->id, cmd->device->lun);
- cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
- return 0;
- }
-#endif
-
- local_irq_save(flags);
- if ((hostdata->options & (OPTION_DEBUG_INIT_ONLY|OPTION_DEBUG_PROBE_ONLY))
- || ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
- !(hostdata->debug_lun_limit[cmd->device->id] & (1 << cmd->device->lun)))
-#ifdef LINUX_1_2
- || cmd->device->id > 7
-#else
- || cmd->device->id >= host->max_id
-#endif
- || cmd->device->id == host->this_id
- || hostdata->state == STATE_DISABLED) {
- printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
- cmd->device->id, cmd->device->lun);
- cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
- local_irq_restore(flags);
- return 0;
- }
-
- if ((hostdata->options & OPTION_DEBUG_NCOMMANDS_LIMIT) &&
- (hostdata->debug_count_limit == 0)) {
- printk("scsi%d : maximum commands exceeded\n", host->host_no);
- cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
- local_irq_restore(flags);
- return 0;
- }
-
- if (hostdata->options & OPTION_DEBUG_READ_ONLY) {
- switch (cmd->cmnd[0]) {
- case WRITE_6:
- case WRITE_10:
- printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
- host->host_no);
- cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
- local_irq_restore(flags);
- return 0;
- }
- }
-
- if ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
- hostdata->debug_count_limit != -1)
- --hostdata->debug_count_limit;
-
- cmd->result = 0xffff; /* The NCR will overwrite message
- and status with valid data */
- cmd->host_scribble = (unsigned char *) tmp = create_cmd (cmd);
-
- /*
- * REQUEST SENSE commands are inserted at the head of the queue
- * so that we do not clear the contingent allegiance condition
- * they may be looking at.
- */
-
- if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
- cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue;
- hostdata->issue_queue = cmd;
- } else {
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->SCp.ptr;
- tmp = (Scsi_Cmnd *) tmp->SCp.ptr);
- tmp->SCp.ptr = (unsigned char *) cmd;
- }
- local_irq_restore(flags);
- run_process_issue_queue();
- return 0;
-}
-
-/*
- * Function : void to_schedule_list (struct Scsi_Host *host,
- * struct NCR53c7x0_hostdata * hostdata, Scsi_Cmnd *cmd)
- *
- * Purpose : takes a SCSI command which was just removed from the
- * issue queue, and deals with it by inserting it in the first
- * free slot in the schedule list or by terminating it immediately.
- *
- * Inputs :
- * host - SCSI host adapter; hostdata - hostdata structure for
- * this adapter; cmd - a pointer to the command; should have
- * the host_scribble field initialized to point to a valid
- *
- * Side effects :
- * cmd is added to the per instance schedule list, with minor
- * twiddling done to the host specific fields of cmd.
- *
- */
-
-static __inline__ void
-to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
- struct NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- Scsi_Cmnd *tmp = cmd->cmd;
- unsigned long flags;
- /* dsa start is negative, so subtraction is used */
- volatile u32 *ncrcurrent;
-
- int i;
- NCR53c7x0_local_setup(host);
-#if 0
- printk("scsi%d : new dsa is 0x%lx (virt 0x%p)\n", host->host_no,
- virt_to_bus(hostdata->dsa), hostdata->dsa);
-#endif
-
- local_irq_save(flags);
-
- /*
- * Work around race condition : if an interrupt fired and we
- * got disabled forget about this command.
- */
-
- if (hostdata->state == STATE_DISABLED) {
- printk("scsi%d : driver disabled\n", host->host_no);
- tmp->result = (DID_BAD_TARGET << 16);
- cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
- hostdata->free = cmd;
- tmp->scsi_done(tmp);
- local_irq_restore(flags);
- return;
- }
-
- for (i = host->can_queue, ncrcurrent = hostdata->schedule;
- i > 0 && ncrcurrent[0] != hostdata->NOP_insn;
- --i, ncrcurrent += 2 /* JUMP instructions are two words */);
-
- if (i > 0) {
- ++hostdata->busy[tmp->device->id][tmp->device->lun];
- cmd->next = hostdata->running_list;
- hostdata->running_list = cmd;
-
- /* Restore this instruction to a NOP once the command starts */
- cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) /
- sizeof(u32)] = (u32) virt_to_bus ((void *)ncrcurrent);
- /* Replace the current jump operand. */
- ncrcurrent[1] =
- virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
- hostdata->E_dsa_code_template;
- /* Replace the NOP instruction with a JUMP */
- ncrcurrent[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
- } else {
- printk ("scsi%d: no free slot\n", host->host_no);
- disable(host);
- tmp->result = (DID_ERROR << 16);
- cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
- hostdata->free = cmd;
- tmp->scsi_done(tmp);
- local_irq_restore(flags);
- return;
- }
-
- /*
- * If the NCR chip is in an idle state, start it running the scheduler
- * immediately. Otherwise, signal the chip to jump to schedule as
- * soon as it is idle.
- */
-
- if (hostdata->idle) {
- hostdata->idle = 0;
- hostdata->state = STATE_RUNNING;
- NCR53c7x0_write32 (DSP_REG, virt_to_bus ((void *)hostdata->schedule));
- if (hostdata->options & OPTION_DEBUG_TRACE)
- NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
- DCNTL_SSM | DCNTL_STD);
- } else {
- NCR53c7x0_write8(hostdata->istat, ISTAT_10_SIGP);
- }
-
- local_irq_restore(flags);
-}
-
-/*
- * Function : busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata
- * *hostdata, Scsi_Cmnd *cmd)
- *
- * Purpose : decide if we can pass the given SCSI command on to the
- * device in question or not.
- *
- * Returns : non-zero when we're busy, 0 when we aren't.
- */
-
-static __inline__ int
-busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
- Scsi_Cmnd *cmd) {
- /* FIXME : in the future, this needs to accommodate SCSI-II tagged
- queuing, and we may be able to play with fairness here a bit.
- */
- return hostdata->busy[cmd->device->id][cmd->device->lun];
-}
-
-/*
- * Function : process_issue_queue (void)
- *
- * Purpose : transfer commands from the issue queue to NCR start queue
- * of each NCR53c7/8xx in the system, avoiding kernel stack
- * overflows when the scsi_done() function is invoked recursively.
- *
- * NOTE : process_issue_queue exits with interrupts *disabled*, so the
- * caller must reenable them if it desires.
- *
- * NOTE : process_issue_queue should be called from both
- * NCR53c7x0_queue_command() and from the interrupt handler
- * after command completion in case NCR53c7x0_queue_command()
- * isn't invoked again but we've freed up resources that are
- * needed.
- */
-
-static void
-process_issue_queue (unsigned long flags) {
- Scsi_Cmnd *tmp, *prev;
- struct Scsi_Host *host;
- struct NCR53c7x0_hostdata *hostdata;
- int done;
-
- /*
- * We run (with interrupts disabled) until we're sure that none of
- * the host adapters have anything that can be done, at which point
- * we set process_issue_queue_running to 0 and exit.
- *
- * Interrupts are enabled before doing various other internal
- * instructions, after we've decided that we need to run through
- * the loop again.
- *
- */
-
- do {
- local_irq_disable(); /* Freeze request queues */
- done = 1;
- for (host = first_host; host && host->hostt == the_template;
- host = host->next) {
- hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
- local_irq_disable();
- if (hostdata->issue_queue) {
- if (hostdata->state == STATE_DISABLED) {
- tmp = (Scsi_Cmnd *) hostdata->issue_queue;
- hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
- tmp->result = (DID_BAD_TARGET << 16);
- if (tmp->host_scribble) {
- ((struct NCR53c7x0_cmd *)tmp->host_scribble)->next =
- hostdata->free;
- hostdata->free =
- (struct NCR53c7x0_cmd *)tmp->host_scribble;
- tmp->host_scribble = NULL;
- }
- tmp->scsi_done (tmp);
- done = 0;
- } else
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
- prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *)
- tmp->SCp.ptr)
- if (!tmp->host_scribble ||
- !busyp (host, hostdata, tmp)) {
- if (prev)
- prev->SCp.ptr = tmp->SCp.ptr;
- else
- hostdata->issue_queue = (Scsi_Cmnd *)
- tmp->SCp.ptr;
- tmp->SCp.ptr = NULL;
- if (tmp->host_scribble) {
- if (hostdata->options & OPTION_DEBUG_QUEUES)
- printk ("scsi%d : moving command for target %d lun %d to start list\n",
- host->host_no, tmp->device->id, tmp->device->lun);
-
-
- to_schedule_list (host, hostdata,
- (struct NCR53c7x0_cmd *)
- tmp->host_scribble);
- } else {
- if (((tmp->result & 0xff) == 0xff) ||
- ((tmp->result & 0xff00) == 0xff00)) {
- printk ("scsi%d : danger Will Robinson!\n",
- host->host_no);
- tmp->result = DID_ERROR << 16;
- disable (host);
- }
- tmp->scsi_done(tmp);
- }
- done = 0;
- } /* if target/lun is not busy */
- } /* if hostdata->issue_queue */
- if (!done)
- local_irq_restore(flags);
- } /* for host */
- } while (!done);
- process_issue_queue_running = 0;
-}
-
-/*
- * Function : static void intr_scsi (struct Scsi_Host *host,
- * struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : handle all SCSI interrupts, indicated by the setting
- * of the SIP bit in the ISTAT register.
- *
- * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
- * may be NULL.
- */
-
-static void
-intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) host->hostdata[0];
- unsigned char sstat0_sist0, sist1, /* Registers */
- fatal; /* Did a fatal interrupt
- occur ? */
-
- NCR53c7x0_local_setup(host);
-
- fatal = 0;
-
- sstat0_sist0 = NCR53c7x0_read8(SSTAT0_REG);
- sist1 = 0;
-
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : SIST0 0x%0x, SIST1 0x%0x\n", host->host_no,
- sstat0_sist0, sist1);
-
- /* 250ms selection timeout */
- if (sstat0_sist0 & SSTAT0_700_STO) {
- fatal = 1;
- if (hostdata->options & OPTION_DEBUG_INTR) {
- printk ("scsi%d : Selection Timeout\n", host->host_no);
- if (cmd) {
- printk("scsi%d : target %d, lun %d, command ",
- host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
- __scsi_print_command (cmd->cmd->cmnd);
- printk("scsi%d : dsp = 0x%x (virt 0x%p)\n", host->host_no,
- NCR53c7x0_read32(DSP_REG),
- bus_to_virt(NCR53c7x0_read32(DSP_REG)));
- } else {
- printk("scsi%d : no command\n", host->host_no);
- }
- }
-/*
- * XXX - question : how do we want to handle the Illegal Instruction
- * interrupt, which may occur before or after the Selection Timeout
- * interrupt?
- */
-
- if (1) {
- hostdata->idle = 1;
- hostdata->expecting_sto = 0;
-
- if (hostdata->test_running) {
- hostdata->test_running = 0;
- hostdata->test_completed = 3;
- } else if (cmd) {
- abnormal_finished(cmd, DID_BAD_TARGET << 16);
- }
-#if 0
- hostdata->intrs = 0;
-#endif
- }
- }
-
-/*
- * FIXME : in theory, we can also get a UDC when a STO occurs.
- */
- if (sstat0_sist0 & SSTAT0_UDC) {
- fatal = 1;
- if (cmd) {
- printk("scsi%d : target %d lun %d unexpected disconnect\n",
- host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
- print_lots (host);
- abnormal_finished(cmd, DID_ERROR << 16);
- } else
- printk("scsi%d : unexpected disconnect (no command)\n",
- host->host_no);
-
- hostdata->dsp = (u32 *) hostdata->schedule;
- hostdata->dsp_changed = 1;
- }
-
- /* SCSI PARITY error */
- if (sstat0_sist0 & SSTAT0_PAR) {
- fatal = 1;
- if (cmd && cmd->cmd) {
- printk("scsi%d : target %d lun %d parity error.\n",
- host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
- abnormal_finished (cmd, DID_PARITY << 16);
- } else
- printk("scsi%d : parity error\n", host->host_no);
- /* Should send message out, parity error */
-
- /* XXX - Reduce synchronous transfer rate! */
- hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- /* SCSI GROSS error */
- }
-
- if (sstat0_sist0 & SSTAT0_SGE) {
- fatal = 1;
- printk("scsi%d : gross error, saved2_dsa = 0x%x\n", host->host_no,
- (unsigned int)hostdata->saved2_dsa);
- print_lots (host);
-
- /*
- * A SCSI gross error may occur when we have
- *
- * - A synchronous offset which causes the SCSI FIFO to be overwritten.
- *
- * - A REQ which causes the maximum synchronous offset programmed in
- * the SXFER register to be exceeded.
- *
- * - A phase change with an outstanding synchronous offset.
- *
- * - Residual data in the synchronous data FIFO, with a transfer
- * other than a synchronous receive is started.$#
- */
-
-
- /* XXX Should deduce synchronous transfer rate! */
- hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- /* Phase mismatch */
- }
-
- if (sstat0_sist0 & SSTAT0_MA) {
- fatal = 1;
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : SSTAT0_MA\n", host->host_no);
- intr_phase_mismatch (host, cmd);
- }
-
-#if 0
- if (sstat0_sist0 & SIST0_800_RSL)
- printk ("scsi%d : Oh no Mr. Bill!\n", host->host_no);
-#endif
-
-/*
- * If a fatal SCSI interrupt occurs, we must insure that the DMA and
- * SCSI FIFOs were flushed.
- */
-
- if (fatal) {
- if (!hostdata->dstat_valid) {
- hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
- hostdata->dstat_valid = 1;
- }
-
- if (!(hostdata->dstat & DSTAT_DFE)) {
- printk ("scsi%d : DMA FIFO not empty\n", host->host_no);
- /*
- * Really need to check this code for 710 RGH.
- * Havn't seen any problems, but maybe we should FLUSH before
- * clearing sometimes.
- */
- NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
- while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF)
- ;
- hostdata->dstat |= DSTAT_DFE;
- }
- }
-}
-
-#ifdef CYCLIC_TRACE
-
-/*
- * The following implements a cyclic log of instructions executed, if you turn
- * TRACE on. It will also print the log for you. Very useful when debugging
- * 53c710 support, possibly not really needed any more.
- */
-
-u32 insn_log[4096];
-u32 insn_log_index = 0;
-
-void log1 (u32 i)
-{
- insn_log[insn_log_index++] = i;
- if (insn_log_index == 4096)
- insn_log_index = 0;
-}
-
-void log_insn (u32 *ip)
-{
- log1 ((u32)ip);
- log1 (*ip);
- log1 (*(ip+1));
- if (((*ip >> 24) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)
- log1 (*(ip+2));
-}
-
-void dump_log(void)
-{
- int cnt = 0;
- int i = insn_log_index;
- int size;
- struct Scsi_Host *host = first_host;
-
- while (cnt < 4096) {
- printk ("%08x (+%6x): ", insn_log[i], (insn_log[i] - (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata[0])->script))/4);
- if (++i == 4096)
- i = 0;
- cnt++;
- if (((insn_log[i] >> 24) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)
- size = 3;
- else
- size = 2;
- while (size--) {
- printk ("%08x ", insn_log[i]);
- if (++i == 4096)
- i = 0;
- cnt++;
- }
- printk ("\n");
- }
-}
-#endif
-
-
-/*
- * Function : static void NCR53c7x0_intfly (struct Scsi_Host *host)
- *
- * Purpose : Scan command queue for specified host, looking for completed
- * commands.
- *
- * Inputs : Scsi_Host pointer.
- *
- * This is called from the interrupt handler, when a simulated INTFLY
- * interrupt occurs.
- */
-
-static void
-NCR53c7x0_intfly (struct Scsi_Host *host)
-{
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata; /* host->hostdata[0] */
- struct NCR53c7x0_cmd *cmd, /* command which halted */
- **cmd_prev_ptr;
- unsigned long flags;
- char search_found = 0; /* Got at least one ? */
-
- hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
- NCR53c7x0_local_setup(host);
-
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : INTFLY\n", host->host_no);
-
- /*
- * Traverse our list of running commands, and look
- * for those with valid (non-0xff ff) status and message
- * bytes encoded in the result which signify command
- * completion.
- */
-
- local_irq_save(flags);
-restart:
- for (cmd_prev_ptr = (struct NCR53c7x0_cmd **)&(hostdata->running_list),
- cmd = (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
- cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next),
- cmd = (struct NCR53c7x0_cmd *) cmd->next)
- {
- Scsi_Cmnd *tmp;
-
- if (!cmd) {
- printk("scsi%d : very weird.\n", host->host_no);
- break;
- }
-
- if (!(tmp = cmd->cmd)) {
- printk("scsi%d : weird. NCR53c7x0_cmd has no Scsi_Cmnd\n",
- host->host_no);
- continue;
- }
- /* Copy the result over now; may not be complete,
- * but subsequent tests may as well be done on
- * cached memory.
- */
- tmp->result = cmd->result;
-
- if (((tmp->result & 0xff) == 0xff) ||
- ((tmp->result & 0xff00) == 0xff00))
- continue;
-
- search_found = 1;
-
- if (cmd->bounce.len)
- memcpy ((void *)cmd->bounce.addr,
- (void *)cmd->bounce.buf, cmd->bounce.len);
-
- /* Important - remove from list _before_ done is called */
- if (cmd_prev_ptr)
- *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next;
-
- --hostdata->busy[tmp->device->id][tmp->device->lun];
- cmd->next = hostdata->free;
- hostdata->free = cmd;
-
- tmp->host_scribble = NULL;
-
- if (hostdata->options & OPTION_DEBUG_INTR) {
- printk ("scsi%d : command complete : pid %lu, id %d,lun %d result 0x%x ",
- host->host_no, tmp->pid, tmp->device->id, tmp->device->lun, tmp->result);
- __scsi_print_command (tmp->cmnd);
- }
-
- tmp->scsi_done(tmp);
- goto restart;
- }
- local_irq_restore(flags);
-
- if (!search_found) {
- printk ("scsi%d : WARNING : INTFLY with no completed commands.\n",
- host->host_no);
- } else {
- run_process_issue_queue();
- }
- return;
-}
-
-/*
- * Function : static irqreturn_t NCR53c7x0_intr (int irq, void *dev_id)
- *
- * Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
- * the same IRQ line.
- *
- * Inputs : Since we're using the IRQF_DISABLED interrupt handler
- * semantics, irq indicates the interrupt which invoked
- * this handler.
- *
- * On the 710 we simualte an INTFLY with a script interrupt, and the
- * script interrupt handler will call back to this function.
- */
-
-static irqreturn_t
-NCR53c7x0_intr (int irq, void *dev_id)
-{
- NCR53c7x0_local_declare();
- struct Scsi_Host *host; /* Host we are looking at */
- unsigned char istat; /* Values of interrupt regs */
- struct NCR53c7x0_hostdata *hostdata; /* host->hostdata[0] */
- struct NCR53c7x0_cmd *cmd; /* command which halted */
- u32 *dsa; /* DSA */
- int handled = 0;
-
-#ifdef NCR_DEBUG
- char buf[80]; /* Debugging sprintf buffer */
- size_t buflen; /* Length of same */
-#endif
-
- host = (struct Scsi_Host *)dev_id;
- hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
- NCR53c7x0_local_setup(host);
-
- /*
- * Only read istat once per loop, since reading it again will unstack
- * interrupts
- */
-
- while ((istat = NCR53c7x0_read8(hostdata->istat)) & (ISTAT_SIP|ISTAT_DIP)) {
- handled = 1;
- hostdata->dsp_changed = 0;
- hostdata->dstat_valid = 0;
- hostdata->state = STATE_HALTED;
-
- if (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK)
- printk ("scsi%d : SCSI FIFO not empty\n", host->host_no);
-
- /*
- * NCR53c700 and NCR53c700-66 change the current SCSI
- * process, hostdata->ncrcurrent, in the Linux driver so
- * cmd = hostdata->ncrcurrent.
- *
- * With other chips, we must look through the commands
- * executing and find the command structure which
- * corresponds to the DSA register.
- */
-
- if (hostdata->options & OPTION_700) {
- cmd = (struct NCR53c7x0_cmd *) hostdata->ncrcurrent;
- } else {
- dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
- for (cmd = (struct NCR53c7x0_cmd *) hostdata->running_list;
- cmd && (dsa + (hostdata->dsa_start / sizeof(u32))) != cmd->dsa;
- cmd = (struct NCR53c7x0_cmd *)(cmd->next))
- ;
- }
- if (hostdata->options & OPTION_DEBUG_INTR) {
- if (cmd) {
- printk("scsi%d : interrupt for pid %lu, id %d, lun %d ",
- host->host_no, cmd->cmd->pid, (int) cmd->cmd->device->id,
- (int) cmd->cmd->device->lun);
- __scsi_print_command (cmd->cmd->cmnd);
- } else {
- printk("scsi%d : no active command\n", host->host_no);
- }
- }
-
- if (istat & ISTAT_SIP) {
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : ISTAT_SIP\n", host->host_no);
- intr_scsi (host, cmd);
- }
-
- if (istat & ISTAT_DIP) {
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : ISTAT_DIP\n", host->host_no);
- intr_dma (host, cmd);
- }
-
- if (!hostdata->dstat_valid) {
- hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
- hostdata->dstat_valid = 1;
- }
-
- if (!(hostdata->dstat & DSTAT_DFE)) {
- printk ("scsi%d : DMA FIFO not empty\n", host->host_no);
- /* Really need to check this out for 710 RGH */
- NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
- while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF)
- ;
- hostdata->dstat |= DSTAT_DFE;
- }
-
- if (!hostdata->idle && hostdata->state == STATE_HALTED) {
- if (!hostdata->dsp_changed)
- hostdata->dsp = (u32 *)bus_to_virt(NCR53c7x0_read32(DSP_REG));
-#if 0
- printk("scsi%d : new dsp is 0x%lx (virt 0x%p)\n",
- host->host_no, virt_to_bus(hostdata->dsp), hostdata->dsp);
-#endif
-
- hostdata->state = STATE_RUNNING;
- NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp));
- if (hostdata->options & OPTION_DEBUG_TRACE) {
-#ifdef CYCLIC_TRACE
- log_insn (hostdata->dsp);
-#else
- print_insn (host, hostdata->dsp, "t ", 1);
-#endif
- NCR53c7x0_write8 (DCNTL_REG,
- hostdata->saved_dcntl | DCNTL_SSM | DCNTL_STD);
- }
- }
- }
- return IRQ_HANDLED;
-}
-
-
-/*
- * Function : static int abort_connected (struct Scsi_Host *host)
- *
- * Purpose : Assuming that the NCR SCSI processor is currently
- * halted, break the currently established nexus. Clean
- * up of the NCR53c7x0_cmd and Scsi_Cmnd structures should
- * be done on receipt of the abort interrupt.
- *
- * Inputs : host - SCSI host
- *
- */
-
-static int
-abort_connected (struct Scsi_Host *host) {
-#ifdef NEW_ABORT
- NCR53c7x0_local_declare();
-#endif
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
-/* FIXME : this probably should change for production kernels; at the
- least, counter should move to a per-host structure. */
- static int counter = 5;
-#ifdef NEW_ABORT
- int sstat, phase, offset;
- u32 *script;
- NCR53c7x0_local_setup(host);
-#endif
-
- if (--counter <= 0) {
- disable(host);
- return 0;
- }
-
- printk ("scsi%d : DANGER : abort_connected() called \n",
- host->host_no);
-
-#ifdef NEW_ABORT
-
-/*
- * New strategy : Rather than using a generic abort routine,
- * we'll specifically try to source or sink the appropriate
- * amount of data for the phase we're currently in (taking into
- * account the current synchronous offset)
- */
-
- sstat = NCR53c8x0_read8 (SSTAT2_REG);
- offset = OFFSET (sstat & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
- phase = sstat & SSTAT2_PHASE_MASK;
-
-/*
- * SET ATN
- * MOVE source_or_sink, WHEN CURRENT PHASE
- * < repeat for each outstanding byte >
- * JUMP send_abort_message
- */
-
- script = hostdata->abort_script = kmalloc (
- 8 /* instruction size */ * (
- 1 /* set ATN */ +
- (!offset ? 1 : offset) /* One transfer per outstanding byte */ +
- 1 /* send abort message */),
- GFP_ATOMIC);
-
-
-#else /* def NEW_ABORT */
- hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
- sizeof(u32);
-#endif /* def NEW_ABORT */
- hostdata->dsp_changed = 1;
-
-/* XXX - need to flag the command as aborted after the abort_connected
- code runs
- */
- return 0;
-}
-
-/*
- * Function : static int datapath_residual (Scsi_Host *host)
- *
- * Purpose : return residual data count of what's in the chip.
- *
- * Inputs : host - SCSI host
- */
-
-static int
-datapath_residual (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- int count, synchronous, sstat;
- unsigned int ddir;
-
- NCR53c7x0_local_setup(host);
- /* COMPAT : the 700 and 700-66 need to use DFIFO_00_BO_MASK */
- count = ((NCR53c7x0_read8 (DFIFO_REG) & DFIFO_10_BO_MASK) -
- (NCR53c7x0_read32 (DBC_REG) & DFIFO_10_BO_MASK)) & DFIFO_10_BO_MASK;
- synchronous = NCR53c7x0_read8 (SXFER_REG) & SXFER_MO_MASK;
- /* COMPAT : DDIR is elsewhere on non-'8xx chips. */
- ddir = NCR53c7x0_read8 (CTEST0_REG_700) & CTEST0_700_DDIR;
-
- if (ddir) {
- /* Receive */
- if (synchronous)
- count += (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
- else
- if (NCR53c7x0_read8 (SSTAT1_REG) & SSTAT1_ILF)
- ++count;
- } else {
- /* Send */
- sstat = NCR53c7x0_read8 (SSTAT1_REG);
- if (sstat & SSTAT1_OLF)
- ++count;
- if (synchronous && (sstat & SSTAT1_ORF))
- ++count;
- }
- return count;
-}
-
-/*
- * Function : static const char * sbcl_to_phase (int sbcl)_
- *
- * Purpose : Convert SBCL register to user-parsable phase representation
- *
- * Inputs : sbcl - value of sbcl register
- */
-
-
-static const char *
-sbcl_to_phase (int sbcl) {
- switch (sbcl & SBCL_PHASE_MASK) {
- case SBCL_PHASE_DATAIN:
- return "DATAIN";
- case SBCL_PHASE_DATAOUT:
- return "DATAOUT";
- case SBCL_PHASE_MSGIN:
- return "MSGIN";
- case SBCL_PHASE_MSGOUT:
- return "MSGOUT";
- case SBCL_PHASE_CMDOUT:
- return "CMDOUT";
- case SBCL_PHASE_STATIN:
- return "STATUSIN";
- default:
- return "unknown";
- }
-}
-
-/*
- * Function : static const char * sstat2_to_phase (int sstat)_
- *
- * Purpose : Convert SSTAT2 register to user-parsable phase representation
- *
- * Inputs : sstat - value of sstat register
- */
-
-
-static const char *
-sstat2_to_phase (int sstat) {
- switch (sstat & SSTAT2_PHASE_MASK) {
- case SSTAT2_PHASE_DATAIN:
- return "DATAIN";
- case SSTAT2_PHASE_DATAOUT:
- return "DATAOUT";
- case SSTAT2_PHASE_MSGIN:
- return "MSGIN";
- case SSTAT2_PHASE_MSGOUT:
- return "MSGOUT";
- case SSTAT2_PHASE_CMDOUT:
- return "CMDOUT";
- case SSTAT2_PHASE_STATIN:
- return "STATUSIN";
- default:
- return "unknown";
- }
-}
-
-/*
- * Function : static void intr_phase_mismatch (struct Scsi_Host *host,
- * struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : Handle phase mismatch interrupts
- *
- * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
- * may be NULL.
- *
- * Side effects : The abort_connected() routine is called or the NCR chip
- * is restarted, jumping to the command_complete entry point, or
- * patching the address and transfer count of the current instruction
- * and calling the msg_in entry point as appropriate.
- */
-
-static void
-intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- u32 dbc_dcmd, *dsp, *dsp_next;
- unsigned char dcmd, sbcl;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- int residual;
- enum {ACTION_ABORT, ACTION_ABORT_PRINT, ACTION_CONTINUE} action =
- ACTION_ABORT_PRINT;
- const char *where = NULL;
-
- NCR53c7x0_local_setup(host);
-
- /*
- * Corrective action is based on where in the SCSI SCRIPT(tm) the error
- * occurred, as well as which SCSI phase we are currently in.
- */
- dsp_next = bus_to_virt(NCR53c7x0_read32(DSP_REG));
-
- /*
- * Fetch the current instruction, and remove the operands for easier
- * interpretation.
- */
- dbc_dcmd = NCR53c7x0_read32(DBC_REG);
- dcmd = (dbc_dcmd & 0xff000000) >> 24;
- /*
- * Like other processors, the NCR adjusts the instruction pointer before
- * instruction decode. Set the DSP address back to what it should
- * be for this instruction based on its size (2 or 3 32 bit words).
- */
- dsp = dsp_next - NCR53c7x0_insn_size(dcmd);
-
-
- /*
- * Read new SCSI phase from the SBCL lines. Since all of our code uses
- * a WHEN conditional instead of an IF conditional, we don't need to
- * wait for a new REQ.
- */
- sbcl = NCR53c7x0_read8(SBCL_REG) & SBCL_PHASE_MASK;
-
- if (!cmd) {
- action = ACTION_ABORT_PRINT;
- where = "no current command";
- /*
- * The way my SCSI SCRIPTS(tm) are architected, recoverable phase
- * mismatches should only occur where we're doing a multi-byte
- * BMI instruction. Specifically, this means
- *
- * - select messages (a SCSI-I target may ignore additional messages
- * after the IDENTIFY; any target may reject a SDTR or WDTR)
- *
- * - command out (targets may send a message to signal an error
- * condition, or go into STATUSIN after they've decided
- * they don't like the command.
- *
- * - reply_message (targets may reject a multi-byte message in the
- * middle)
- *
- * - data transfer routines (command completion with buffer space
- * left, disconnect message, or error message)
- */
- } else if (((dsp >= cmd->data_transfer_start &&
- dsp < cmd->data_transfer_end)) || dsp == (cmd->residual + 2)) {
- if ((dcmd & (DCMD_TYPE_MASK|DCMD_BMI_OP_MASK|DCMD_BMI_INDIRECT|
- DCMD_BMI_MSG|DCMD_BMI_CD)) == (DCMD_TYPE_BMI|
- DCMD_BMI_OP_MOVE_I)) {
- residual = datapath_residual (host);
- if (hostdata->options & OPTION_DEBUG_DISCONNECT)
- printk ("scsi%d : handling residual transfer (+ %d bytes from DMA FIFO)\n",
- host->host_no, residual);
-
- /*
- * The first instruction is a CALL to the alternate handler for
- * this data transfer phase, so we can do calls to
- * munge_msg_restart as we would if control were passed
- * from normal dynamic code.
- */
- if (dsp != cmd->residual + 2) {
- cmd->residual[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
- ((dcmd & DCMD_BMI_IO) ? DCMD_TCI_IO : 0)) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd->residual[1] = virt_to_bus(hostdata->script)
- + ((dcmd & DCMD_BMI_IO)
- ? hostdata->E_other_in : hostdata->E_other_out);
- }
-
- /*
- * The second instruction is the a data transfer block
- * move instruction, reflecting the pointer and count at the
- * time of the phase mismatch.
- */
- cmd->residual[2] = dbc_dcmd + residual;
- cmd->residual[3] = NCR53c7x0_read32(DNAD_REG) - residual;
-
- /*
- * The third and final instruction is a jump to the instruction
- * which follows the instruction which had to be 'split'
- */
- if (dsp != cmd->residual + 2) {
- cmd->residual[4] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP)
- << 24) | DBC_TCI_TRUE;
- cmd->residual[5] = virt_to_bus(dsp_next);
- }
-
- /*
- * For the sake of simplicity, transfer control to the
- * conditional CALL at the start of the residual buffer.
- */
- hostdata->dsp = cmd->residual;
- hostdata->dsp_changed = 1;
- action = ACTION_CONTINUE;
- } else {
- where = "non-BMI dynamic DSA code";
- action = ACTION_ABORT_PRINT;
- }
- } else if (dsp == (hostdata->script + hostdata->E_select_msgout / 4 + 2)) {
- /* RGH 290697: Added +2 above, to compensate for the script
- * instruction which disables the selection timer. */
- /* Release ATN */
- NCR53c7x0_write8 (SOCL_REG, 0);
- switch (sbcl) {
- /*
- * Some devices (SQ555 come to mind) grab the IDENTIFY message
- * sent on selection, and decide to go into COMMAND OUT phase
- * rather than accepting the rest of the messages or rejecting
- * them. Handle these devices gracefully.
- */
- case SBCL_PHASE_CMDOUT:
- hostdata->dsp = dsp + 2 /* two _words_ */;
- hostdata->dsp_changed = 1;
- printk ("scsi%d : target %d ignored SDTR and went into COMMAND OUT\n",
- host->host_no, cmd->cmd->device->id);
- cmd->flags &= ~CMD_FLAG_SDTR;
- action = ACTION_CONTINUE;
- break;
- case SBCL_PHASE_MSGIN:
- hostdata->dsp = hostdata->script + hostdata->E_msg_in /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- action = ACTION_CONTINUE;
- break;
- default:
- where="select message out";
- action = ACTION_ABORT_PRINT;
- }
- /*
- * Some SCSI devices will interpret a command as they read the bytes
- * off the SCSI bus, and may decide that the command is Bogus before
- * they've read the entire command off the bus.
- */
- } else if (dsp == hostdata->script + hostdata->E_cmdout_cmdout / sizeof
- (u32)) {
- hostdata->dsp = hostdata->script + hostdata->E_data_transfer /
- sizeof (u32);
- hostdata->dsp_changed = 1;
- action = ACTION_CONTINUE;
- /* FIXME : we need to handle message reject, etc. within msg_respond. */
-#ifdef notyet
- } else if (dsp == hostdata->script + hostdata->E_reply_message) {
- switch (sbcl) {
- /* Any other phase mismatches abort the currently executing command. */
-#endif
- } else {
- where = "unknown location";
- action = ACTION_ABORT_PRINT;
- }
-
- /* Flush DMA FIFO */
- if (!hostdata->dstat_valid) {
- hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
- hostdata->dstat_valid = 1;
- }
- if (!(hostdata->dstat & DSTAT_DFE)) {
- /* Really need to check this out for 710 RGH */
- NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
- while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF);
- hostdata->dstat |= DSTAT_DFE;
- }
-
- switch (action) {
- case ACTION_ABORT_PRINT:
- printk("scsi%d : %s : unexpected phase %s.\n",
- host->host_no, where ? where : "unknown location",
- sbcl_to_phase(sbcl));
- print_lots (host);
- /* Fall through to ACTION_ABORT */
- case ACTION_ABORT:
- abort_connected (host);
- break;
- case ACTION_CONTINUE:
- break;
- }
-
-#if 0
- if (hostdata->dsp_changed) {
- printk("scsi%d: new dsp 0x%p\n", host->host_no, hostdata->dsp);
- print_insn (host, hostdata->dsp, "", 1);
- }
-#endif
-}
-
-/*
- * Function : static void intr_bf (struct Scsi_Host *host,
- * struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : handle BUS FAULT interrupts
- *
- * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
- * may be NULL.
- */
-
-static void
-intr_bf (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- u32 *dsp,
- *next_dsp, /* Current dsp */
- *dsa,
- dbc_dcmd; /* DCMD (high eight bits) + DBC */
- char *reason = NULL;
- /* Default behavior is for a silent error, with a retry until we've
- exhausted retries. */
- enum {MAYBE, ALWAYS, NEVER} retry = MAYBE;
- int report = 0;
- NCR53c7x0_local_setup(host);
-
- dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
- next_dsp = bus_to_virt (NCR53c7x0_read32(DSP_REG));
- dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
-/* FIXME - check chip type */
- dsa = bus_to_virt (NCR53c7x0_read32(DSA_REG));
-
- /*
- * Bus faults can be caused by either a Bad Address or
- * Target Abort. We should check the Received Target Abort
- * bit of the PCI status register and Master Abort Bit.
- *
- * - Master Abort bit indicates that no device claimed
- * the address with DEVSEL within five clocks
- *
- * - Target Abort bit indicates that a target claimed it,
- * but changed its mind once it saw the byte enables.
- *
- */
-
- /* 53c710, not PCI system */
- report = 1;
- reason = "Unknown";
-
-#ifndef notyet
- report = 1;
-#endif
- if (report && reason)
- {
- printk(KERN_ALERT "scsi%d : BUS FAULT reason = %s\n",
- host->host_no, reason ? reason : "unknown");
- print_lots (host);
- }
-
-#ifndef notyet
- retry = NEVER;
-#endif
-
- /*
- * TODO : we should attempt to recover from any spurious bus
- * faults. After X retries, we should figure that things are
- * sufficiently wedged, and call NCR53c7xx_reset.
- *
- * This code should only get executed once we've decided that we
- * cannot retry.
- */
-
- if (retry == NEVER) {
- printk(KERN_ALERT " mail richard@sleepie.demon.co.uk\n");
- FATAL (host);
- }
-}
-
-/*
- * Function : static void intr_dma (struct Scsi_Host *host,
- * struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : handle all DMA interrupts, indicated by the setting
- * of the DIP bit in the ISTAT register.
- *
- * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
- * may be NULL.
- */
-
-static void
-intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned char dstat; /* DSTAT */
- u32 *dsp,
- *next_dsp, /* Current dsp */
- *dsa,
- dbc_dcmd; /* DCMD (high eight bits) + DBC */
- int tmp;
- unsigned long flags;
- NCR53c7x0_local_setup(host);
-
- if (!hostdata->dstat_valid) {
- hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
- hostdata->dstat_valid = 1;
- }
-
- dstat = hostdata->dstat;
-
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk("scsi%d : DSTAT=0x%x\n", host->host_no, (int) dstat);
-
- dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
- next_dsp = bus_to_virt(NCR53c7x0_read32(DSP_REG));
- dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
-/* XXX - check chip type */
- dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
-
- /*
- * DSTAT_ABRT is the aborted interrupt. This is set whenever the
- * SCSI chip is aborted.
- *
- * With NCR53c700 and NCR53c700-66 style chips, we should only
- * get this when the chip is currently running the accept
- * reselect/select code and we have set the abort bit in the
- * ISTAT register.
- *
- */
-
- if (dstat & DSTAT_ABRT) {
-#if 0
- /* XXX - add code here to deal with normal abort */
- if ((hostdata->options & OPTION_700) && (hostdata->state ==
- STATE_ABORTING)) {
- } else
-#endif
- {
- printk(KERN_ALERT "scsi%d : unexpected abort interrupt at\n"
- " ", host->host_no);
- print_insn (host, dsp, KERN_ALERT "s ", 1);
- FATAL (host);
- }
- }
-
- /*
- * DSTAT_SSI is the single step interrupt. Should be generated
- * whenever we have single stepped or are tracing.
- */
-
- if (dstat & DSTAT_SSI) {
- if (hostdata->options & OPTION_DEBUG_TRACE) {
- /* Don't print instr. until we write DSP at end of intr function */
- } else if (hostdata->options & OPTION_DEBUG_SINGLE) {
- print_insn (host, dsp, "s ", 0);
- local_irq_save(flags);
-/* XXX - should we do this, or can we get away with writing dsp? */
-
- NCR53c7x0_write8 (DCNTL_REG, (NCR53c7x0_read8(DCNTL_REG) &
- ~DCNTL_SSM) | DCNTL_STD);
- local_irq_restore(flags);
- } else {
- printk(KERN_ALERT "scsi%d : unexpected single step interrupt at\n"
- " ", host->host_no);
- print_insn (host, dsp, KERN_ALERT "", 1);
- printk(KERN_ALERT " mail drew@PoohSticks.ORG\n");
- FATAL (host);
- }
- }
-
- /*
- * DSTAT_IID / DSTAT_OPC (same bit, same meaning, only the name
- * is different) is generated whenever an illegal instruction is
- * encountered.
- *
- * XXX - we may want to emulate INTFLY here, so we can use
- * the same SCSI SCRIPT (tm) for NCR53c710 through NCR53c810
- * chips.
- */
-
- if (dstat & DSTAT_OPC) {
- /*
- * Ascertain if this IID interrupts occurred before or after a STO
- * interrupt. Since the interrupt handling code now leaves
- * DSP unmodified until _after_ all stacked interrupts have been
- * processed, reading the DSP returns the original DSP register.
- * This means that if dsp lies between the select code, and
- * message out following the selection code (where the IID interrupt
- * would have to have occurred by due to the implicit wait for REQ),
- * we have an IID interrupt resulting from a STO condition and
- * can ignore it.
- */
-
- if (((dsp >= (hostdata->script + hostdata->E_select / sizeof(u32))) &&
- (dsp <= (hostdata->script + hostdata->E_select_msgout /
- sizeof(u32) + 8))) || (hostdata->test_running == 2)) {
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : ignoring DSTAT_IID for SSTAT_STO\n",
- host->host_no);
- if (hostdata->expecting_iid) {
- hostdata->expecting_iid = 0;
- hostdata->idle = 1;
- if (hostdata->test_running == 2) {
- hostdata->test_running = 0;
- hostdata->test_completed = 3;
- } else if (cmd)
- abnormal_finished (cmd, DID_BAD_TARGET << 16);
- } else {
- hostdata->expecting_sto = 1;
- }
- /*
- * We can't guarantee we'll be able to execute the WAIT DISCONNECT
- * instruction within the 3.4us of bus free and arbitration delay
- * that a target can RESELECT in and assert REQ after we've dropped
- * ACK. If this happens, we'll get an illegal instruction interrupt.
- * Doing away with the WAIT DISCONNECT instructions broke everything,
- * so instead I'll settle for moving one WAIT DISCONNECT a few
- * instructions closer to the CLEAR ACK before it to minimize the
- * chances of this happening, and handle it if it occurs anyway.
- *
- * Simply continue with what we were doing, and control should
- * be transferred to the schedule routine which will ultimately
- * pass control onto the reselection or selection (not yet)
- * code.
- */
- } else if (dbc_dcmd == 0x48000000 && (NCR53c7x0_read8 (SBCL_REG) &
- SBCL_REQ)) {
- if (!(hostdata->options & OPTION_NO_PRINT_RACE))
- {
- printk("scsi%d: REQ before WAIT DISCONNECT IID\n",
- host->host_no);
- hostdata->options |= OPTION_NO_PRINT_RACE;
- }
- } else {
- printk(KERN_ALERT "scsi%d : invalid instruction\n", host->host_no);
- print_lots (host);
- printk(KERN_ALERT " mail Richard@sleepie.demon.co.uk with ALL\n"
- " boot messages and diagnostic output\n");
- FATAL (host);
- }
- }
-
- /*
- * DSTAT_BF are bus fault errors. DSTAT_800_BF is valid for 710 also.
- */
-
- if (dstat & DSTAT_800_BF) {
- intr_bf (host, cmd);
- }
-
-
- /*
- * DSTAT_SIR interrupts are generated by the execution of
- * the INT instruction. Since the exact values available
- * are determined entirely by the SCSI script running,
- * and are local to a particular script, a unique handler
- * is called for each script.
- */
-
- if (dstat & DSTAT_SIR) {
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : DSTAT_SIR\n", host->host_no);
- switch ((tmp = hostdata->dstat_sir_intr (host, cmd))) {
- case SPECIFIC_INT_NOTHING:
- case SPECIFIC_INT_RESTART:
- break;
- case SPECIFIC_INT_ABORT:
- abort_connected(host);
- break;
- case SPECIFIC_INT_PANIC:
- printk(KERN_ALERT "scsi%d : failure at ", host->host_no);
- print_insn (host, dsp, KERN_ALERT "", 1);
- printk(KERN_ALERT " dstat_sir_intr() returned SPECIFIC_INT_PANIC\n");
- FATAL (host);
- break;
- case SPECIFIC_INT_BREAK:
- intr_break (host, cmd);
- break;
- default:
- printk(KERN_ALERT "scsi%d : failure at ", host->host_no);
- print_insn (host, dsp, KERN_ALERT "", 1);
- printk(KERN_ALERT" dstat_sir_intr() returned unknown value %d\n",
- tmp);
- FATAL (host);
- }
- }
-}
-
-/*
- * Function : static int print_insn (struct Scsi_Host *host,
- * u32 *insn, int kernel)
- *
- * Purpose : print numeric representation of the instruction pointed
- * to by insn to the debugging or kernel message buffer
- * as appropriate.
- *
- * If desired, a user level program can interpret this
- * information.
- *
- * Inputs : host, insn - host, pointer to instruction, prefix -
- * string to prepend, kernel - use printk instead of debugging buffer.
- *
- * Returns : size, in u32s, of instruction printed.
- */
-
-/*
- * FIXME: should change kernel parameter so that it takes an ENUM
- * specifying severity - either KERN_ALERT or KERN_PANIC so
- * all panic messages are output with the same severity.
- */
-
-static int
-print_insn (struct Scsi_Host *host, const u32 *insn,
- const char *prefix, int kernel) {
- char buf[160], /* Temporary buffer and pointer. ICKY
- arbitrary length. */
-
-
- *tmp;
- unsigned char dcmd; /* dcmd register for *insn */
- int size;
-
- /*
- * Check to see if the instruction pointer is not bogus before
- * indirecting through it; avoiding red-zone at start of
- * memory.
- *
- * FIXME: icky magic needs to happen here on non-intel boxes which
- * don't have kernel memory mapped in like this. Might be reasonable
- * to use vverify()?
- */
-
- if (virt_to_phys((void *)insn) < PAGE_SIZE ||
- virt_to_phys((void *)(insn + 8)) > virt_to_phys(high_memory) ||
- ((((dcmd = (insn[0] >> 24) & 0xff) & DCMD_TYPE_MMI) == DCMD_TYPE_MMI) &&
- virt_to_phys((void *)(insn + 12)) > virt_to_phys(high_memory))) {
- size = 0;
- sprintf (buf, "%s%p: address out of range\n",
- prefix, insn);
- } else {
-/*
- * FIXME : (void *) cast in virt_to_bus should be unnecessary, because
- * it should take const void * as argument.
- */
-#if !defined(CONFIG_MVME16x) && !defined(CONFIG_BVME6000)
- sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)",
- (prefix ? prefix : ""), virt_to_bus((void *) insn), insn,
- insn[0], insn[1], bus_to_virt (insn[1]));
-#else
- /* Remove virtual addresses to reduce output, as they are the same */
- sprintf(buf, "%s0x%x (+%x) : 0x%08x 0x%08x",
- (prefix ? prefix : ""), (u32)insn, ((u32)insn -
- (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata[0])->script))/4,
- insn[0], insn[1]);
-#endif
- tmp = buf + strlen(buf);
- if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI) {
-#if !defined(CONFIG_MVME16x) && !defined(CONFIG_BVME6000)
- sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2],
- bus_to_virt(insn[2]));
-#else
- /* Remove virtual addr to reduce output, as it is the same */
- sprintf (tmp, " 0x%08x\n", insn[2]);
-#endif
- size = 3;
- } else {
- sprintf (tmp, "\n");
- size = 2;
- }
- }
-
- if (kernel)
- printk ("%s", buf);
-#ifdef NCR_DEBUG
- else {
- size_t len = strlen(buf);
- debugger_kernel_write(host, buf, len);
- }
-#endif
- return size;
-}
-
-/*
- * Function : int NCR53c7xx_abort (Scsi_Cmnd *cmd)
- *
- * Purpose : Abort an errant SCSI command, doing all necessary
- * cleanup of the issue_queue, running_list, shared Linux/NCR
- * dsa issue and reconnect queues.
- *
- * Inputs : cmd - command to abort, code - entire result field
- *
- * Returns : 0 on success, -1 on failure.
- */
-
-int
-NCR53c7xx_abort (Scsi_Cmnd *cmd) {
- NCR53c7x0_local_declare();
- struct Scsi_Host *host = cmd->device->host;
- struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *)
- host->hostdata[0] : NULL;
- unsigned long flags;
- struct NCR53c7x0_cmd *curr, **prev;
- Scsi_Cmnd *me, **last;
-#if 0
- static long cache_pid = -1;
-#endif
-
-
- if (!host) {
- printk ("Bogus SCSI command pid %ld; no host structure\n",
- cmd->pid);
- return SCSI_ABORT_ERROR;
- } else if (!hostdata) {
- printk ("Bogus SCSI host %d; no hostdata\n", host->host_no);
- return SCSI_ABORT_ERROR;
- }
- NCR53c7x0_local_setup(host);
-
-/*
- * CHECK : I don't think that reading ISTAT will unstack any interrupts,
- * since we need to write the INTF bit to clear it, and SCSI/DMA
- * interrupts don't clear until we read SSTAT/SIST and DSTAT registers.
- *
- * See that this is the case. Appears to be correct on the 710, at least.
- *
- * I suspect that several of our failures may be coming from a new fatal
- * interrupt (possibly due to a phase mismatch) happening after we've left
- * the interrupt handler, but before the PIC has had the interrupt condition
- * cleared.
- */
-
- if (NCR53c7x0_read8(hostdata->istat) & (ISTAT_DIP|ISTAT_SIP)) {
- printk ("scsi%d : dropped interrupt for command %ld\n", host->host_no,
- cmd->pid);
- NCR53c7x0_intr (host->irq, NULL, NULL);
- return SCSI_ABORT_BUSY;
- }
-
- local_irq_save(flags);
-#if 0
- if (cache_pid == cmd->pid)
- panic ("scsi%d : bloody fetus %d\n", host->host_no, cmd->pid);
- else
- cache_pid = cmd->pid;
-#endif
-
-
-/*
- * The command could be hiding in the issue_queue. This would be very
- * nice, as commands can't be moved from the high level driver's issue queue
- * into the shared queue until an interrupt routine is serviced, and this
- * moving is atomic.
- *
- * If this is the case, we don't have to worry about anything - we simply
- * pull the command out of the old queue, and call it aborted.
- */
-
- for (me = (Scsi_Cmnd *) hostdata->issue_queue,
- last = (Scsi_Cmnd **) &(hostdata->issue_queue);
- me && me != cmd; last = (Scsi_Cmnd **)&(me->SCp.ptr),
- me = (Scsi_Cmnd *)me->SCp.ptr);
-
- if (me) {
- *last = (Scsi_Cmnd *) me->SCp.ptr;
- if (me->host_scribble) {
- ((struct NCR53c7x0_cmd *)me->host_scribble)->next = hostdata->free;
- hostdata->free = (struct NCR53c7x0_cmd *) me->host_scribble;
- me->host_scribble = NULL;
- }
- cmd->result = DID_ABORT << 16;
- cmd->scsi_done(cmd);
- printk ("scsi%d : found command %ld in Linux issue queue\n",
- host->host_no, me->pid);
- local_irq_restore(flags);
- run_process_issue_queue();
- return SCSI_ABORT_SUCCESS;
- }
-
-/*
- * That failing, the command could be in our list of already executing
- * commands. If this is the case, drastic measures are called for.
- */
-
- for (curr = (struct NCR53c7x0_cmd *) hostdata->running_list,
- prev = (struct NCR53c7x0_cmd **) &(hostdata->running_list);
- curr && curr->cmd != cmd; prev = (struct NCR53c7x0_cmd **)
- &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
-
- if (curr) {
- if ((curr->result & 0xff) != 0xff && (curr->result & 0xff00) != 0xff00) {
- cmd->result = curr->result;
- if (prev)
- *prev = (struct NCR53c7x0_cmd *) curr->next;
- curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
- cmd->host_scribble = NULL;
- hostdata->free = curr;
- cmd->scsi_done(cmd);
- printk ("scsi%d : found finished command %ld in running list\n",
- host->host_no, cmd->pid);
- local_irq_restore(flags);
- return SCSI_ABORT_NOT_RUNNING;
- } else {
- printk ("scsi%d : DANGER : command running, can not abort.\n",
- cmd->device->host->host_no);
- local_irq_restore(flags);
- return SCSI_ABORT_BUSY;
- }
- }
-
-/*
- * And if we couldn't find it in any of our queues, it must have been
- * a dropped interrupt.
- */
-
- curr = (struct NCR53c7x0_cmd *) cmd->host_scribble;
- if (curr) {
- curr->next = hostdata->free;
- hostdata->free = curr;
- cmd->host_scribble = NULL;
- }
-
- if (curr == NULL || ((curr->result & 0xff00) == 0xff00) ||
- ((curr->result & 0xff) == 0xff)) {
- printk ("scsi%d : did this command ever run?\n", host->host_no);
- cmd->result = DID_ABORT << 16;
- } else {
- printk ("scsi%d : probably lost INTFLY, normal completion\n",
- host->host_no);
- cmd->result = curr->result;
-/*
- * FIXME : We need to add an additional flag which indicates if a
- * command was ever counted as BUSY, so if we end up here we can
- * decrement the busy count if and only if it is necessary.
- */
- --hostdata->busy[cmd->device->id][cmd->device->lun];
- }
- local_irq_restore(flags);
- cmd->scsi_done(cmd);
-
-/*
- * We need to run process_issue_queue since termination of this command
- * may allow another queued command to execute first?
- */
- return SCSI_ABORT_NOT_RUNNING;
-}
-
-/*
- * Function : int NCR53c7xx_reset (Scsi_Cmnd *cmd)
- *
- * Purpose : perform a hard reset of the SCSI bus and NCR
- * chip.
- *
- * Inputs : cmd - command which caused the SCSI RESET
- *
- * Returns : 0 on success.
- */
-
-int
-NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) {
- NCR53c7x0_local_declare();
- unsigned long flags;
- int found = 0;
- struct NCR53c7x0_cmd * c;
- Scsi_Cmnd *tmp;
- /*
- * When we call scsi_done(), it's going to wake up anything sleeping on the
- * resources which were in use by the aborted commands, and we'll start to
- * get new commands.
- *
- * We can't let this happen until after we've re-initialized the driver
- * structures, and can't reinitialize those structures until after we've
- * dealt with their contents.
- *
- * So, we need to find all of the commands which were running, stick
- * them on a linked list of completed commands (we'll use the host_scribble
- * pointer), do our reinitialization, and then call the done function for
- * each command.
- */
- Scsi_Cmnd *nuke_list = NULL;
- struct Scsi_Host *host = cmd->device->host;
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) host->hostdata[0];
-
- NCR53c7x0_local_setup(host);
- local_irq_save(flags);
- ncr_halt (host);
- print_lots (host);
- dump_events (host, 30);
- ncr_scsi_reset (host);
- for (tmp = nuke_list = return_outstanding_commands (host, 1 /* free */,
- 0 /* issue */ ); tmp; tmp = (Scsi_Cmnd *) tmp->SCp.buffer)
- if (tmp == cmd) {
- found = 1;
- break;
- }
-
- /*
- * If we didn't find the command which caused this reset in our running
- * list, then we've lost it. See that it terminates normally anyway.
- */
- if (!found) {
- c = (struct NCR53c7x0_cmd *) cmd->host_scribble;
- if (c) {
- cmd->host_scribble = NULL;
- c->next = hostdata->free;
- hostdata->free = c;
- } else
- printk ("scsi%d: lost command %ld\n", host->host_no, cmd->pid);
- cmd->SCp.buffer = (struct scatterlist *) nuke_list;
- nuke_list = cmd;
- }
-
- NCR53c7x0_driver_init (host);
- hostdata->soft_reset (host);
- if (hostdata->resets == 0)
- disable(host);
- else if (hostdata->resets != -1)
- --hostdata->resets;
- local_irq_restore(flags);
- for (; nuke_list; nuke_list = tmp) {
- tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
- nuke_list->result = DID_RESET << 16;
- nuke_list->scsi_done (nuke_list);
- }
- local_irq_restore(flags);
- return SCSI_RESET_SUCCESS;
-}
-
-/*
- * The NCR SDMS bios follows Annex A of the SCSI-CAM draft, and
- * therefore shares the scsicam_bios_param function.
- */
-
-/*
- * Function : int insn_to_offset (Scsi_Cmnd *cmd, u32 *insn)
- *
- * Purpose : convert instructions stored at NCR pointer into data
- * pointer offset.
- *
- * Inputs : cmd - SCSI command; insn - pointer to instruction. Either current
- * DSP, or saved data pointer.
- *
- * Returns : offset on success, -1 on failure.
- */
-
-
-static int
-insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) cmd->device->host->hostdata[0];
- struct NCR53c7x0_cmd *ncmd =
- (struct NCR53c7x0_cmd *) cmd->host_scribble;
- int offset = 0, buffers;
- struct scatterlist *segment;
- char *ptr;
- int found = 0;
-
-/*
- * With the current code implementation, if the insn is inside dynamically
- * generated code, the data pointer will be the instruction preceding
- * the next transfer segment.
- */
-
- if (!check_address ((unsigned long) ncmd, sizeof (struct NCR53c7x0_cmd)) &&
- ((insn >= ncmd->data_transfer_start &&
- insn < ncmd->data_transfer_end) ||
- (insn >= ncmd->residual &&
- insn < (ncmd->residual +
- sizeof(ncmd->residual))))) {
- ptr = bus_to_virt(insn[3]);
-
- if ((buffers = cmd->use_sg)) {
- for (offset = 0,
- segment = (struct scatterlist *) cmd->request_buffer;
- buffers && !((found = ((ptr >= (char *)page_address(segment->page)+segment->offset) &&
- (ptr < ((char *)page_address(segment->page)+segment->offset+segment->length)))));
- --buffers, offset += segment->length, ++segment)
-#if 0
- printk("scsi%d: comparing 0x%p to 0x%p\n",
- cmd->device->host->host_no, saved, page_address(segment->page+segment->offset));
-#else
- ;
-#endif
- offset += ptr - ((char *)page_address(segment->page)+segment->offset);
- } else {
- found = 1;
- offset = ptr - (char *) (cmd->request_buffer);
- }
- } else if ((insn >= hostdata->script +
- hostdata->E_data_transfer / sizeof(u32)) &&
- (insn <= hostdata->script +
- hostdata->E_end_data_transfer / sizeof(u32))) {
- found = 1;
- offset = 0;
- }
- return found ? offset : -1;
-}
-
-
-
-/*
- * Function : void print_progress (Scsi_Cmnd *cmd)
- *
- * Purpose : print the current location of the saved data pointer
- *
- * Inputs : cmd - command we are interested in
- *
- */
-
-static void
-print_progress (Scsi_Cmnd *cmd) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_cmd *ncmd =
- (struct NCR53c7x0_cmd *) cmd->host_scribble;
- int offset, i;
- char *where;
- u32 *ptr;
- NCR53c7x0_local_setup (cmd->device->host);
-
- if (check_address ((unsigned long) ncmd,sizeof (struct NCR53c7x0_cmd)) == 0)
- {
- printk("\nNCR53c7x0_cmd fields:\n");
- printk(" bounce.len=0x%x, addr=0x%0x, buf[]=0x%02x %02x %02x %02x\n",
- ncmd->bounce.len, ncmd->bounce.addr, ncmd->bounce.buf[0],
- ncmd->bounce.buf[1], ncmd->bounce.buf[2], ncmd->bounce.buf[3]);
- printk(" result=%04x, cdb[0]=0x%02x\n", ncmd->result, ncmd->cmnd[0]);
- }
-
- for (i = 0; i < 2; ++i) {
- if (check_address ((unsigned long) ncmd,
- sizeof (struct NCR53c7x0_cmd)) == -1)
- continue;
- if (!i) {
- where = "saved";
- ptr = bus_to_virt(ncmd->saved_data_pointer);
- } else {
- where = "active";
- ptr = bus_to_virt (NCR53c7x0_read32 (DSP_REG) -
- NCR53c7x0_insn_size (NCR53c7x0_read8 (DCMD_REG)) *
- sizeof(u32));
- }
- offset = insn_to_offset (cmd, ptr);
-
- if (offset != -1)
- printk ("scsi%d : %s data pointer at offset %d\n",
- cmd->device->host->host_no, where, offset);
- else {
- int size;
- printk ("scsi%d : can't determine %s data pointer offset\n",
- cmd->device->host->host_no, where);
- if (ncmd) {
- size = print_insn (cmd->device->host,
- bus_to_virt(ncmd->saved_data_pointer), "", 1);
- print_insn (cmd->device->host,
- bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
- "", 1);
- }
- }
- }
-}
-
-
-static void
-print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- int i, len;
- char *ptr;
- Scsi_Cmnd *cmd;
-
- if (check_address ((unsigned long) dsa, hostdata->dsa_end -
- hostdata->dsa_start) == -1) {
- printk("scsi%d : bad dsa virt 0x%p\n", host->host_no, dsa);
- return;
- }
- printk("%sscsi%d : dsa at phys 0x%lx (virt 0x%p)\n"
- " + %d : dsa_msgout length = %u, data = 0x%x (virt 0x%p)\n" ,
- prefix ? prefix : "",
- host->host_no, virt_to_bus (dsa), dsa, hostdata->dsa_msgout,
- dsa[hostdata->dsa_msgout / sizeof(u32)],
- dsa[hostdata->dsa_msgout / sizeof(u32) + 1],
- bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
-
- /*
- * Only print messages if they're sane in length so we don't
- * blow the kernel printk buffer on something which won't buy us
- * anything.
- */
-
- if (dsa[hostdata->dsa_msgout / sizeof(u32)] <
- sizeof (hostdata->free->select))
- for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
- ptr = bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]);
- i > 0 && !check_address ((unsigned long) ptr, 1);
- ptr += len, i -= len) {
- printk(" ");
- len = spi_print_msg(ptr);
- printk("\n");
- if (!len)
- break;
- }
-
- printk(" + %d : select_indirect = 0x%x\n",
- hostdata->dsa_select, dsa[hostdata->dsa_select / sizeof(u32)]);
- cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
- printk(" + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
- (u32) virt_to_bus(cmd));
- /* XXX Maybe we should access cmd->host_scribble->result here. RGH */
- if (cmd) {
- printk(" result = 0x%x, target = %d, lun = %d, cmd = ",
- cmd->result, cmd->device->id, cmd->device->lun);
- __scsi_print_command(cmd->cmnd);
- } else
- printk("\n");
- printk(" + %d : dsa_next = 0x%x\n", hostdata->dsa_next,
- dsa[hostdata->dsa_next / sizeof(u32)]);
- if (cmd) {
- printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
- " script : ",
- host->host_no, cmd->device->id,
- hostdata->sync[cmd->device->id].sxfer_sanity,
- hostdata->sync[cmd->device->id].scntl3_sanity);
- for (i = 0; i < (sizeof(hostdata->sync[cmd->device->id].script) / 4); ++i)
- printk ("0x%x ", hostdata->sync[cmd->device->id].script[i]);
- printk ("\n");
- print_progress (cmd);
- }
-}
-/*
- * Function : void print_queues (Scsi_Host *host)
- *
- * Purpose : print the contents of the NCR issue and reconnect queues
- *
- * Inputs : host - SCSI host we are interested in
- *
- */
-
-static void
-print_queues (struct Scsi_Host *host) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- u32 *dsa, *next_dsa;
- volatile u32 *ncrcurrent;
- int left;
- Scsi_Cmnd *cmd, *next_cmd;
- unsigned long flags;
-
- printk ("scsi%d : issue queue\n", host->host_no);
-
- for (left = host->can_queue, cmd = (Scsi_Cmnd *) hostdata->issue_queue;
- left >= 0 && cmd;
- cmd = next_cmd) {
- next_cmd = (Scsi_Cmnd *) cmd->SCp.ptr;
- local_irq_save(flags);
- if (cmd->host_scribble) {
- if (check_address ((unsigned long) (cmd->host_scribble),
- sizeof (cmd->host_scribble)) == -1)
- printk ("scsi%d: scsi pid %ld bad pointer to NCR53c7x0_cmd\n",
- host->host_no, cmd->pid);
- /* print_dsa does sanity check on address, no need to check */
- else
- print_dsa (host, ((struct NCR53c7x0_cmd *) cmd->host_scribble)
- -> dsa, "");
- } else
- printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
- host->host_no, cmd->pid, cmd->device->id, cmd->device->lun);
- local_irq_restore(flags);
- }
-
- if (left <= 0) {
- printk ("scsi%d : loop detected in issue queue\n",
- host->host_no);
- }
-
- /*
- * Traverse the NCR reconnect and start DSA structures, printing out
- * each element until we hit the end or detect a loop. Currently,
- * the reconnect structure is a linked list; and the start structure
- * is an array. Eventually, the reconnect structure will become a
- * list as well, since this simplifies the code.
- */
-
- printk ("scsi%d : schedule dsa array :\n", host->host_no);
- for (left = host->can_queue, ncrcurrent = hostdata->schedule;
- left > 0; ncrcurrent += 2, --left)
- if (ncrcurrent[0] != hostdata->NOP_insn)
-/* FIXME : convert pointer to dsa_begin to pointer to dsa. */
- print_dsa (host, bus_to_virt (ncrcurrent[1] -
- (hostdata->E_dsa_code_begin -
- hostdata->E_dsa_code_template)), "");
- printk ("scsi%d : end schedule dsa array\n", host->host_no);
-
- printk ("scsi%d : reconnect_dsa_head :\n", host->host_no);
-
- for (left = host->can_queue,
- dsa = bus_to_virt (hostdata->reconnect_dsa_head);
- left >= 0 && dsa;
- dsa = next_dsa) {
- local_irq_save(flags);
- if (check_address ((unsigned long) dsa, sizeof(dsa)) == -1) {
- printk ("scsi%d: bad DSA pointer 0x%p", host->host_no,
- dsa);
- next_dsa = NULL;
- }
- else
- {
- next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
- print_dsa (host, dsa, "");
- }
- local_irq_restore(flags);
- }
- printk ("scsi%d : end reconnect_dsa_head\n", host->host_no);
- if (left < 0)
- printk("scsi%d: possible loop in ncr reconnect list\n",
- host->host_no);
-}
-
-static void
-print_lots (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) host->hostdata[0];
- u32 *dsp_next, *dsp, *dsa, dbc_dcmd;
- unsigned char dcmd, sbcl;
- int i, size;
- NCR53c7x0_local_setup(host);
-
- if ((dsp_next = bus_to_virt(NCR53c7x0_read32 (DSP_REG)))) {
- dbc_dcmd = NCR53c7x0_read32(DBC_REG);
- dcmd = (dbc_dcmd & 0xff000000) >> 24;
- dsp = dsp_next - NCR53c7x0_insn_size(dcmd);
- dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
- sbcl = NCR53c7x0_read8 (SBCL_REG);
-
- /*
- * For the 53c710, the following will report value 0 for SCNTL3
- * and STEST0 - we don't have these registers.
- */
- printk ("scsi%d : DCMD|DBC=0x%x, DNAD=0x%x (virt 0x%p)\n"
- " DSA=0x%lx (virt 0x%p)\n"
- " DSPS=0x%x, TEMP=0x%x (virt 0x%p), DMODE=0x%x\n"
- " SXFER=0x%x, SCNTL3=0x%x\n"
- " %s%s%sphase=%s, %d bytes in SCSI FIFO\n"
- " SCRATCH=0x%x, saved2_dsa=0x%0lx\n",
- host->host_no, dbc_dcmd, NCR53c7x0_read32(DNAD_REG),
- bus_to_virt(NCR53c7x0_read32(DNAD_REG)),
- virt_to_bus(dsa), dsa,
- NCR53c7x0_read32(DSPS_REG), NCR53c7x0_read32(TEMP_REG),
- bus_to_virt (NCR53c7x0_read32(TEMP_REG)),
- (int) NCR53c7x0_read8(hostdata->dmode),
- (int) NCR53c7x0_read8(SXFER_REG),
- ((hostdata->chip / 100) == 8) ?
- (int) NCR53c7x0_read8(SCNTL3_REG_800) : 0,
- (sbcl & SBCL_BSY) ? "BSY " : "",
- (sbcl & SBCL_SEL) ? "SEL " : "",
- (sbcl & SBCL_REQ) ? "REQ " : "",
- sstat2_to_phase(NCR53c7x0_read8 (((hostdata->chip / 100) == 8) ?
- SSTAT1_REG : SSTAT2_REG)),
- (NCR53c7x0_read8 ((hostdata->chip / 100) == 8 ?
- SSTAT1_REG : SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT,
- ((hostdata->chip / 100) == 8) ? NCR53c7x0_read8 (STEST0_REG_800) :
- NCR53c7x0_read32(SCRATCHA_REG_800),
- hostdata->saved2_dsa);
- printk ("scsi%d : DSP 0x%lx (virt 0x%p) ->\n", host->host_no,
- virt_to_bus(dsp), dsp);
- for (i = 6; i > 0; --i, dsp += size)
- size = print_insn (host, dsp, "", 1);
- if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
- if ((hostdata->chip / 100) == 8)
- printk ("scsi%d : connected (SDID=0x%x, SSID=0x%x)\n",
- host->host_no, NCR53c7x0_read8 (SDID_REG_800),
- NCR53c7x0_read8 (SSID_REG_800));
- else
- printk ("scsi%d : connected (SDID=0x%x)\n",
- host->host_no, NCR53c7x0_read8 (SDID_REG_700));
- print_dsa (host, dsa, "");
- }
-
-#if 1
- print_queues (host);
-#endif
- }
-}
-
-/*
- * Function : static int shutdown (struct Scsi_Host *host)
- *
- * Purpose : does a clean (we hope) shutdown of the NCR SCSI
- * chip. Use prior to dumping core, unloading the NCR driver,
- *
- * Returns : 0 on success
- */
-static int
-shutdown (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- unsigned long flags;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- NCR53c7x0_local_setup(host);
- local_irq_save(flags);
-/* Get in a state where we can reset the SCSI bus */
- ncr_halt (host);
- ncr_scsi_reset (host);
- hostdata->soft_reset(host);
-
- disable (host);
- local_irq_restore(flags);
- return 0;
-}
-
-/*
- * Function : void ncr_scsi_reset (struct Scsi_Host *host)
- *
- * Purpose : reset the SCSI bus.
- */
-
-static void
-ncr_scsi_reset (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- unsigned long flags;
- NCR53c7x0_local_setup(host);
- local_irq_save(flags);
- NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
- udelay(25); /* Minimum amount of time to assert RST */
- NCR53c7x0_write8(SCNTL1_REG, 0);
- local_irq_restore(flags);
-}
-
-/*
- * Function : void hard_reset (struct Scsi_Host *host)
- *
- */
-
-static void
-hard_reset (struct Scsi_Host *host) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned long flags;
- local_irq_save(flags);
- ncr_scsi_reset(host);
- NCR53c7x0_driver_init (host);
- if (hostdata->soft_reset)
- hostdata->soft_reset (host);
- local_irq_restore(flags);
-}
-
-
-/*
- * Function : Scsi_Cmnd *return_outstanding_commands (struct Scsi_Host *host,
- * int free, int issue)
- *
- * Purpose : return a linked list (using the SCp.buffer field as next,
- * so we don't perturb hostdata. We don't use a field of the
- * NCR53c7x0_cmd structure since we may not have allocated one
- * for the command causing the reset.) of Scsi_Cmnd structures that
- * had propagated below the Linux issue queue level. If free is set,
- * free the NCR53c7x0_cmd structures which are associated with
- * the Scsi_Cmnd structures, and clean up any internal
- * NCR lists that the commands were on. If issue is set,
- * also return commands in the issue queue.
- *
- * Returns : linked list of commands
- *
- * NOTE : the caller should insure that the NCR chip is halted
- * if the free flag is set.
- */
-
-static Scsi_Cmnd *
-return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- struct NCR53c7x0_cmd *c;
- int i;
- u32 *ncrcurrent;
- Scsi_Cmnd *list = NULL, *tmp;
- for (c = (struct NCR53c7x0_cmd *) hostdata->running_list; c;
- c = (struct NCR53c7x0_cmd *) c->next) {
- if (c->cmd->SCp.buffer) {
- printk ("scsi%d : loop detected in running list!\n", host->host_no);
- break;
- } else {
- printk ("Duh? Bad things happening in the NCR driver\n");
- break;
- }
-
- c->cmd->SCp.buffer = (struct scatterlist *) list;
- list = c->cmd;
- if (free) {
- c->next = hostdata->free;
- hostdata->free = c;
- }
- }
-
- if (free) {
- for (i = 0, ncrcurrent = (u32 *) hostdata->schedule;
- i < host->can_queue; ++i, ncrcurrent += 2) {
- ncrcurrent[0] = hostdata->NOP_insn;
- ncrcurrent[1] = 0xdeadbeef;
- }
- hostdata->ncrcurrent = NULL;
- }
-
- if (issue) {
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; tmp = tmp->next) {
- if (tmp->SCp.buffer) {
- printk ("scsi%d : loop detected in issue queue!\n",
- host->host_no);
- break;
- }
- tmp->SCp.buffer = (struct scatterlist *) list;
- list = tmp;
- }
- if (free)
- hostdata->issue_queue = NULL;
-
- }
- return list;
-}
-
-/*
- * Function : static int disable (struct Scsi_Host *host)
- *
- * Purpose : disables the given NCR host, causing all commands
- * to return a driver error. Call this so we can unload the
- * module during development and try again. Eventually,
- * we should be able to find clean workarounds for these
- * problems.
- *
- * Inputs : host - hostadapter to twiddle
- *
- * Returns : 0 on success.
- */
-
-static int
-disable (struct Scsi_Host *host) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned long flags;
- Scsi_Cmnd *nuke_list, *tmp;
- local_irq_save(flags);
- if (hostdata->state != STATE_HALTED)
- ncr_halt (host);
- nuke_list = return_outstanding_commands (host, 1 /* free */, 1 /* issue */);
- hard_reset (host);
- hostdata->state = STATE_DISABLED;
- local_irq_restore(flags);
- printk ("scsi%d : nuking commands\n", host->host_no);
- for (; nuke_list; nuke_list = tmp) {
- tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
- nuke_list->result = DID_ERROR << 16;
- nuke_list->scsi_done(nuke_list);
- }
- printk ("scsi%d : done. \n", host->host_no);
- printk (KERN_ALERT "scsi%d : disabled. Unload and reload\n",
- host->host_no);
- return 0;
-}
-
-/*
- * Function : static int ncr_halt (struct Scsi_Host *host)
- *
- * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
- *
- * Inputs : host - SCSI chip to halt
- *
- * Returns : 0 on success
- */
-
-static int
-ncr_halt (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- unsigned long flags;
- unsigned char istat, tmp;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- int stage;
- NCR53c7x0_local_setup(host);
-
- local_irq_save(flags);
- /* Stage 0 : eat all interrupts
- Stage 1 : set ABORT
- Stage 2 : eat all but abort interrupts
- Stage 3 : eat all interrupts
- */
- for (stage = 0;;) {
- if (stage == 1) {
- NCR53c7x0_write8(hostdata->istat, ISTAT_ABRT);
- ++stage;
- }
- istat = NCR53c7x0_read8 (hostdata->istat);
- if (istat & ISTAT_SIP) {
- tmp = NCR53c7x0_read8(SSTAT0_REG);
- } else if (istat & ISTAT_DIP) {
- tmp = NCR53c7x0_read8(DSTAT_REG);
- if (stage == 2) {
- if (tmp & DSTAT_ABRT) {
- NCR53c7x0_write8(hostdata->istat, 0);
- ++stage;
- } else {
- printk(KERN_ALERT "scsi%d : could not halt NCR chip\n",
- host->host_no);
- disable (host);
- }
- }
- }
- if (!(istat & (ISTAT_SIP|ISTAT_DIP))) {
- if (stage == 0)
- ++stage;
- else if (stage == 3)
- break;
- }
- }
- hostdata->state = STATE_HALTED;
- local_irq_restore(flags);
-#if 0
- print_lots (host);
-#endif
- return 0;
-}
-
-/*
- * Function: event_name (int event)
- *
- * Purpose: map event enum into user-readable strings.
- */
-
-static const char *
-event_name (int event) {
- switch (event) {
- case EVENT_NONE: return "none";
- case EVENT_ISSUE_QUEUE: return "to issue queue";
- case EVENT_START_QUEUE: return "to start queue";
- case EVENT_SELECT: return "selected";
- case EVENT_DISCONNECT: return "disconnected";
- case EVENT_RESELECT: return "reselected";
- case EVENT_COMPLETE: return "completed";
- case EVENT_IDLE: return "idle";
- case EVENT_SELECT_FAILED: return "select failed";
- case EVENT_BEFORE_SELECT: return "before select";
- case EVENT_RESELECT_FAILED: return "reselect failed";
- default: return "unknown";
- }
-}
-
-/*
- * Function : void dump_events (struct Scsi_Host *host, count)
- *
- * Purpose : print last count events which have occurred.
- */
-static void
-dump_events (struct Scsi_Host *host, int count) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- struct NCR53c7x0_event event;
- int i;
- unsigned long flags;
- if (hostdata->events) {
- if (count > hostdata->event_size)
- count = hostdata->event_size;
- for (i = hostdata->event_index; count > 0;
- i = (i ? i - 1 : hostdata->event_size -1), --count) {
-/*
- * By copying the event we're currently examining with interrupts
- * disabled, we can do multiple printk(), etc. operations and
- * still be guaranteed that they're happening on the same
- * event structure.
- */
- local_irq_save(flags);
-#if 0
- event = hostdata->events[i];
-#else
- memcpy ((void *) &event, (void *) &(hostdata->events[i]),
- sizeof(event));
-#endif
-
- local_irq_restore(flags);
- printk ("scsi%d : %s event %d at %ld secs %ld usecs target %d lun %d\n",
- host->host_no, event_name (event.event), count,
- (long) event.time.tv_sec, (long) event.time.tv_usec,
- event.target, event.lun);
- if (event.dsa)
- printk (" event for dsa 0x%lx (virt 0x%p)\n",
- virt_to_bus(event.dsa), event.dsa);
- if (event.pid != -1) {
- printk (" event for pid %ld ", event.pid);
- __scsi_print_command (event.cmnd);
- }
- }
- }
-}
-
-/*
- * Function: check_address
- *
- * Purpose: Check to see if a possibly corrupt pointer will fault the
- * kernel.
- *
- * Inputs: addr - address; size - size of area
- *
- * Returns: 0 if area is OK, -1 on error.
- *
- * NOTES: should be implemented in terms of vverify on kernels
- * that have it.
- */
-
-static int
-check_address (unsigned long addr, int size) {
- return (virt_to_phys((void *)addr) < PAGE_SIZE || virt_to_phys((void *)(addr + size)) > virt_to_phys(high_memory) ? -1 : 0);
-}
-
-#ifdef MODULE
-int
-NCR53c7x0_release(struct Scsi_Host *host) {
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) host->hostdata[0];
- struct NCR53c7x0_cmd *cmd, *tmp;
- shutdown (host);
- if (host->irq != SCSI_IRQ_NONE)
- {
- int irq_count;
- struct Scsi_Host *tmp;
- for (irq_count = 0, tmp = first_host; tmp; tmp = tmp->next)
- if (tmp->hostt == the_template && tmp->irq == host->irq)
- ++irq_count;
- if (irq_count == 1)
- free_irq(host->irq, NULL);
- }
- if (host->dma_channel != DMA_NONE)
- free_dma(host->dma_channel);
- if (host->io_port)
- release_region(host->io_port, host->n_io_port);
-
- for (cmd = (struct NCR53c7x0_cmd *) hostdata->free; cmd; cmd = tmp,
- --hostdata->num_cmds) {
- tmp = (struct NCR53c7x0_cmd *) cmd->next;
- /*
- * If we're going to loop, try to stop it to get a more accurate
- * count of the leaked commands.
- */
- cmd->next = NULL;
- if (cmd->free)
- cmd->free ((void *) cmd->real, cmd->size);
- }
- if (hostdata->num_cmds)
- printk ("scsi%d : leaked %d NCR53c7x0_cmd structures\n",
- host->host_no, hostdata->num_cmds);
-
- vfree(hostdata->events);
-
- /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
- * XXX may be invalid (CONFIG_060_WRITETHROUGH)
- */
- kernel_set_cachemode((void *)hostdata, 8192, IOMAP_FULL_CACHING);
- free_pages ((u32)hostdata, 1);
- return 1;
-}
-#endif /* def MODULE */
diff --git a/drivers/scsi/53c7xx.h b/drivers/scsi/53c7xx.h
deleted file mode 100644
index 218f3b9..0000000
--- a/drivers/scsi/53c7xx.h
+++ /dev/null
@@ -1,1608 +0,0 @@
-/*
- * 53c710 driver. Modified from Drew Eckhardts driver
- * for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * I have left the code for the 53c8xx family in here, because it didn't
- * seem worth removing it. The possibility of IO_MAPPED chips rather
- * than MEMORY_MAPPED remains, in case someone wants to add support for
- * 53c710 chips on Intel PCs (some older machines have them on the
- * motherboard).
- *
- * NOTE THERE MAY BE PROBLEMS WITH CASTS IN read8 AND Co.
- */
-
-/*
- * NCR 53c{7,8}0x0 driver, header file
- *
- * Sponsored by
- * iX Multiuser Multitasking Magazine
- * Hannover, Germany
- * hm@ix.de
- *
- * Copyright 1993, 1994, 1995 Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@PoohSticks.ORG
- * +1 (303) 786-7975
- *
- * TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
- *
- * PRE-ALPHA
- *
- * For more information, please consult
- *
- * NCR 53C700/53C700-66
- * SCSI I/O Processor
- * Data Manual
- *
- * NCR 53C810
- * PCI-SCSI I/O Processor
- * Data Manual
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * +1 (719) 578-3400
- *
- * Toll free literature number
- * +1 (800) 334-5454
- *
- */
-
-#ifndef NCR53c710_H
-#define NCR53c710_H
-
-#ifndef HOSTS_C
-
-/* SCSI control 0 rw, default = 0xc0 */
-#define SCNTL0_REG 0x00
-#define SCNTL0_ARB1 0x80 /* 0 0 = simple arbitration */
-#define SCNTL0_ARB2 0x40 /* 1 1 = full arbitration */
-#define SCNTL0_STRT 0x20 /* Start Sequence */
-#define SCNTL0_WATN 0x10 /* Select with ATN */
-#define SCNTL0_EPC 0x08 /* Enable parity checking */
-/* Bit 2 is reserved on 800 series chips */
-#define SCNTL0_EPG_700 0x04 /* Enable parity generation */
-#define SCNTL0_AAP 0x02 /* ATN/ on parity error */
-#define SCNTL0_TRG 0x01 /* Target mode */
-
-/* SCSI control 1 rw, default = 0x00 */
-
-#define SCNTL1_REG 0x01
-#define SCNTL1_EXC 0x80 /* Extra Clock Cycle of Data setup */
-#define SCNTL1_ADB 0x40 /* contents of SODL on bus */
-#define SCNTL1_ESR_700 0x20 /* Enable SIOP response to selection
- and reselection */
-#define SCNTL1_DHP_800 0x20 /* Disable halt on parity error or ATN
- target mode only */
-#define SCNTL1_CON 0x10 /* Connected */
-#define SCNTL1_RST 0x08 /* SCSI RST/ */
-#define SCNTL1_AESP 0x04 /* Force bad parity */
-#define SCNTL1_SND_700 0x02 /* Start SCSI send */
-#define SCNTL1_IARB_800 0x02 /* Immediate Arbitration, start
- arbitration immediately after
- busfree is detected */
-#define SCNTL1_RCV_700 0x01 /* Start SCSI receive */
-#define SCNTL1_SST_800 0x01 /* Start SCSI transfer */
-
-/* SCSI control 2 rw, */
-
-#define SCNTL2_REG_800 0x02
-#define SCNTL2_800_SDU 0x80 /* SCSI disconnect unexpected */
-
-/* SCSI control 3 rw */
-
-#define SCNTL3_REG_800 0x03
-#define SCNTL3_800_SCF_SHIFT 4
-#define SCNTL3_800_SCF_MASK 0x70
-#define SCNTL3_800_SCF2 0x40 /* Synchronous divisor */
-#define SCNTL3_800_SCF1 0x20 /* 0x00 = SCLK/3 */
-#define SCNTL3_800_SCF0 0x10 /* 0x10 = SCLK/1 */
- /* 0x20 = SCLK/1.5
- 0x30 = SCLK/2
- 0x40 = SCLK/3 */
-
-#define SCNTL3_800_CCF_SHIFT 0
-#define SCNTL3_800_CCF_MASK 0x07
-#define SCNTL3_800_CCF2 0x04 /* 0x00 50.01 to 66 */
-#define SCNTL3_800_CCF1 0x02 /* 0x01 16.67 to 25 */
-#define SCNTL3_800_CCF0 0x01 /* 0x02 25.01 - 37.5
- 0x03 37.51 - 50
- 0x04 50.01 - 66 */
-
-/*
- * SCSI destination ID rw - the appropriate bit is set for the selected
- * target ID. This is written by the SCSI SCRIPTS processor.
- * default = 0x00
- */
-#define SDID_REG_700 0x02
-#define SDID_REG_800 0x06
-
-#define GP_REG_800 0x07 /* General purpose IO */
-#define GP_800_IO1 0x02
-#define GP_800_IO2 0x01
-
-/* SCSI interrupt enable rw, default = 0x00 */
-#define SIEN_REG_700 0x03
-#define SIEN0_REG_800 0x40
-#define SIEN_MA 0x80 /* Phase mismatch (ini) or ATN (tgt) */
-#define SIEN_FC 0x40 /* Function complete */
-#define SIEN_700_STO 0x20 /* Selection or reselection timeout */
-#define SIEN_800_SEL 0x20 /* Selected */
-#define SIEN_700_SEL 0x10 /* Selected or reselected */
-#define SIEN_800_RESEL 0x10 /* Reselected */
-#define SIEN_SGE 0x08 /* SCSI gross error */
-#define SIEN_UDC 0x04 /* Unexpected disconnect */
-#define SIEN_RST 0x02 /* SCSI RST/ received */
-#define SIEN_PAR 0x01 /* Parity error */
-
-/*
- * SCSI chip ID rw
- * NCR53c700 :
- * When arbitrating, the highest bit is used, when reselection or selection
- * occurs, the chip responds to all IDs for which a bit is set.
- * default = 0x00
- * NCR53c810 :
- * Uses bit mapping
- */
-#define SCID_REG 0x04
-/* Bit 7 is reserved on 800 series chips */
-#define SCID_800_RRE 0x40 /* Enable response to reselection */
-#define SCID_800_SRE 0x20 /* Enable response to selection */
-/* Bits four and three are reserved on 800 series chips */
-#define SCID_800_ENC_MASK 0x07 /* Encoded SCSI ID */
-
-/* SCSI transfer rw, default = 0x00 */
-#define SXFER_REG 0x05
-#define SXFER_DHP 0x80 /* Disable halt on parity */
-
-#define SXFER_TP2 0x40 /* Transfer period msb */
-#define SXFER_TP1 0x20
-#define SXFER_TP0 0x10 /* lsb */
-#define SXFER_TP_MASK 0x70
-/* FIXME : SXFER_TP_SHIFT == 5 is right for '8xx chips */
-#define SXFER_TP_SHIFT 5
-#define SXFER_TP_4 0x00 /* Divisors */
-#define SXFER_TP_5 0x10<<1
-#define SXFER_TP_6 0x20<<1
-#define SXFER_TP_7 0x30<<1
-#define SXFER_TP_8 0x40<<1
-#define SXFER_TP_9 0x50<<1
-#define SXFER_TP_10 0x60<<1
-#define SXFER_TP_11 0x70<<1
-
-#define SXFER_MO3 0x08 /* Max offset msb */
-#define SXFER_MO2 0x04
-#define SXFER_MO1 0x02
-#define SXFER_MO0 0x01 /* lsb */
-#define SXFER_MO_MASK 0x0f
-#define SXFER_MO_SHIFT 0
-
-/*
- * SCSI output data latch rw
- * The contents of this register are driven onto the SCSI bus when
- * the Assert Data Bus bit of the SCNTL1 register is set and
- * the CD, IO, and MSG bits of the SOCL register match the SCSI phase
- */
-#define SODL_REG_700 0x06
-#define SODL_REG_800 0x54
-
-
-/*
- * SCSI output control latch rw, default = 0
- * Note that when the chip is being manually programmed as an initiator,
- * the MSG, CD, and IO bits must be set correctly for the phase the target
- * is driving the bus in. Otherwise no data transfer will occur due to
- * phase mismatch.
- */
-
-#define SOCL_REG 0x07
-#define SOCL_REQ 0x80 /* REQ */
-#define SOCL_ACK 0x40 /* ACK */
-#define SOCL_BSY 0x20 /* BSY */
-#define SOCL_SEL 0x10 /* SEL */
-#define SOCL_ATN 0x08 /* ATN */
-#define SOCL_MSG 0x04 /* MSG */
-#define SOCL_CD 0x02 /* C/D */
-#define SOCL_IO 0x01 /* I/O */
-
-/*
- * SCSI first byte received latch ro
- * This register contains the first byte received during a block MOVE
- * SCSI SCRIPTS instruction, including
- *
- * Initiator mode Target mode
- * Message in Command
- * Status Message out
- * Data in Data out
- *
- * It also contains the selecting or reselecting device's ID and our
- * ID.
- *
- * Note that this is the register the various IF conditionals can
- * operate on.
- */
-#define SFBR_REG 0x08
-
-/*
- * SCSI input data latch ro
- * In initiator mode, data is latched into this register on the rising
- * edge of REQ/. In target mode, data is latched on the rising edge of
- * ACK/
- */
-#define SIDL_REG_700 0x09
-#define SIDL_REG_800 0x50
-
-/*
- * SCSI bus data lines ro
- * This register reflects the instantaneous status of the SCSI data
- * lines. Note that SCNTL0 must be set to disable parity checking,
- * otherwise reading this register will latch new parity.
- */
-#define SBDL_REG_700 0x0a
-#define SBDL_REG_800 0x58
-
-#define SSID_REG_800 0x0a
-#define SSID_800_VAL 0x80 /* Exactly two bits asserted at sel */
-#define SSID_800_ENCID_MASK 0x07 /* Device which performed operation */
-
-
-/*
- * SCSI bus control lines rw,
- * instantaneous readout of control lines
- */
-#define SBCL_REG 0x0b
-#define SBCL_REQ 0x80 /* REQ ro */
-#define SBCL_ACK 0x40 /* ACK ro */
-#define SBCL_BSY 0x20 /* BSY ro */
-#define SBCL_SEL 0x10 /* SEL ro */
-#define SBCL_ATN 0x08 /* ATN ro */
-#define SBCL_MSG 0x04 /* MSG ro */
-#define SBCL_CD 0x02 /* C/D ro */
-#define SBCL_IO 0x01 /* I/O ro */
-#define SBCL_PHASE_CMDOUT SBCL_CD
-#define SBCL_PHASE_DATAIN SBCL_IO
-#define SBCL_PHASE_DATAOUT 0
-#define SBCL_PHASE_MSGIN (SBCL_CD|SBCL_IO|SBCL_MSG)
-#define SBCL_PHASE_MSGOUT (SBCL_CD|SBCL_MSG)
-#define SBCL_PHASE_STATIN (SBCL_CD|SBCL_IO)
-#define SBCL_PHASE_MASK (SBCL_CD|SBCL_IO|SBCL_MSG)
-/*
- * Synchronous SCSI Clock Control bits
- * 0 - set by DCNTL
- * 1 - SCLK / 1.0
- * 2 - SCLK / 1.5
- * 3 - SCLK / 2.0
- */
-#define SBCL_SSCF1 0x02 /* wo, -66 only */
-#define SBCL_SSCF0 0x01 /* wo, -66 only */
-#define SBCL_SSCF_MASK 0x03
-
-/*
- * XXX note : when reading the DSTAT and STAT registers to clear interrupts,
- * insure that 10 clocks elapse between the two
- */
-/* DMA status ro */
-#define DSTAT_REG 0x0c
-#define DSTAT_DFE 0x80 /* DMA FIFO empty */
-#define DSTAT_800_MDPE 0x40 /* Master Data Parity Error */
-#define DSTAT_800_BF 0x20 /* Bus Fault */
-#define DSTAT_ABRT 0x10 /* Aborted - set on error */
-#define DSTAT_SSI 0x08 /* SCRIPTS single step interrupt */
-#define DSTAT_SIR 0x04 /* SCRIPTS interrupt received -
- set when INT instruction is
- executed */
-#define DSTAT_WTD 0x02 /* Watchdog timeout detected */
-#define DSTAT_OPC 0x01 /* Illegal instruction */
-#define DSTAT_800_IID 0x01 /* Same thing, different name */
-
-
-/* NCR53c800 moves this stuff into SIST0 */
-#define SSTAT0_REG 0x0d /* SCSI status 0 ro */
-#define SIST0_REG_800 0x42
-#define SSTAT0_MA 0x80 /* ini : phase mismatch,
- * tgt : ATN/ asserted
- */
-#define SSTAT0_CMP 0x40 /* function complete */
-#define SSTAT0_700_STO 0x20 /* Selection or reselection timeout */
-#define SIST0_800_SEL 0x20 /* Selected */
-#define SSTAT0_700_SEL 0x10 /* Selected or reselected */
-#define SIST0_800_RSL 0x10 /* Reselected */
-#define SSTAT0_SGE 0x08 /* SCSI gross error */
-#define SSTAT0_UDC 0x04 /* Unexpected disconnect */
-#define SSTAT0_RST 0x02 /* SCSI RST/ received */
-#define SSTAT0_PAR 0x01 /* Parity error */
-
-/* And uses SSTAT0 for what was SSTAT1 */
-
-#define SSTAT1_REG 0x0e /* SCSI status 1 ro */
-#define SSTAT1_ILF 0x80 /* SIDL full */
-#define SSTAT1_ORF 0x40 /* SODR full */
-#define SSTAT1_OLF 0x20 /* SODL full */
-#define SSTAT1_AIP 0x10 /* Arbitration in progress */
-#define SSTAT1_LOA 0x08 /* Lost arbitration */
-#define SSTAT1_WOA 0x04 /* Won arbitration */
-#define SSTAT1_RST 0x02 /* Instant readout of RST/ */
-#define SSTAT1_SDP 0x01 /* Instant readout of SDP/ */
-
-#define SSTAT2_REG 0x0f /* SCSI status 2 ro */
-#define SSTAT2_FF3 0x80 /* number of bytes in synchronous */
-#define SSTAT2_FF2 0x40 /* data FIFO */
-#define SSTAT2_FF1 0x20
-#define SSTAT2_FF0 0x10
-#define SSTAT2_FF_MASK 0xf0
-#define SSTAT2_FF_SHIFT 4
-
-/*
- * Latched signals, latched on the leading edge of REQ/ for initiators,
- * ACK/ for targets.
- */
-#define SSTAT2_SDP 0x08 /* SDP */
-#define SSTAT2_MSG 0x04 /* MSG */
-#define SSTAT2_CD 0x02 /* C/D */
-#define SSTAT2_IO 0x01 /* I/O */
-#define SSTAT2_PHASE_CMDOUT SSTAT2_CD
-#define SSTAT2_PHASE_DATAIN SSTAT2_IO
-#define SSTAT2_PHASE_DATAOUT 0
-#define SSTAT2_PHASE_MSGIN (SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
-#define SSTAT2_PHASE_MSGOUT (SSTAT2_CD|SSTAT2_MSG)
-#define SSTAT2_PHASE_STATIN (SSTAT2_CD|SSTAT2_IO)
-#define SSTAT2_PHASE_MASK (SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
-
-
-/* NCR53c700-66 only */
-#define SCRATCHA_REG_00 0x10 /* through 0x13 Scratch A rw */
-/* NCR53c710 and higher */
-#define DSA_REG 0x10 /* DATA structure address */
-
-#define CTEST0_REG_700 0x14 /* Chip test 0 ro */
-#define CTEST0_REG_800 0x18 /* Chip test 0 rw, general purpose */
-/* 0x80 - 0x04 are reserved */
-#define CTEST0_700_RTRG 0x02 /* Real target mode */
-#define CTEST0_700_DDIR 0x01 /* Data direction, 1 =
- * SCSI bus to host, 0 =
- * host to SCSI.
- */
-
-#define CTEST1_REG_700 0x15 /* Chip test 1 ro */
-#define CTEST1_REG_800 0x19 /* Chip test 1 ro */
-#define CTEST1_FMT3 0x80 /* Identify which byte lanes are empty */
-#define CTEST1_FMT2 0x40 /* in the DMA FIFO */
-#define CTEST1_FMT1 0x20
-#define CTEST1_FMT0 0x10
-
-#define CTEST1_FFL3 0x08 /* Identify which bytes lanes are full */
-#define CTEST1_FFL2 0x04 /* in the DMA FIFO */
-#define CTEST1_FFL1 0x02
-#define CTEST1_FFL0 0x01
-
-#define CTEST2_REG_700 0x16 /* Chip test 2 ro */
-#define CTEST2_REG_800 0x1a /* Chip test 2 ro */
-
-#define CTEST2_800_DDIR 0x80 /* 1 = SCSI->host */
-#define CTEST2_800_SIGP 0x40 /* A copy of SIGP in ISTAT.
- Reading this register clears */
-#define CTEST2_800_CIO 0x20 /* Configured as IO */.
-#define CTEST2_800_CM 0x10 /* Configured as memory */
-
-/* 0x80 - 0x40 are reserved on 700 series chips */
-#define CTEST2_700_SOFF 0x20 /* SCSI Offset Compare,
- * As an initiator, this bit is
- * one when the synchronous offset
- * is zero, as a target this bit
- * is one when the synchronous
- * offset is at the maximum
- * defined in SXFER
- */
-#define CTEST2_700_SFP 0x10 /* SCSI FIFO parity bit,
- * reading CTEST3 unloads a byte
- * from the FIFO and sets this
- */
-#define CTEST2_700_DFP 0x08 /* DMA FIFO parity bit,
- * reading CTEST6 unloads a byte
- * from the FIFO and sets this
- */
-#define CTEST2_TEOP 0x04 /* SCSI true end of process,
- * indicates a totally finished
- * transfer
- */
-#define CTEST2_DREQ 0x02 /* Data request signal */
-/* 0x01 is reserved on 700 series chips */
-#define CTEST2_800_DACK 0x01
-
-/*
- * Chip test 3 ro
- * Unloads the bottom byte of the eight deep SCSI synchronous FIFO,
- * check SSTAT2 FIFO full bits to determine size. Note that a GROSS
- * error results if a read is attempted on this register. Also note
- * that 16 and 32 bit reads of this register will cause corruption.
- */
-#define CTEST3_REG_700 0x17
-/* Chip test 3 rw */
-#define CTEST3_REG_800 0x1b
-#define CTEST3_800_V3 0x80 /* Chip revision */
-#define CTEST3_800_V2 0x40
-#define CTEST3_800_V1 0x20
-#define CTEST3_800_V0 0x10
-#define CTEST3_800_FLF 0x08 /* Flush DMA FIFO */
-#define CTEST3_800_CLF 0x04 /* Clear DMA FIFO */
-#define CTEST3_800_FM 0x02 /* Fetch mode pin */
-/* bit 0 is reserved on 800 series chips */
-
-#define CTEST4_REG_700 0x18 /* Chip test 4 rw */
-#define CTEST4_REG_800 0x21 /* Chip test 4 rw */
-/* 0x80 is reserved on 700 series chips */
-#define CTEST4_800_BDIS 0x80 /* Burst mode disable */
-#define CTEST4_ZMOD 0x40 /* High impedance mode */
-#define CTEST4_SZM 0x20 /* SCSI bus high impedance */
-#define CTEST4_700_SLBE 0x10 /* SCSI loopback enabled */
-#define CTEST4_800_SRTM 0x10 /* Shadow Register Test Mode */
-#define CTEST4_700_SFWR 0x08 /* SCSI FIFO write enable,
- * redirects writes from SODL
- * to the SCSI FIFO.
- */
-#define CTEST4_800_MPEE 0x08 /* Enable parity checking
- during master cycles on PCI
- bus */
-
-/*
- * These bits send the contents of the CTEST6 register to the appropriate
- * byte lane of the 32 bit DMA FIFO. Normal operation is zero, otherwise
- * the high bit means the low two bits select the byte lane.
- */
-#define CTEST4_FBL2 0x04
-#define CTEST4_FBL1 0x02
-#define CTEST4_FBL0 0x01
-#define CTEST4_FBL_MASK 0x07
-#define CTEST4_FBL_0 0x04 /* Select DMA FIFO byte lane 0 */
-#define CTEST4_FBL_1 0x05 /* Select DMA FIFO byte lane 1 */
-#define CTEST4_FBL_2 0x06 /* Select DMA FIFO byte lane 2 */
-#define CTEST4_FBL_3 0x07 /* Select DMA FIFO byte lane 3 */
-#define CTEST4_800_SAVE (CTEST4_800_BDIS)
-
-
-#define CTEST5_REG_700 0x19 /* Chip test 5 rw */
-#define CTEST5_REG_800 0x22 /* Chip test 5 rw */
-/*
- * Clock Address Incrementor. When set, it increments the
- * DNAD register to the next bus size boundary. It automatically
- * resets itself when the operation is complete.
- */
-#define CTEST5_ADCK 0x80
-/*
- * Clock Byte Counter. When set, it decrements the DBC register to
- * the next bus size boundary.
- */
-#define CTEST5_BBCK 0x40
-/*
- * Reset SCSI Offset. Setting this bit to 1 clears the current offset
- * pointer in the SCSI synchronous offset counter (SSTAT). This bit
- * is set to 1 if a SCSI Gross Error Condition occurs. The offset should
- * be cleared when a synchronous transfer fails. When written, it is
- * automatically cleared after the SCSI synchronous offset counter is
- * reset.
- */
-/* Bit 5 is reserved on 800 series chips */
-#define CTEST5_700_ROFF 0x20
-/*
- * Master Control for Set or Reset pulses. When 1, causes the low
- * four bits of register to set when set, 0 causes the low bits to
- * clear when set.
- */
-#define CTEST5_MASR 0x10
-#define CTEST5_DDIR 0x08 /* DMA direction */
-/*
- * Bits 2-0 are reserved on 800 series chips
- */
-#define CTEST5_700_EOP 0x04 /* End of process */
-#define CTEST5_700_DREQ 0x02 /* Data request */
-#define CTEST5_700_DACK 0x01 /* Data acknowledge */
-
-/*
- * Chip test 6 rw - writing to this register writes to the byte
- * lane in the DMA FIFO as determined by the FBL bits in the CTEST4
- * register.
- */
-#define CTEST6_REG_700 0x1a
-#define CTEST6_REG_800 0x23
-
-#define CTEST7_REG 0x1b /* Chip test 7 rw */
-/* 0x80 - 0x40 are reserved on NCR53c700 and NCR53c700-66 chips */
-#define CTEST7_10_CDIS 0x80 /* Cache burst disable */
-#define CTEST7_10_SC1 0x40 /* Snoop control bits */
-#define CTEST7_10_SC0 0x20
-#define CTEST7_10_SC_MASK 0x60
-/* 0x20 is reserved on the NCR53c700 */
-#define CTEST7_0060_FM 0x20 /* Fetch mode */
-#define CTEST7_STD 0x10 /* Selection timeout disable */
-#define CTEST7_DFP 0x08 /* DMA FIFO parity bit for CTEST6 */
-#define CTEST7_EVP 0x04 /* 1 = host bus even parity, 0 = odd */
-#define CTEST7_10_TT1 0x02 /* Transfer type */
-#define CTEST7_00_DC 0x02 /* Set to drive DC low during instruction
- fetch */
-#define CTEST7_DIFF 0x01 /* Differential mode */
-
-#define CTEST7_SAVE ( CTEST7_EVP | CTEST7_DIFF )
-
-
-#define TEMP_REG 0x1c /* through 0x1f Temporary stack rw */
-
-#define DFIFO_REG 0x20 /* DMA FIFO rw */
-/*
- * 0x80 is reserved on the NCR53c710, the CLF and FLF bits have been
- * moved into the CTEST8 register.
- */
-#define DFIFO_00_FLF 0x80 /* Flush DMA FIFO to memory */
-#define DFIFO_00_CLF 0x40 /* Clear DMA and SCSI FIFOs */
-#define DFIFO_BO6 0x40
-#define DFIFO_BO5 0x20
-#define DFIFO_BO4 0x10
-#define DFIFO_BO3 0x08
-#define DFIFO_BO2 0x04
-#define DFIFO_BO1 0x02
-#define DFIFO_BO0 0x01
-#define DFIFO_10_BO_MASK 0x7f /* 7 bit counter */
-#define DFIFO_00_BO_MASK 0x3f /* 6 bit counter */
-
-/*
- * Interrupt status rw
- * Note that this is the only register which can be read while SCSI
- * SCRIPTS are being executed.
- */
-#define ISTAT_REG_700 0x21
-#define ISTAT_REG_800 0x14
-#define ISTAT_ABRT 0x80 /* Software abort, write
- *1 to abort, wait for interrupt. */
-/* 0x40 and 0x20 are reserved on NCR53c700 and NCR53c700-66 chips */
-#define ISTAT_10_SRST 0x40 /* software reset */
-#define ISTAT_10_SIGP 0x20 /* signal script */
-/* 0x10 is reserved on NCR53c700 series chips */
-#define ISTAT_800_SEM 0x10 /* semaphore */
-#define ISTAT_CON 0x08 /* 1 when connected */
-#define ISTAT_800_INTF 0x04 /* Interrupt on the fly */
-#define ISTAT_700_PRE 0x04 /* Pointer register empty.
- * Set to 1 when DSPS and DSP
- * registers are empty in pipeline
- * mode, always set otherwise.
- */
-#define ISTAT_SIP 0x02 /* SCSI interrupt pending from
- * SCSI portion of SIOP see
- * SSTAT0
- */
-#define ISTAT_DIP 0x01 /* DMA interrupt pending
- * see DSTAT
- */
-
-/* NCR53c700-66 and NCR53c710 only */
-#define CTEST8_REG 0x22 /* Chip test 8 rw */
-#define CTEST8_0066_EAS 0x80 /* Enable alternate SCSI clock,
- * ie read from SCLK/ rather than CLK/
- */
-#define CTEST8_0066_EFM 0x40 /* Enable fetch and master outputs */
-#define CTEST8_0066_GRP 0x20 /* Generate Receive Parity for
- * pass through. This insures that
- * bad parity won't reach the host
- * bus.
- */
-#define CTEST8_0066_TE 0x10 /* TolerANT enable. Enable
- * active negation, should only
- * be used for slow SCSI
- * non-differential.
- */
-#define CTEST8_0066_HSC 0x08 /* Halt SCSI clock */
-#define CTEST8_0066_SRA 0x04 /* Shorten REQ/ACK filtering,
- * must be set for fast SCSI-II
- * speeds.
- */
-#define CTEST8_0066_DAS 0x02 /* Disable automatic target/initiator
- * switching.
- */
-#define CTEST8_0066_LDE 0x01 /* Last disconnect enable.
- * The status of pending
- * disconnect is maintained by
- * the core, eliminating
- * the possibility of missing a
- * selection or reselection
- * while waiting to fetch a
- * WAIT DISCONNECT opcode.
- */
-
-#define CTEST8_10_V3 0x80 /* Chip revision */
-#define CTEST8_10_V2 0x40
-#define CTEST8_10_V1 0x20
-#define CTEST8_10_V0 0x10
-#define CTEST8_10_V_MASK 0xf0
-#define CTEST8_10_FLF 0x08 /* Flush FIFOs */
-#define CTEST8_10_CLF 0x04 /* Clear FIFOs */
-#define CTEST8_10_FM 0x02 /* Fetch pin mode */
-#define CTEST8_10_SM 0x01 /* Snoop pin mode */
-
-
-/*
- * The CTEST9 register may be used to differentiate between a
- * NCR53c700 and a NCR53c710.
- *
- * Write 0xff to this register.
- * Read it.
- * If the contents are 0xff, it is a NCR53c700
- * If the contents are 0x00, it is a NCR53c700-66 first revision
- * If the contents are some other value, it is some other NCR53c700-66
- */
-#define CTEST9_REG_00 0x23 /* Chip test 9 ro */
-#define LCRC_REG_10 0x23
-
-/*
- * 0x24 through 0x27 are the DMA byte counter register. Instructions
- * write their high 8 bits into the DCMD register, the low 24 bits into
- * the DBC register.
- *
- * Function is dependent on the command type being executed.
- */
-
-
-#define DBC_REG 0x24
-/*
- * For Block Move Instructions, DBC is a 24 bit quantity representing
- * the number of bytes to transfer.
- * For Transfer Control Instructions, DBC is bit fielded as follows :
- */
-/* Bits 20 - 23 should be clear */
-#define DBC_TCI_TRUE (1 << 19) /* Jump when true */
-#define DBC_TCI_COMPARE_DATA (1 << 18) /* Compare data */
-#define DBC_TCI_COMPARE_PHASE (1 << 17) /* Compare phase with DCMD field */
-#define DBC_TCI_WAIT_FOR_VALID (1 << 16) /* Wait for REQ */
-/* Bits 8 - 15 are reserved on some implementations ? */
-#define DBC_TCI_MASK_MASK 0xff00 /* Mask for data compare */
-#define DBC_TCI_MASK_SHIFT 8
-#define DBC_TCI_DATA_MASK 0xff /* Data to be compared */
-#define DBC_TCI_DATA_SHIFT 0
-
-#define DBC_RWRI_IMMEDIATE_MASK 0xff00 /* Immediate data */
-#define DBC_RWRI_IMMEDIATE_SHIFT 8 /* Amount to shift */
-#define DBC_RWRI_ADDRESS_MASK 0x3f0000 /* Register address */
-#define DBC_RWRI_ADDRESS_SHIFT 16
-
-
-/*
- * DMA command r/w
- */
-#define DCMD_REG 0x27
-#define DCMD_TYPE_MASK 0xc0 /* Masks off type */
-#define DCMD_TYPE_BMI 0x00 /* Indicates a Block Move instruction */
-#define DCMD_BMI_IO 0x01 /* I/O, CD, and MSG bits selecting */
-#define DCMD_BMI_CD 0x02 /* the phase for the block MOVE */
-#define DCMD_BMI_MSG 0x04 /* instruction */
-
-#define DCMD_BMI_OP_MASK 0x18 /* mask for opcode */
-#define DCMD_BMI_OP_MOVE_T 0x00 /* MOVE */
-#define DCMD_BMI_OP_MOVE_I 0x08 /* MOVE Initiator */
-
-#define DCMD_BMI_INDIRECT 0x20 /* Indirect addressing */
-
-#define DCMD_TYPE_TCI 0x80 /* Indicates a Transfer Control
- instruction */
-#define DCMD_TCI_IO 0x01 /* I/O, CD, and MSG bits selecting */
-#define DCMD_TCI_CD 0x02 /* the phase for the block MOVE */
-#define DCMD_TCI_MSG 0x04 /* instruction */
-#define DCMD_TCI_OP_MASK 0x38 /* mask for opcode */
-#define DCMD_TCI_OP_JUMP 0x00 /* JUMP */
-#define DCMD_TCI_OP_CALL 0x08 /* CALL */
-#define DCMD_TCI_OP_RETURN 0x10 /* RETURN */
-#define DCMD_TCI_OP_INT 0x18 /* INT */
-
-#define DCMD_TYPE_RWRI 0x40 /* Indicates I/O or register Read/Write
- instruction */
-#define DCMD_RWRI_OPC_MASK 0x38 /* Opcode mask */
-#define DCMD_RWRI_OPC_WRITE 0x28 /* Write SFBR to register */
-#define DCMD_RWRI_OPC_READ 0x30 /* Read register to SFBR */
-#define DCMD_RWRI_OPC_MODIFY 0x38 /* Modify in place */
-
-#define DCMD_RWRI_OP_MASK 0x07
-#define DCMD_RWRI_OP_MOVE 0x00
-#define DCMD_RWRI_OP_SHL 0x01
-#define DCMD_RWRI_OP_OR 0x02
-#define DCMD_RWRI_OP_XOR 0x03
-#define DCMD_RWRI_OP_AND 0x04
-#define DCMD_RWRI_OP_SHR 0x05
-#define DCMD_RWRI_OP_ADD 0x06
-#define DCMD_RWRI_OP_ADDC 0x07
-
-#define DCMD_TYPE_MMI 0xc0 /* Indicates a Memory Move instruction
- (three words) */
-
-
-#define DNAD_REG 0x28 /* through 0x2b DMA next address for
- data */
-#define DSP_REG 0x2c /* through 0x2f DMA SCRIPTS pointer rw */
-#define DSPS_REG 0x30 /* through 0x33 DMA SCRIPTS pointer
- save rw */
-#define DMODE_REG_00 0x34 /* DMA mode rw */
-#define DMODE_00_BL1 0x80 /* Burst length bits */
-#define DMODE_00_BL0 0x40
-#define DMODE_BL_MASK 0xc0
-/* Burst lengths (800) */
-#define DMODE_BL_2 0x00 /* 2 transfer */
-#define DMODE_BL_4 0x40 /* 4 transfers */
-#define DMODE_BL_8 0x80 /* 8 transfers */
-#define DMODE_BL_16 0xc0 /* 16 transfers */
-
-#define DMODE_10_BL_1 0x00 /* 1 transfer */
-#define DMODE_10_BL_2 0x40 /* 2 transfers */
-#define DMODE_10_BL_4 0x80 /* 4 transfers */
-#define DMODE_10_BL_8 0xc0 /* 8 transfers */
-#define DMODE_10_FC2 0x20 /* Driven to FC2 pin */
-#define DMODE_10_FC1 0x10 /* Driven to FC1 pin */
-#define DMODE_710_PD 0x08 /* Program/data on FC0 pin */
-#define DMODE_710_UO 0x02 /* User prog. output */
-
-#define DMODE_700_BW16 0x20 /* Host buswidth = 16 */
-#define DMODE_700_286 0x10 /* 286 mode */
-#define DMODE_700_IOM 0x08 /* Transfer to IO port */
-#define DMODE_700_FAM 0x04 /* Fixed address mode */
-#define DMODE_700_PIPE 0x02 /* Pipeline mode disables
- * automatic fetch / exec
- */
-#define DMODE_MAN 0x01 /* Manual start mode,
- * requires a 1 to be written
- * to the start DMA bit in the DCNTL
- * register to run scripts
- */
-
-#define DMODE_700_SAVE ( DMODE_00_BL_MASK | DMODE_00_BW16 | DMODE_00_286 )
-
-/* NCR53c800 series only */
-#define SCRATCHA_REG_800 0x34 /* through 0x37 Scratch A rw */
-/* NCR53c710 only */
-#define SCRATCHB_REG_10 0x34 /* through 0x37 scratch B rw */
-
-#define DMODE_REG_10 0x38 /* DMA mode rw, NCR53c710 and newer */
-#define DMODE_800_SIOM 0x20 /* Source IO = 1 */
-#define DMODE_800_DIOM 0x10 /* Destination IO = 1 */
-#define DMODE_800_ERL 0x08 /* Enable Read Line */
-
-/* 35-38 are reserved on 700 and 700-66 series chips */
-#define DIEN_REG 0x39 /* DMA interrupt enable rw */
-/* 0x80, 0x40, and 0x20 are reserved on 700-series chips */
-#define DIEN_800_MDPE 0x40 /* Master data parity error */
-#define DIEN_800_BF 0x20 /* BUS fault */
-#define DIEN_700_BF 0x20 /* BUS fault */
-#define DIEN_ABRT 0x10 /* Enable aborted interrupt */
-#define DIEN_SSI 0x08 /* Enable single step interrupt */
-#define DIEN_SIR 0x04 /* Enable SCRIPTS INT command
- * interrupt
- */
-/* 0x02 is reserved on 800 series chips */
-#define DIEN_700_WTD 0x02 /* Enable watchdog timeout interrupt */
-#define DIEN_700_OPC 0x01 /* Enable illegal instruction
- * interrupt
- */
-#define DIEN_800_IID 0x01 /* Same meaning, different name */
-
-/*
- * DMA watchdog timer rw
- * set in 16 CLK input periods.
- */
-#define DWT_REG 0x3a
-
-/* DMA control rw */
-#define DCNTL_REG 0x3b
-#define DCNTL_700_CF1 0x80 /* Clock divisor bits */
-#define DCNTL_700_CF0 0x40
-#define DCNTL_700_CF_MASK 0xc0
-/* Clock divisors Divisor SCLK range (MHZ) */
-#define DCNTL_700_CF_2 0x00 /* 2.0 37.51-50.00 */
-#define DCNTL_700_CF_1_5 0x40 /* 1.5 25.01-37.50 */
-#define DCNTL_700_CF_1 0x80 /* 1.0 16.67-25.00 */
-#define DCNTL_700_CF_3 0xc0 /* 3.0 50.01-66.67 (53c700-66) */
-
-#define DCNTL_700_S16 0x20 /* Load scripts 16 bits at a time */
-#define DCNTL_SSM 0x10 /* Single step mode */
-#define DCNTL_700_LLM 0x08 /* Low level mode, can only be set
- * after selection */
-#define DCNTL_800_IRQM 0x08 /* Totem pole IRQ pin */
-#define DCNTL_STD 0x04 /* Start DMA / SCRIPTS */
-/* 0x02 is reserved */
-#define DCNTL_00_RST 0x01 /* Software reset, resets everything
- * but 286 mode bit in DMODE. On the
- * NCR53c710, this bit moved to CTEST8
- */
-#define DCNTL_10_COM 0x01 /* 700 software compatibility mode */
-#define DCNTL_10_EA 0x20 /* Enable Ack - needed for MVME16x */
-
-#define DCNTL_700_SAVE ( DCNTL_CF_MASK | DCNTL_S16)
-
-
-/* NCR53c700-66 only */
-#define SCRATCHB_REG_00 0x3c /* through 0x3f scratch b rw */
-#define SCRATCHB_REG_800 0x5c /* through 0x5f scratch b rw */
-/* NCR53c710 only */
-#define ADDER_REG_10 0x3c /* Adder, NCR53c710 only */
-
-#define SIEN1_REG_800 0x41
-#define SIEN1_800_STO 0x04 /* selection/reselection timeout */
-#define SIEN1_800_GEN 0x02 /* general purpose timer */
-#define SIEN1_800_HTH 0x01 /* handshake to handshake */
-
-#define SIST1_REG_800 0x43
-#define SIST1_800_STO 0x04 /* selection/reselection timeout */
-#define SIST1_800_GEN 0x02 /* general purpose timer */
-#define SIST1_800_HTH 0x01 /* handshake to handshake */
-
-#define SLPAR_REG_800 0x44 /* Parity */
-
-#define MACNTL_REG_800 0x46 /* Memory access control */
-#define MACNTL_800_TYP3 0x80
-#define MACNTL_800_TYP2 0x40
-#define MACNTL_800_TYP1 0x20
-#define MACNTL_800_TYP0 0x10
-#define MACNTL_800_DWR 0x08
-#define MACNTL_800_DRD 0x04
-#define MACNTL_800_PSCPT 0x02
-#define MACNTL_800_SCPTS 0x01
-
-#define GPCNTL_REG_800 0x47 /* General Purpose Pin Control */
-
-/* Timeouts are expressed such that 0=off, 1=100us, doubling after that */
-#define STIME0_REG_800 0x48 /* SCSI Timer Register 0 */
-#define STIME0_800_HTH_MASK 0xf0 /* Handshake to Handshake timeout */
-#define STIME0_800_HTH_SHIFT 4
-#define STIME0_800_SEL_MASK 0x0f /* Selection timeout */
-#define STIME0_800_SEL_SHIFT 0
-
-#define STIME1_REG_800 0x49
-#define STIME1_800_GEN_MASK 0x0f /* General purpose timer */
-
-#define RESPID_REG_800 0x4a /* Response ID, bit fielded. 8
- bits on narrow chips, 16 on WIDE */
-
-#define STEST0_REG_800 0x4c
-#define STEST0_800_SLT 0x08 /* Selection response logic test */
-#define STEST0_800_ART 0x04 /* Arbitration priority encoder test */
-#define STEST0_800_SOZ 0x02 /* Synchronous offset zero */
-#define STEST0_800_SOM 0x01 /* Synchronous offset maximum */
-
-#define STEST1_REG_800 0x4d
-#define STEST1_800_SCLK 0x80 /* Disable SCSI clock */
-
-#define STEST2_REG_800 0x4e
-#define STEST2_800_SCE 0x80 /* Enable SOCL/SODL */
-#define STEST2_800_ROF 0x40 /* Reset SCSI sync offset */
-#define STEST2_800_SLB 0x10 /* Enable SCSI loopback mode */
-#define STEST2_800_SZM 0x08 /* SCSI high impedance mode */
-#define STEST2_800_EXT 0x02 /* Extend REQ/ACK filter 30 to 60ns */
-#define STEST2_800_LOW 0x01 /* SCSI low level mode */
-
-#define STEST3_REG_800 0x4f
-#define STEST3_800_TE 0x80 /* Enable active negation */
-#define STEST3_800_STR 0x40 /* SCSI FIFO test read */
-#define STEST3_800_HSC 0x20 /* Halt SCSI clock */
-#define STEST3_800_DSI 0x10 /* Disable single initiator response */
-#define STEST3_800_TTM 0x04 /* Time test mode */
-#define STEST3_800_CSF 0x02 /* Clear SCSI FIFO */
-#define STEST3_800_STW 0x01 /* SCSI FIFO test write */
-
-#define OPTION_PARITY 0x1 /* Enable parity checking */
-#define OPTION_TAGGED_QUEUE 0x2 /* Enable SCSI-II tagged queuing */
-#define OPTION_700 0x8 /* Always run NCR53c700 scripts */
-#define OPTION_INTFLY 0x10 /* Use INTFLY interrupts */
-#define OPTION_DEBUG_INTR 0x20 /* Debug interrupts */
-#define OPTION_DEBUG_INIT_ONLY 0x40 /* Run initialization code and
- simple test code, return
- DID_NO_CONNECT if any SCSI
- commands are attempted. */
-#define OPTION_DEBUG_READ_ONLY 0x80 /* Return DID_ERROR if any
- SCSI write is attempted */
-#define OPTION_DEBUG_TRACE 0x100 /* Animated trace mode, print
- each address and instruction
- executed to debug buffer. */
-#define OPTION_DEBUG_SINGLE 0x200 /* stop after executing one
- instruction */
-#define OPTION_SYNCHRONOUS 0x400 /* Enable sync SCSI. */
-#define OPTION_MEMORY_MAPPED 0x800 /* NCR registers have valid
- memory mapping */
-#define OPTION_IO_MAPPED 0x1000 /* NCR registers have valid
- I/O mapping */
-#define OPTION_DEBUG_PROBE_ONLY 0x2000 /* Probe only, don't even init */
-#define OPTION_DEBUG_TESTS_ONLY 0x4000 /* Probe, init, run selected tests */
-#define OPTION_DEBUG_TEST0 0x08000 /* Run test 0 */
-#define OPTION_DEBUG_TEST1 0x10000 /* Run test 1 */
-#define OPTION_DEBUG_TEST2 0x20000 /* Run test 2 */
-#define OPTION_DEBUG_DUMP 0x40000 /* Dump commands */
-#define OPTION_DEBUG_TARGET_LIMIT 0x80000 /* Only talk to target+luns specified */
-#define OPTION_DEBUG_NCOMMANDS_LIMIT 0x100000 /* Limit the number of commands */
-#define OPTION_DEBUG_SCRIPT 0x200000 /* Print when checkpoints are passed */
-#define OPTION_DEBUG_FIXUP 0x400000 /* print fixup values */
-#define OPTION_DEBUG_DSA 0x800000
-#define OPTION_DEBUG_CORRUPTION 0x1000000 /* Detect script corruption */
-#define OPTION_DEBUG_SDTR 0x2000000 /* Debug SDTR problem */
-#define OPTION_DEBUG_MISMATCH 0x4000000 /* Debug phase mismatches */
-#define OPTION_DISCONNECT 0x8000000 /* Allow disconnect */
-#define OPTION_DEBUG_DISCONNECT 0x10000000
-#define OPTION_ALWAYS_SYNCHRONOUS 0x20000000 /* Negotiate sync. transfers
- on power up */
-#define OPTION_DEBUG_QUEUES 0x80000000
-#define OPTION_DEBUG_ALLOCATION 0x100000000LL
-#define OPTION_DEBUG_SYNCHRONOUS 0x200000000LL /* Sanity check SXFER and
- SCNTL3 registers */
-#define OPTION_NO_ASYNC 0x400000000LL /* Don't automagically send
- SDTR for async transfers when
- we haven't been told to do
- a synchronous transfer. */
-#define OPTION_NO_PRINT_RACE 0x800000000LL /* Don't print message when
- the reselect/WAIT DISCONNECT
- race condition hits */
-#if !defined(PERM_OPTIONS)
-#define PERM_OPTIONS 0
-#endif
-
-/*
- * Some data which is accessed by the NCR chip must be 4-byte aligned.
- * For some hosts the default is less than that (eg. 68K uses 2-byte).
- * Alignment has only been forced where it is important; also if one
- * 32 bit structure field is aligned then it is assumed that following
- * 32 bit fields are also aligned. Take care when adding fields
- * which are other than 32 bit.
- */
-
-struct NCR53c7x0_synchronous {
- u32 select_indirect /* Value used for indirect selection */
- __attribute__ ((aligned (4)));
- u32 sscf_710; /* Used to set SSCF bits for 710 */
- u32 script[8]; /* Size ?? Script used when target is
- reselected */
- unsigned char synchronous_want[5]; /* Per target desired SDTR */
-/*
- * Set_synchronous programs these, select_indirect and current settings after
- * int_debug_should show a match.
- */
- unsigned char sxfer_sanity, scntl3_sanity;
-};
-
-#define CMD_FLAG_SDTR 1 /* Initiating synchronous
- transfer negotiation */
-#define CMD_FLAG_WDTR 2 /* Initiating wide transfer
- negotiation */
-#define CMD_FLAG_DID_SDTR 4 /* did SDTR */
-#define CMD_FLAG_DID_WDTR 8 /* did WDTR */
-
-struct NCR53c7x0_table_indirect {
- u32 count;
- void *address;
-};
-
-enum ncr_event {
- EVENT_NONE = 0,
-/*
- * Order is IMPORTANT, since these must correspond to the event interrupts
- * in 53c7,8xx.scr
- */
-
- EVENT_ISSUE_QUEUE = 0x5000000, /* 0 Command was added to issue queue */
- EVENT_START_QUEUE, /* 1 Command moved to start queue */
- EVENT_SELECT, /* 2 Command completed selection */
- EVENT_DISCONNECT, /* 3 Command disconnected */
- EVENT_RESELECT, /* 4 Command reselected */
- EVENT_COMPLETE, /* 5 Command completed */
- EVENT_IDLE, /* 6 */
- EVENT_SELECT_FAILED, /* 7 */
- EVENT_BEFORE_SELECT, /* 8 */
- EVENT_RESELECT_FAILED /* 9 */
-};
-
-struct NCR53c7x0_event {
- enum ncr_event event; /* What type of event */
- unsigned char target;
- unsigned char lun;
- struct timeval time;
- u32 *dsa; /* What's in the DSA register now (virt) */
-/*
- * A few things from that SCSI pid so we know what happened after
- * the Scsi_Cmnd structure in question may have disappeared.
- */
- unsigned long pid; /* The SCSI PID which caused this
- event */
- unsigned char cmnd[12];
-};
-
-/*
- * Things in the NCR53c7x0_cmd structure are split into two parts :
- *
- * 1. A fixed portion, for things which are not accessed directly by static NCR
- * code (ie, are referenced only by the Linux side of the driver,
- * or only by dynamically generated code).
- *
- * 2. The DSA portion, for things which are accessed directly by static NCR
- * code.
- *
- * This is a little ugly, but it
- * 1. Avoids conflicts between the NCR code's picture of the structure, and
- * Linux code's idea of what it looks like.
- *
- * 2. Minimizes the pain in the Linux side of the code needed
- * to calculate real dsa locations for things, etc.
- *
- */
-
-struct NCR53c7x0_cmd {
- void *real; /* Real, unaligned address for
- free function */
- void (* free)(void *, int); /* Command to deallocate; NULL
- for structures allocated with
- scsi_register, etc. */
- Scsi_Cmnd *cmd; /* Associated Scsi_Cmnd
- structure, Scsi_Cmnd points
- at NCR53c7x0_cmd using
- host_scribble structure */
-
- int size; /* scsi_malloc'd size of this
- structure */
-
- int flags; /* CMD_* flags */
-
- unsigned char cmnd[12]; /* CDB, copied from Scsi_Cmnd */
- int result; /* Copy to Scsi_Cmnd when done */
-
- struct { /* Private non-cached bounce buffer */
- unsigned char buf[256];
- u32 addr;
- u32 len;
- } bounce;
-
-/*
- * SDTR and WIDE messages are an either/or affair
- * in this message, since we will go into message out and send
- * _the whole mess_ without dropping out of message out to
- * let the target go into message in after sending the first
- * message.
- */
-
- unsigned char select[11]; /* Select message, includes
- IDENTIFY
- (optional) QUEUE TAG
- (optional) SDTR or WDTR
- */
-
-
- volatile struct NCR53c7x0_cmd *next; /* Linux maintained lists (free,
- running, eventually finished */
-
-
- u32 *data_transfer_start; /* Start of data transfer routines */
- u32 *data_transfer_end; /* Address after end of data transfer o
- routines */
-/*
- * The following three fields were moved from the DSA proper to here
- * since only dynamically generated NCR code refers to them, meaning
- * we don't need dsa_* absolutes, and it is simpler to let the
- * host code refer to them directly.
- */
-
-/*
- * HARD CODED : residual and saved_residual need to agree with the sizes
- * used in NCR53c7,8xx.scr.
- *
- * FIXME: we want to consider the case where we have odd-length
- * scatter/gather buffers and a WIDE transfer, in which case
- * we'll need to use the CHAIN MOVE instruction. Ick.
- */
- u32 residual[6] __attribute__ ((aligned (4)));
- /* Residual data transfer which
- allows pointer code to work
- right.
-
- [0-1] : Conditional call to
- appropriate other transfer
- routine.
- [2-3] : Residual block transfer
- instruction.
- [4-5] : Jump to instruction
- after splice.
- */
- u32 saved_residual[6]; /* Copy of old residual, so we
- can get another partial
- transfer and still recover
- */
-
- u32 saved_data_pointer; /* Saved data pointer */
-
- u32 dsa_next_addr; /* _Address_ of dsa_next field
- in this dsa for RISCy
- style constant. */
-
- u32 dsa_addr; /* Address of dsa; RISCy style
- constant */
-
- u32 dsa[0]; /* Variable length (depending
- on host type, number of scatter /
- gather buffers, etc). */
-};
-
-struct NCR53c7x0_break {
- u32 *address, old_instruction[2];
- struct NCR53c7x0_break *next;
- unsigned char old_size; /* Size of old instruction */
-};
-
-/* Indicates that the NCR is not executing code */
-#define STATE_HALTED 0
-/*
- * Indicates that the NCR is executing the wait for select / reselect
- * script. Only used when running NCR53c700 compatible scripts, only
- * state during which an ABORT is _not_ considered an error condition.
- */
-#define STATE_WAITING 1
-/* Indicates that the NCR is executing other code. */
-#define STATE_RUNNING 2
-/*
- * Indicates that the NCR was being aborted.
- */
-#define STATE_ABORTING 3
-/* Indicates that the NCR was successfully aborted. */
-#define STATE_ABORTED 4
-/* Indicates that the NCR has been disabled due to a fatal error */
-#define STATE_DISABLED 5
-
-/*
- * Where knowledge of SCSI SCRIPT(tm) specified values are needed
- * in an interrupt handler, an interrupt handler exists for each
- * different SCSI script so we don't have name space problems.
- *
- * Return values of these handlers are as follows :
- */
-#define SPECIFIC_INT_NOTHING 0 /* don't even restart */
-#define SPECIFIC_INT_RESTART 1 /* restart at the next instruction */
-#define SPECIFIC_INT_ABORT 2 /* recoverable error, abort cmd */
-#define SPECIFIC_INT_PANIC 3 /* unrecoverable error, panic */
-#define SPECIFIC_INT_DONE 4 /* normal command completion */
-#define SPECIFIC_INT_BREAK 5 /* break point encountered */
-
-struct NCR53c7x0_hostdata {
- int size; /* Size of entire Scsi_Host
- structure */
- int board; /* set to board type, useful if
- we have host specific things,
- ie, a general purpose I/O
- bit is being used to enable
- termination, etc. */
-
- int chip; /* set to chip type; 700-66 is
- 700-66, rest are last three
- digits of part number */
-
- char valid_ids[8]; /* Valid SCSI ID's for adapter */
-
- u32 *dsp; /* dsp to restart with after
- all stacked interrupts are
- handled. */
-
- unsigned dsp_changed:1; /* Has dsp changed within this
- set of stacked interrupts ? */
-
- unsigned char dstat; /* Most recent value of dstat */
- unsigned dstat_valid:1;
-
- unsigned expecting_iid:1; /* Expect IID interrupt */
- unsigned expecting_sto:1; /* Expect STO interrupt */
-
- /*
- * The code stays cleaner if we use variables with function
- * pointers and offsets that are unique for the different
- * scripts rather than having a slew of switch(hostdata->chip)
- * statements.
- *
- * It also means that the #defines from the SCSI SCRIPTS(tm)
- * don't have to be visible outside of the script-specific
- * instructions, preventing name space pollution.
- */
-
- void (* init_fixup)(struct Scsi_Host *host);
- void (* init_save_regs)(struct Scsi_Host *host);
- void (* dsa_fixup)(struct NCR53c7x0_cmd *cmd);
- void (* soft_reset)(struct Scsi_Host *host);
- int (* run_tests)(struct Scsi_Host *host);
-
- /*
- * Called when DSTAT_SIR is set, indicating an interrupt generated
- * by the INT instruction, where values are unique for each SCSI
- * script. Should return one of the SPEC_* values.
- */
-
- int (* dstat_sir_intr)(struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
-
- int dsa_len; /* Size of DSA structure */
-
- /*
- * Location of DSA fields for the SCSI SCRIPT corresponding to this
- * chip.
- */
-
- s32 dsa_start;
- s32 dsa_end;
- s32 dsa_next;
- s32 dsa_prev;
- s32 dsa_cmnd;
- s32 dsa_select;
- s32 dsa_msgout;
- s32 dsa_cmdout;
- s32 dsa_dataout;
- s32 dsa_datain;
- s32 dsa_msgin;
- s32 dsa_msgout_other;
- s32 dsa_write_sync;
- s32 dsa_write_resume;
- s32 dsa_check_reselect;
- s32 dsa_status;
- s32 dsa_saved_pointer;
- s32 dsa_jump_dest;
-
- /*
- * Important entry points that generic fixup code needs
- * to know about, fixed up.
- */
-
- s32 E_accept_message;
- s32 E_command_complete;
- s32 E_data_transfer;
- s32 E_dsa_code_template;
- s32 E_dsa_code_template_end;
- s32 E_end_data_transfer;
- s32 E_msg_in;
- s32 E_initiator_abort;
- s32 E_other_transfer;
- s32 E_other_in;
- s32 E_other_out;
- s32 E_target_abort;
- s32 E_debug_break;
- s32 E_reject_message;
- s32 E_respond_message;
- s32 E_select;
- s32 E_select_msgout;
- s32 E_test_0;
- s32 E_test_1;
- s32 E_test_2;
- s32 E_test_3;
- s32 E_dsa_zero;
- s32 E_cmdout_cmdout;
- s32 E_wait_reselect;
- s32 E_dsa_code_begin;
-
- long long options; /* Bitfielded set of options enabled */
- volatile u32 test_completed; /* Test completed */
- int test_running; /* Test currently running */
- s32 test_source
- __attribute__ ((aligned (4)));
- volatile s32 test_dest;
-
- volatile int state; /* state of driver, only used for
- OPTION_700 */
-
- unsigned char dmode; /*
- * set to the address of the DMODE
- * register for this chip.
- */
- unsigned char istat; /*
- * set to the address of the ISTAT
- * register for this chip.
- */
-
- int scsi_clock; /*
- * SCSI clock in HZ. 0 may be used
- * for unknown, although this will
- * disable synchronous negotiation.
- */
-
- volatile int intrs; /* Number of interrupts */
- volatile int resets; /* Number of SCSI resets */
- unsigned char saved_dmode;
- unsigned char saved_ctest4;
- unsigned char saved_ctest7;
- unsigned char saved_dcntl;
- unsigned char saved_scntl3;
-
- unsigned char this_id_mask;
-
- /* Debugger information */
- struct NCR53c7x0_break *breakpoints, /* Linked list of all break points */
- *breakpoint_current; /* Current breakpoint being stepped
- through, NULL if we are running
- normally. */
-#ifdef NCR_DEBUG
- int debug_size; /* Size of debug buffer */
- volatile int debug_count; /* Current data count */
- volatile char *debug_buf; /* Output ring buffer */
- volatile char *debug_write; /* Current write pointer */
- volatile char *debug_read; /* Current read pointer */
-#endif /* def NCR_DEBUG */
-
- /* XXX - primitive debugging junk, remove when working ? */
- int debug_print_limit; /* Number of commands to print
- out exhaustive debugging
- information for if
- OPTION_DEBUG_DUMP is set */
-
- unsigned char debug_lun_limit[16]; /* If OPTION_DEBUG_TARGET_LIMIT
- set, puke if commands are sent
- to other target/lun combinations */
-
- int debug_count_limit; /* Number of commands to execute
- before puking to limit debugging
- output */
-
-
- volatile unsigned idle:1; /* set to 1 if idle */
-
- /*
- * Table of synchronous+wide transfer parameters set on a per-target
- * basis.
- */
-
- volatile struct NCR53c7x0_synchronous sync[16]
- __attribute__ ((aligned (4)));
-
- volatile Scsi_Cmnd *issue_queue
- __attribute__ ((aligned (4)));
- /* waiting to be issued by
- Linux driver */
- volatile struct NCR53c7x0_cmd *running_list;
- /* commands running, maintained
- by Linux driver */
-
- volatile struct NCR53c7x0_cmd *ncrcurrent; /* currently connected
- nexus, ONLY valid for
- NCR53c700/NCR53c700-66
- */
-
- volatile struct NCR53c7x0_cmd *spare; /* pointer to spare,
- allocated at probe time,
- which we can use for
- initialization */
- volatile struct NCR53c7x0_cmd *free;
- int max_cmd_size; /* Maximum size of NCR53c7x0_cmd
- based on number of
- scatter/gather segments, etc.
- */
- volatile int num_cmds; /* Number of commands
- allocated */
- volatile int extra_allocate;
- volatile unsigned char cmd_allocated[16]; /* Have we allocated commands
- for this target yet? If not,
- do so ASAP */
- volatile unsigned char busy[16][8]; /* number of commands
- executing on each target
- */
- /*
- * Eventually, I'll switch to a coroutine for calling
- * cmd->done(cmd), etc. so that we can overlap interrupt
- * processing with this code for maximum performance.
- */
-
- volatile struct NCR53c7x0_cmd *finished_queue;
-
- /* Shared variables between SCRIPT and host driver */
- volatile u32 *schedule
- __attribute__ ((aligned (4))); /* Array of JUMPs to dsa_begin
- routines of various DSAs.
- When not in use, replace
- with jump to next slot */
-
-
- volatile unsigned char msg_buf[16]; /* buffer for messages
- other than the command
- complete message */
-
- /* Per-target default synchronous and WIDE messages */
- volatile unsigned char synchronous_want[16][5];
- volatile unsigned char wide_want[16][4];
-
- /* Bit fielded set of targets we want to speak synchronously with */
- volatile u16 initiate_sdtr;
- /* Bit fielded set of targets we want to speak wide with */
- volatile u16 initiate_wdtr;
- /* Bit fielded list of targets we've talked to. */
- volatile u16 talked_to;
-
- /* Array of bit-fielded lun lists that we need to request_sense */
- volatile unsigned char request_sense[16];
-
- u32 addr_reconnect_dsa_head
- __attribute__ ((aligned (4))); /* RISCy style constant,
- address of following */
- volatile u32 reconnect_dsa_head;
- /* Data identifying nexus we are trying to match during reselection */
- volatile unsigned char reselected_identify; /* IDENTIFY message */
- volatile unsigned char reselected_tag; /* second byte of queue tag
- message or 0 */
-
- /* These were static variables before we moved them */
-
- s32 NCR53c7xx_zero
- __attribute__ ((aligned (4)));
- s32 NCR53c7xx_sink;
- u32 NOP_insn;
- char NCR53c7xx_msg_reject;
- char NCR53c7xx_msg_abort;
- char NCR53c7xx_msg_nop;
-
- /*
- * Following item introduced by RGH to support NCRc710, which is
- * VERY brain-dead when it come to memory moves
- */
-
- /* DSA save area used only by the NCR chip */
- volatile unsigned long saved2_dsa
- __attribute__ ((aligned (4)));
-
- volatile unsigned long emulated_intfly
- __attribute__ ((aligned (4)));
-
- volatile int event_size, event_index;
- volatile struct NCR53c7x0_event *events;
-
- /* If we need to generate code to kill off the currently connected
- command, this is where we do it. Should have a BMI instruction
- to source or sink the current data, followed by a JUMP
- to abort_connected */
-
- u32 *abort_script;
-
- int script_count; /* Size of script in words */
- u32 script[0]; /* Relocated SCSI script */
-
-};
-
-#define SCSI_IRQ_NONE 255
-#define DMA_NONE 255
-#define IRQ_AUTO 254
-#define DMA_AUTO 254
-
-#define BOARD_GENERIC 0
-
-#define NCR53c7x0_insn_size(insn) \
- (((insn) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI ? 3 : 2)
-
-
-#define NCR53c7x0_local_declare() \
- volatile unsigned char *NCR53c7x0_address_memory; \
- unsigned int NCR53c7x0_address_io; \
- int NCR53c7x0_memory_mapped
-
-#define NCR53c7x0_local_setup(host) \
- NCR53c7x0_address_memory = (void *) (host)->base; \
- NCR53c7x0_address_io = (unsigned int) (host)->io_port; \
- NCR53c7x0_memory_mapped = ((struct NCR53c7x0_hostdata *) \
- host->hostdata[0])-> options & OPTION_MEMORY_MAPPED
-
-#ifdef BIG_ENDIAN
-/* These could be more efficient, given that we are always memory mapped,
- * but they don't give the same problems as the write macros, so leave
- * them. */
-#ifdef __mc68000__
-#define NCR53c7x0_read8(address) \
- ((unsigned int)raw_inb((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) )
-
-#define NCR53c7x0_read16(address) \
- ((unsigned int)raw_inw((u32)NCR53c7x0_address_memory + ((u32)(address)^2)))
-#else
-#define NCR53c7x0_read8(address) \
- (NCR53c7x0_memory_mapped ? \
- (unsigned int)readb((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) : \
- inb(NCR53c7x0_address_io + (address)))
-
-#define NCR53c7x0_read16(address) \
- (NCR53c7x0_memory_mapped ? \
- (unsigned int)readw((u32)NCR53c7x0_address_memory + ((u32)(address)^2)) : \
- inw(NCR53c7x0_address_io + (address)))
-#endif /* mc68000 */
-#else
-#define NCR53c7x0_read8(address) \
- (NCR53c7x0_memory_mapped ? \
- (unsigned int)readb((u32)NCR53c7x0_address_memory + (u32)(address)) : \
- inb(NCR53c7x0_address_io + (address)))
-
-#define NCR53c7x0_read16(address) \
- (NCR53c7x0_memory_mapped ? \
- (unsigned int)readw((u32)NCR53c7x0_address_memory + (u32)(address)) : \
- inw(NCR53c7x0_address_io + (address)))
-#endif
-
-#ifdef __mc68000__
-#define NCR53c7x0_read32(address) \
- ((unsigned int) raw_inl((u32)NCR53c7x0_address_memory + (u32)(address)))
-#else
-#define NCR53c7x0_read32(address) \
- (NCR53c7x0_memory_mapped ? \
- (unsigned int) readl((u32)NCR53c7x0_address_memory + (u32)(address)) : \
- inl(NCR53c7x0_address_io + (address)))
-#endif /* mc68000*/
-
-#ifdef BIG_ENDIAN
-/* If we are big-endian, then we are not Intel, so probably don't have
- * an i/o map as well as a memory map. So, let's assume memory mapped.
- * Also, I am having terrible problems trying to persuade the compiler
- * not to lay down code which does a read after write for these macros.
- * If you remove 'volatile' from writeb() and friends it is ok....
- */
-
-#define NCR53c7x0_write8(address,value) \
- *(volatile unsigned char *) \
- ((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) = (value)
-
-#define NCR53c7x0_write16(address,value) \
- *(volatile unsigned short *) \
- ((u32)NCR53c7x0_address_memory + ((u32)(address)^2)) = (value)
-
-#define NCR53c7x0_write32(address,value) \
- *(volatile unsigned long *) \
- ((u32)NCR53c7x0_address_memory + ((u32)(address))) = (value)
-
-#else
-
-#define NCR53c7x0_write8(address,value) \
- (NCR53c7x0_memory_mapped ? \
- ({writeb((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) : \
- outb((value), NCR53c7x0_address_io + (address)))
-
-#define NCR53c7x0_write16(address,value) \
- (NCR53c7x0_memory_mapped ? \
- ({writew((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) : \
- outw((value), NCR53c7x0_address_io + (address)))
-
-#define NCR53c7x0_write32(address,value) \
- (NCR53c7x0_memory_mapped ? \
- ({writel((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) : \
- outl((value), NCR53c7x0_address_io + (address)))
-
-#endif
-
-/* Patch arbitrary 32 bit words in the script */
-#define patch_abs_32(script, offset, symbol, value) \
- for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
- (u32)); ++i) { \
- (script)[A_##symbol##_used[i] - (offset)] += (value); \
- if (hostdata->options & OPTION_DEBUG_FIXUP) \
- printk("scsi%d : %s reference %d at 0x%x in %s is now 0x%x\n",\
- host->host_no, #symbol, i, A_##symbol##_used[i] - \
- (int)(offset), #script, (script)[A_##symbol##_used[i] - \
- (offset)]); \
- }
-
-/* Patch read/write instruction immediate field */
-#define patch_abs_rwri_data(script, offset, symbol, value) \
- for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
- (u32)); ++i) \
- (script)[A_##symbol##_used[i] - (offset)] = \
- ((script)[A_##symbol##_used[i] - (offset)] & \
- ~DBC_RWRI_IMMEDIATE_MASK) | \
- (((value) << DBC_RWRI_IMMEDIATE_SHIFT) & \
- DBC_RWRI_IMMEDIATE_MASK)
-
-/* Patch transfer control instruction data field */
-#define patch_abs_tci_data(script, offset, symbol, value) \
- for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
- (u32)); ++i) \
- (script)[A_##symbol##_used[i] - (offset)] = \
- ((script)[A_##symbol##_used[i] - (offset)] & \
- ~DBC_TCI_DATA_MASK) | \
- (((value) << DBC_TCI_DATA_SHIFT) & \
- DBC_TCI_DATA_MASK)
-
-/* Patch field in dsa structure (assignment should be +=?) */
-#define patch_dsa_32(dsa, symbol, word, value) \
- { \
- (dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(u32) \
- + (word)] = (value); \
- if (hostdata->options & OPTION_DEBUG_DSA) \
- printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n", \
- #dsa, #symbol, hostdata->##symbol, \
- (word), (u32) (value)); \
- }
-
-/* Paranoid people could use panic() here. */
-#define FATAL(host) shutdown((host));
-
-extern int ncr53c7xx_init(struct scsi_host_template *tpnt, int board, int chip,
- unsigned long base, int io_port, int irq, int dma,
- long long options, int clock);
-
-#endif /* NCR53c710_C */
-#endif /* NCR53c710_H */
diff --git a/drivers/scsi/53c7xx.scr b/drivers/scsi/53c7xx.scr
deleted file mode 100644
index 9c5694a..0000000
--- a/drivers/scsi/53c7xx.scr
+++ /dev/null
@@ -1,1591 +0,0 @@
-#undef DEBUG
-#undef EVENTS
-#undef NO_SELECTION_TIMEOUT
-#define BIG_ENDIAN
-
-; 53c710 driver. Modified from Drew Eckhardts driver
-; for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
-;
-; I have left the script for the 53c8xx family in here, as it is likely
-; to be useful to see what I changed when bug hunting.
-
-; NCR 53c810 driver, main script
-; Sponsored by
-; iX Multiuser Multitasking Magazine
-; hm@ix.de
-;
-; Copyright 1993, 1994, 1995 Drew Eckhardt
-; Visionary Computing
-; (Unix and Linux consulting and custom programming)
-; drew@PoohSticks.ORG
-; +1 (303) 786-7975
-;
-; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
-;
-; PRE-ALPHA
-;
-; For more information, please consult
-;
-; NCR 53C810
-; PCI-SCSI I/O Processor
-; Data Manual
-;
-; NCR 53C710
-; SCSI I/O Processor
-; Programmers Guide
-;
-; NCR Microelectronics
-; 1635 Aeroplaza Drive
-; Colorado Springs, CO 80916
-; 1+ (719) 578-3400
-;
-; Toll free literature number
-; +1 (800) 334-5454
-;
-; IMPORTANT : This code is self modifying due to the limitations of
-; the NCR53c7,8xx series chips. Persons debugging this code with
-; the remote debugger should take this into account, and NOT set
-; breakpoints in modified instructions.
-;
-; Design:
-; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard
-; microcontroller using a simple instruction set.
-;
-; So, to minimize the effects of interrupt latency, and to maximize
-; throughput, this driver offloads the practical maximum amount
-; of processing to the SCSI chip while still maintaining a common
-; structure.
-;
-; Where tradeoffs were needed between efficiency on the older
-; chips and the newer NCR53c800 series, the NCR53c800 series
-; was chosen.
-;
-; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully
-; automate SCSI transfers without host processor intervention, this
-; isn't the case with the NCR53c710 and newer chips which allow
-;
-; - reads and writes to the internal registers from within the SCSI
-; scripts, allowing the SCSI SCRIPTS(tm) code to save processor
-; state so that multiple threads of execution are possible, and also
-; provide an ALU for loop control, etc.
-;
-; - table indirect addressing for some instructions. This allows
-; pointers to be located relative to the DSA ((Data Structure
-; Address) register.
-;
-; These features make it possible to implement a mailbox style interface,
-; where the same piece of code is run to handle I/O for multiple threads
-; at once minimizing our need to relocate code. Since the NCR53c700/
-; NCR53c800 series have a unique combination of features, making a
-; a standard ingoing/outgoing mailbox system, costly, I've modified it.
-;
-; - Mailboxes are a mixture of code and data. This lets us greatly
-; simplify the NCR53c810 code and do things that would otherwise
-; not be possible.
-;
-; The saved data pointer is now implemented as follows :
-;
-; Control flow has been architected such that if control reaches
-; munge_save_data_pointer, on a restore pointers message or
-; reconnection, a jump to the address formerly in the TEMP register
-; will allow the SCSI command to resume execution.
-;
-
-;
-; Note : the DSA structures must be aligned on 32 bit boundaries,
-; since the source and destination of MOVE MEMORY instructions
-; must share the same alignment and this is the alignment of the
-; NCR registers.
-;
-
-; For some systems (MVME166, for example) dmode is always the same, so don't
-; waste time writing it
-
-#if 1
-#define DMODE_MEMORY_TO_NCR
-#define DMODE_MEMORY_TO_MEMORY
-#define DMODE_NCR_TO_MEMORY
-#else
-#define DMODE_MEMORY_TO_NCR MOVE dmode_memory_to_ncr TO DMODE
-#define DMODE_MEMORY_TO_MEMORY MOVE dmode_memory_to_memory TO DMODE
-#define DMODE_NCR_TO_MEMORY MOVE dmode_ncr_to_memory TO DMODE
-#endif
-
-ABSOLUTE dsa_temp_lun = 0 ; Patch to lun for current dsa
-ABSOLUTE dsa_temp_next = 0 ; Patch to dsa next for current dsa
-ABSOLUTE dsa_temp_addr_next = 0 ; Patch to address of dsa next address
- ; for current dsa
-ABSOLUTE dsa_temp_sync = 0 ; Patch to address of per-target
- ; sync routine
-ABSOLUTE dsa_sscf_710 = 0 ; Patch to address of per-target
- ; sscf value (53c710)
-ABSOLUTE dsa_temp_target = 0 ; Patch to id for current dsa
-ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command
- ; saved data pointer
-ABSOLUTE dsa_temp_addr_residual = 0 ; Patch to address of per-command
- ; current residual code
-ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command
- ; saved residual code
-ABSOLUTE dsa_temp_addr_new_value = 0 ; Address of value for JUMP operand
-ABSOLUTE dsa_temp_addr_array_value = 0 ; Address to copy to
-ABSOLUTE dsa_temp_addr_dsa_value = 0 ; Address of this DSA value
-
-;
-; Once a device has initiated reselection, we need to compare it
-; against the singly linked list of commands which have disconnected
-; and are pending reselection. These commands are maintained in
-; an unordered singly linked list of DSA structures, through the
-; DSA pointers at their 'centers' headed by the reconnect_dsa_head
-; pointer.
-;
-; To avoid complications in removing commands from the list,
-; I minimize the amount of expensive (at eight operations per
-; addition @ 500-600ns each) pointer operations which must
-; be done in the NCR driver by precomputing them on the
-; host processor during dsa structure generation.
-;
-; The fixed-up per DSA code knows how to recognize the nexus
-; associated with the corresponding SCSI command, and modifies
-; the source and destination pointers for the MOVE MEMORY
-; instruction which is executed when reselected_ok is called
-; to remove the command from the list. Similarly, DSA is
-; loaded with the address of the next DSA structure and
-; reselected_check_next is called if a failure occurs.
-;
-; Perhaps more concisely, the net effect of the mess is
-;
-; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head,
-; src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) {
-; src = &dsa->next;
-; if (target_id == dsa->id && target_lun == dsa->lun) {
-; *dest = *src;
-; break;
-; }
-; }
-;
-; if (!dsa)
-; error (int_err_unexpected_reselect);
-; else
-; longjmp (dsa->jump_resume, 0);
-;
-;
-
-#if (CHIP != 700) && (CHIP != 70066)
-; Define DSA structure used for mailboxes
-ENTRY dsa_code_template
-dsa_code_template:
-ENTRY dsa_code_begin
-dsa_code_begin:
-; RGH: Don't care about TEMP and DSA here
- DMODE_MEMORY_TO_NCR
- MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch
- DMODE_MEMORY_TO_MEMORY
-#if (CHIP == 710)
- MOVE MEMORY 4, addr_scratch, saved_dsa
- ; We are about to go and select the device, so must set SSCF bits
- MOVE MEMORY 4, dsa_sscf_710, addr_scratch
-#ifdef BIG_ENDIAN
- MOVE SCRATCH3 TO SFBR
-#else
- MOVE SCRATCH0 TO SFBR
-#endif
- MOVE SFBR TO SBCL
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#else
- CALL scratch_to_dsa
-#endif
- CALL select
-; Handle the phase mismatch which may have resulted from the
-; MOVE FROM dsa_msgout if we returned here. The CLEAR ATN
-; may or may not be necessary, and we should update script_asm.pl
-; to handle multiple pieces.
- CLEAR ATN
- CLEAR ACK
-
-; Replace second operand with address of JUMP instruction dest operand
-; in schedule table for this DSA. Becomes dsa_jump_dest in 53c7,8xx.c.
-ENTRY dsa_code_fix_jump
-dsa_code_fix_jump:
- MOVE MEMORY 4, NOP_insn, 0
- JUMP select_done
-
-; wrong_dsa loads the DSA register with the value of the dsa_next
-; field.
-;
-wrong_dsa:
-#if (CHIP == 710)
-; NOTE DSA is corrupt when we arrive here!
-#endif
-; Patch the MOVE MEMORY INSTRUCTION such that
-; the destination address is the address of the OLD
-; next pointer.
-;
- MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 8
- DMODE_MEMORY_TO_NCR
-;
-; Move the _contents_ of the next pointer into the DSA register as
-; the next I_T_L or I_T_L_Q tupple to check against the established
-; nexus.
-;
- MOVE MEMORY 4, dsa_temp_next, addr_scratch
- DMODE_MEMORY_TO_MEMORY
-#if (CHIP == 710)
- MOVE MEMORY 4, addr_scratch, saved_dsa
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#else
- CALL scratch_to_dsa
-#endif
- JUMP reselected_check_next
-
-ABSOLUTE dsa_save_data_pointer = 0
-ENTRY dsa_code_save_data_pointer
-dsa_code_save_data_pointer:
-#if (CHIP == 710)
- ; When we get here, TEMP has been saved in jump_temp+4, DSA is corrupt
- ; We MUST return with DSA correct
- MOVE MEMORY 4, jump_temp+4, dsa_temp_addr_saved_pointer
-; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
- MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
- CLEAR ACK
-#ifdef DEBUG
- INT int_debug_saved
-#endif
- MOVE MEMORY 4, saved_dsa, addr_dsa
- JUMP jump_temp
-#else
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_temp, dsa_temp_addr_saved_pointer
- DMODE_MEMORY_TO_MEMORY
-; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
- MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
- CLEAR ACK
-#ifdef DEBUG
- INT int_debug_saved
-#endif
- RETURN
-#endif
-ABSOLUTE dsa_restore_pointers = 0
-ENTRY dsa_code_restore_pointers
-dsa_code_restore_pointers:
-#if (CHIP == 710)
- ; TEMP and DSA are corrupt when we get here, but who cares!
- MOVE MEMORY 4, dsa_temp_addr_saved_pointer, jump_temp + 4
-; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
- MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
- CLEAR ACK
- ; Restore DSA, note we don't care about TEMP
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#ifdef DEBUG
- INT int_debug_restored
-#endif
- JUMP jump_temp
-#else
- DMODE_MEMORY_TO_NCR
- MOVE MEMORY 4, dsa_temp_addr_saved_pointer, addr_temp
- DMODE_MEMORY_TO_MEMORY
-; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
- MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
- CLEAR ACK
-#ifdef DEBUG
- INT int_debug_restored
-#endif
- RETURN
-#endif
-
-ABSOLUTE dsa_check_reselect = 0
-; dsa_check_reselect determines whether or not the current target and
-; lun match the current DSA
-ENTRY dsa_code_check_reselect
-dsa_code_check_reselect:
-#if (CHIP == 710)
- /* Arrives here with DSA correct */
- /* Assumes we are always ID 7 */
- MOVE LCRC TO SFBR ; LCRC has our ID and his ID bits set
- JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0x80
-#else
- MOVE SSID TO SFBR ; SSID contains 3 bit target ID
-; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
- JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0xf8
-#endif
-;
-; Hack - move to scratch first, since SFBR is not writeable
-; via the CPU and hence a MOVE MEMORY instruction.
-;
- DMODE_MEMORY_TO_NCR
- MOVE MEMORY 1, reselected_identify, addr_scratch
- DMODE_MEMORY_TO_MEMORY
-#ifdef BIG_ENDIAN
- ; BIG ENDIAN ON MVME16x
- MOVE SCRATCH3 TO SFBR
-#else
- MOVE SCRATCH0 TO SFBR
-#endif
-; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
-; Are you sure about that? richard@sleepie.demon.co.uk
- JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8
-; Patch the MOVE MEMORY INSTRUCTION such that
-; the source address is the address of this dsa's
-; next pointer.
- MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 4
- CALL reselected_ok
-#if (CHIP == 710)
-; Restore DSA following memory moves in reselected_ok
-; dsa_temp_sync doesn't really care about DSA, but it has an
-; optional debug INT so a valid DSA is a good idea.
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
- CALL dsa_temp_sync
-; Release ACK on the IDENTIFY message _after_ we've set the synchronous
-; transfer parameters!
- CLEAR ACK
-; Implicitly restore pointers on reselection, so a RETURN
-; will transfer control back to the right spot.
- CALL REL (dsa_code_restore_pointers)
- RETURN
-ENTRY dsa_zero
-dsa_zero:
-ENTRY dsa_code_template_end
-dsa_code_template_end:
-
-; Perform sanity check for dsa_fields_start == dsa_code_template_end -
-; dsa_zero, puke.
-
-ABSOLUTE dsa_fields_start = 0 ; Sanity marker
- ; pad 48 bytes (fix this RSN)
-ABSOLUTE dsa_next = 48 ; len 4 Next DSA
- ; del 4 Previous DSA address
-ABSOLUTE dsa_cmnd = 56 ; len 4 Scsi_Cmnd * for this thread.
-ABSOLUTE dsa_select = 60 ; len 4 Device ID, Period, Offset for
- ; table indirect select
-ABSOLUTE dsa_msgout = 64 ; len 8 table indirect move parameter for
- ; select message
-ABSOLUTE dsa_cmdout = 72 ; len 8 table indirect move parameter for
- ; command
-ABSOLUTE dsa_dataout = 80 ; len 4 code pointer for dataout
-ABSOLUTE dsa_datain = 84 ; len 4 code pointer for datain
-ABSOLUTE dsa_msgin = 88 ; len 8 table indirect move for msgin
-ABSOLUTE dsa_status = 96 ; len 8 table indirect move for status byte
-ABSOLUTE dsa_msgout_other = 104 ; len 8 table indirect for normal message out
- ; (Synchronous transfer negotiation, etc).
-ABSOLUTE dsa_end = 112
-
-ABSOLUTE schedule = 0 ; Array of JUMP dsa_begin or JUMP (next),
- ; terminated by a call to JUMP wait_reselect
-
-; Linked lists of DSA structures
-ABSOLUTE reconnect_dsa_head = 0 ; Link list of DSAs which can reconnect
-ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing
- ; address of reconnect_dsa_head
-
-; These select the source and destination of a MOVE MEMORY instruction
-ABSOLUTE dmode_memory_to_memory = 0x0
-ABSOLUTE dmode_memory_to_ncr = 0x0
-ABSOLUTE dmode_ncr_to_memory = 0x0
-
-ABSOLUTE addr_scratch = 0x0
-ABSOLUTE addr_temp = 0x0
-#if (CHIP == 710)
-ABSOLUTE saved_dsa = 0x0
-ABSOLUTE emulfly = 0x0
-ABSOLUTE addr_dsa = 0x0
-#endif
-#endif /* CHIP != 700 && CHIP != 70066 */
-
-; Interrupts -
-; MSB indicates type
-; 0 handle error condition
-; 1 handle message
-; 2 handle normal condition
-; 3 debugging interrupt
-; 4 testing interrupt
-; Next byte indicates specific error
-
-; XXX not yet implemented, I'm not sure if I want to -
-; Next byte indicates the routine the error occurred in
-; The LSB indicates the specific place the error occurred
-
-ABSOLUTE int_err_unexpected_phase = 0x00000000 ; Unexpected phase encountered
-ABSOLUTE int_err_selected = 0x00010000 ; SELECTED (nee RESELECTED)
-ABSOLUTE int_err_unexpected_reselect = 0x00020000
-ABSOLUTE int_err_check_condition = 0x00030000
-ABSOLUTE int_err_no_phase = 0x00040000
-ABSOLUTE int_msg_wdtr = 0x01000000 ; WDTR message received
-ABSOLUTE int_msg_sdtr = 0x01010000 ; SDTR received
-ABSOLUTE int_msg_1 = 0x01020000 ; single byte special message
- ; received
-
-ABSOLUTE int_norm_select_complete = 0x02000000 ; Select complete, reprogram
- ; registers.
-ABSOLUTE int_norm_reselect_complete = 0x02010000 ; Nexus established
-ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete
-ABSOLUTE int_norm_disconnected = 0x02030000 ; Disconnected
-ABSOLUTE int_norm_aborted =0x02040000 ; Aborted *dsa
-ABSOLUTE int_norm_reset = 0x02050000 ; Generated BUS reset.
-ABSOLUTE int_norm_emulateintfly = 0x02060000 ; 53C710 Emulated intfly
-ABSOLUTE int_debug_break = 0x03000000 ; Break point
-#ifdef DEBUG
-ABSOLUTE int_debug_scheduled = 0x03010000 ; new I/O scheduled
-ABSOLUTE int_debug_idle = 0x03020000 ; scheduler is idle
-ABSOLUTE int_debug_dsa_loaded = 0x03030000 ; dsa reloaded
-ABSOLUTE int_debug_reselected = 0x03040000 ; NCR reselected
-ABSOLUTE int_debug_head = 0x03050000 ; issue head overwritten
-ABSOLUTE int_debug_disconnected = 0x03060000 ; disconnected
-ABSOLUTE int_debug_disconnect_msg = 0x03070000 ; got message to disconnect
-ABSOLUTE int_debug_dsa_schedule = 0x03080000 ; in dsa_schedule
-ABSOLUTE int_debug_reselect_check = 0x03090000 ; Check for reselection of DSA
-ABSOLUTE int_debug_reselected_ok = 0x030a0000 ; Reselection accepted
-#endif
-ABSOLUTE int_debug_panic = 0x030b0000 ; Panic driver
-#ifdef DEBUG
-ABSOLUTE int_debug_saved = 0x030c0000 ; save/restore pointers
-ABSOLUTE int_debug_restored = 0x030d0000
-ABSOLUTE int_debug_sync = 0x030e0000 ; Sanity check synchronous
- ; parameters.
-ABSOLUTE int_debug_datain = 0x030f0000 ; going into data in phase
- ; now.
-ABSOLUTE int_debug_check_dsa = 0x03100000 ; Sanity check DSA against
- ; SDID.
-#endif
-
-ABSOLUTE int_test_1 = 0x04000000 ; Test 1 complete
-ABSOLUTE int_test_2 = 0x04010000 ; Test 2 complete
-ABSOLUTE int_test_3 = 0x04020000 ; Test 3 complete
-
-
-; These should start with 0x05000000, with low bits incrementing for
-; each one.
-
-#ifdef EVENTS
-ABSOLUTE int_EVENT_SELECT = 0
-ABSOLUTE int_EVENT_DISCONNECT = 0
-ABSOLUTE int_EVENT_RESELECT = 0
-ABSOLUTE int_EVENT_COMPLETE = 0
-ABSOLUTE int_EVENT_IDLE = 0
-ABSOLUTE int_EVENT_SELECT_FAILED = 0
-ABSOLUTE int_EVENT_BEFORE_SELECT = 0
-ABSOLUTE int_EVENT_RESELECT_FAILED = 0
-#endif
-
-ABSOLUTE NCR53c7xx_msg_abort = 0 ; Pointer to abort message
-ABSOLUTE NCR53c7xx_msg_reject = 0 ; Pointer to reject message
-ABSOLUTE NCR53c7xx_zero = 0 ; long with zero in it, use for source
-ABSOLUTE NCR53c7xx_sink = 0 ; long to dump worthless data in
-ABSOLUTE NOP_insn = 0 ; NOP instruction
-
-; Pointer to message, potentially multi-byte
-ABSOLUTE msg_buf = 0
-
-; Pointer to holding area for reselection information
-ABSOLUTE reselected_identify = 0
-ABSOLUTE reselected_tag = 0
-
-; Request sense command pointer, it's a 6 byte command, should
-; be constant for all commands since we always want 16 bytes of
-; sense and we don't need to change any fields as we did under
-; SCSI-I when we actually cared about the LUN field.
-;EXTERNAL NCR53c7xx_sense ; Request sense command
-
-#if (CHIP != 700) && (CHIP != 70066)
-; dsa_schedule
-; PURPOSE : after a DISCONNECT message has been received, and pointers
-; saved, insert the current DSA structure at the head of the
-; disconnected queue and fall through to the scheduler.
-;
-; CALLS : OK
-;
-; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list
-; of disconnected commands
-;
-; MODIFIES : SCRATCH, reconnect_dsa_head
-;
-; EXITS : always passes control to schedule
-
-ENTRY dsa_schedule
-dsa_schedule:
-#ifdef DEBUG
- INT int_debug_dsa_schedule
-#endif
-
-;
-; Calculate the address of the next pointer within the DSA
-; structure of the command that is currently disconnecting
-;
-#if (CHIP == 710)
- ; Read what should be the current DSA from memory - actual DSA
- ; register is probably corrupt
- MOVE MEMORY 4, saved_dsa, addr_scratch
-#else
- CALL dsa_to_scratch
-#endif
- MOVE SCRATCH0 + dsa_next TO SCRATCH0
- MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
- MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
- MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
-
-; Point the next field of this DSA structure at the current disconnected
-; list
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8
- DMODE_MEMORY_TO_MEMORY
-dsa_schedule_insert:
- MOVE MEMORY 4, reconnect_dsa_head, 0
-
-; And update the head pointer.
-#if (CHIP == 710)
- ; Read what should be the current DSA from memory - actual DSA
- ; register is probably corrupt
- MOVE MEMORY 4, saved_dsa, addr_scratch
-#else
- CALL dsa_to_scratch
-#endif
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, reconnect_dsa_head
- DMODE_MEMORY_TO_MEMORY
-/* Temporarily, see what happens. */
-#ifndef ORIGINAL
-#if (CHIP != 710)
- MOVE SCNTL2 & 0x7f TO SCNTL2
-#endif
- CLEAR ACK
-#endif
-#if (CHIP == 710)
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
- WAIT DISCONNECT
-#ifdef EVENTS
- INT int_EVENT_DISCONNECT;
-#endif
-#ifdef DEBUG
- INT int_debug_disconnected
-#endif
- JUMP schedule
-#endif
-
-;
-; select
-;
-; PURPOSE : establish a nexus for the SCSI command referenced by DSA.
-; On success, the current DSA structure is removed from the issue
-; queue. Usually, this is entered as a fall-through from schedule,
-; although the contingent allegiance handling code will write
-; the select entry address to the DSP to restart a command as a
-; REQUEST SENSE. A message is sent (usually IDENTIFY, although
-; additional SDTR or WDTR messages may be sent). COMMAND OUT
-; is handled.
-;
-; INPUTS : DSA - SCSI command, issue_dsa_head
-;
-; CALLS : NOT OK
-;
-; MODIFIES : SCRATCH, issue_dsa_head
-;
-; EXITS : on reselection or selection, go to select_failed
-; otherwise, RETURN so control is passed back to
-; dsa_begin.
-;
-
-ENTRY select
-select:
-
-#ifdef EVENTS
- INT int_EVENT_BEFORE_SELECT
-#endif
-
-#ifdef DEBUG
- INT int_debug_scheduled
-#endif
- CLEAR TARGET
-
-; XXX
-;
-; In effect, SELECTION operations are backgrounded, with execution
-; continuing until code which waits for REQ or a fatal interrupt is
-; encountered.
-;
-; So, for more performance, we could overlap the code which removes
-; the command from the NCRs issue queue with the selection, but
-; at this point I don't want to deal with the error recovery.
-;
-
-#if (CHIP != 700) && (CHIP != 70066)
-#if (CHIP == 710)
- ; Enable selection timer
-#ifdef NO_SELECTION_TIMEOUT
- MOVE CTEST7 & 0xff TO CTEST7
-#else
- MOVE CTEST7 & 0xef TO CTEST7
-#endif
-#endif
- SELECT ATN FROM dsa_select, select_failed
- JUMP select_msgout, WHEN MSG_OUT
-ENTRY select_msgout
-select_msgout:
-#if (CHIP == 710)
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-#endif
- MOVE FROM dsa_msgout, WHEN MSG_OUT
-#else
-ENTRY select_msgout
- SELECT ATN 0, select_failed
-select_msgout:
- MOVE 0, 0, WHEN MSGOUT
-#endif
-
-#ifdef EVENTS
- INT int_EVENT_SELECT
-#endif
- RETURN
-
-;
-; select_done
-;
-; PURPOSE: continue on to normal data transfer; called as the exit
-; point from dsa_begin.
-;
-; INPUTS: dsa
-;
-; CALLS: OK
-;
-;
-
-select_done:
-#if (CHIP == 710)
-; NOTE DSA is corrupt when we arrive here!
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
-
-#ifdef DEBUG
-ENTRY select_check_dsa
-select_check_dsa:
- INT int_debug_check_dsa
-#endif
-
-; After a successful selection, we should get either a CMD phase or
-; some transfer request negotiation message.
-
- JUMP cmdout, WHEN CMD
- INT int_err_unexpected_phase, WHEN NOT MSG_IN
-
-select_msg_in:
- CALL msg_in, WHEN MSG_IN
- JUMP select_msg_in, WHEN MSG_IN
-
-cmdout:
- INT int_err_unexpected_phase, WHEN NOT CMD
-#if (CHIP == 700)
- INT int_norm_selected
-#endif
-ENTRY cmdout_cmdout
-cmdout_cmdout:
-#if (CHIP != 700) && (CHIP != 70066)
- MOVE FROM dsa_cmdout, WHEN CMD
-#else
- MOVE 0, 0, WHEN CMD
-#endif /* (CHIP != 700) && (CHIP != 70066) */
-
-;
-; data_transfer
-; other_out
-; other_in
-; other_transfer
-;
-; PURPOSE : handle the main data transfer for a SCSI command in
-; several parts. In the first part, data_transfer, DATA_IN
-; and DATA_OUT phases are allowed, with the user provided
-; code (usually dynamically generated based on the scatter/gather
-; list associated with a SCSI command) called to handle these
-; phases.
-;
-; After control has passed to one of the user provided
-; DATA_IN or DATA_OUT routines, back calls are made to
-; other_transfer_in or other_transfer_out to handle non-DATA IN
-; and DATA OUT phases respectively, with the state of the active
-; data pointer being preserved in TEMP.
-;
-; On completion, the user code passes control to other_transfer
-; which causes DATA_IN and DATA_OUT to result in unexpected_phase
-; interrupts so that data overruns may be trapped.
-;
-; INPUTS : DSA - SCSI command
-;
-; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in
-; other_transfer
-;
-; MODIFIES : SCRATCH
-;
-; EXITS : if STATUS IN is detected, signifying command completion,
-; the NCR jumps to command_complete. If MSG IN occurs, a
-; CALL is made to msg_in. Otherwise, other_transfer runs in
-; an infinite loop.
-;
-
-ENTRY data_transfer
-data_transfer:
- JUMP cmdout_cmdout, WHEN CMD
- CALL msg_in, WHEN MSG_IN
- INT int_err_unexpected_phase, WHEN MSG_OUT
- JUMP do_dataout, WHEN DATA_OUT
- JUMP do_datain, WHEN DATA_IN
- JUMP command_complete, WHEN STATUS
- JUMP data_transfer
-ENTRY end_data_transfer
-end_data_transfer:
-
-;
-; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain
-; should be fixed up whenever the nexus changes so it can point to the
-; correct routine for that command.
-;
-
-#if (CHIP != 700) && (CHIP != 70066)
-; Nasty jump to dsa->dataout
-do_dataout:
-#if (CHIP == 710)
- MOVE MEMORY 4, saved_dsa, addr_scratch
-#else
- CALL dsa_to_scratch
-#endif
- MOVE SCRATCH0 + dsa_dataout TO SCRATCH0
- MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
- MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
- MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4
- DMODE_MEMORY_TO_MEMORY
-dataout_to_jump:
- MOVE MEMORY 4, 0, dataout_jump + 4
-#if (CHIP == 710)
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
-dataout_jump:
- JUMP 0
-
-; Nasty jump to dsa->dsain
-do_datain:
-#if (CHIP == 710)
- MOVE MEMORY 4, saved_dsa, addr_scratch
-#else
- CALL dsa_to_scratch
-#endif
- MOVE SCRATCH0 + dsa_datain TO SCRATCH0
- MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
- MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
- MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, datain_to_jump + 4
- DMODE_MEMORY_TO_MEMORY
-ENTRY datain_to_jump
-datain_to_jump:
- MOVE MEMORY 4, 0, datain_jump + 4
-#if (CHIP == 710)
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
-#ifdef DEBUG
- INT int_debug_datain
-#endif
-datain_jump:
- JUMP 0
-#endif /* (CHIP != 700) && (CHIP != 70066) */
-
-
-; Note that other_out and other_in loop until a non-data phase
-; is discovered, so we only execute return statements when we
-; can go on to the next data phase block move statement.
-
-ENTRY other_out
-other_out:
-#if 0
- INT 0x03ffdead
-#endif
- INT int_err_unexpected_phase, WHEN CMD
- JUMP msg_in_restart, WHEN MSG_IN
- INT int_err_unexpected_phase, WHEN MSG_OUT
- INT int_err_unexpected_phase, WHEN DATA_IN
- JUMP command_complete, WHEN STATUS
- JUMP other_out, WHEN NOT DATA_OUT
-#if (CHIP == 710)
-; TEMP should be OK, as we got here from a call in the user dataout code.
-#endif
- RETURN
-
-ENTRY other_in
-other_in:
-#if 0
- INT 0x03ffdead
-#endif
- INT int_err_unexpected_phase, WHEN CMD
- JUMP msg_in_restart, WHEN MSG_IN
- INT int_err_unexpected_phase, WHEN MSG_OUT
- INT int_err_unexpected_phase, WHEN DATA_OUT
- JUMP command_complete, WHEN STATUS
- JUMP other_in, WHEN NOT DATA_IN
-#if (CHIP == 710)
-; TEMP should be OK, as we got here from a call in the user datain code.
-#endif
- RETURN
-
-
-ENTRY other_transfer
-other_transfer:
- INT int_err_unexpected_phase, WHEN CMD
- CALL msg_in, WHEN MSG_IN
- INT int_err_unexpected_phase, WHEN MSG_OUT
- INT int_err_unexpected_phase, WHEN DATA_OUT
- INT int_err_unexpected_phase, WHEN DATA_IN
- JUMP command_complete, WHEN STATUS
- JUMP other_transfer
-
-;
-; msg_in_restart
-; msg_in
-; munge_msg
-;
-; PURPOSE : process messages from a target. msg_in is called when the
-; caller hasn't read the first byte of the message. munge_message
-; is called when the caller has read the first byte of the message,
-; and left it in SFBR. msg_in_restart is called when the caller
-; hasn't read the first byte of the message, and wishes RETURN
-; to transfer control back to the address of the conditional
-; CALL instruction rather than to the instruction after it.
-;
-; Various int_* interrupts are generated when the host system
-; needs to intervene, as is the case with SDTR, WDTR, and
-; INITIATE RECOVERY messages.
-;
-; When the host system handles one of these interrupts,
-; it can respond by reentering at reject_message,
-; which rejects the message and returns control to
-; the caller of msg_in or munge_msg, accept_message
-; which clears ACK and returns control, or reply_message
-; which sends the message pointed to by the DSA
-; msgout_other table indirect field.
-;
-; DISCONNECT messages are handled by moving the command
-; to the reconnect_dsa_queue.
-#if (CHIP == 710)
-; NOTE: DSA should be valid when we get here - we cannot save both it
-; and TEMP in this routine.
-#endif
-;
-; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg
-; only)
-;
-; CALLS : NO. The TEMP register isn't backed up to allow nested calls.
-;
-; MODIFIES : SCRATCH, DSA on DISCONNECT
-;
-; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS,
-; and normal return from message handlers running under
-; Linux, control is returned to the caller. Receipt
-; of DISCONNECT messages pass control to dsa_schedule.
-;
-ENTRY msg_in_restart
-msg_in_restart:
-; XXX - hackish
-;
-; Since it's easier to debug changes to the statically
-; compiled code, rather than the dynamically generated
-; stuff, such as
-;
-; MOVE x, y, WHEN data_phase
-; CALL other_z, WHEN NOT data_phase
-; MOVE x, y, WHEN data_phase
-;
-; I'd like to have certain routines (notably the message handler)
-; restart on the conditional call rather than the next instruction.
-;
-; So, subtract 8 from the return address
-
- MOVE TEMP0 + 0xf8 TO TEMP0
- MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY
- MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY
- MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY
-
-ENTRY msg_in
-msg_in:
- MOVE 1, msg_buf, WHEN MSG_IN
-
-munge_msg:
- JUMP munge_extended, IF 0x01 ; EXTENDED MESSAGE
- JUMP munge_2, IF 0x20, AND MASK 0xdf ; two byte message
-;
-; XXX - I've seen a handful of broken SCSI devices which fail to issue
-; a SAVE POINTERS message before disconnecting in the middle of
-; a transfer, assuming that the DATA POINTER will be implicitly
-; restored.
-;
-; Historically, I've often done an implicit save when the DISCONNECT
-; message is processed. We may want to consider having the option of
-; doing that here.
-;
- JUMP munge_save_data_pointer, IF 0x02 ; SAVE DATA POINTER
- JUMP munge_restore_pointers, IF 0x03 ; RESTORE POINTERS
- JUMP munge_disconnect, IF 0x04 ; DISCONNECT
- INT int_msg_1, IF 0x07 ; MESSAGE REJECT
- INT int_msg_1, IF 0x0f ; INITIATE RECOVERY
-#ifdef EVENTS
- INT int_EVENT_SELECT_FAILED
-#endif
- JUMP reject_message
-
-munge_2:
- JUMP reject_message
-;
-; The SCSI standard allows targets to recover from transient
-; error conditions by backing up the data pointer with a
-; RESTORE POINTERS message.
-;
-; So, we must save and restore the _residual_ code as well as
-; the current instruction pointer. Because of this messiness,
-; it is simpler to put dynamic code in the dsa for this and to
-; just do a simple jump down there.
-;
-
-munge_save_data_pointer:
-#if (CHIP == 710)
- ; We have something in TEMP here, so first we must save that
- MOVE TEMP0 TO SFBR
- MOVE SFBR TO SCRATCH0
- MOVE TEMP1 TO SFBR
- MOVE SFBR TO SCRATCH1
- MOVE TEMP2 TO SFBR
- MOVE SFBR TO SCRATCH2
- MOVE TEMP3 TO SFBR
- MOVE SFBR TO SCRATCH3
- MOVE MEMORY 4, addr_scratch, jump_temp + 4
- ; Now restore DSA
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
- MOVE DSA0 + dsa_save_data_pointer TO SFBR
- MOVE SFBR TO SCRATCH0
- MOVE DSA1 + 0xff TO SFBR WITH CARRY
- MOVE SFBR TO SCRATCH1
- MOVE DSA2 + 0xff TO SFBR WITH CARRY
- MOVE SFBR TO SCRATCH2
- MOVE DSA3 + 0xff TO SFBR WITH CARRY
- MOVE SFBR TO SCRATCH3
-
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4
- DMODE_MEMORY_TO_MEMORY
-jump_dsa_save:
- JUMP 0
-
-munge_restore_pointers:
-#if (CHIP == 710)
- ; The code at dsa_restore_pointers will RETURN, but we don't care
- ; about TEMP here, as it will overwrite it anyway.
-#endif
- MOVE DSA0 + dsa_restore_pointers TO SFBR
- MOVE SFBR TO SCRATCH0
- MOVE DSA1 + 0xff TO SFBR WITH CARRY
- MOVE SFBR TO SCRATCH1
- MOVE DSA2 + 0xff TO SFBR WITH CARRY
- MOVE SFBR TO SCRATCH2
- MOVE DSA3 + 0xff TO SFBR WITH CARRY
- MOVE SFBR TO SCRATCH3
-
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4
- DMODE_MEMORY_TO_MEMORY
-jump_dsa_restore:
- JUMP 0
-
-
-munge_disconnect:
-#ifdef DEBUG
- INT int_debug_disconnect_msg
-#endif
-
-/*
- * Before, we overlapped processing with waiting for disconnect, but
- * debugging was beginning to appear messy. Temporarily move things
- * to just before the WAIT DISCONNECT.
- */
-
-#ifdef ORIGINAL
-#if (CHIP == 710)
-; Following clears Unexpected Disconnect bit. What do we do?
-#else
- MOVE SCNTL2 & 0x7f TO SCNTL2
-#endif
- CLEAR ACK
-#endif
-
-#if (CHIP != 700) && (CHIP != 70066)
- JUMP dsa_schedule
-#else
- WAIT DISCONNECT
- INT int_norm_disconnected
-#endif
-
-munge_extended:
- CLEAR ACK
- INT int_err_unexpected_phase, WHEN NOT MSG_IN
- MOVE 1, msg_buf + 1, WHEN MSG_IN
- JUMP munge_extended_2, IF 0x02
- JUMP munge_extended_3, IF 0x03
- JUMP reject_message
-
-munge_extended_2:
- CLEAR ACK
- MOVE 1, msg_buf + 2, WHEN MSG_IN
- JUMP reject_message, IF NOT 0x02 ; Must be WDTR
- CLEAR ACK
- MOVE 1, msg_buf + 3, WHEN MSG_IN
- INT int_msg_wdtr
-
-munge_extended_3:
- CLEAR ACK
- MOVE 1, msg_buf + 2, WHEN MSG_IN
- JUMP reject_message, IF NOT 0x01 ; Must be SDTR
- CLEAR ACK
- MOVE 2, msg_buf + 3, WHEN MSG_IN
- INT int_msg_sdtr
-
-ENTRY reject_message
-reject_message:
- SET ATN
- CLEAR ACK
- MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT
- RETURN
-
-ENTRY accept_message
-accept_message:
- CLEAR ATN
- CLEAR ACK
- RETURN
-
-ENTRY respond_message
-respond_message:
- SET ATN
- CLEAR ACK
- MOVE FROM dsa_msgout_other, WHEN MSG_OUT
- RETURN
-
-;
-; command_complete
-;
-; PURPOSE : handle command termination when STATUS IN is detected by reading
-; a status byte followed by a command termination message.
-;
-; Normal termination results in an INTFLY instruction, and
-; the host system can pick out which command terminated by
-; examining the MESSAGE and STATUS buffers of all currently
-; executing commands;
-;
-; Abnormal (CHECK_CONDITION) termination results in an
-; int_err_check_condition interrupt so that a REQUEST SENSE
-; command can be issued out-of-order so that no other command
-; clears the contingent allegiance condition.
-;
-;
-; INPUTS : DSA - command
-;
-; CALLS : OK
-;
-; EXITS : On successful termination, control is passed to schedule.
-; On abnormal termination, the user will usually modify the
-; DSA fields and corresponding buffers and return control
-; to select.
-;
-
-ENTRY command_complete
-command_complete:
- MOVE FROM dsa_status, WHEN STATUS
-#if (CHIP != 700) && (CHIP != 70066)
- MOVE SFBR TO SCRATCH0 ; Save status
-#endif /* (CHIP != 700) && (CHIP != 70066) */
-ENTRY command_complete_msgin
-command_complete_msgin:
- MOVE FROM dsa_msgin, WHEN MSG_IN
-; Indicate that we should be expecting a disconnect
-#if (CHIP != 710)
- MOVE SCNTL2 & 0x7f TO SCNTL2
-#else
- ; Above code cleared the Unexpected Disconnect bit, what do we do?
-#endif
- CLEAR ACK
-#if (CHIP != 700) && (CHIP != 70066)
- WAIT DISCONNECT
-
-;
-; The SCSI specification states that when a UNIT ATTENTION condition
-; is pending, as indicated by a CHECK CONDITION status message,
-; the target shall revert to asynchronous transfers. Since
-; synchronous transfers parameters are maintained on a per INITIATOR/TARGET
-; basis, and returning control to our scheduler could work on a command
-; running on another lun on that target using the old parameters, we must
-; interrupt the host processor to get them changed, or change them ourselves.
-;
-; Once SCSI-II tagged queueing is implemented, things will be even more
-; hairy, since contingent allegiance conditions exist on a per-target/lun
-; basis, and issuing a new command with a different tag would clear it.
-; In these cases, we must interrupt the host processor to get a request
-; added to the HEAD of the queue with the request sense command, or we
-; must automatically issue the request sense command.
-
-#if 0
- MOVE SCRATCH0 TO SFBR
- JUMP command_failed, IF 0x02
-#endif
-#if (CHIP == 710)
-#if defined(MVME16x_INTFLY)
-; For MVME16x (ie CHIP=710) we will force an INTFLY by triggering a software
-; interrupt (SW7). We can use SCRATCH, as we are about to jump to
-; schedule, which corrupts it anyway. Will probably remove this later,
-; but want to check performance effects first.
-
-#define INTFLY_ADDR 0xfff40070
-
- MOVE 0 TO SCRATCH0
- MOVE 0x80 TO SCRATCH1
- MOVE 0 TO SCRATCH2
- MOVE 0 TO SCRATCH3
- MOVE MEMORY 4, addr_scratch, INTFLY_ADDR
-#else
- INT int_norm_emulateintfly
-#endif
-#else
- INTFLY
-#endif
-#endif /* (CHIP != 700) && (CHIP != 70066) */
-#if (CHIP == 710)
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
-#ifdef EVENTS
- INT int_EVENT_COMPLETE
-#endif
-#if (CHIP != 700) && (CHIP != 70066)
- JUMP schedule
-command_failed:
- INT int_err_check_condition
-#else
- INT int_norm_command_complete
-#endif
-
-;
-; wait_reselect
-;
-; PURPOSE : This is essentially the idle routine, where control lands
-; when there are no new processes to schedule. wait_reselect
-; waits for reselection, selection, and new commands.
-;
-; When a successful reselection occurs, with the aid
-; of fixed up code in each DSA, wait_reselect walks the
-; reconnect_dsa_queue, asking each dsa if the target ID
-; and LUN match its.
-;
-; If a match is found, a call is made back to reselected_ok,
-; which through the miracles of self modifying code, extracts
-; the found DSA from the reconnect_dsa_queue and then
-; returns control to the DSAs thread of execution.
-;
-; INPUTS : NONE
-;
-; CALLS : OK
-;
-; MODIFIES : DSA,
-;
-; EXITS : On successful reselection, control is returned to the
-; DSA which called reselected_ok. If the WAIT RESELECT
-; was interrupted by a new commands arrival signaled by
-; SIG_P, control is passed to schedule. If the NCR is
-; selected, the host system is interrupted with an
-; int_err_selected which is usually responded to by
-; setting DSP to the target_abort address.
-
-ENTRY wait_reselect
-wait_reselect:
-#ifdef EVENTS
- int int_EVENT_IDLE
-#endif
-#ifdef DEBUG
- int int_debug_idle
-#endif
- WAIT RESELECT wait_reselect_failed
-
-reselected:
-#ifdef EVENTS
- int int_EVENT_RESELECT
-#endif
- CLEAR TARGET
- DMODE_MEMORY_TO_MEMORY
- ; Read all data needed to reestablish the nexus -
- MOVE 1, reselected_identify, WHEN MSG_IN
- ; We used to CLEAR ACK here.
-#if (CHIP != 700) && (CHIP != 70066)
-#ifdef DEBUG
- int int_debug_reselected
-#endif
-
- ; Point DSA at the current head of the disconnected queue.
- DMODE_MEMORY_TO_NCR
- MOVE MEMORY 4, reconnect_dsa_head, addr_scratch
- DMODE_MEMORY_TO_MEMORY
-#if (CHIP == 710)
- MOVE MEMORY 4, addr_scratch, saved_dsa
-#else
- CALL scratch_to_dsa
-#endif
-
- ; Fix the update-next pointer so that the reconnect_dsa_head
- ; pointer is the one that will be updated if this DSA is a hit
- ; and we remove it from the queue.
-
- MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok_patch + 8
-#if (CHIP == 710)
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
-
-ENTRY reselected_check_next
-reselected_check_next:
-#ifdef DEBUG
- INT int_debug_reselect_check
-#endif
- ; Check for a NULL pointer.
- MOVE DSA0 TO SFBR
- JUMP reselected_not_end, IF NOT 0
- MOVE DSA1 TO SFBR
- JUMP reselected_not_end, IF NOT 0
- MOVE DSA2 TO SFBR
- JUMP reselected_not_end, IF NOT 0
- MOVE DSA3 TO SFBR
- JUMP reselected_not_end, IF NOT 0
- INT int_err_unexpected_reselect
-
-reselected_not_end:
- ;
- ; XXX the ALU is only eight bits wide, and the assembler
- ; wont do the dirt work for us. As long as dsa_check_reselect
- ; is negative, we need to sign extend with 1 bits to the full
- ; 32 bit width of the address.
- ;
- ; A potential work around would be to have a known alignment
- ; of the DSA structure such that the base address plus
- ; dsa_check_reselect doesn't require carrying from bytes
- ; higher than the LSB.
- ;
-
- MOVE DSA0 TO SFBR
- MOVE SFBR + dsa_check_reselect TO SCRATCH0
- MOVE DSA1 TO SFBR
- MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY
- MOVE DSA2 TO SFBR
- MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY
- MOVE DSA3 TO SFBR
- MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY
-
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, reselected_check + 4
- DMODE_MEMORY_TO_MEMORY
-#if (CHIP == 710)
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
-reselected_check:
- JUMP 0
-
-
-;
-;
-#if (CHIP == 710)
-; We have problems here - the memory move corrupts TEMP and DSA. This
-; routine is called from DSA code, and patched from many places. Scratch
-; is probably free when it is called.
-; We have to:
-; copy temp to scratch, one byte at a time
-; write scratch to patch a jump in place of the return
-; do the move memory
-; jump to the patched in return address
-; DSA is corrupt when we get here, and can be left corrupt
-
-ENTRY reselected_ok
-reselected_ok:
- MOVE TEMP0 TO SFBR
- MOVE SFBR TO SCRATCH0
- MOVE TEMP1 TO SFBR
- MOVE SFBR TO SCRATCH1
- MOVE TEMP2 TO SFBR
- MOVE SFBR TO SCRATCH2
- MOVE TEMP3 TO SFBR
- MOVE SFBR TO SCRATCH3
- MOVE MEMORY 4, addr_scratch, reselected_ok_jump + 4
-reselected_ok_patch:
- MOVE MEMORY 4, 0, 0
-reselected_ok_jump:
- JUMP 0
-#else
-ENTRY reselected_ok
-reselected_ok:
-reselected_ok_patch:
- MOVE MEMORY 4, 0, 0 ; Patched : first word
- ; is address of
- ; successful dsa_next
- ; Second word is last
- ; unsuccessful dsa_next,
- ; starting with
- ; dsa_reconnect_head
- ; We used to CLEAR ACK here.
-#ifdef DEBUG
- INT int_debug_reselected_ok
-#endif
-#ifdef DEBUG
- INT int_debug_check_dsa
-#endif
- RETURN ; Return control to where
-#endif
-#else
- INT int_norm_reselected
-#endif /* (CHIP != 700) && (CHIP != 70066) */
-
-selected:
- INT int_err_selected;
-
-;
-; A select or reselect failure can be caused by one of two conditions :
-; 1. SIG_P was set. This will be the case if the user has written
-; a new value to a previously NULL head of the issue queue.
-;
-; 2. The NCR53c810 was selected or reselected by another device.
-;
-; 3. The bus was already busy since we were selected or reselected
-; before starting the command.
-
-wait_reselect_failed:
-#ifdef EVENTS
- INT int_EVENT_RESELECT_FAILED
-#endif
-; Check selected bit.
-#if (CHIP == 710)
- ; Must work out how to tell if we are selected....
-#else
- MOVE SIST0 & 0x20 TO SFBR
- JUMP selected, IF 0x20
-#endif
-; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
- MOVE CTEST2 & 0x40 TO SFBR
- JUMP schedule, IF 0x40
-; Check connected bit.
-; FIXME: this needs to change if we support target mode
- MOVE ISTAT & 0x08 TO SFBR
- JUMP reselected, IF 0x08
-; FIXME : Something bogus happened, and we shouldn't fail silently.
-#if 0
- JUMP schedule
-#else
- INT int_debug_panic
-#endif
-
-
-select_failed:
-#if (CHIP == 710)
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-#endif
-#ifdef EVENTS
- int int_EVENT_SELECT_FAILED
-#endif
-; Otherwise, mask the selected and reselected bits off SIST0
-#if (CHIP ==710)
- ; Let's assume we don't get selected for now
- MOVE SSTAT0 & 0x10 TO SFBR
-#else
- MOVE SIST0 & 0x30 TO SFBR
- JUMP selected, IF 0x20
-#endif
- JUMP reselected, IF 0x10
-; If SIGP is set, the user just gave us another command, and
-; we should restart or return to the scheduler.
-; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
- MOVE CTEST2 & 0x40 TO SFBR
- JUMP select, IF 0x40
-; Check connected bit.
-; FIXME: this needs to change if we support target mode
-; FIXME: is this really necessary?
- MOVE ISTAT & 0x08 TO SFBR
- JUMP reselected, IF 0x08
-; FIXME : Something bogus happened, and we shouldn't fail silently.
-#if 0
- JUMP schedule
-#else
- INT int_debug_panic
-#endif
-
-;
-; test_1
-; test_2
-;
-; PURPOSE : run some verification tests on the NCR. test_1
-; copies test_src to test_dest and interrupts the host
-; processor, testing for cache coherency and interrupt
-; problems in the processes.
-;
-; test_2 runs a command with offsets relative to the
-; DSA on entry, and is useful for miscellaneous experimentation.
-;
-
-; Verify that interrupts are working correctly and that we don't
-; have a cache invalidation problem.
-
-ABSOLUTE test_src = 0, test_dest = 0
-ENTRY test_1
-test_1:
- MOVE MEMORY 4, test_src, test_dest
- INT int_test_1
-
-;
-; Run arbitrary commands, with test code establishing a DSA
-;
-
-ENTRY test_2
-test_2:
- CLEAR TARGET
-#if (CHIP == 710)
- ; Enable selection timer
-#ifdef NO_SELECTION_TIMEOUT
- MOVE CTEST7 & 0xff TO CTEST7
-#else
- MOVE CTEST7 & 0xef TO CTEST7
-#endif
-#endif
- SELECT ATN FROM 0, test_2_fail
- JUMP test_2_msgout, WHEN MSG_OUT
-ENTRY test_2_msgout
-test_2_msgout:
-#if (CHIP == 710)
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-#endif
- MOVE FROM 8, WHEN MSG_OUT
- MOVE FROM 16, WHEN CMD
- MOVE FROM 24, WHEN DATA_IN
- MOVE FROM 32, WHEN STATUS
- MOVE FROM 40, WHEN MSG_IN
-#if (CHIP != 710)
- MOVE SCNTL2 & 0x7f TO SCNTL2
-#endif
- CLEAR ACK
- WAIT DISCONNECT
-test_2_fail:
-#if (CHIP == 710)
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-#endif
- INT int_test_2
-
-ENTRY debug_break
-debug_break:
- INT int_debug_break
-
-;
-; initiator_abort
-; target_abort
-;
-; PURPOSE : Abort the currently established nexus from with initiator
-; or target mode.
-;
-;
-
-ENTRY target_abort
-target_abort:
- SET TARGET
- DISCONNECT
- CLEAR TARGET
- JUMP schedule
-
-ENTRY initiator_abort
-initiator_abort:
- SET ATN
-;
-; The SCSI-I specification says that targets may go into MSG out at
-; their leisure upon receipt of the ATN single. On all versions of the
-; specification, we can't change phases until REQ transitions true->false,
-; so we need to sink/source one byte of data to allow the transition.
-;
-; For the sake of safety, we'll only source one byte of data in all
-; cases, but to accommodate the SCSI-I dain bramage, we'll sink an
-; arbitrary number of bytes.
- JUMP spew_cmd, WHEN CMD
- JUMP eat_msgin, WHEN MSG_IN
- JUMP eat_datain, WHEN DATA_IN
- JUMP eat_status, WHEN STATUS
- JUMP spew_dataout, WHEN DATA_OUT
- JUMP sated
-spew_cmd:
- MOVE 1, NCR53c7xx_zero, WHEN CMD
- JUMP sated
-eat_msgin:
- MOVE 1, NCR53c7xx_sink, WHEN MSG_IN
- JUMP eat_msgin, WHEN MSG_IN
- JUMP sated
-eat_status:
- MOVE 1, NCR53c7xx_sink, WHEN STATUS
- JUMP eat_status, WHEN STATUS
- JUMP sated
-eat_datain:
- MOVE 1, NCR53c7xx_sink, WHEN DATA_IN
- JUMP eat_datain, WHEN DATA_IN
- JUMP sated
-spew_dataout:
- MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT
-sated:
-#if (CHIP != 710)
- MOVE SCNTL2 & 0x7f TO SCNTL2
-#endif
- MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT
- WAIT DISCONNECT
- INT int_norm_aborted
-
-#if (CHIP != 710)
-;
-; dsa_to_scratch
-; scratch_to_dsa
-;
-; PURPOSE :
-; The NCR chips cannot do a move memory instruction with the DSA register
-; as the source or destination. So, we provide a couple of subroutines
-; that let us switch between the DSA register and scratch register.
-;
-; Memory moves to/from the DSPS register also don't work, but we
-; don't use them.
-;
-;
-
-
-dsa_to_scratch:
- MOVE DSA0 TO SFBR
- MOVE SFBR TO SCRATCH0
- MOVE DSA1 TO SFBR
- MOVE SFBR TO SCRATCH1
- MOVE DSA2 TO SFBR
- MOVE SFBR TO SCRATCH2
- MOVE DSA3 TO SFBR
- MOVE SFBR TO SCRATCH3
- RETURN
-
-scratch_to_dsa:
- MOVE SCRATCH0 TO SFBR
- MOVE SFBR TO DSA0
- MOVE SCRATCH1 TO SFBR
- MOVE SFBR TO DSA1
- MOVE SCRATCH2 TO SFBR
- MOVE SFBR TO DSA2
- MOVE SCRATCH3 TO SFBR
- MOVE SFBR TO DSA3
- RETURN
-#endif
-
-#if (CHIP == 710)
-; Little patched jump, used to overcome problems with TEMP getting
-; corrupted on memory moves.
-
-jump_temp:
- JUMP 0
-#endif
diff --git a/drivers/scsi/53c7xx_d.h_shipped b/drivers/scsi/53c7xx_d.h_shipped
deleted file mode 100644
index 21d31b0..0000000
--- a/drivers/scsi/53c7xx_d.h_shipped
+++ /dev/null
@@ -1,2874 +0,0 @@
-/* DO NOT EDIT - Generated automatically by script_asm.pl */
-static u32 SCRIPT[] = {
-/*
-
-
-
-
-
-; 53c710 driver. Modified from Drew Eckhardts driver
-; for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
-;
-; I have left the script for the 53c8xx family in here, as it is likely
-; to be useful to see what I changed when bug hunting.
-
-; NCR 53c810 driver, main script
-; Sponsored by
-; iX Multiuser Multitasking Magazine
-; hm@ix.de
-;
-; Copyright 1993, 1994, 1995 Drew Eckhardt
-; Visionary Computing
-; (Unix and Linux consulting and custom programming)
-; drew@PoohSticks.ORG
-; +1 (303) 786-7975
-;
-; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
-;
-; PRE-ALPHA
-;
-; For more information, please consult
-;
-; NCR 53C810
-; PCI-SCSI I/O Processor
-; Data Manual
-;
-; NCR 53C710
-; SCSI I/O Processor
-; Programmers Guide
-;
-; NCR Microelectronics
-; 1635 Aeroplaza Drive
-; Colorado Springs, CO 80916
-; 1+ (719) 578-3400
-;
-; Toll free literature number
-; +1 (800) 334-5454
-;
-; IMPORTANT : This code is self modifying due to the limitations of
-; the NCR53c7,8xx series chips. Persons debugging this code with
-; the remote debugger should take this into account, and NOT set
-; breakpoints in modified instructions.
-;
-; Design:
-; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard
-; microcontroller using a simple instruction set.
-;
-; So, to minimize the effects of interrupt latency, and to maximize
-; throughput, this driver offloads the practical maximum amount
-; of processing to the SCSI chip while still maintaining a common
-; structure.
-;
-; Where tradeoffs were needed between efficiency on the older
-; chips and the newer NCR53c800 series, the NCR53c800 series
-; was chosen.
-;
-; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully
-; automate SCSI transfers without host processor intervention, this
-; isn't the case with the NCR53c710 and newer chips which allow
-;
-; - reads and writes to the internal registers from within the SCSI
-; scripts, allowing the SCSI SCRIPTS(tm) code to save processor
-; state so that multiple threads of execution are possible, and also
-; provide an ALU for loop control, etc.
-;
-; - table indirect addressing for some instructions. This allows
-; pointers to be located relative to the DSA ((Data Structure
-; Address) register.
-;
-; These features make it possible to implement a mailbox style interface,
-; where the same piece of code is run to handle I/O for multiple threads
-; at once minimizing our need to relocate code. Since the NCR53c700/
-; NCR53c800 series have a unique combination of features, making a
-; a standard ingoing/outgoing mailbox system, costly, I've modified it.
-;
-; - Mailboxes are a mixture of code and data. This lets us greatly
-; simplify the NCR53c810 code and do things that would otherwise
-; not be possible.
-;
-; The saved data pointer is now implemented as follows :
-;
-; Control flow has been architected such that if control reaches
-; munge_save_data_pointer, on a restore pointers message or
-; reconnection, a jump to the address formerly in the TEMP register
-; will allow the SCSI command to resume execution.
-;
-
-;
-; Note : the DSA structures must be aligned on 32 bit boundaries,
-; since the source and destination of MOVE MEMORY instructions
-; must share the same alignment and this is the alignment of the
-; NCR registers.
-;
-
-; For some systems (MVME166, for example) dmode is always the same, so don't
-; waste time writing it
-
-
-
-
-
-
-
-
-
-
-
-ABSOLUTE dsa_temp_lun = 0 ; Patch to lun for current dsa
-ABSOLUTE dsa_temp_next = 0 ; Patch to dsa next for current dsa
-ABSOLUTE dsa_temp_addr_next = 0 ; Patch to address of dsa next address
- ; for current dsa
-ABSOLUTE dsa_temp_sync = 0 ; Patch to address of per-target
- ; sync routine
-ABSOLUTE dsa_sscf_710 = 0 ; Patch to address of per-target
- ; sscf value (53c710)
-ABSOLUTE dsa_temp_target = 0 ; Patch to id for current dsa
-ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command
- ; saved data pointer
-ABSOLUTE dsa_temp_addr_residual = 0 ; Patch to address of per-command
- ; current residual code
-ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command
- ; saved residual code
-ABSOLUTE dsa_temp_addr_new_value = 0 ; Address of value for JUMP operand
-ABSOLUTE dsa_temp_addr_array_value = 0 ; Address to copy to
-ABSOLUTE dsa_temp_addr_dsa_value = 0 ; Address of this DSA value
-
-;
-; Once a device has initiated reselection, we need to compare it
-; against the singly linked list of commands which have disconnected
-; and are pending reselection. These commands are maintained in
-; an unordered singly linked list of DSA structures, through the
-; DSA pointers at their 'centers' headed by the reconnect_dsa_head
-; pointer.
-;
-; To avoid complications in removing commands from the list,
-; I minimize the amount of expensive (at eight operations per
-; addition @ 500-600ns each) pointer operations which must
-; be done in the NCR driver by precomputing them on the
-; host processor during dsa structure generation.
-;
-; The fixed-up per DSA code knows how to recognize the nexus
-; associated with the corresponding SCSI command, and modifies
-; the source and destination pointers for the MOVE MEMORY
-; instruction which is executed when reselected_ok is called
-; to remove the command from the list. Similarly, DSA is
-; loaded with the address of the next DSA structure and
-; reselected_check_next is called if a failure occurs.
-;
-; Perhaps more concisely, the net effect of the mess is
-;
-; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head,
-; src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) {
-; src = &dsa->next;
-; if (target_id == dsa->id && target_lun == dsa->lun) {
-; *dest = *src;
-; break;
-; }
-; }
-;
-; if (!dsa)
-; error (int_err_unexpected_reselect);
-; else
-; longjmp (dsa->jump_resume, 0);
-;
-;
-
-
-; Define DSA structure used for mailboxes
-ENTRY dsa_code_template
-dsa_code_template:
-ENTRY dsa_code_begin
-dsa_code_begin:
-; RGH: Don't care about TEMP and DSA here
-
- MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch
-
-at 0x00000000 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
- MOVE MEMORY 4, addr_scratch, saved_dsa
-
-at 0x00000003 : */ 0xc0000004,0x00000000,0x00000000,
-/*
- ; We are about to go and select the device, so must set SSCF bits
- MOVE MEMORY 4, dsa_sscf_710, addr_scratch
-
-at 0x00000006 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
- MOVE SCRATCH3 TO SFBR
-
-at 0x00000009 : */ 0x72370000,0x00000000,
-/*
-
-
-
- MOVE SFBR TO SBCL
-
-at 0x0000000b : */ 0x6a0b0000,0x00000000,
-/*
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x0000000d : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
- CALL select
-
-at 0x00000010 : */ 0x88080000,0x000001f8,
-/*
-; Handle the phase mismatch which may have resulted from the
-; MOVE FROM dsa_msgout if we returned here. The CLEAR ATN
-; may or may not be necessary, and we should update script_asm.pl
-; to handle multiple pieces.
- CLEAR ATN
-
-at 0x00000012 : */ 0x60000008,0x00000000,
-/*
- CLEAR ACK
-
-at 0x00000014 : */ 0x60000040,0x00000000,
-/*
-
-; Replace second operand with address of JUMP instruction dest operand
-; in schedule table for this DSA. Becomes dsa_jump_dest in 53c7,8xx.c.
-ENTRY dsa_code_fix_jump
-dsa_code_fix_jump:
- MOVE MEMORY 4, NOP_insn, 0
-
-at 0x00000016 : */ 0xc0000004,0x00000000,0x00000000,
-/*
- JUMP select_done
-
-at 0x00000019 : */ 0x80080000,0x00000230,
-/*
-
-; wrong_dsa loads the DSA register with the value of the dsa_next
-; field.
-;
-wrong_dsa:
-
-; NOTE DSA is corrupt when we arrive here!
-
-; Patch the MOVE MEMORY INSTRUCTION such that
-; the destination address is the address of the OLD
-; next pointer.
-;
- MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 8
-
-at 0x0000001b : */ 0xc0000004,0x00000000,0x000007ec,
-/*
-
-;
-; Move the _contents_ of the next pointer into the DSA register as
-; the next I_T_L or I_T_L_Q tupple to check against the established
-; nexus.
-;
- MOVE MEMORY 4, dsa_temp_next, addr_scratch
-
-at 0x0000001e : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
- MOVE MEMORY 4, addr_scratch, saved_dsa
-
-at 0x00000021 : */ 0xc0000004,0x00000000,0x00000000,
-/*
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x00000024 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
- JUMP reselected_check_next
-
-at 0x00000027 : */ 0x80080000,0x000006f0,
-/*
-
-ABSOLUTE dsa_save_data_pointer = 0
-ENTRY dsa_code_save_data_pointer
-dsa_code_save_data_pointer:
-
- ; When we get here, TEMP has been saved in jump_temp+4, DSA is corrupt
- ; We MUST return with DSA correct
- MOVE MEMORY 4, jump_temp+4, dsa_temp_addr_saved_pointer
-
-at 0x00000029 : */ 0xc0000004,0x000009c8,0x00000000,
-/*
-; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
- MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
-
-at 0x0000002c : */ 0xc0000018,0x00000000,0x00000000,
-/*
- CLEAR ACK
-
-at 0x0000002f : */ 0x60000040,0x00000000,
-/*
-
-
-
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x00000031 : */ 0xc0000004,0x00000000,0x00000000,
-/*
- JUMP jump_temp
-
-at 0x00000034 : */ 0x80080000,0x000009c4,
-/*
-
-ABSOLUTE dsa_restore_pointers = 0
-ENTRY dsa_code_restore_pointers
-dsa_code_restore_pointers:
-
- ; TEMP and DSA are corrupt when we get here, but who cares!
- MOVE MEMORY 4, dsa_temp_addr_saved_pointer, jump_temp + 4
-
-at 0x00000036 : */ 0xc0000004,0x00000000,0x000009c8,
-/*
-; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
- MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
-
-at 0x00000039 : */ 0xc0000018,0x00000000,0x00000000,
-/*
- CLEAR ACK
-
-at 0x0000003c : */ 0x60000040,0x00000000,
-/*
- ; Restore DSA, note we don't care about TEMP
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x0000003e : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
- JUMP jump_temp
-
-at 0x00000041 : */ 0x80080000,0x000009c4,
-/*
-
-
-ABSOLUTE dsa_check_reselect = 0
-; dsa_check_reselect determines whether or not the current target and
-; lun match the current DSA
-ENTRY dsa_code_check_reselect
-dsa_code_check_reselect:
-
-
-
- MOVE LCRC TO SFBR ; LCRC has our ID and his ID bits set
-
-at 0x00000043 : */ 0x72230000,0x00000000,
-/*
- JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0x80
-
-at 0x00000045 : */ 0x80848000,0x00ffff50,
-/*
-
-
-
-
-
-;
-; Hack - move to scratch first, since SFBR is not writeable
-; via the CPU and hence a MOVE MEMORY instruction.
-;
-
- MOVE MEMORY 1, reselected_identify, addr_scratch
-
-at 0x00000047 : */ 0xc0000001,0x00000000,0x00000000,
-/*
-
-
- ; BIG ENDIAN ON MVME16x
- MOVE SCRATCH3 TO SFBR
-
-at 0x0000004a : */ 0x72370000,0x00000000,
-/*
-
-
-
-; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
-; Are you sure about that? richard@sleepie.demon.co.uk
- JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8
-
-at 0x0000004c : */ 0x8084f800,0x00ffff34,
-/*
-; Patch the MOVE MEMORY INSTRUCTION such that
-; the source address is the address of this dsa's
-; next pointer.
- MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 4
-
-at 0x0000004e : */ 0xc0000004,0x00000000,0x000007e8,
-/*
- CALL reselected_ok
-
-at 0x00000051 : */ 0x88080000,0x00000798,
-/*
-
-; Restore DSA following memory moves in reselected_ok
-; dsa_temp_sync doesn't really care about DSA, but it has an
-; optional debug INT so a valid DSA is a good idea.
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x00000053 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
- CALL dsa_temp_sync
-
-at 0x00000056 : */ 0x88080000,0x00000000,
-/*
-; Release ACK on the IDENTIFY message _after_ we've set the synchronous
-; transfer parameters!
- CLEAR ACK
-
-at 0x00000058 : */ 0x60000040,0x00000000,
-/*
-; Implicitly restore pointers on reselection, so a RETURN
-; will transfer control back to the right spot.
- CALL REL (dsa_code_restore_pointers)
-
-at 0x0000005a : */ 0x88880000,0x00ffff68,
-/*
- RETURN
-
-at 0x0000005c : */ 0x90080000,0x00000000,
-/*
-ENTRY dsa_zero
-dsa_zero:
-ENTRY dsa_code_template_end
-dsa_code_template_end:
-
-; Perform sanity check for dsa_fields_start == dsa_code_template_end -
-; dsa_zero, puke.
-
-ABSOLUTE dsa_fields_start = 0 ; Sanity marker
- ; pad 48 bytes (fix this RSN)
-ABSOLUTE dsa_next = 48 ; len 4 Next DSA
- ; del 4 Previous DSA address
-ABSOLUTE dsa_cmnd = 56 ; len 4 Scsi_Cmnd * for this thread.
-ABSOLUTE dsa_select = 60 ; len 4 Device ID, Period, Offset for
- ; table indirect select
-ABSOLUTE dsa_msgout = 64 ; len 8 table indirect move parameter for
- ; select message
-ABSOLUTE dsa_cmdout = 72 ; len 8 table indirect move parameter for
- ; command
-ABSOLUTE dsa_dataout = 80 ; len 4 code pointer for dataout
-ABSOLUTE dsa_datain = 84 ; len 4 code pointer for datain
-ABSOLUTE dsa_msgin = 88 ; len 8 table indirect move for msgin
-ABSOLUTE dsa_status = 96 ; len 8 table indirect move for status byte
-ABSOLUTE dsa_msgout_other = 104 ; len 8 table indirect for normal message out
- ; (Synchronous transfer negotiation, etc).
-ABSOLUTE dsa_end = 112
-
-ABSOLUTE schedule = 0 ; Array of JUMP dsa_begin or JUMP (next),
- ; terminated by a call to JUMP wait_reselect
-
-; Linked lists of DSA structures
-ABSOLUTE reconnect_dsa_head = 0 ; Link list of DSAs which can reconnect
-ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing
- ; address of reconnect_dsa_head
-
-; These select the source and destination of a MOVE MEMORY instruction
-ABSOLUTE dmode_memory_to_memory = 0x0
-ABSOLUTE dmode_memory_to_ncr = 0x0
-ABSOLUTE dmode_ncr_to_memory = 0x0
-
-ABSOLUTE addr_scratch = 0x0
-ABSOLUTE addr_temp = 0x0
-
-ABSOLUTE saved_dsa = 0x0
-ABSOLUTE emulfly = 0x0
-ABSOLUTE addr_dsa = 0x0
-
-
-
-; Interrupts -
-; MSB indicates type
-; 0 handle error condition
-; 1 handle message
-; 2 handle normal condition
-; 3 debugging interrupt
-; 4 testing interrupt
-; Next byte indicates specific error
-
-; XXX not yet implemented, I'm not sure if I want to -
-; Next byte indicates the routine the error occurred in
-; The LSB indicates the specific place the error occurred
-
-ABSOLUTE int_err_unexpected_phase = 0x00000000 ; Unexpected phase encountered
-ABSOLUTE int_err_selected = 0x00010000 ; SELECTED (nee RESELECTED)
-ABSOLUTE int_err_unexpected_reselect = 0x00020000
-ABSOLUTE int_err_check_condition = 0x00030000
-ABSOLUTE int_err_no_phase = 0x00040000
-ABSOLUTE int_msg_wdtr = 0x01000000 ; WDTR message received
-ABSOLUTE int_msg_sdtr = 0x01010000 ; SDTR received
-ABSOLUTE int_msg_1 = 0x01020000 ; single byte special message
- ; received
-
-ABSOLUTE int_norm_select_complete = 0x02000000 ; Select complete, reprogram
- ; registers.
-ABSOLUTE int_norm_reselect_complete = 0x02010000 ; Nexus established
-ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete
-ABSOLUTE int_norm_disconnected = 0x02030000 ; Disconnected
-ABSOLUTE int_norm_aborted =0x02040000 ; Aborted *dsa
-ABSOLUTE int_norm_reset = 0x02050000 ; Generated BUS reset.
-ABSOLUTE int_norm_emulateintfly = 0x02060000 ; 53C710 Emulated intfly
-ABSOLUTE int_debug_break = 0x03000000 ; Break point
-
-ABSOLUTE int_debug_panic = 0x030b0000 ; Panic driver
-
-
-ABSOLUTE int_test_1 = 0x04000000 ; Test 1 complete
-ABSOLUTE int_test_2 = 0x04010000 ; Test 2 complete
-ABSOLUTE int_test_3 = 0x04020000 ; Test 3 complete
-
-
-; These should start with 0x05000000, with low bits incrementing for
-; each one.
-
-
-
-ABSOLUTE NCR53c7xx_msg_abort = 0 ; Pointer to abort message
-ABSOLUTE NCR53c7xx_msg_reject = 0 ; Pointer to reject message
-ABSOLUTE NCR53c7xx_zero = 0 ; long with zero in it, use for source
-ABSOLUTE NCR53c7xx_sink = 0 ; long to dump worthless data in
-ABSOLUTE NOP_insn = 0 ; NOP instruction
-
-; Pointer to message, potentially multi-byte
-ABSOLUTE msg_buf = 0
-
-; Pointer to holding area for reselection information
-ABSOLUTE reselected_identify = 0
-ABSOLUTE reselected_tag = 0
-
-; Request sense command pointer, it's a 6 byte command, should
-; be constant for all commands since we always want 16 bytes of
-; sense and we don't need to change any fields as we did under
-; SCSI-I when we actually cared about the LUN field.
-;EXTERNAL NCR53c7xx_sense ; Request sense command
-
-
-; dsa_schedule
-; PURPOSE : after a DISCONNECT message has been received, and pointers
-; saved, insert the current DSA structure at the head of the
-; disconnected queue and fall through to the scheduler.
-;
-; CALLS : OK
-;
-; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list
-; of disconnected commands
-;
-; MODIFIES : SCRATCH, reconnect_dsa_head
-;
-; EXITS : always passes control to schedule
-
-ENTRY dsa_schedule
-dsa_schedule:
-
-
-
-
-;
-; Calculate the address of the next pointer within the DSA
-; structure of the command that is currently disconnecting
-;
-
- ; Read what should be the current DSA from memory - actual DSA
- ; register is probably corrupt
- MOVE MEMORY 4, saved_dsa, addr_scratch
-
-at 0x0000005e : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
- MOVE SCRATCH0 + dsa_next TO SCRATCH0
-
-at 0x00000061 : */ 0x7e343000,0x00000000,
-/*
- MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
-
-at 0x00000063 : */ 0x7f350000,0x00000000,
-/*
- MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
-
-at 0x00000065 : */ 0x7f360000,0x00000000,
-/*
- MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
-
-at 0x00000067 : */ 0x7f370000,0x00000000,
-/*
-
-; Point the next field of this DSA structure at the current disconnected
-; list
-
- MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8
-
-at 0x00000069 : */ 0xc0000004,0x00000000,0x000001b8,
-/*
-
-dsa_schedule_insert:
- MOVE MEMORY 4, reconnect_dsa_head, 0
-
-at 0x0000006c : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-; And update the head pointer.
-
- ; Read what should be the current DSA from memory - actual DSA
- ; register is probably corrupt
- MOVE MEMORY 4, saved_dsa, addr_scratch
-
-at 0x0000006f : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
-
- MOVE MEMORY 4, addr_scratch, reconnect_dsa_head
-
-at 0x00000072 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
-
-
-
- CLEAR ACK
-
-at 0x00000075 : */ 0x60000040,0x00000000,
-/*
-
-
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x00000077 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
- WAIT DISCONNECT
-
-at 0x0000007a : */ 0x48000000,0x00000000,
-/*
-
-
-
-
-
-
- JUMP schedule
-
-at 0x0000007c : */ 0x80080000,0x00000000,
-/*
-
-
-;
-; select
-;
-; PURPOSE : establish a nexus for the SCSI command referenced by DSA.
-; On success, the current DSA structure is removed from the issue
-; queue. Usually, this is entered as a fall-through from schedule,
-; although the contingent allegiance handling code will write
-; the select entry address to the DSP to restart a command as a
-; REQUEST SENSE. A message is sent (usually IDENTIFY, although
-; additional SDTR or WDTR messages may be sent). COMMAND OUT
-; is handled.
-;
-; INPUTS : DSA - SCSI command, issue_dsa_head
-;
-; CALLS : NOT OK
-;
-; MODIFIES : SCRATCH, issue_dsa_head
-;
-; EXITS : on reselection or selection, go to select_failed
-; otherwise, RETURN so control is passed back to
-; dsa_begin.
-;
-
-ENTRY select
-select:
-
-
-
-
-
-
-
-
- CLEAR TARGET
-
-at 0x0000007e : */ 0x60000200,0x00000000,
-/*
-
-; XXX
-;
-; In effect, SELECTION operations are backgrounded, with execution
-; continuing until code which waits for REQ or a fatal interrupt is
-; encountered.
-;
-; So, for more performance, we could overlap the code which removes
-; the command from the NCRs issue queue with the selection, but
-; at this point I don't want to deal with the error recovery.
-;
-
-
-
- ; Enable selection timer
-
-
-
- MOVE CTEST7 & 0xef TO CTEST7
-
-at 0x00000080 : */ 0x7c1bef00,0x00000000,
-/*
-
-
- SELECT ATN FROM dsa_select, select_failed
-
-at 0x00000082 : */ 0x4300003c,0x00000828,
-/*
- JUMP select_msgout, WHEN MSG_OUT
-
-at 0x00000084 : */ 0x860b0000,0x00000218,
-/*
-ENTRY select_msgout
-select_msgout:
-
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-
-at 0x00000086 : */ 0x7a1b1000,0x00000000,
-/*
-
- MOVE FROM dsa_msgout, WHEN MSG_OUT
-
-at 0x00000088 : */ 0x1e000000,0x00000040,
-/*
-
-
-
-
-
-
-
-
-
-
- RETURN
-
-at 0x0000008a : */ 0x90080000,0x00000000,
-/*
-
-;
-; select_done
-;
-; PURPOSE: continue on to normal data transfer; called as the exit
-; point from dsa_begin.
-;
-; INPUTS: dsa
-;
-; CALLS: OK
-;
-;
-
-select_done:
-
-; NOTE DSA is corrupt when we arrive here!
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x0000008c : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
-
-
-
-
-
-; After a successful selection, we should get either a CMD phase or
-; some transfer request negotiation message.
-
- JUMP cmdout, WHEN CMD
-
-at 0x0000008f : */ 0x820b0000,0x0000025c,
-/*
- INT int_err_unexpected_phase, WHEN NOT MSG_IN
-
-at 0x00000091 : */ 0x9f030000,0x00000000,
-/*
-
-select_msg_in:
- CALL msg_in, WHEN MSG_IN
-
-at 0x00000093 : */ 0x8f0b0000,0x0000041c,
-/*
- JUMP select_msg_in, WHEN MSG_IN
-
-at 0x00000095 : */ 0x870b0000,0x0000024c,
-/*
-
-cmdout:
- INT int_err_unexpected_phase, WHEN NOT CMD
-
-at 0x00000097 : */ 0x9a030000,0x00000000,
-/*
-
-
-
-ENTRY cmdout_cmdout
-cmdout_cmdout:
-
- MOVE FROM dsa_cmdout, WHEN CMD
-
-at 0x00000099 : */ 0x1a000000,0x00000048,
-/*
-
-
-
-
-;
-; data_transfer
-; other_out
-; other_in
-; other_transfer
-;
-; PURPOSE : handle the main data transfer for a SCSI command in
-; several parts. In the first part, data_transfer, DATA_IN
-; and DATA_OUT phases are allowed, with the user provided
-; code (usually dynamically generated based on the scatter/gather
-; list associated with a SCSI command) called to handle these
-; phases.
-;
-; After control has passed to one of the user provided
-; DATA_IN or DATA_OUT routines, back calls are made to
-; other_transfer_in or other_transfer_out to handle non-DATA IN
-; and DATA OUT phases respectively, with the state of the active
-; data pointer being preserved in TEMP.
-;
-; On completion, the user code passes control to other_transfer
-; which causes DATA_IN and DATA_OUT to result in unexpected_phase
-; interrupts so that data overruns may be trapped.
-;
-; INPUTS : DSA - SCSI command
-;
-; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in
-; other_transfer
-;
-; MODIFIES : SCRATCH
-;
-; EXITS : if STATUS IN is detected, signifying command completion,
-; the NCR jumps to command_complete. If MSG IN occurs, a
-; CALL is made to msg_in. Otherwise, other_transfer runs in
-; an infinite loop.
-;
-
-ENTRY data_transfer
-data_transfer:
- JUMP cmdout_cmdout, WHEN CMD
-
-at 0x0000009b : */ 0x820b0000,0x00000264,
-/*
- CALL msg_in, WHEN MSG_IN
-
-at 0x0000009d : */ 0x8f0b0000,0x0000041c,
-/*
- INT int_err_unexpected_phase, WHEN MSG_OUT
-
-at 0x0000009f : */ 0x9e0b0000,0x00000000,
-/*
- JUMP do_dataout, WHEN DATA_OUT
-
-at 0x000000a1 : */ 0x800b0000,0x000002a4,
-/*
- JUMP do_datain, WHEN DATA_IN
-
-at 0x000000a3 : */ 0x810b0000,0x000002fc,
-/*
- JUMP command_complete, WHEN STATUS
-
-at 0x000000a5 : */ 0x830b0000,0x0000065c,
-/*
- JUMP data_transfer
-
-at 0x000000a7 : */ 0x80080000,0x0000026c,
-/*
-ENTRY end_data_transfer
-end_data_transfer:
-
-;
-; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain
-; should be fixed up whenever the nexus changes so it can point to the
-; correct routine for that command.
-;
-
-
-; Nasty jump to dsa->dataout
-do_dataout:
-
- MOVE MEMORY 4, saved_dsa, addr_scratch
-
-at 0x000000a9 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
- MOVE SCRATCH0 + dsa_dataout TO SCRATCH0
-
-at 0x000000ac : */ 0x7e345000,0x00000000,
-/*
- MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
-
-at 0x000000ae : */ 0x7f350000,0x00000000,
-/*
- MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
-
-at 0x000000b0 : */ 0x7f360000,0x00000000,
-/*
- MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
-
-at 0x000000b2 : */ 0x7f370000,0x00000000,
-/*
-
- MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4
-
-at 0x000000b4 : */ 0xc0000004,0x00000000,0x000002e0,
-/*
-
-dataout_to_jump:
- MOVE MEMORY 4, 0, dataout_jump + 4
-
-at 0x000000b7 : */ 0xc0000004,0x00000000,0x000002f8,
-/*
-
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x000000ba : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-dataout_jump:
- JUMP 0
-
-at 0x000000bd : */ 0x80080000,0x00000000,
-/*
-
-; Nasty jump to dsa->dsain
-do_datain:
-
- MOVE MEMORY 4, saved_dsa, addr_scratch
-
-at 0x000000bf : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
- MOVE SCRATCH0 + dsa_datain TO SCRATCH0
-
-at 0x000000c2 : */ 0x7e345400,0x00000000,
-/*
- MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
-
-at 0x000000c4 : */ 0x7f350000,0x00000000,
-/*
- MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
-
-at 0x000000c6 : */ 0x7f360000,0x00000000,
-/*
- MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
-
-at 0x000000c8 : */ 0x7f370000,0x00000000,
-/*
-
- MOVE MEMORY 4, addr_scratch, datain_to_jump + 4
-
-at 0x000000ca : */ 0xc0000004,0x00000000,0x00000338,
-/*
-
-ENTRY datain_to_jump
-datain_to_jump:
- MOVE MEMORY 4, 0, datain_jump + 4
-
-at 0x000000cd : */ 0xc0000004,0x00000000,0x00000350,
-/*
-
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x000000d0 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
-
-datain_jump:
- JUMP 0
-
-at 0x000000d3 : */ 0x80080000,0x00000000,
-/*
-
-
-
-; Note that other_out and other_in loop until a non-data phase
-; is discovered, so we only execute return statements when we
-; can go on to the next data phase block move statement.
-
-ENTRY other_out
-other_out:
-
-
-
- INT int_err_unexpected_phase, WHEN CMD
-
-at 0x000000d5 : */ 0x9a0b0000,0x00000000,
-/*
- JUMP msg_in_restart, WHEN MSG_IN
-
-at 0x000000d7 : */ 0x870b0000,0x000003fc,
-/*
- INT int_err_unexpected_phase, WHEN MSG_OUT
-
-at 0x000000d9 : */ 0x9e0b0000,0x00000000,
-/*
- INT int_err_unexpected_phase, WHEN DATA_IN
-
-at 0x000000db : */ 0x990b0000,0x00000000,
-/*
- JUMP command_complete, WHEN STATUS
-
-at 0x000000dd : */ 0x830b0000,0x0000065c,
-/*
- JUMP other_out, WHEN NOT DATA_OUT
-
-at 0x000000df : */ 0x80030000,0x00000354,
-/*
-
-; TEMP should be OK, as we got here from a call in the user dataout code.
-
- RETURN
-
-at 0x000000e1 : */ 0x90080000,0x00000000,
-/*
-
-ENTRY other_in
-other_in:
-
-
-
- INT int_err_unexpected_phase, WHEN CMD
-
-at 0x000000e3 : */ 0x9a0b0000,0x00000000,
-/*
- JUMP msg_in_restart, WHEN MSG_IN
-
-at 0x000000e5 : */ 0x870b0000,0x000003fc,
-/*
- INT int_err_unexpected_phase, WHEN MSG_OUT
-
-at 0x000000e7 : */ 0x9e0b0000,0x00000000,
-/*
- INT int_err_unexpected_phase, WHEN DATA_OUT
-
-at 0x000000e9 : */ 0x980b0000,0x00000000,
-/*
- JUMP command_complete, WHEN STATUS
-
-at 0x000000eb : */ 0x830b0000,0x0000065c,
-/*
- JUMP other_in, WHEN NOT DATA_IN
-
-at 0x000000ed : */ 0x81030000,0x0000038c,
-/*
-
-; TEMP should be OK, as we got here from a call in the user datain code.
-
- RETURN
-
-at 0x000000ef : */ 0x90080000,0x00000000,
-/*
-
-
-ENTRY other_transfer
-other_transfer:
- INT int_err_unexpected_phase, WHEN CMD
-
-at 0x000000f1 : */ 0x9a0b0000,0x00000000,
-/*
- CALL msg_in, WHEN MSG_IN
-
-at 0x000000f3 : */ 0x8f0b0000,0x0000041c,
-/*
- INT int_err_unexpected_phase, WHEN MSG_OUT
-
-at 0x000000f5 : */ 0x9e0b0000,0x00000000,
-/*
- INT int_err_unexpected_phase, WHEN DATA_OUT
-
-at 0x000000f7 : */ 0x980b0000,0x00000000,
-/*
- INT int_err_unexpected_phase, WHEN DATA_IN
-
-at 0x000000f9 : */ 0x990b0000,0x00000000,
-/*
- JUMP command_complete, WHEN STATUS
-
-at 0x000000fb : */ 0x830b0000,0x0000065c,
-/*
- JUMP other_transfer
-
-at 0x000000fd : */ 0x80080000,0x000003c4,
-/*
-
-;
-; msg_in_restart
-; msg_in
-; munge_msg
-;
-; PURPOSE : process messages from a target. msg_in is called when the
-; caller hasn't read the first byte of the message. munge_message
-; is called when the caller has read the first byte of the message,
-; and left it in SFBR. msg_in_restart is called when the caller
-; hasn't read the first byte of the message, and wishes RETURN
-; to transfer control back to the address of the conditional
-; CALL instruction rather than to the instruction after it.
-;
-; Various int_* interrupts are generated when the host system
-; needs to intervene, as is the case with SDTR, WDTR, and
-; INITIATE RECOVERY messages.
-;
-; When the host system handles one of these interrupts,
-; it can respond by reentering at reject_message,
-; which rejects the message and returns control to
-; the caller of msg_in or munge_msg, accept_message
-; which clears ACK and returns control, or reply_message
-; which sends the message pointed to by the DSA
-; msgout_other table indirect field.
-;
-; DISCONNECT messages are handled by moving the command
-; to the reconnect_dsa_queue.
-
-; NOTE: DSA should be valid when we get here - we cannot save both it
-; and TEMP in this routine.
-
-;
-; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg
-; only)
-;
-; CALLS : NO. The TEMP register isn't backed up to allow nested calls.
-;
-; MODIFIES : SCRATCH, DSA on DISCONNECT
-;
-; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS,
-; and normal return from message handlers running under
-; Linux, control is returned to the caller. Receipt
-; of DISCONNECT messages pass control to dsa_schedule.
-;
-ENTRY msg_in_restart
-msg_in_restart:
-; XXX - hackish
-;
-; Since it's easier to debug changes to the statically
-; compiled code, rather than the dynamically generated
-; stuff, such as
-;
-; MOVE x, y, WHEN data_phase
-; CALL other_z, WHEN NOT data_phase
-; MOVE x, y, WHEN data_phase
-;
-; I'd like to have certain routines (notably the message handler)
-; restart on the conditional call rather than the next instruction.
-;
-; So, subtract 8 from the return address
-
- MOVE TEMP0 + 0xf8 TO TEMP0
-
-at 0x000000ff : */ 0x7e1cf800,0x00000000,
-/*
- MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY
-
-at 0x00000101 : */ 0x7f1dff00,0x00000000,
-/*
- MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY
-
-at 0x00000103 : */ 0x7f1eff00,0x00000000,
-/*
- MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY
-
-at 0x00000105 : */ 0x7f1fff00,0x00000000,
-/*
-
-ENTRY msg_in
-msg_in:
- MOVE 1, msg_buf, WHEN MSG_IN
-
-at 0x00000107 : */ 0x0f000001,0x00000000,
-/*
-
-munge_msg:
- JUMP munge_extended, IF 0x01 ; EXTENDED MESSAGE
-
-at 0x00000109 : */ 0x800c0001,0x00000574,
-/*
- JUMP munge_2, IF 0x20, AND MASK 0xdf ; two byte message
-
-at 0x0000010b : */ 0x800cdf20,0x00000464,
-/*
-;
-; XXX - I've seen a handful of broken SCSI devices which fail to issue
-; a SAVE POINTERS message before disconnecting in the middle of
-; a transfer, assuming that the DATA POINTER will be implicitly
-; restored.
-;
-; Historically, I've often done an implicit save when the DISCONNECT
-; message is processed. We may want to consider having the option of
-; doing that here.
-;
- JUMP munge_save_data_pointer, IF 0x02 ; SAVE DATA POINTER
-
-at 0x0000010d : */ 0x800c0002,0x0000046c,
-/*
- JUMP munge_restore_pointers, IF 0x03 ; RESTORE POINTERS
-
-at 0x0000010f : */ 0x800c0003,0x00000518,
-/*
- JUMP munge_disconnect, IF 0x04 ; DISCONNECT
-
-at 0x00000111 : */ 0x800c0004,0x0000056c,
-/*
- INT int_msg_1, IF 0x07 ; MESSAGE REJECT
-
-at 0x00000113 : */ 0x980c0007,0x01020000,
-/*
- INT int_msg_1, IF 0x0f ; INITIATE RECOVERY
-
-at 0x00000115 : */ 0x980c000f,0x01020000,
-/*
-
-
-
- JUMP reject_message
-
-at 0x00000117 : */ 0x80080000,0x00000604,
-/*
-
-munge_2:
- JUMP reject_message
-
-at 0x00000119 : */ 0x80080000,0x00000604,
-/*
-;
-; The SCSI standard allows targets to recover from transient
-; error conditions by backing up the data pointer with a
-; RESTORE POINTERS message.
-;
-; So, we must save and restore the _residual_ code as well as
-; the current instruction pointer. Because of this messiness,
-; it is simpler to put dynamic code in the dsa for this and to
-; just do a simple jump down there.
-;
-
-munge_save_data_pointer:
-
- ; We have something in TEMP here, so first we must save that
- MOVE TEMP0 TO SFBR
-
-at 0x0000011b : */ 0x721c0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH0
-
-at 0x0000011d : */ 0x6a340000,0x00000000,
-/*
- MOVE TEMP1 TO SFBR
-
-at 0x0000011f : */ 0x721d0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH1
-
-at 0x00000121 : */ 0x6a350000,0x00000000,
-/*
- MOVE TEMP2 TO SFBR
-
-at 0x00000123 : */ 0x721e0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH2
-
-at 0x00000125 : */ 0x6a360000,0x00000000,
-/*
- MOVE TEMP3 TO SFBR
-
-at 0x00000127 : */ 0x721f0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH3
-
-at 0x00000129 : */ 0x6a370000,0x00000000,
-/*
- MOVE MEMORY 4, addr_scratch, jump_temp + 4
-
-at 0x0000012b : */ 0xc0000004,0x00000000,0x000009c8,
-/*
- ; Now restore DSA
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x0000012e : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
- MOVE DSA0 + dsa_save_data_pointer TO SFBR
-
-at 0x00000131 : */ 0x76100000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH0
-
-at 0x00000133 : */ 0x6a340000,0x00000000,
-/*
- MOVE DSA1 + 0xff TO SFBR WITH CARRY
-
-at 0x00000135 : */ 0x7711ff00,0x00000000,
-/*
- MOVE SFBR TO SCRATCH1
-
-at 0x00000137 : */ 0x6a350000,0x00000000,
-/*
- MOVE DSA2 + 0xff TO SFBR WITH CARRY
-
-at 0x00000139 : */ 0x7712ff00,0x00000000,
-/*
- MOVE SFBR TO SCRATCH2
-
-at 0x0000013b : */ 0x6a360000,0x00000000,
-/*
- MOVE DSA3 + 0xff TO SFBR WITH CARRY
-
-at 0x0000013d : */ 0x7713ff00,0x00000000,
-/*
- MOVE SFBR TO SCRATCH3
-
-at 0x0000013f : */ 0x6a370000,0x00000000,
-/*
-
-
- MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4
-
-at 0x00000141 : */ 0xc0000004,0x00000000,0x00000514,
-/*
-
-jump_dsa_save:
- JUMP 0
-
-at 0x00000144 : */ 0x80080000,0x00000000,
-/*
-
-munge_restore_pointers:
-
- ; The code at dsa_restore_pointers will RETURN, but we don't care
- ; about TEMP here, as it will overwrite it anyway.
-
- MOVE DSA0 + dsa_restore_pointers TO SFBR
-
-at 0x00000146 : */ 0x76100000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH0
-
-at 0x00000148 : */ 0x6a340000,0x00000000,
-/*
- MOVE DSA1 + 0xff TO SFBR WITH CARRY
-
-at 0x0000014a : */ 0x7711ff00,0x00000000,
-/*
- MOVE SFBR TO SCRATCH1
-
-at 0x0000014c : */ 0x6a350000,0x00000000,
-/*
- MOVE DSA2 + 0xff TO SFBR WITH CARRY
-
-at 0x0000014e : */ 0x7712ff00,0x00000000,
-/*
- MOVE SFBR TO SCRATCH2
-
-at 0x00000150 : */ 0x6a360000,0x00000000,
-/*
- MOVE DSA3 + 0xff TO SFBR WITH CARRY
-
-at 0x00000152 : */ 0x7713ff00,0x00000000,
-/*
- MOVE SFBR TO SCRATCH3
-
-at 0x00000154 : */ 0x6a370000,0x00000000,
-/*
-
-
- MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4
-
-at 0x00000156 : */ 0xc0000004,0x00000000,0x00000568,
-/*
-
-jump_dsa_restore:
- JUMP 0
-
-at 0x00000159 : */ 0x80080000,0x00000000,
-/*
-
-
-munge_disconnect:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- JUMP dsa_schedule
-
-at 0x0000015b : */ 0x80080000,0x00000178,
-/*
-
-
-
-
-
-munge_extended:
- CLEAR ACK
-
-at 0x0000015d : */ 0x60000040,0x00000000,
-/*
- INT int_err_unexpected_phase, WHEN NOT MSG_IN
-
-at 0x0000015f : */ 0x9f030000,0x00000000,
-/*
- MOVE 1, msg_buf + 1, WHEN MSG_IN
-
-at 0x00000161 : */ 0x0f000001,0x00000001,
-/*
- JUMP munge_extended_2, IF 0x02
-
-at 0x00000163 : */ 0x800c0002,0x000005a4,
-/*
- JUMP munge_extended_3, IF 0x03
-
-at 0x00000165 : */ 0x800c0003,0x000005d4,
-/*
- JUMP reject_message
-
-at 0x00000167 : */ 0x80080000,0x00000604,
-/*
-
-munge_extended_2:
- CLEAR ACK
-
-at 0x00000169 : */ 0x60000040,0x00000000,
-/*
- MOVE 1, msg_buf + 2, WHEN MSG_IN
-
-at 0x0000016b : */ 0x0f000001,0x00000002,
-/*
- JUMP reject_message, IF NOT 0x02 ; Must be WDTR
-
-at 0x0000016d : */ 0x80040002,0x00000604,
-/*
- CLEAR ACK
-
-at 0x0000016f : */ 0x60000040,0x00000000,
-/*
- MOVE 1, msg_buf + 3, WHEN MSG_IN
-
-at 0x00000171 : */ 0x0f000001,0x00000003,
-/*
- INT int_msg_wdtr
-
-at 0x00000173 : */ 0x98080000,0x01000000,
-/*
-
-munge_extended_3:
- CLEAR ACK
-
-at 0x00000175 : */ 0x60000040,0x00000000,
-/*
- MOVE 1, msg_buf + 2, WHEN MSG_IN
-
-at 0x00000177 : */ 0x0f000001,0x00000002,
-/*
- JUMP reject_message, IF NOT 0x01 ; Must be SDTR
-
-at 0x00000179 : */ 0x80040001,0x00000604,
-/*
- CLEAR ACK
-
-at 0x0000017b : */ 0x60000040,0x00000000,
-/*
- MOVE 2, msg_buf + 3, WHEN MSG_IN
-
-at 0x0000017d : */ 0x0f000002,0x00000003,
-/*
- INT int_msg_sdtr
-
-at 0x0000017f : */ 0x98080000,0x01010000,
-/*
-
-ENTRY reject_message
-reject_message:
- SET ATN
-
-at 0x00000181 : */ 0x58000008,0x00000000,
-/*
- CLEAR ACK
-
-at 0x00000183 : */ 0x60000040,0x00000000,
-/*
- MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT
-
-at 0x00000185 : */ 0x0e000001,0x00000000,
-/*
- RETURN
-
-at 0x00000187 : */ 0x90080000,0x00000000,
-/*
-
-ENTRY accept_message
-accept_message:
- CLEAR ATN
-
-at 0x00000189 : */ 0x60000008,0x00000000,
-/*
- CLEAR ACK
-
-at 0x0000018b : */ 0x60000040,0x00000000,
-/*
- RETURN
-
-at 0x0000018d : */ 0x90080000,0x00000000,
-/*
-
-ENTRY respond_message
-respond_message:
- SET ATN
-
-at 0x0000018f : */ 0x58000008,0x00000000,
-/*
- CLEAR ACK
-
-at 0x00000191 : */ 0x60000040,0x00000000,
-/*
- MOVE FROM dsa_msgout_other, WHEN MSG_OUT
-
-at 0x00000193 : */ 0x1e000000,0x00000068,
-/*
- RETURN
-
-at 0x00000195 : */ 0x90080000,0x00000000,
-/*
-
-;
-; command_complete
-;
-; PURPOSE : handle command termination when STATUS IN is detected by reading
-; a status byte followed by a command termination message.
-;
-; Normal termination results in an INTFLY instruction, and
-; the host system can pick out which command terminated by
-; examining the MESSAGE and STATUS buffers of all currently
-; executing commands;
-;
-; Abnormal (CHECK_CONDITION) termination results in an
-; int_err_check_condition interrupt so that a REQUEST SENSE
-; command can be issued out-of-order so that no other command
-; clears the contingent allegiance condition.
-;
-;
-; INPUTS : DSA - command
-;
-; CALLS : OK
-;
-; EXITS : On successful termination, control is passed to schedule.
-; On abnormal termination, the user will usually modify the
-; DSA fields and corresponding buffers and return control
-; to select.
-;
-
-ENTRY command_complete
-command_complete:
- MOVE FROM dsa_status, WHEN STATUS
-
-at 0x00000197 : */ 0x1b000000,0x00000060,
-/*
-
- MOVE SFBR TO SCRATCH0 ; Save status
-
-at 0x00000199 : */ 0x6a340000,0x00000000,
-/*
-
-ENTRY command_complete_msgin
-command_complete_msgin:
- MOVE FROM dsa_msgin, WHEN MSG_IN
-
-at 0x0000019b : */ 0x1f000000,0x00000058,
-/*
-; Indicate that we should be expecting a disconnect
-
-
-
- ; Above code cleared the Unexpected Disconnect bit, what do we do?
-
- CLEAR ACK
-
-at 0x0000019d : */ 0x60000040,0x00000000,
-/*
-
- WAIT DISCONNECT
-
-at 0x0000019f : */ 0x48000000,0x00000000,
-/*
-
-;
-; The SCSI specification states that when a UNIT ATTENTION condition
-; is pending, as indicated by a CHECK CONDITION status message,
-; the target shall revert to asynchronous transfers. Since
-; synchronous transfers parameters are maintained on a per INITIATOR/TARGET
-; basis, and returning control to our scheduler could work on a command
-; running on another lun on that target using the old parameters, we must
-; interrupt the host processor to get them changed, or change them ourselves.
-;
-; Once SCSI-II tagged queueing is implemented, things will be even more
-; hairy, since contingent allegiance conditions exist on a per-target/lun
-; basis, and issuing a new command with a different tag would clear it.
-; In these cases, we must interrupt the host processor to get a request
-; added to the HEAD of the queue with the request sense command, or we
-; must automatically issue the request sense command.
-
-
-
-
-
-
-
- INT int_norm_emulateintfly
-
-at 0x000001a1 : */ 0x98080000,0x02060000,
-/*
-
-
-
-
-
-
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x000001a3 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
-
-
- JUMP schedule
-
-at 0x000001a6 : */ 0x80080000,0x00000000,
-/*
-command_failed:
- INT int_err_check_condition
-
-at 0x000001a8 : */ 0x98080000,0x00030000,
-/*
-
-
-
-
-;
-; wait_reselect
-;
-; PURPOSE : This is essentially the idle routine, where control lands
-; when there are no new processes to schedule. wait_reselect
-; waits for reselection, selection, and new commands.
-;
-; When a successful reselection occurs, with the aid
-; of fixed up code in each DSA, wait_reselect walks the
-; reconnect_dsa_queue, asking each dsa if the target ID
-; and LUN match its.
-;
-; If a match is found, a call is made back to reselected_ok,
-; which through the miracles of self modifying code, extracts
-; the found DSA from the reconnect_dsa_queue and then
-; returns control to the DSAs thread of execution.
-;
-; INPUTS : NONE
-;
-; CALLS : OK
-;
-; MODIFIES : DSA,
-;
-; EXITS : On successful reselection, control is returned to the
-; DSA which called reselected_ok. If the WAIT RESELECT
-; was interrupted by a new commands arrival signaled by
-; SIG_P, control is passed to schedule. If the NCR is
-; selected, the host system is interrupted with an
-; int_err_selected which is usually responded to by
-; setting DSP to the target_abort address.
-
-ENTRY wait_reselect
-wait_reselect:
-
-
-
-
-
-
- WAIT RESELECT wait_reselect_failed
-
-at 0x000001aa : */ 0x50000000,0x00000800,
-/*
-
-reselected:
-
-
-
- CLEAR TARGET
-
-at 0x000001ac : */ 0x60000200,0x00000000,
-/*
-
- ; Read all data needed to reestablish the nexus -
- MOVE 1, reselected_identify, WHEN MSG_IN
-
-at 0x000001ae : */ 0x0f000001,0x00000000,
-/*
- ; We used to CLEAR ACK here.
-
-
-
-
-
- ; Point DSA at the current head of the disconnected queue.
-
- MOVE MEMORY 4, reconnect_dsa_head, addr_scratch
-
-at 0x000001b0 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
- MOVE MEMORY 4, addr_scratch, saved_dsa
-
-at 0x000001b3 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
-
- ; Fix the update-next pointer so that the reconnect_dsa_head
- ; pointer is the one that will be updated if this DSA is a hit
- ; and we remove it from the queue.
-
- MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok_patch + 8
-
-at 0x000001b6 : */ 0xc0000004,0x00000000,0x000007ec,
-/*
-
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x000001b9 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-ENTRY reselected_check_next
-reselected_check_next:
-
-
-
- ; Check for a NULL pointer.
- MOVE DSA0 TO SFBR
-
-at 0x000001bc : */ 0x72100000,0x00000000,
-/*
- JUMP reselected_not_end, IF NOT 0
-
-at 0x000001be : */ 0x80040000,0x00000738,
-/*
- MOVE DSA1 TO SFBR
-
-at 0x000001c0 : */ 0x72110000,0x00000000,
-/*
- JUMP reselected_not_end, IF NOT 0
-
-at 0x000001c2 : */ 0x80040000,0x00000738,
-/*
- MOVE DSA2 TO SFBR
-
-at 0x000001c4 : */ 0x72120000,0x00000000,
-/*
- JUMP reselected_not_end, IF NOT 0
-
-at 0x000001c6 : */ 0x80040000,0x00000738,
-/*
- MOVE DSA3 TO SFBR
-
-at 0x000001c8 : */ 0x72130000,0x00000000,
-/*
- JUMP reselected_not_end, IF NOT 0
-
-at 0x000001ca : */ 0x80040000,0x00000738,
-/*
- INT int_err_unexpected_reselect
-
-at 0x000001cc : */ 0x98080000,0x00020000,
-/*
-
-reselected_not_end:
- ;
- ; XXX the ALU is only eight bits wide, and the assembler
- ; wont do the dirt work for us. As long as dsa_check_reselect
- ; is negative, we need to sign extend with 1 bits to the full
- ; 32 bit width of the address.
- ;
- ; A potential work around would be to have a known alignment
- ; of the DSA structure such that the base address plus
- ; dsa_check_reselect doesn't require carrying from bytes
- ; higher than the LSB.
- ;
-
- MOVE DSA0 TO SFBR
-
-at 0x000001ce : */ 0x72100000,0x00000000,
-/*
- MOVE SFBR + dsa_check_reselect TO SCRATCH0
-
-at 0x000001d0 : */ 0x6e340000,0x00000000,
-/*
- MOVE DSA1 TO SFBR
-
-at 0x000001d2 : */ 0x72110000,0x00000000,
-/*
- MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY
-
-at 0x000001d4 : */ 0x6f35ff00,0x00000000,
-/*
- MOVE DSA2 TO SFBR
-
-at 0x000001d6 : */ 0x72120000,0x00000000,
-/*
- MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY
-
-at 0x000001d8 : */ 0x6f36ff00,0x00000000,
-/*
- MOVE DSA3 TO SFBR
-
-at 0x000001da : */ 0x72130000,0x00000000,
-/*
- MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY
-
-at 0x000001dc : */ 0x6f37ff00,0x00000000,
-/*
-
-
- MOVE MEMORY 4, addr_scratch, reselected_check + 4
-
-at 0x000001de : */ 0xc0000004,0x00000000,0x00000794,
-/*
-
-
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x000001e1 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-reselected_check:
- JUMP 0
-
-at 0x000001e4 : */ 0x80080000,0x00000000,
-/*
-
-
-;
-;
-
-; We have problems here - the memory move corrupts TEMP and DSA. This
-; routine is called from DSA code, and patched from many places. Scratch
-; is probably free when it is called.
-; We have to:
-; copy temp to scratch, one byte at a time
-; write scratch to patch a jump in place of the return
-; do the move memory
-; jump to the patched in return address
-; DSA is corrupt when we get here, and can be left corrupt
-
-ENTRY reselected_ok
-reselected_ok:
- MOVE TEMP0 TO SFBR
-
-at 0x000001e6 : */ 0x721c0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH0
-
-at 0x000001e8 : */ 0x6a340000,0x00000000,
-/*
- MOVE TEMP1 TO SFBR
-
-at 0x000001ea : */ 0x721d0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH1
-
-at 0x000001ec : */ 0x6a350000,0x00000000,
-/*
- MOVE TEMP2 TO SFBR
-
-at 0x000001ee : */ 0x721e0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH2
-
-at 0x000001f0 : */ 0x6a360000,0x00000000,
-/*
- MOVE TEMP3 TO SFBR
-
-at 0x000001f2 : */ 0x721f0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH3
-
-at 0x000001f4 : */ 0x6a370000,0x00000000,
-/*
- MOVE MEMORY 4, addr_scratch, reselected_ok_jump + 4
-
-at 0x000001f6 : */ 0xc0000004,0x00000000,0x000007f4,
-/*
-reselected_ok_patch:
- MOVE MEMORY 4, 0, 0
-
-at 0x000001f9 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-reselected_ok_jump:
- JUMP 0
-
-at 0x000001fc : */ 0x80080000,0x00000000,
-/*
-
-
-
-
-
-selected:
- INT int_err_selected;
-
-at 0x000001fe : */ 0x98080000,0x00010000,
-/*
-
-;
-; A select or reselect failure can be caused by one of two conditions :
-; 1. SIG_P was set. This will be the case if the user has written
-; a new value to a previously NULL head of the issue queue.
-;
-; 2. The NCR53c810 was selected or reselected by another device.
-;
-; 3. The bus was already busy since we were selected or reselected
-; before starting the command.
-
-wait_reselect_failed:
-
-
-
-; Check selected bit.
-
- ; Must work out how to tell if we are selected....
-
-
-
-
-; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
- MOVE CTEST2 & 0x40 TO SFBR
-
-at 0x00000200 : */ 0x74164000,0x00000000,
-/*
- JUMP schedule, IF 0x40
-
-at 0x00000202 : */ 0x800c0040,0x00000000,
-/*
-; Check connected bit.
-; FIXME: this needs to change if we support target mode
- MOVE ISTAT & 0x08 TO SFBR
-
-at 0x00000204 : */ 0x74210800,0x00000000,
-/*
- JUMP reselected, IF 0x08
-
-at 0x00000206 : */ 0x800c0008,0x000006b0,
-/*
-; FIXME : Something bogus happened, and we shouldn't fail silently.
-
-
-
- INT int_debug_panic
-
-at 0x00000208 : */ 0x98080000,0x030b0000,
-/*
-
-
-
-select_failed:
-
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-
-at 0x0000020a : */ 0x7a1b1000,0x00000000,
-/*
-
-
-
-
-; Otherwise, mask the selected and reselected bits off SIST0
-
- ; Let's assume we don't get selected for now
- MOVE SSTAT0 & 0x10 TO SFBR
-
-at 0x0000020c : */ 0x740d1000,0x00000000,
-/*
-
-
-
-
- JUMP reselected, IF 0x10
-
-at 0x0000020e : */ 0x800c0010,0x000006b0,
-/*
-; If SIGP is set, the user just gave us another command, and
-; we should restart or return to the scheduler.
-; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
- MOVE CTEST2 & 0x40 TO SFBR
-
-at 0x00000210 : */ 0x74164000,0x00000000,
-/*
- JUMP select, IF 0x40
-
-at 0x00000212 : */ 0x800c0040,0x000001f8,
-/*
-; Check connected bit.
-; FIXME: this needs to change if we support target mode
-; FIXME: is this really necessary?
- MOVE ISTAT & 0x08 TO SFBR
-
-at 0x00000214 : */ 0x74210800,0x00000000,
-/*
- JUMP reselected, IF 0x08
-
-at 0x00000216 : */ 0x800c0008,0x000006b0,
-/*
-; FIXME : Something bogus happened, and we shouldn't fail silently.
-
-
-
- INT int_debug_panic
-
-at 0x00000218 : */ 0x98080000,0x030b0000,
-/*
-
-
-;
-; test_1
-; test_2
-;
-; PURPOSE : run some verification tests on the NCR. test_1
-; copies test_src to test_dest and interrupts the host
-; processor, testing for cache coherency and interrupt
-; problems in the processes.
-;
-; test_2 runs a command with offsets relative to the
-; DSA on entry, and is useful for miscellaneous experimentation.
-;
-
-; Verify that interrupts are working correctly and that we don't
-; have a cache invalidation problem.
-
-ABSOLUTE test_src = 0, test_dest = 0
-ENTRY test_1
-test_1:
- MOVE MEMORY 4, test_src, test_dest
-
-at 0x0000021a : */ 0xc0000004,0x00000000,0x00000000,
-/*
- INT int_test_1
-
-at 0x0000021d : */ 0x98080000,0x04000000,
-/*
-
-;
-; Run arbitrary commands, with test code establishing a DSA
-;
-
-ENTRY test_2
-test_2:
- CLEAR TARGET
-
-at 0x0000021f : */ 0x60000200,0x00000000,
-/*
-
- ; Enable selection timer
-
-
-
- MOVE CTEST7 & 0xef TO CTEST7
-
-at 0x00000221 : */ 0x7c1bef00,0x00000000,
-/*
-
-
- SELECT ATN FROM 0, test_2_fail
-
-at 0x00000223 : */ 0x43000000,0x000008dc,
-/*
- JUMP test_2_msgout, WHEN MSG_OUT
-
-at 0x00000225 : */ 0x860b0000,0x0000089c,
-/*
-ENTRY test_2_msgout
-test_2_msgout:
-
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-
-at 0x00000227 : */ 0x7a1b1000,0x00000000,
-/*
-
- MOVE FROM 8, WHEN MSG_OUT
-
-at 0x00000229 : */ 0x1e000000,0x00000008,
-/*
- MOVE FROM 16, WHEN CMD
-
-at 0x0000022b : */ 0x1a000000,0x00000010,
-/*
- MOVE FROM 24, WHEN DATA_IN
-
-at 0x0000022d : */ 0x19000000,0x00000018,
-/*
- MOVE FROM 32, WHEN STATUS
-
-at 0x0000022f : */ 0x1b000000,0x00000020,
-/*
- MOVE FROM 40, WHEN MSG_IN
-
-at 0x00000231 : */ 0x1f000000,0x00000028,
-/*
-
-
-
- CLEAR ACK
-
-at 0x00000233 : */ 0x60000040,0x00000000,
-/*
- WAIT DISCONNECT
-
-at 0x00000235 : */ 0x48000000,0x00000000,
-/*
-test_2_fail:
-
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-
-at 0x00000237 : */ 0x7a1b1000,0x00000000,
-/*
-
- INT int_test_2
-
-at 0x00000239 : */ 0x98080000,0x04010000,
-/*
-
-ENTRY debug_break
-debug_break:
- INT int_debug_break
-
-at 0x0000023b : */ 0x98080000,0x03000000,
-/*
-
-;
-; initiator_abort
-; target_abort
-;
-; PURPOSE : Abort the currently established nexus from with initiator
-; or target mode.
-;
-;
-
-ENTRY target_abort
-target_abort:
- SET TARGET
-
-at 0x0000023d : */ 0x58000200,0x00000000,
-/*
- DISCONNECT
-
-at 0x0000023f : */ 0x48000000,0x00000000,
-/*
- CLEAR TARGET
-
-at 0x00000241 : */ 0x60000200,0x00000000,
-/*
- JUMP schedule
-
-at 0x00000243 : */ 0x80080000,0x00000000,
-/*
-
-ENTRY initiator_abort
-initiator_abort:
- SET ATN
-
-at 0x00000245 : */ 0x58000008,0x00000000,
-/*
-;
-; The SCSI-I specification says that targets may go into MSG out at
-; their leisure upon receipt of the ATN single. On all versions of the
-; specification, we can't change phases until REQ transitions true->false,
-; so we need to sink/source one byte of data to allow the transition.
-;
-; For the sake of safety, we'll only source one byte of data in all
-; cases, but to accommodate the SCSI-I dain bramage, we'll sink an
-; arbitrary number of bytes.
- JUMP spew_cmd, WHEN CMD
-
-at 0x00000247 : */ 0x820b0000,0x0000094c,
-/*
- JUMP eat_msgin, WHEN MSG_IN
-
-at 0x00000249 : */ 0x870b0000,0x0000095c,
-/*
- JUMP eat_datain, WHEN DATA_IN
-
-at 0x0000024b : */ 0x810b0000,0x0000098c,
-/*
- JUMP eat_status, WHEN STATUS
-
-at 0x0000024d : */ 0x830b0000,0x00000974,
-/*
- JUMP spew_dataout, WHEN DATA_OUT
-
-at 0x0000024f : */ 0x800b0000,0x000009a4,
-/*
- JUMP sated
-
-at 0x00000251 : */ 0x80080000,0x000009ac,
-/*
-spew_cmd:
- MOVE 1, NCR53c7xx_zero, WHEN CMD
-
-at 0x00000253 : */ 0x0a000001,0x00000000,
-/*
- JUMP sated
-
-at 0x00000255 : */ 0x80080000,0x000009ac,
-/*
-eat_msgin:
- MOVE 1, NCR53c7xx_sink, WHEN MSG_IN
-
-at 0x00000257 : */ 0x0f000001,0x00000000,
-/*
- JUMP eat_msgin, WHEN MSG_IN
-
-at 0x00000259 : */ 0x870b0000,0x0000095c,
-/*
- JUMP sated
-
-at 0x0000025b : */ 0x80080000,0x000009ac,
-/*
-eat_status:
- MOVE 1, NCR53c7xx_sink, WHEN STATUS
-
-at 0x0000025d : */ 0x0b000001,0x00000000,
-/*
- JUMP eat_status, WHEN STATUS
-
-at 0x0000025f : */ 0x830b0000,0x00000974,
-/*
- JUMP sated
-
-at 0x00000261 : */ 0x80080000,0x000009ac,
-/*
-eat_datain:
- MOVE 1, NCR53c7xx_sink, WHEN DATA_IN
-
-at 0x00000263 : */ 0x09000001,0x00000000,
-/*
- JUMP eat_datain, WHEN DATA_IN
-
-at 0x00000265 : */ 0x810b0000,0x0000098c,
-/*
- JUMP sated
-
-at 0x00000267 : */ 0x80080000,0x000009ac,
-/*
-spew_dataout:
- MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT
-
-at 0x00000269 : */ 0x08000001,0x00000000,
-/*
-sated:
-
-
-
- MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT
-
-at 0x0000026b : */ 0x0e000001,0x00000000,
-/*
- WAIT DISCONNECT
-
-at 0x0000026d : */ 0x48000000,0x00000000,
-/*
- INT int_norm_aborted
-
-at 0x0000026f : */ 0x98080000,0x02040000,
-/*
-
-
-
-
-; Little patched jump, used to overcome problems with TEMP getting
-; corrupted on memory moves.
-
-jump_temp:
- JUMP 0
-
-at 0x00000271 : */ 0x80080000,0x00000000,
-};
-
-#define A_NCR53c7xx_msg_abort 0x00000000
-static u32 A_NCR53c7xx_msg_abort_used[] __attribute((unused)) = {
- 0x0000026c,
-};
-
-#define A_NCR53c7xx_msg_reject 0x00000000
-static u32 A_NCR53c7xx_msg_reject_used[] __attribute((unused)) = {
- 0x00000186,
-};
-
-#define A_NCR53c7xx_sink 0x00000000
-static u32 A_NCR53c7xx_sink_used[] __attribute((unused)) = {
- 0x00000258,
- 0x0000025e,
- 0x00000264,
-};
-
-#define A_NCR53c7xx_zero 0x00000000
-static u32 A_NCR53c7xx_zero_used[] __attribute((unused)) = {
- 0x00000254,
- 0x0000026a,
-};
-
-#define A_NOP_insn 0x00000000
-static u32 A_NOP_insn_used[] __attribute((unused)) = {
- 0x00000017,
-};
-
-#define A_addr_dsa 0x00000000
-static u32 A_addr_dsa_used[] __attribute((unused)) = {
- 0x0000000f,
- 0x00000026,
- 0x00000033,
- 0x00000040,
- 0x00000055,
- 0x00000079,
- 0x0000008e,
- 0x000000bc,
- 0x000000d2,
- 0x00000130,
- 0x000001a5,
- 0x000001bb,
- 0x000001e3,
-};
-
-#define A_addr_reconnect_dsa_head 0x00000000
-static u32 A_addr_reconnect_dsa_head_used[] __attribute((unused)) = {
- 0x000001b7,
-};
-
-#define A_addr_scratch 0x00000000
-static u32 A_addr_scratch_used[] __attribute((unused)) = {
- 0x00000002,
- 0x00000004,
- 0x00000008,
- 0x00000020,
- 0x00000022,
- 0x00000049,
- 0x00000060,
- 0x0000006a,
- 0x00000071,
- 0x00000073,
- 0x000000ab,
- 0x000000b5,
- 0x000000c1,
- 0x000000cb,
- 0x0000012c,
- 0x00000142,
- 0x00000157,
- 0x000001b2,
- 0x000001b4,
- 0x000001df,
- 0x000001f7,
-};
-
-#define A_addr_temp 0x00000000
-static u32 A_addr_temp_used[] __attribute((unused)) = {
-};
-
-#define A_dmode_memory_to_memory 0x00000000
-static u32 A_dmode_memory_to_memory_used[] __attribute((unused)) = {
-};
-
-#define A_dmode_memory_to_ncr 0x00000000
-static u32 A_dmode_memory_to_ncr_used[] __attribute((unused)) = {
-};
-
-#define A_dmode_ncr_to_memory 0x00000000
-static u32 A_dmode_ncr_to_memory_used[] __attribute((unused)) = {
-};
-
-#define A_dsa_check_reselect 0x00000000
-static u32 A_dsa_check_reselect_used[] __attribute((unused)) = {
- 0x000001d0,
-};
-
-#define A_dsa_cmdout 0x00000048
-static u32 A_dsa_cmdout_used[] __attribute((unused)) = {
- 0x0000009a,
-};
-
-#define A_dsa_cmnd 0x00000038
-static u32 A_dsa_cmnd_used[] __attribute((unused)) = {
-};
-
-#define A_dsa_datain 0x00000054
-static u32 A_dsa_datain_used[] __attribute((unused)) = {
- 0x000000c2,
-};
-
-#define A_dsa_dataout 0x00000050
-static u32 A_dsa_dataout_used[] __attribute((unused)) = {
- 0x000000ac,
-};
-
-#define A_dsa_end 0x00000070
-static u32 A_dsa_end_used[] __attribute((unused)) = {
-};
-
-#define A_dsa_fields_start 0x00000000
-static u32 A_dsa_fields_start_used[] __attribute((unused)) = {
-};
-
-#define A_dsa_msgin 0x00000058
-static u32 A_dsa_msgin_used[] __attribute((unused)) = {
- 0x0000019c,
-};
-
-#define A_dsa_msgout 0x00000040
-static u32 A_dsa_msgout_used[] __attribute((unused)) = {
- 0x00000089,
-};
-
-#define A_dsa_msgout_other 0x00000068
-static u32 A_dsa_msgout_other_used[] __attribute((unused)) = {
- 0x00000194,
-};
-
-#define A_dsa_next 0x00000030
-static u32 A_dsa_next_used[] __attribute((unused)) = {
- 0x00000061,
-};
-
-#define A_dsa_restore_pointers 0x00000000
-static u32 A_dsa_restore_pointers_used[] __attribute((unused)) = {
- 0x00000146,
-};
-
-#define A_dsa_save_data_pointer 0x00000000
-static u32 A_dsa_save_data_pointer_used[] __attribute((unused)) = {
- 0x00000131,
-};
-
-#define A_dsa_select 0x0000003c
-static u32 A_dsa_select_used[] __attribute((unused)) = {
- 0x00000082,
-};
-
-#define A_dsa_sscf_710 0x00000000
-static u32 A_dsa_sscf_710_used[] __attribute((unused)) = {
- 0x00000007,
-};
-
-#define A_dsa_status 0x00000060
-static u32 A_dsa_status_used[] __attribute((unused)) = {
- 0x00000198,
-};
-
-#define A_dsa_temp_addr_array_value 0x00000000
-static u32 A_dsa_temp_addr_array_value_used[] __attribute((unused)) = {
-};
-
-#define A_dsa_temp_addr_dsa_value 0x00000000
-static u32 A_dsa_temp_addr_dsa_value_used[] __attribute((unused)) = {
- 0x00000001,
-};
-
-#define A_dsa_temp_addr_new_value 0x00000000
-static u32 A_dsa_temp_addr_new_value_used[] __attribute((unused)) = {
-};
-
-#define A_dsa_temp_addr_next 0x00000000
-static u32 A_dsa_temp_addr_next_used[] __attribute((unused)) = {
- 0x0000001c,
- 0x0000004f,
-};
-
-#define A_dsa_temp_addr_residual 0x00000000
-static u32 A_dsa_temp_addr_residual_used[] __attribute((unused)) = {
- 0x0000002d,
- 0x0000003b,
-};
-
-#define A_dsa_temp_addr_saved_pointer 0x00000000
-static u32 A_dsa_temp_addr_saved_pointer_used[] __attribute((unused)) = {
- 0x0000002b,
- 0x00000037,
-};
-
-#define A_dsa_temp_addr_saved_residual 0x00000000
-static u32 A_dsa_temp_addr_saved_residual_used[] __attribute((unused)) = {
- 0x0000002e,
- 0x0000003a,
-};
-
-#define A_dsa_temp_lun 0x00000000
-static u32 A_dsa_temp_lun_used[] __attribute((unused)) = {
- 0x0000004c,
-};
-
-#define A_dsa_temp_next 0x00000000
-static u32 A_dsa_temp_next_used[] __attribute((unused)) = {
- 0x0000001f,
-};
-
-#define A_dsa_temp_sync 0x00000000
-static u32 A_dsa_temp_sync_used[] __attribute((unused)) = {
- 0x00000057,
-};
-
-#define A_dsa_temp_target 0x00000000
-static u32 A_dsa_temp_target_used[] __attribute((unused)) = {
- 0x00000045,
-};
-
-#define A_emulfly 0x00000000
-static u32 A_emulfly_used[] __attribute((unused)) = {
-};
-
-#define A_int_debug_break 0x03000000
-static u32 A_int_debug_break_used[] __attribute((unused)) = {
- 0x0000023c,
-};
-
-#define A_int_debug_panic 0x030b0000
-static u32 A_int_debug_panic_used[] __attribute((unused)) = {
- 0x00000209,
- 0x00000219,
-};
-
-#define A_int_err_check_condition 0x00030000
-static u32 A_int_err_check_condition_used[] __attribute((unused)) = {
- 0x000001a9,
-};
-
-#define A_int_err_no_phase 0x00040000
-static u32 A_int_err_no_phase_used[] __attribute((unused)) = {
-};
-
-#define A_int_err_selected 0x00010000
-static u32 A_int_err_selected_used[] __attribute((unused)) = {
- 0x000001ff,
-};
-
-#define A_int_err_unexpected_phase 0x00000000
-static u32 A_int_err_unexpected_phase_used[] __attribute((unused)) = {
- 0x00000092,
- 0x00000098,
- 0x000000a0,
- 0x000000d6,
- 0x000000da,
- 0x000000dc,
- 0x000000e4,
- 0x000000e8,
- 0x000000ea,
- 0x000000f2,
- 0x000000f6,
- 0x000000f8,
- 0x000000fa,
- 0x00000160,
-};
-
-#define A_int_err_unexpected_reselect 0x00020000
-static u32 A_int_err_unexpected_reselect_used[] __attribute((unused)) = {
- 0x000001cd,
-};
-
-#define A_int_msg_1 0x01020000
-static u32 A_int_msg_1_used[] __attribute((unused)) = {
- 0x00000114,
- 0x00000116,
-};
-
-#define A_int_msg_sdtr 0x01010000
-static u32 A_int_msg_sdtr_used[] __attribute((unused)) = {
- 0x00000180,
-};
-
-#define A_int_msg_wdtr 0x01000000
-static u32 A_int_msg_wdtr_used[] __attribute((unused)) = {
- 0x00000174,
-};
-
-#define A_int_norm_aborted 0x02040000
-static u32 A_int_norm_aborted_used[] __attribute((unused)) = {
- 0x00000270,
-};
-
-#define A_int_norm_command_complete 0x02020000
-static u32 A_int_norm_command_complete_used[] __attribute((unused)) = {
-};
-
-#define A_int_norm_disconnected 0x02030000
-static u32 A_int_norm_disconnected_used[] __attribute((unused)) = {
-};
-
-#define A_int_norm_emulateintfly 0x02060000
-static u32 A_int_norm_emulateintfly_used[] __attribute((unused)) = {
- 0x000001a2,
-};
-
-#define A_int_norm_reselect_complete 0x02010000
-static u32 A_int_norm_reselect_complete_used[] __attribute((unused)) = {
-};
-
-#define A_int_norm_reset 0x02050000
-static u32 A_int_norm_reset_used[] __attribute((unused)) = {
-};
-
-#define A_int_norm_select_complete 0x02000000
-static u32 A_int_norm_select_complete_used[] __attribute((unused)) = {
-};
-
-#define A_int_test_1 0x04000000
-static u32 A_int_test_1_used[] __attribute((unused)) = {
- 0x0000021e,
-};
-
-#define A_int_test_2 0x04010000
-static u32 A_int_test_2_used[] __attribute((unused)) = {
- 0x0000023a,
-};
-
-#define A_int_test_3 0x04020000
-static u32 A_int_test_3_used[] __attribute((unused)) = {
-};
-
-#define A_msg_buf 0x00000000
-static u32 A_msg_buf_used[] __attribute((unused)) = {
- 0x00000108,
- 0x00000162,
- 0x0000016c,
- 0x00000172,
- 0x00000178,
- 0x0000017e,
-};
-
-#define A_reconnect_dsa_head 0x00000000
-static u32 A_reconnect_dsa_head_used[] __attribute((unused)) = {
- 0x0000006d,
- 0x00000074,
- 0x000001b1,
-};
-
-#define A_reselected_identify 0x00000000
-static u32 A_reselected_identify_used[] __attribute((unused)) = {
- 0x00000048,
- 0x000001af,
-};
-
-#define A_reselected_tag 0x00000000
-static u32 A_reselected_tag_used[] __attribute((unused)) = {
-};
-
-#define A_saved_dsa 0x00000000
-static u32 A_saved_dsa_used[] __attribute((unused)) = {
- 0x00000005,
- 0x0000000e,
- 0x00000023,
- 0x00000025,
- 0x00000032,
- 0x0000003f,
- 0x00000054,
- 0x0000005f,
- 0x00000070,
- 0x00000078,
- 0x0000008d,
- 0x000000aa,
- 0x000000bb,
- 0x000000c0,
- 0x000000d1,
- 0x0000012f,
- 0x000001a4,
- 0x000001b5,
- 0x000001ba,
- 0x000001e2,
-};
-
-#define A_schedule 0x00000000
-static u32 A_schedule_used[] __attribute((unused)) = {
- 0x0000007d,
- 0x000001a7,
- 0x00000203,
- 0x00000244,
-};
-
-#define A_test_dest 0x00000000
-static u32 A_test_dest_used[] __attribute((unused)) = {
- 0x0000021c,
-};
-
-#define A_test_src 0x00000000
-static u32 A_test_src_used[] __attribute((unused)) = {
- 0x0000021b,
-};
-
-#define Ent_accept_message 0x00000624
-#define Ent_cmdout_cmdout 0x00000264
-#define Ent_command_complete 0x0000065c
-#define Ent_command_complete_msgin 0x0000066c
-#define Ent_data_transfer 0x0000026c
-#define Ent_datain_to_jump 0x00000334
-#define Ent_debug_break 0x000008ec
-#define Ent_dsa_code_begin 0x00000000
-#define Ent_dsa_code_check_reselect 0x0000010c
-#define Ent_dsa_code_fix_jump 0x00000058
-#define Ent_dsa_code_restore_pointers 0x000000d8
-#define Ent_dsa_code_save_data_pointer 0x000000a4
-#define Ent_dsa_code_template 0x00000000
-#define Ent_dsa_code_template_end 0x00000178
-#define Ent_dsa_schedule 0x00000178
-#define Ent_dsa_zero 0x00000178
-#define Ent_end_data_transfer 0x000002a4
-#define Ent_initiator_abort 0x00000914
-#define Ent_msg_in 0x0000041c
-#define Ent_msg_in_restart 0x000003fc
-#define Ent_other_in 0x0000038c
-#define Ent_other_out 0x00000354
-#define Ent_other_transfer 0x000003c4
-#define Ent_reject_message 0x00000604
-#define Ent_reselected_check_next 0x000006f0
-#define Ent_reselected_ok 0x00000798
-#define Ent_respond_message 0x0000063c
-#define Ent_select 0x000001f8
-#define Ent_select_msgout 0x00000218
-#define Ent_target_abort 0x000008f4
-#define Ent_test_1 0x00000868
-#define Ent_test_2 0x0000087c
-#define Ent_test_2_msgout 0x0000089c
-#define Ent_wait_reselect 0x000006a8
-static u32 LABELPATCHES[] __attribute((unused)) = {
- 0x00000011,
- 0x0000001a,
- 0x0000001d,
- 0x00000028,
- 0x0000002a,
- 0x00000035,
- 0x00000038,
- 0x00000042,
- 0x00000050,
- 0x00000052,
- 0x0000006b,
- 0x00000083,
- 0x00000085,
- 0x00000090,
- 0x00000094,
- 0x00000096,
- 0x0000009c,
- 0x0000009e,
- 0x000000a2,
- 0x000000a4,
- 0x000000a6,
- 0x000000a8,
- 0x000000b6,
- 0x000000b9,
- 0x000000cc,
- 0x000000cf,
- 0x000000d8,
- 0x000000de,
- 0x000000e0,
- 0x000000e6,
- 0x000000ec,
- 0x000000ee,
- 0x000000f4,
- 0x000000fc,
- 0x000000fe,
- 0x0000010a,
- 0x0000010c,
- 0x0000010e,
- 0x00000110,
- 0x00000112,
- 0x00000118,
- 0x0000011a,
- 0x0000012d,
- 0x00000143,
- 0x00000158,
- 0x0000015c,
- 0x00000164,
- 0x00000166,
- 0x00000168,
- 0x0000016e,
- 0x0000017a,
- 0x000001ab,
- 0x000001b8,
- 0x000001bf,
- 0x000001c3,
- 0x000001c7,
- 0x000001cb,
- 0x000001e0,
- 0x000001f8,
- 0x00000207,
- 0x0000020f,
- 0x00000213,
- 0x00000217,
- 0x00000224,
- 0x00000226,
- 0x00000248,
- 0x0000024a,
- 0x0000024c,
- 0x0000024e,
- 0x00000250,
- 0x00000252,
- 0x00000256,
- 0x0000025a,
- 0x0000025c,
- 0x00000260,
- 0x00000262,
- 0x00000266,
- 0x00000268,
-};
-
-static struct {
- u32 offset;
- void *address;
-} EXTERNAL_PATCHES[] __attribute((unused)) = {
-};
-
-static u32 INSTRUCTIONS __attribute((unused)) = 290;
-static u32 PATCHES __attribute((unused)) = 78;
-static u32 EXTERNAL_PATCHES_LEN __attribute((unused)) = 0;
diff --git a/drivers/scsi/53c7xx_u.h_shipped b/drivers/scsi/53c7xx_u.h_shipped
deleted file mode 100644
index 7b33717..0000000
--- a/drivers/scsi/53c7xx_u.h_shipped
+++ /dev/null
@@ -1,102 +0,0 @@
-#undef A_NCR53c7xx_msg_abort
-#undef A_NCR53c7xx_msg_reject
-#undef A_NCR53c7xx_sink
-#undef A_NCR53c7xx_zero
-#undef A_NOP_insn
-#undef A_addr_dsa
-#undef A_addr_reconnect_dsa_head
-#undef A_addr_scratch
-#undef A_addr_temp
-#undef A_dmode_memory_to_memory
-#undef A_dmode_memory_to_ncr
-#undef A_dmode_ncr_to_memory
-#undef A_dsa_check_reselect
-#undef A_dsa_cmdout
-#undef A_dsa_cmnd
-#undef A_dsa_datain
-#undef A_dsa_dataout
-#undef A_dsa_end
-#undef A_dsa_fields_start
-#undef A_dsa_msgin
-#undef A_dsa_msgout
-#undef A_dsa_msgout_other
-#undef A_dsa_next
-#undef A_dsa_restore_pointers
-#undef A_dsa_save_data_pointer
-#undef A_dsa_select
-#undef A_dsa_sscf_710
-#undef A_dsa_status
-#undef A_dsa_temp_addr_array_value
-#undef A_dsa_temp_addr_dsa_value
-#undef A_dsa_temp_addr_new_value
-#undef A_dsa_temp_addr_next
-#undef A_dsa_temp_addr_residual
-#undef A_dsa_temp_addr_saved_pointer
-#undef A_dsa_temp_addr_saved_residual
-#undef A_dsa_temp_lun
-#undef A_dsa_temp_next
-#undef A_dsa_temp_sync
-#undef A_dsa_temp_target
-#undef A_emulfly
-#undef A_int_debug_break
-#undef A_int_debug_panic
-#undef A_int_err_check_condition
-#undef A_int_err_no_phase
-#undef A_int_err_selected
-#undef A_int_err_unexpected_phase
-#undef A_int_err_unexpected_reselect
-#undef A_int_msg_1
-#undef A_int_msg_sdtr
-#undef A_int_msg_wdtr
-#undef A_int_norm_aborted
-#undef A_int_norm_command_complete
-#undef A_int_norm_disconnected
-#undef A_int_norm_emulateintfly
-#undef A_int_norm_reselect_complete
-#undef A_int_norm_reset
-#undef A_int_norm_select_complete
-#undef A_int_test_1
-#undef A_int_test_2
-#undef A_int_test_3
-#undef A_msg_buf
-#undef A_reconnect_dsa_head
-#undef A_reselected_identify
-#undef A_reselected_tag
-#undef A_saved_dsa
-#undef A_schedule
-#undef A_test_dest
-#undef A_test_src
-#undef Ent_accept_message
-#undef Ent_cmdout_cmdout
-#undef Ent_command_complete
-#undef Ent_command_complete_msgin
-#undef Ent_data_transfer
-#undef Ent_datain_to_jump
-#undef Ent_debug_break
-#undef Ent_dsa_code_begin
-#undef Ent_dsa_code_check_reselect
-#undef Ent_dsa_code_fix_jump
-#undef Ent_dsa_code_restore_pointers
-#undef Ent_dsa_code_save_data_pointer
-#undef Ent_dsa_code_template
-#undef Ent_dsa_code_template_end
-#undef Ent_dsa_schedule
-#undef Ent_dsa_zero
-#undef Ent_end_data_transfer
-#undef Ent_initiator_abort
-#undef Ent_msg_in
-#undef Ent_msg_in_restart
-#undef Ent_other_in
-#undef Ent_other_out
-#undef Ent_other_transfer
-#undef Ent_reject_message
-#undef Ent_reselected_check_next
-#undef Ent_reselected_ok
-#undef Ent_respond_message
-#undef Ent_select
-#undef Ent_select_msgout
-#undef Ent_target_abort
-#undef Ent_test_1
-#undef Ent_test_2
-#undef Ent_test_2_msgout
-#undef Ent_wait_reselect
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 96f4cab0..9b20617 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -304,18 +304,10 @@
static void BusLogic_DeallocateCCB(struct BusLogic_CCB *CCB)
{
struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter;
- struct scsi_cmnd *cmd = CCB->Command;
- if (cmd->use_sg != 0) {
- pci_unmap_sg(HostAdapter->PCI_Device,
- (struct scatterlist *)cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- } else if (cmd->request_bufflen != 0) {
- pci_unmap_single(HostAdapter->PCI_Device, CCB->DataPointer,
- CCB->DataLength, cmd->sc_data_direction);
- }
+ scsi_dma_unmap(CCB->Command);
pci_unmap_single(HostAdapter->PCI_Device, CCB->SenseDataPointer,
- CCB->SenseDataLength, PCI_DMA_FROMDEVICE);
+ CCB->SenseDataLength, PCI_DMA_FROMDEVICE);
CCB->Command = NULL;
CCB->Status = BusLogic_CCB_Free;
@@ -2648,7 +2640,8 @@
*/
if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 && CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally) {
struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[CCB->TargetID];
- struct SCSI_Inquiry *InquiryResult = (struct SCSI_Inquiry *) Command->request_buffer;
+ struct SCSI_Inquiry *InquiryResult =
+ (struct SCSI_Inquiry *) scsi_sglist(Command);
TargetFlags->TargetExists = true;
TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue;
TargetFlags->WideTransfersSupported = InquiryResult->WBus16;
@@ -2819,9 +2812,8 @@
int CDB_Length = Command->cmd_len;
int TargetID = Command->device->id;
int LogicalUnit = Command->device->lun;
- void *BufferPointer = Command->request_buffer;
- int BufferLength = Command->request_bufflen;
- int SegmentCount = Command->use_sg;
+ int BufferLength = scsi_bufflen(Command);
+ int Count;
struct BusLogic_CCB *CCB;
/*
SCSI REQUEST_SENSE commands will be executed automatically by the Host
@@ -2851,36 +2843,35 @@
return 0;
}
}
+
/*
Initialize the fields in the BusLogic Command Control Block (CCB).
*/
- if (SegmentCount == 0 && BufferLength != 0) {
- CCB->Opcode = BusLogic_InitiatorCCB;
- CCB->DataLength = BufferLength;
- CCB->DataPointer = pci_map_single(HostAdapter->PCI_Device,
- BufferPointer, BufferLength,
- Command->sc_data_direction);
- } else if (SegmentCount != 0) {
- struct scatterlist *ScatterList = (struct scatterlist *) BufferPointer;
- int Segment, Count;
+ Count = scsi_dma_map(Command);
+ BUG_ON(Count < 0);
+ if (Count) {
+ struct scatterlist *sg;
+ int i;
- Count = pci_map_sg(HostAdapter->PCI_Device, ScatterList, SegmentCount,
- Command->sc_data_direction);
CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather;
CCB->DataLength = Count * sizeof(struct BusLogic_ScatterGatherSegment);
if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
CCB->DataPointer = (unsigned int) CCB->DMA_Handle + ((unsigned long) &CCB->ScatterGatherList - (unsigned long) CCB);
else
CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList);
- for (Segment = 0; Segment < Count; Segment++) {
- CCB->ScatterGatherList[Segment].SegmentByteCount = sg_dma_len(ScatterList + Segment);
- CCB->ScatterGatherList[Segment].SegmentDataPointer = sg_dma_address(ScatterList + Segment);
+
+ scsi_for_each_sg(Command, sg, Count, i) {
+ CCB->ScatterGatherList[i].SegmentByteCount =
+ sg_dma_len(sg);
+ CCB->ScatterGatherList[i].SegmentDataPointer =
+ sg_dma_address(sg);
}
- } else {
+ } else if (!Count) {
CCB->Opcode = BusLogic_InitiatorCCB;
CCB->DataLength = BufferLength;
CCB->DataPointer = 0;
}
+
switch (CDB[0]) {
case READ_6:
case READ_10:
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index eb46cb0..9d2119b 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -10,6 +10,7 @@
config SCSI
tristate "SCSI device support"
depends on BLOCK
+ select SCSI_DMA if HAS_DMA
---help---
If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
any other SCSI device under Linux, say Y and make sure that you know
@@ -29,6 +30,10 @@
However, do not compile this as a module if your root file system
(the one containing the directory /) is located on a SCSI device.
+config SCSI_DMA
+ bool
+ default n
+
config SCSI_TGT
tristate "SCSI target support"
depends on SCSI && EXPERIMENTAL
@@ -739,7 +744,7 @@
config SCSI_IBMMCA
tristate "IBMMCA SCSI support"
- depends on MCA_LEGACY && SCSI
+ depends on MCA && SCSI
---help---
This is support for the IBM SCSI adapter found in many of the PS/2
series computers. These machines have an MCA bus, so you need to
@@ -1007,6 +1012,11 @@
To compile this driver as a module, choose M here: the
module will be called stex.
+config 53C700_BE_BUS
+ bool
+ depends on SCSI_A4000T || SCSI_ZORRO7XX || MVME16x_SCSI || BVME6000_SCSI
+ default y
+
config SCSI_SYM53C8XX_2
tristate "SYM53C8XX Version 2 SCSI support"
depends on PCI && SCSI
@@ -1611,13 +1621,25 @@
If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use
one in the near future, say Y to this question. Otherwise, say N.
-config SCSI_AMIGA7XX
- bool "Amiga NCR53c710 SCSI support (EXPERIMENTAL)"
- depends on AMIGA && SCSI && EXPERIMENTAL && BROKEN
+config SCSI_A4000T
+ tristate "A4000T NCR53c710 SCSI support (EXPERIMENTAL)"
+ depends on AMIGA && SCSI && EXPERIMENTAL
+ select SCSI_SPI_ATTRS
help
- Support for various NCR53c710-based SCSI controllers on the Amiga.
+ If you have an Amiga 4000T and have SCSI devices connected to the
+ built-in SCSI controller, say Y. Otherwise, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called a4000t.
+
+config SCSI_ZORRO7XX
+ tristate "Zorro NCR53c710 SCSI support (EXPERIMENTAL)"
+ depends on ZORRO && SCSI && EXPERIMENTAL
+ select SCSI_SPI_ATTRS
+ help
+ Support for various NCR53c710-based SCSI controllers on Zorro
+ expansion boards for the Amiga.
This includes:
- - the builtin SCSI controller on the Amiga 4000T,
- the Amiga 4091 Zorro III SCSI-2 controller,
- the MacroSystem Development's WarpEngine Amiga SCSI-2 controller
(info at
@@ -1625,10 +1647,6 @@
- the SCSI controller on the Phase5 Blizzard PowerUP 603e+
accelerator card for the Amiga 1200,
- the SCSI controller on the GVP Turbo 040/060 accelerator.
- Note that all of the above SCSI controllers, except for the builtin
- SCSI controller on the Amiga 4000T, reside on the Zorro expansion
- bus, so you also have to enable Zorro bus support if you want to use
- them.
config OKTAGON_SCSI
tristate "BSC Oktagon SCSI support (EXPERIMENTAL)"
@@ -1712,8 +1730,8 @@
single-board computer.
config MVME16x_SCSI
- bool "NCR53C710 SCSI driver for MVME16x"
- depends on MVME16x && SCSI && BROKEN
+ tristate "NCR53C710 SCSI driver for MVME16x"
+ depends on MVME16x && SCSI
select SCSI_SPI_ATTRS
help
The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710
@@ -1721,22 +1739,14 @@
will want to say Y to this question.
config BVME6000_SCSI
- bool "NCR53C710 SCSI driver for BVME6000"
- depends on BVME6000 && SCSI && BROKEN
+ tristate "NCR53C710 SCSI driver for BVME6000"
+ depends on BVME6000 && SCSI
select SCSI_SPI_ATTRS
help
The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710
SCSI controller chip. Almost everyone using one of these boards
will want to say Y to this question.
-config SCSI_NCR53C7xx_FAST
- bool "allow FAST-SCSI [10MHz]"
- depends on SCSI_AMIGA7XX || MVME16x_SCSI || BVME6000_SCSI
- help
- This will enable 10MHz FAST-SCSI transfers with your host
- adapter. Some systems have problems with that speed, so it's safest
- to say N here.
-
config SUN3_SCSI
tristate "Sun3 NCR5380 SCSI"
depends on SUN3 && SCSI
@@ -1766,8 +1776,6 @@
To compile this driver as a module, choose M here: the
module will be called esp.
-# bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI
-
config ZFCP
tristate "FCP host bus adapter driver for IBM eServer zSeries"
depends on S390 && QDIO && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index b1b6327..0f86895 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -37,7 +37,8 @@
obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o
obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
-obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o
+obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o
+obj-$(CONFIG_SCSI_ZORRO7XX) += 53c700.o zorro7xx.o
obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o
@@ -53,8 +54,8 @@
obj-$(CONFIG_MAC_SCSI) += mac_scsi.o
obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o
obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o
-obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o
-obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o
+obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o
+obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o
obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o
obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o
obj-$(CONFIG_SCSI_PSI240I) += psi240i.o
@@ -89,7 +90,6 @@
obj-$(CONFIG_SCSI_LPFC) += lpfc/
obj-$(CONFIG_SCSI_PAS16) += pas16.o
obj-$(CONFIG_SCSI_SEAGATE) += seagate.o
-obj-$(CONFIG_SCSI_FD_8xx) += seagate.o
obj-$(CONFIG_SCSI_T128) += t128.o
obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o
obj-$(CONFIG_SCSI_DTC3280) += dtc.o
@@ -148,9 +148,9 @@
obj-$(CONFIG_SCSI_WAIT_SCAN) += scsi_wait_scan.o
scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \
- scsicam.o scsi_error.o scsi_lib.o \
- scsi_scan.o scsi_sysfs.o \
- scsi_devinfo.o
+ scsicam.o scsi_error.o scsi_lib.o
+scsi_mod-$(CONFIG_SCSI_DMA) += scsi_lib_dma.o
+scsi_mod-y += scsi_scan.o scsi_sysfs.o scsi_devinfo.o
scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o
scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
@@ -168,10 +168,8 @@
oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o
# Files generated that shall be removed upon make clean
-clean-files := 53c7xx_d.h 53c700_d.h \
- 53c7xx_u.h 53c700_u.h
+clean-files := 53c700_d.h 53c700_u.h
-$(obj)/53c7xx.o: $(obj)/53c7xx_d.h $(obj)/53c7xx_u.h
$(obj)/53c700.o $(MODVERDIR)/$(obj)/53c700.ver: $(obj)/53c700_d.h
# If you want to play with the firmware, uncomment
@@ -179,11 +177,6 @@
ifdef GENERATE_FIRMWARE
-$(obj)/53c7xx_d.h: $(src)/53c7xx.scr $(src)/script_asm.pl
- $(CPP) -traditional -DCHIP=710 - < $< | grep -v '^#' | $(PERL) -s $(src)/script_asm.pl -ncr7x0_family $@ $(@:_d.h=_u.h)
-
-$(obj)/53c7xx_u.h: $(obj)/53c7xx_d.h
-
$(obj)/53c700_d.h: $(src)/53c700.scr $(src)/script_asm.pl
$(PERL) -s $(src)/script_asm.pl -ncr7x0_family $@ $(@:_d.h=_u.h) < $<
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 88ea5a1..f8e449a 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -347,7 +347,7 @@
if((r & bit) == val)
return 0;
if(!in_interrupt())
- yield();
+ cond_resched();
else
cpu_relax();
}
@@ -357,7 +357,7 @@
static struct {
unsigned char value;
const char *name;
-} phases[] = {
+} phases[] __maybe_unused = {
{PHASE_DATAOUT, "DATAOUT"},
{PHASE_DATAIN, "DATAIN"},
{PHASE_CMDOUT, "CMDOUT"},
@@ -575,7 +575,8 @@
* Locks: none, irqs must be enabled on entry
*/
-static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible)
+static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
+ int possible)
{
NCR5380_local_declare();
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
@@ -629,7 +630,8 @@
* Locks: none
*/
-static void __init NCR5380_print_options(struct Scsi_Host *instance)
+static void __init __maybe_unused
+NCR5380_print_options(struct Scsi_Host *instance)
{
printk(" generic options"
#ifdef AUTOPROBE_IRQ
@@ -703,8 +705,8 @@
static
char *lprint_opcode(int opcode, char *pos, char *buffer, int length);
-static
-int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, char **start, off_t offset, int length, int inout)
+static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance,
+ char *buffer, char **start, off_t offset, int length, int inout)
{
char *pos = buffer;
struct NCR5380_hostdata *hostdata;
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index 713a108..bccf13f 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -299,7 +299,7 @@
static irqreturn_t NCR5380_intr(int irq, void *dev_id);
#endif
static void NCR5380_main(struct work_struct *work);
-static void NCR5380_print_options(struct Scsi_Host *instance);
+static void __maybe_unused NCR5380_print_options(struct Scsi_Host *instance);
#ifdef NDEBUG
static void NCR5380_print_phase(struct Scsi_Host *instance);
static void NCR5380_print(struct Scsi_Host *instance);
@@ -307,8 +307,8 @@
static int NCR5380_abort(Scsi_Cmnd * cmd);
static int NCR5380_bus_reset(Scsi_Cmnd * cmd);
static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
-static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, char **start,
-off_t offset, int length, int inout);
+static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance,
+ char *buffer, char **start, off_t offset, int length, int inout);
static void NCR5380_reselect(struct Scsi_Host *instance);
static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag);
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index 7c0b17f..eda8c48 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -698,7 +698,7 @@
int i;
VDEB(printk("NCR53c406a_queue called\n"));
- DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->target, SCpnt->lun, SCpnt->request_bufflen));
+ DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->target, SCpnt->lun, scsi_bufflen(SCpnt)));
#if 0
VDEB(for (i = 0; i < SCpnt->cmd_len; i++)
@@ -785,8 +785,8 @@
unsigned char status, int_reg;
#if USE_PIO
unsigned char pio_status;
- struct scatterlist *sglist;
- unsigned int sgcount;
+ struct scatterlist *sg;
+ int i;
#endif
VDEB(printk("NCR53c406a_intr called\n"));
@@ -866,22 +866,18 @@
current_SC->SCp.phase = data_out;
VDEB(printk("NCR53c406a: Data-Out phase\n"));
outb(FLUSH_FIFO, CMD_REG);
- LOAD_DMA_COUNT(current_SC->request_bufflen); /* Max transfer size */
+ LOAD_DMA_COUNT(scsi_bufflen(current_SC)); /* Max transfer size */
#if USE_DMA /* No s/g support for DMA */
- NCR53c406a_dma_write(current_SC->request_buffer, current_SC->request_bufflen);
+ NCR53c406a_dma_write(scsi_sglist(current_SC),
+ scsdi_bufflen(current_SC));
+
#endif /* USE_DMA */
outb(TRANSFER_INFO | DMA_OP, CMD_REG);
#if USE_PIO
- if (!current_SC->use_sg) /* Don't use scatter-gather */
- NCR53c406a_pio_write(current_SC->request_buffer, current_SC->request_bufflen);
- else { /* use scatter-gather */
- sgcount = current_SC->use_sg;
- sglist = current_SC->request_buffer;
- while (sgcount--) {
- NCR53c406a_pio_write(page_address(sglist->page) + sglist->offset, sglist->length);
- sglist++;
- }
- }
+ scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) {
+ NCR53c406a_pio_write(page_address(sg->page) + sg->offset,
+ sg->length);
+ }
REG0;
#endif /* USE_PIO */
}
@@ -893,22 +889,17 @@
current_SC->SCp.phase = data_in;
VDEB(printk("NCR53c406a: Data-In phase\n"));
outb(FLUSH_FIFO, CMD_REG);
- LOAD_DMA_COUNT(current_SC->request_bufflen); /* Max transfer size */
+ LOAD_DMA_COUNT(scsi_bufflen(current_SC)); /* Max transfer size */
#if USE_DMA /* No s/g support for DMA */
- NCR53c406a_dma_read(current_SC->request_buffer, current_SC->request_bufflen);
+ NCR53c406a_dma_read(scsi_sglist(current_SC),
+ scsdi_bufflen(current_SC));
#endif /* USE_DMA */
outb(TRANSFER_INFO | DMA_OP, CMD_REG);
#if USE_PIO
- if (!current_SC->use_sg) /* Don't use scatter-gather */
- NCR53c406a_pio_read(current_SC->request_buffer, current_SC->request_bufflen);
- else { /* Use scatter-gather */
- sgcount = current_SC->use_sg;
- sglist = current_SC->request_buffer;
- while (sgcount--) {
- NCR53c406a_pio_read(page_address(sglist->page) + sglist->offset, sglist->length);
- sglist++;
- }
- }
+ scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) {
+ NCR53c406a_pio_read(page_address(sg->page) + sg->offset,
+ sg->length);
+ }
REG0;
#endif /* USE_PIO */
}
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index 7f4241b..f608d4a 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -19,27 +19,6 @@
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * --------------------------------------------------------------------------
- *
- * 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, immediately at the beginning of the file.
- * 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.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * Where this Software is combined with software released under the terms of
- * the GNU General Public License ("GPL") and the terms of the GPL would require the
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
- *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -75,6 +54,8 @@
* 9/28/04 Christoph Hellwig <hch@lst.de>
* - merge the two source files
* - remove internal queueing code
+ * 14/06/07 Alan Cox <alan@redhat.com>
+ * - Grand cleanup and Linuxisation
*/
#include <linux/module.h>
@@ -102,14 +83,12 @@
#include "a100u2w.h"
-#define JIFFIES_TO_MS(t) ((t) * 1000 / HZ)
-#define MS_TO_JIFFIES(j) ((j * HZ) / 1000)
+static struct orc_scb *__orc_alloc_scb(struct orc_host * host);
+static void inia100_scb_handler(struct orc_host *host, struct orc_scb *scb);
-static ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp);
-static void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
+static struct orc_nvram nvram, *nvramp = &nvram;
-static NVRAM nvram, *nvramp = &nvram;
-static UCHAR dftNvRam[64] =
+static u8 default_nvram[64] =
{
/*----------header -------------*/
0x01, /* 0x00: Sub System Vendor ID 0 */
@@ -158,823 +137,882 @@
};
-/***************************************************************************/
-static void waitForPause(unsigned amount)
-{
- ULONG the_time = jiffies + MS_TO_JIFFIES(amount);
- while (time_before_eq(jiffies, the_time))
- cpu_relax();
-}
-
-/***************************************************************************/
-static UCHAR waitChipReady(ORC_HCS * hcsp)
+static u8 wait_chip_ready(struct orc_host * host)
{
int i;
for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
- if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP) /* Wait HOSTSTOP set */
+ if (inb(host->base + ORC_HCTRL) & HOSTSTOP) /* Wait HOSTSTOP set */
return 1;
- waitForPause(100); /* wait 100ms before try again */
+ mdelay(100);
+ }
+ return 0;
+}
+
+static u8 wait_firmware_ready(struct orc_host * host)
+{
+ int i;
+
+ for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
+ if (inb(host->base + ORC_HSTUS) & RREADY) /* Wait READY set */
+ return 1;
+ mdelay(100); /* wait 100ms before try again */
}
return 0;
}
/***************************************************************************/
-static UCHAR waitFWReady(ORC_HCS * hcsp)
+static u8 wait_scsi_reset_done(struct orc_host * host)
{
int i;
for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
- if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) /* Wait READY set */
+ if (!(inb(host->base + ORC_HCTRL) & SCSIRST)) /* Wait SCSIRST done */
return 1;
- waitForPause(100); /* wait 100ms before try again */
+ mdelay(100); /* wait 100ms before try again */
}
return 0;
}
/***************************************************************************/
-static UCHAR waitSCSIRSTdone(ORC_HCS * hcsp)
+static u8 wait_HDO_off(struct orc_host * host)
{
int i;
for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
- if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST)) /* Wait SCSIRST done */
+ if (!(inb(host->base + ORC_HCTRL) & HDO)) /* Wait HDO off */
return 1;
- waitForPause(100); /* wait 100ms before try again */
+ mdelay(100); /* wait 100ms before try again */
}
return 0;
}
/***************************************************************************/
-static UCHAR waitHDOoff(ORC_HCS * hcsp)
+static u8 wait_hdi_set(struct orc_host * host, u8 * data)
{
int i;
for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
- if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO)) /* Wait HDO off */
- return 1;
- waitForPause(100); /* wait 100ms before try again */
- }
- return 0;
-}
-
-/***************************************************************************/
-static UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData)
-{
- int i;
-
- for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
- if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI)
+ if ((*data = inb(host->base + ORC_HSTUS)) & HDI)
return 1; /* Wait HDI set */
- waitForPause(100); /* wait 100ms before try again */
+ mdelay(100); /* wait 100ms before try again */
}
return 0;
}
/***************************************************************************/
-static unsigned short get_FW_version(ORC_HCS * hcsp)
+static unsigned short orc_read_fwrev(struct orc_host * host)
{
- UCHAR bData;
- union {
- unsigned short sVersion;
- unsigned char cVersion[2];
- } Version;
+ u16 version;
+ u8 data;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_VERSION);
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(ORC_CMD_VERSION, host->base + ORC_HDATA);
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- if (waitHDIset(hcsp, &bData) == 0) /* Wait HDI set */
+ if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */
return 0;
- Version.cVersion[0] = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
- ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */
+ version = inb(host->base + ORC_HDATA);
+ outb(data, host->base + ORC_HSTUS); /* Clear HDI */
- if (waitHDIset(hcsp, &bData) == 0) /* Wait HDI set */
+ if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */
return 0;
- Version.cVersion[1] = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
- ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */
+ version |= inb(host->base + ORC_HDATA) << 8;
+ outb(data, host->base + ORC_HSTUS); /* Clear HDI */
- return (Version.sVersion);
+ return version;
}
/***************************************************************************/
-static UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value)
+static u8 orc_nv_write(struct orc_host * host, unsigned char address, unsigned char value)
{
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_SET_NVM); /* Write command */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(ORC_CMD_SET_NVM, host->base + ORC_HDATA); /* Write command */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, address); /* Write address */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(address, host->base + ORC_HDATA); /* Write address */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, value); /* Write value */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(value, host->base + ORC_HDATA); /* Write value */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
return 1;
}
/***************************************************************************/
-static UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn)
+static u8 orc_nv_read(struct orc_host * host, u8 address, u8 *ptr)
{
- unsigned char bData;
+ unsigned char data;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_GET_NVM); /* Write command */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(ORC_CMD_GET_NVM, host->base + ORC_HDATA); /* Write command */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, address); /* Write address */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(address, host->base + ORC_HDATA); /* Write address */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- if (waitHDIset(hcsp, &bData) == 0) /* Wait HDI set */
+ if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */
return 0;
- *pDataIn = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
- ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */
+ *ptr = inb(host->base + ORC_HDATA);
+ outb(data, host->base + ORC_HSTUS); /* Clear HDI */
return 1;
+
}
-/***************************************************************************/
-static void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
+/**
+ * orc_exec_sb - Queue an SCB with the HA
+ * @host: host adapter the SCB belongs to
+ * @scb: SCB to queue for execution
+ */
+
+static void orc_exec_scb(struct orc_host * host, struct orc_scb * scb)
{
- scbp->SCB_Status = ORCSCB_POST;
- ORC_WR(hcsp->HCS_Base + ORC_PQUEUE, scbp->SCB_ScbIdx);
- return;
+ scb->status = ORCSCB_POST;
+ outb(scb->scbidx, host->base + ORC_PQUEUE);
}
-/***********************************************************************
- Read SCSI H/A configuration parameters from serial EEPROM
-************************************************************************/
-static int se2_rd_all(ORC_HCS * hcsp)
+/**
+ * se2_rd_all - read SCSI parameters from EEPROM
+ * @host: Host whose EEPROM is being loaded
+ *
+ * Read SCSI H/A configuration parameters from serial EEPROM
+ */
+
+static int se2_rd_all(struct orc_host * host)
{
int i;
- UCHAR *np, chksum = 0;
+ u8 *np, chksum = 0;
- np = (UCHAR *) nvramp;
+ np = (u8 *) nvramp;
for (i = 0; i < 64; i++, np++) { /* <01> */
- if (get_NVRAM(hcsp, (unsigned char) i, np) == 0)
+ if (orc_nv_read(host, (u8) i, np) == 0)
return -1;
-// *np++ = get_NVRAM(hcsp, (unsigned char ) i);
}
-/*------ Is ckecksum ok ? ------*/
- np = (UCHAR *) nvramp;
+ /*------ Is ckecksum ok ? ------*/
+ np = (u8 *) nvramp;
for (i = 0; i < 63; i++)
chksum += *np++;
- if (nvramp->CheckSum != (UCHAR) chksum)
+ if (nvramp->CheckSum != (u8) chksum)
return -1;
return 1;
}
-/************************************************************************
- Update SCSI H/A configuration parameters from serial EEPROM
-*************************************************************************/
-static void se2_update_all(ORC_HCS * hcsp)
+/**
+ * se2_update_all - update the EEPROM
+ * @host: Host whose EEPROM is being updated
+ *
+ * Update changed bytes in the EEPROM image.
+ */
+
+static void se2_update_all(struct orc_host * host)
{ /* setup default pattern */
int i;
- UCHAR *np, *np1, chksum = 0;
+ u8 *np, *np1, chksum = 0;
/* Calculate checksum first */
- np = (UCHAR *) dftNvRam;
+ np = (u8 *) default_nvram;
for (i = 0; i < 63; i++)
chksum += *np++;
*np = chksum;
- np = (UCHAR *) dftNvRam;
- np1 = (UCHAR *) nvramp;
+ np = (u8 *) default_nvram;
+ np1 = (u8 *) nvramp;
for (i = 0; i < 64; i++, np++, np1++) {
- if (*np != *np1) {
- set_NVRAM(hcsp, (unsigned char) i, *np);
- }
+ if (*np != *np1)
+ orc_nv_write(host, (u8) i, *np);
}
- return;
}
-/*************************************************************************
- Function name : read_eeprom
-**************************************************************************/
-static void read_eeprom(ORC_HCS * hcsp)
+/**
+ * read_eeprom - load EEPROM
+ * @host: Host EEPROM to read
+ *
+ * Read the EEPROM for a given host. If it is invalid or fails
+ * the restore the defaults and use them.
+ */
+
+static void read_eeprom(struct orc_host * host)
{
- if (se2_rd_all(hcsp) != 1) {
- se2_update_all(hcsp); /* setup default pattern */
- se2_rd_all(hcsp); /* load again */
+ if (se2_rd_all(host) != 1) {
+ se2_update_all(host); /* setup default pattern */
+ se2_rd_all(host); /* load again */
}
}
-/***************************************************************************/
-static UCHAR load_FW(ORC_HCS * hcsp)
+/**
+ * orc_load_firmware - initialise firmware
+ * @host: Host to set up
+ *
+ * Load the firmware from the EEPROM into controller SRAM. This
+ * is basically a 4K block copy and then a 4K block read to check
+ * correctness. The rest is convulted by the indirect interfaces
+ * in the hardware
+ */
+
+static u8 orc_load_firmware(struct orc_host * host)
{
- U32 dData;
- USHORT wBIOSAddress;
- USHORT i;
- UCHAR *pData, bData;
+ u32 data32;
+ u16 bios_addr;
+ u16 i;
+ u8 *data32_ptr, data;
- bData = ORC_RD(hcsp->HCS_Base, ORC_GCFG);
- ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData | EEPRG); /* Enable EEPROM programming */
- ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, 0x00);
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x00);
- if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0x55) {
- ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */
+ /* Set up the EEPROM for access */
+
+ data = inb(host->base + ORC_GCFG);
+ outb(data | EEPRG, host->base + ORC_GCFG); /* Enable EEPROM programming */
+ outb(0x00, host->base + ORC_EBIOSADR2);
+ outw(0x0000, host->base + ORC_EBIOSADR0);
+ if (inb(host->base + ORC_EBIOSDATA) != 0x55) {
+ outb(data, host->base + ORC_GCFG); /* Disable EEPROM programming */
return 0;
}
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x01);
- if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0xAA) {
- ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */
+ outw(0x0001, host->base + ORC_EBIOSADR0);
+ if (inb(host->base + ORC_EBIOSDATA) != 0xAA) {
+ outb(data, host->base + ORC_GCFG); /* Disable EEPROM programming */
return 0;
}
- ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD); /* Enable SRAM programming */
- pData = (UCHAR *) & dData;
- dData = 0; /* Initial FW address to 0 */
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x10);
- *pData = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x11);
- *(pData + 1) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x12);
- *(pData + 2) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */
- ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, *(pData + 2));
- ORC_WRLONG(hcsp->HCS_Base + ORC_FWBASEADR, dData); /* Write FW address */
- wBIOSAddress = (USHORT) dData; /* FW code locate at BIOS address + ? */
- for (i = 0, pData = (UCHAR *) & dData; /* Download the code */
+ outb(PRGMRST | DOWNLOAD, host->base + ORC_RISCCTL); /* Enable SRAM programming */
+ data32_ptr = (u8 *) & data32;
+ data32 = 0; /* Initial FW address to 0 */
+ outw(0x0010, host->base + ORC_EBIOSADR0);
+ *data32_ptr = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */
+ outw(0x0011, host->base + ORC_EBIOSADR0);
+ *(data32_ptr + 1) = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */
+ outw(0x0012, host->base + ORC_EBIOSADR0);
+ *(data32_ptr + 2) = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */
+ outw(*(data32_ptr + 2), host->base + ORC_EBIOSADR2);
+ outl(data32, host->base + ORC_FWBASEADR); /* Write FW address */
+
+ /* Copy the code from the BIOS to the SRAM */
+
+ bios_addr = (u16) data32; /* FW code locate at BIOS address + ? */
+ for (i = 0, data32_ptr = (u8 *) & data32; /* Download the code */
i < 0x1000; /* Firmware code size = 4K */
- i++, wBIOSAddress++) {
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress);
- *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */
+ i++, bios_addr++) {
+ outw(bios_addr, host->base + ORC_EBIOSADR0);
+ *data32_ptr++ = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */
if ((i % 4) == 3) {
- ORC_WRLONG(hcsp->HCS_Base + ORC_RISCRAM, dData); /* Write every 4 bytes */
- pData = (UCHAR *) & dData;
+ outl(data32, host->base + ORC_RISCRAM); /* Write every 4 bytes */
+ data32_ptr = (u8 *) & data32;
}
}
- ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD); /* Reset program count 0 */
- wBIOSAddress -= 0x1000; /* Reset the BIOS adddress */
- for (i = 0, pData = (UCHAR *) & dData; /* Check the code */
+ /* Go back and check they match */
+
+ outb(PRGMRST | DOWNLOAD, host->base + ORC_RISCCTL); /* Reset program count 0 */
+ bios_addr -= 0x1000; /* Reset the BIOS adddress */
+ for (i = 0, data32_ptr = (u8 *) & data32; /* Check the code */
i < 0x1000; /* Firmware code size = 4K */
- i++, wBIOSAddress++) {
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress);
- *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */
+ i++, bios_addr++) {
+ outw(bios_addr, host->base + ORC_EBIOSADR0);
+ *data32_ptr++ = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */
if ((i % 4) == 3) {
- if (ORC_RDLONG(hcsp->HCS_Base, ORC_RISCRAM) != dData) {
- ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST); /* Reset program to 0 */
- ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /*Disable EEPROM programming */
+ if (inl(host->base + ORC_RISCRAM) != data32) {
+ outb(PRGMRST, host->base + ORC_RISCCTL); /* Reset program to 0 */
+ outb(data, host->base + ORC_GCFG); /*Disable EEPROM programming */
return 0;
}
- pData = (UCHAR *) & dData;
+ data32_ptr = (u8 *) & data32;
}
}
- ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST); /* Reset program to 0 */
- ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */
+
+ /* Success */
+ outb(PRGMRST, host->base + ORC_RISCCTL); /* Reset program to 0 */
+ outb(data, host->base + ORC_GCFG); /* Disable EEPROM programming */
return 1;
}
/***************************************************************************/
-static void setup_SCBs(ORC_HCS * hcsp)
+static void setup_SCBs(struct orc_host * host)
{
- ORC_SCB *pVirScb;
+ struct orc_scb *scb;
int i;
- ESCB *pVirEscb;
- dma_addr_t pPhysEscb;
+ struct orc_extended_scb *escb;
+ dma_addr_t escb_phys;
- /* Setup SCB HCS_Base and SCB Size registers */
- ORC_WR(hcsp->HCS_Base + ORC_SCBSIZE, ORC_MAXQUEUE); /* Total number of SCBs */
- /* SCB HCS_Base address 0 */
- ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE0, hcsp->HCS_physScbArray);
- /* SCB HCS_Base address 1 */
- ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE1, hcsp->HCS_physScbArray);
+ /* Setup SCB base and SCB Size registers */
+ outb(ORC_MAXQUEUE, host->base + ORC_SCBSIZE); /* Total number of SCBs */
+ /* SCB base address 0 */
+ outl(host->scb_phys, host->base + ORC_SCBBASE0);
+ /* SCB base address 1 */
+ outl(host->scb_phys, host->base + ORC_SCBBASE1);
/* setup scatter list address with one buffer */
- pVirScb = hcsp->HCS_virScbArray;
- pVirEscb = hcsp->HCS_virEscbArray;
+ scb = host->scb_virt;
+ escb = host->escb_virt;
for (i = 0; i < ORC_MAXQUEUE; i++) {
- pPhysEscb = (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i));
- pVirScb->SCB_SGPAddr = (U32) pPhysEscb;
- pVirScb->SCB_SensePAddr = (U32) pPhysEscb;
- pVirScb->SCB_EScb = pVirEscb;
- pVirScb->SCB_ScbIdx = i;
- pVirScb++;
- pVirEscb++;
+ escb_phys = (host->escb_phys + (sizeof(struct orc_extended_scb) * i));
+ scb->sg_addr = (u32) escb_phys;
+ scb->sense_addr = (u32) escb_phys;
+ scb->escb = escb;
+ scb->scbidx = i;
+ scb++;
+ escb++;
}
-
- return;
}
-/***************************************************************************/
-static void initAFlag(ORC_HCS * hcsp)
+/**
+ * init_alloc_map - initialise allocation map
+ * @host: host map to configure
+ *
+ * Initialise the allocation maps for this device. If the device
+ * is not quiescent the caller must hold the allocation lock
+ */
+
+static void init_alloc_map(struct orc_host * host)
{
- UCHAR i, j;
+ u8 i, j;
for (i = 0; i < MAX_CHANNELS; i++) {
for (j = 0; j < 8; j++) {
- hcsp->BitAllocFlag[i][j] = 0xffffffff;
+ host->allocation_map[i][j] = 0xffffffff;
}
}
}
-/***************************************************************************/
-static int init_orchid(ORC_HCS * hcsp)
-{
- UBYTE *readBytep;
- USHORT revision;
- UCHAR i;
+/**
+ * init_orchid - initialise the host adapter
+ * @host:host adapter to initialise
+ *
+ * Initialise the controller and if neccessary load the firmware.
+ *
+ * Returns -1 if the initialisation fails.
+ */
- initAFlag(hcsp);
- ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFF); /* Disable all interrupt */
- if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) { /* Orchid is ready */
- revision = get_FW_version(hcsp);
+static int init_orchid(struct orc_host * host)
+{
+ u8 *ptr;
+ u16 revision;
+ u8 i;
+
+ init_alloc_map(host);
+ outb(0xFF, host->base + ORC_GIMSK); /* Disable all interrupts */
+
+ if (inb(host->base + ORC_HSTUS) & RREADY) { /* Orchid is ready */
+ revision = orc_read_fwrev(host);
if (revision == 0xFFFF) {
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST); /* Reset Host Adapter */
- if (waitChipReady(hcsp) == 0)
- return (-1);
- load_FW(hcsp); /* Download FW */
- setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, 0); /* clear HOSTSTOP */
- if (waitFWReady(hcsp) == 0)
- return (-1);
+ outb(DEVRST, host->base + ORC_HCTRL); /* Reset Host Adapter */
+ if (wait_chip_ready(host) == 0)
+ return -1;
+ orc_load_firmware(host); /* Download FW */
+ setup_SCBs(host); /* Setup SCB base and SCB Size registers */
+ outb(0x00, host->base + ORC_HCTRL); /* clear HOSTSTOP */
+ if (wait_firmware_ready(host) == 0)
+ return -1;
/* Wait for firmware ready */
} else {
- setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */
+ setup_SCBs(host); /* Setup SCB base and SCB Size registers */
}
} else { /* Orchid is not Ready */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST); /* Reset Host Adapter */
- if (waitChipReady(hcsp) == 0)
- return (-1);
- load_FW(hcsp); /* Download FW */
- setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); /* Do Hardware Reset & */
+ outb(DEVRST, host->base + ORC_HCTRL); /* Reset Host Adapter */
+ if (wait_chip_ready(host) == 0)
+ return -1;
+ orc_load_firmware(host); /* Download FW */
+ setup_SCBs(host); /* Setup SCB base and SCB Size registers */
+ outb(HDO, host->base + ORC_HCTRL); /* Do Hardware Reset & */
/* clear HOSTSTOP */
- if (waitFWReady(hcsp) == 0) /* Wait for firmware ready */
- return (-1);
+ if (wait_firmware_ready(host) == 0) /* Wait for firmware ready */
+ return -1;
}
-/*------------- get serial EEProm settting -------*/
+ /* Load an EEProm copy into RAM */
+ /* Assumes single threaded at this point */
+ read_eeprom(host);
- read_eeprom(hcsp);
+ if (nvramp->revision != 1)
+ return -1;
- if (nvramp->Revision != 1)
- return (-1);
-
- hcsp->HCS_SCSI_ID = nvramp->SCSI0Id;
- hcsp->HCS_BIOS = nvramp->BIOSConfig1;
- hcsp->HCS_MaxTar = MAX_TARGETS;
- readBytep = (UCHAR *) & (nvramp->Target00Config);
- for (i = 0; i < 16; readBytep++, i++) {
- hcsp->TargetFlag[i] = *readBytep;
- hcsp->MaximumTags[i] = ORC_MAXTAGS;
- } /* for */
-
- if (nvramp->SCSI0Config & NCC_BUSRESET) { /* Reset SCSI bus */
- hcsp->HCS_Flags |= HCF_SCSI_RESET;
+ host->scsi_id = nvramp->scsi_id;
+ host->BIOScfg = nvramp->BIOSConfig1;
+ host->max_targets = MAX_TARGETS;
+ ptr = (u8 *) & (nvramp->Target00Config);
+ for (i = 0; i < 16; ptr++, i++) {
+ host->target_flag[i] = *ptr;
+ host->max_tags[i] = ORC_MAXTAGS;
}
- ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFB); /* enable RP FIFO interrupt */
- return (0);
+
+ if (nvramp->SCSI0Config & NCC_BUSRESET)
+ host->flags |= HCF_SCSI_RESET;
+ outb(0xFB, host->base + ORC_GIMSK); /* enable RP FIFO interrupt */
+ return 0;
}
-/*****************************************************************************
- Function name : orc_reset_scsi_bus
- Description : Reset registers, reset a hanging bus and
- kill active and disconnected commands for target w/o soft reset
- Input : pHCB - Pointer to host adapter structure
- Output : None.
- Return : pSRB - Pointer to SCSI request block.
-*****************************************************************************/
-static int orc_reset_scsi_bus(ORC_HCS * pHCB)
+/**
+ * orc_reset_scsi_bus - perform bus reset
+ * @host: host being reset
+ *
+ * Perform a full bus reset on the adapter.
+ */
+
+static int orc_reset_scsi_bus(struct orc_host * host)
{ /* I need Host Control Block Information */
- ULONG flags;
+ unsigned long flags;
- spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags);
+ spin_lock_irqsave(&host->allocation_lock, flags);
- initAFlag(pHCB);
+ init_alloc_map(host);
/* reset scsi bus */
- ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST);
- if (waitSCSIRSTdone(pHCB) == 0) {
- spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+ outb(SCSIRST, host->base + ORC_HCTRL);
+ /* FIXME: We can spend up to a second with the lock held and
+ interrupts off here */
+ if (wait_scsi_reset_done(host) == 0) {
+ spin_unlock_irqrestore(&host->allocation_lock, flags);
return FAILED;
} else {
- spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+ spin_unlock_irqrestore(&host->allocation_lock, flags);
return SUCCESS;
}
}
-/*****************************************************************************
- Function name : orc_device_reset
- Description : Reset registers, reset a hanging bus and
- kill active and disconnected commands for target w/o soft reset
- Input : pHCB - Pointer to host adapter structure
- Output : None.
- Return : pSRB - Pointer to SCSI request block.
-*****************************************************************************/
-static int orc_device_reset(ORC_HCS * pHCB, struct scsi_cmnd *SCpnt, unsigned int target)
-{ /* I need Host Control Block Information */
- ORC_SCB *pScb;
- ESCB *pVirEscb;
- ORC_SCB *pVirScb;
- UCHAR i;
- ULONG flags;
+/**
+ * orc_device_reset - device reset handler
+ * @host: host to reset
+ * @cmd: command causing the reset
+ * @target; target device
+ *
+ * Reset registers, reset a hanging bus and kill active and disconnected
+ * commands for target w/o soft reset
+ */
- spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags);
- pScb = (ORC_SCB *) NULL;
- pVirEscb = (ESCB *) NULL;
+static int orc_device_reset(struct orc_host * host, struct scsi_cmnd *cmd, unsigned int target)
+{ /* I need Host Control Block Information */
+ struct orc_scb *scb;
+ struct orc_extended_scb *escb;
+ struct orc_scb *host_scb;
+ u8 i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&(host->allocation_lock), flags);
+ scb = (struct orc_scb *) NULL;
+ escb = (struct orc_extended_scb *) NULL;
/* setup scatter list address with one buffer */
- pVirScb = pHCB->HCS_virScbArray;
+ host_scb = host->scb_virt;
- initAFlag(pHCB);
- /* device reset */
+ /* FIXME: is this safe if we then fail to issue the reset or race
+ a completion ? */
+ init_alloc_map(host);
+
+ /* Find the scb corresponding to the command */
for (i = 0; i < ORC_MAXQUEUE; i++) {
- pVirEscb = pVirScb->SCB_EScb;
- if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt))
+ escb = host_scb->escb;
+ if (host_scb->status && escb->srb == cmd)
break;
- pVirScb++;
+ host_scb++;
}
if (i == ORC_MAXQUEUE) {
- printk("Unable to Reset - No SCB Found\n");
- spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+ printk(KERN_ERR "Unable to Reset - No SCB Found\n");
+ spin_unlock_irqrestore(&(host->allocation_lock), flags);
return FAILED;
}
- if ((pScb = orc_alloc_scb(pHCB)) == NULL) {
- spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
- return FAILED;
- }
- pScb->SCB_Opcode = ORC_BUSDEVRST;
- pScb->SCB_Target = target;
- pScb->SCB_HaStat = 0;
- pScb->SCB_TaStat = 0;
- pScb->SCB_Status = 0x0;
- pScb->SCB_Link = 0xFF;
- pScb->SCB_Reserved0 = 0;
- pScb->SCB_Reserved1 = 0;
- pScb->SCB_XferLen = 0;
- pScb->SCB_SGLen = 0;
- pVirEscb->SCB_Srb = NULL;
- pVirEscb->SCB_Srb = SCpnt;
- orc_exec_scb(pHCB, pScb); /* Start execute SCB */
- spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+ /* Allocate a new SCB for the reset command to the firmware */
+ if ((scb = __orc_alloc_scb(host)) == NULL) {
+ /* Can't happen.. */
+ spin_unlock_irqrestore(&(host->allocation_lock), flags);
+ return FAILED;
+ }
+
+ /* Reset device is handled by the firmare, we fill in an SCB and
+ fire it at the controller, it does the rest */
+ scb->opcode = ORC_BUSDEVRST;
+ scb->target = target;
+ scb->hastat = 0;
+ scb->tastat = 0;
+ scb->status = 0x0;
+ scb->link = 0xFF;
+ scb->reserved0 = 0;
+ scb->reserved1 = 0;
+ scb->xferlen = 0;
+ scb->sg_len = 0;
+
+ escb->srb = NULL;
+ escb->srb = cmd;
+ orc_exec_scb(host, scb); /* Start execute SCB */
+ spin_unlock_irqrestore(&host->allocation_lock, flags);
return SUCCESS;
}
+/**
+ * __orc_alloc_scb - allocate an SCB
+ * @host: host to allocate from
+ *
+ * Allocate an SCB and return a pointer to the SCB object. NULL
+ * is returned if no SCB is free. The caller must already hold
+ * the allocator lock at this point.
+ */
-/***************************************************************************/
-static ORC_SCB *__orc_alloc_scb(ORC_HCS * hcsp)
+
+static struct orc_scb *__orc_alloc_scb(struct orc_host * host)
{
- ORC_SCB *pTmpScb;
- UCHAR Ch;
- ULONG idx;
- UCHAR index;
- UCHAR i;
+ u8 channel;
+ unsigned long idx;
+ u8 index;
+ u8 i;
- Ch = hcsp->HCS_Index;
+ channel = host->index;
for (i = 0; i < 8; i++) {
for (index = 0; index < 32; index++) {
- if ((hcsp->BitAllocFlag[Ch][i] >> index) & 0x01) {
- hcsp->BitAllocFlag[Ch][i] &= ~(1 << index);
+ if ((host->allocation_map[channel][i] >> index) & 0x01) {
+ host->allocation_map[channel][i] &= ~(1 << index);
break;
}
}
idx = index + 32 * i;
- pTmpScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (idx * sizeof(ORC_SCB)));
- return (pTmpScb);
+ /* Translate the index to a structure instance */
+ return (struct orc_scb *) ((unsigned long) host->scb_virt + (idx * sizeof(struct orc_scb)));
}
- return (NULL);
+ return NULL;
}
-static ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp)
-{
- ORC_SCB *pTmpScb;
- ULONG flags;
+/**
+ * orc_alloc_scb - allocate an SCB
+ * @host: host to allocate from
+ *
+ * Allocate an SCB and return a pointer to the SCB object. NULL
+ * is returned if no SCB is free.
+ */
- spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
- pTmpScb = __orc_alloc_scb(hcsp);
- spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
- return (pTmpScb);
+static struct orc_scb *orc_alloc_scb(struct orc_host * host)
+{
+ struct orc_scb *scb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->allocation_lock, flags);
+ scb = __orc_alloc_scb(host);
+ spin_unlock_irqrestore(&host->allocation_lock, flags);
+ return scb;
}
+/**
+ * orc_release_scb - release an SCB
+ * @host: host owning the SCB
+ * @scb: SCB that is now free
+ *
+ * Called to return a completed SCB to the allocation pool. Before
+ * calling the SCB must be out of use on both the host and the HA.
+ */
-/***************************************************************************/
-static void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
+static void orc_release_scb(struct orc_host *host, struct orc_scb *scb)
{
- ULONG flags;
- UCHAR Index;
- UCHAR i;
- UCHAR Ch;
+ unsigned long flags;
+ u8 index, i, channel;
- spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
- Ch = hcsp->HCS_Index;
- Index = scbp->SCB_ScbIdx;
- i = Index / 32;
- Index %= 32;
- hcsp->BitAllocFlag[Ch][i] |= (1 << Index);
- spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+ spin_lock_irqsave(&(host->allocation_lock), flags);
+ channel = host->index; /* Channel */
+ index = scb->scbidx;
+ i = index / 32;
+ index %= 32;
+ host->allocation_map[channel][i] |= (1 << index);
+ spin_unlock_irqrestore(&(host->allocation_lock), flags);
}
-/*****************************************************************************
- Function name : abort_SCB
- Description : Abort a queued command.
- (commands that are on the bus can't be aborted easily)
- Input : pHCB - Pointer to host adapter structure
- Output : None.
- Return : pSRB - Pointer to SCSI request block.
-*****************************************************************************/
-static int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb)
+/**
+ * orchid_abort_scb - abort a command
+ *
+ * Abort a queued command that has been passed to the firmware layer
+ * if possible. This is all handled by the firmware. We aks the firmware
+ * and it either aborts the command or fails
+ */
+
+static int orchid_abort_scb(struct orc_host * host, struct orc_scb * scb)
{
- unsigned char bData, bStatus;
+ unsigned char data, status;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_ABORT_SCB); /* Write command */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(ORC_CMD_ABORT_SCB, host->base + ORC_HDATA); /* Write command */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, pScb->SCB_ScbIdx); /* Write address */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(scb->scbidx, host->base + ORC_HDATA); /* Write address */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- if (waitHDIset(hcsp, &bData) == 0) /* Wait HDI set */
+ if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */
return 0;
- bStatus = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
- ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */
+ status = inb(host->base + ORC_HDATA);
+ outb(data, host->base + ORC_HSTUS); /* Clear HDI */
- if (bStatus == 1) /* 0 - Successfully */
+ if (status == 1) /* 0 - Successfully */
return 0; /* 1 - Fail */
return 1;
}
-/*****************************************************************************
- Function name : inia100_abort
- Description : Abort a queued command.
- (commands that are on the bus can't be aborted easily)
- Input : pHCB - Pointer to host adapter structure
- Output : None.
- Return : pSRB - Pointer to SCSI request block.
-*****************************************************************************/
-static int orc_abort_srb(ORC_HCS * hcsp, struct scsi_cmnd *SCpnt)
+static int inia100_abort_cmd(struct orc_host * host, struct scsi_cmnd *cmd)
{
- ESCB *pVirEscb;
- ORC_SCB *pVirScb;
- UCHAR i;
- ULONG flags;
+ struct orc_extended_scb *escb;
+ struct orc_scb *scb;
+ u8 i;
+ unsigned long flags;
- spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
+ spin_lock_irqsave(&(host->allocation_lock), flags);
- pVirScb = hcsp->HCS_virScbArray;
+ scb = host->scb_virt;
- for (i = 0; i < ORC_MAXQUEUE; i++, pVirScb++) {
- pVirEscb = pVirScb->SCB_EScb;
- if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt)) {
- if (pVirScb->SCB_TagMsg == 0) {
- spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
- return FAILED;
+ /* Walk the queue until we find the SCB that belongs to the command
+ block. This isn't a performance critical path so a walk in the park
+ here does no harm */
+
+ for (i = 0; i < ORC_MAXQUEUE; i++, scb++) {
+ escb = scb->escb;
+ if (scb->status && escb->srb == cmd) {
+ if (scb->tag_msg == 0) {
+ goto out;
} else {
- if (abort_SCB(hcsp, pVirScb)) {
- pVirEscb->SCB_Srb = NULL;
- spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+ /* Issue an ABORT to the firmware */
+ if (orchid_abort_scb(host, scb)) {
+ escb->srb = NULL;
+ spin_unlock_irqrestore(&host->allocation_lock, flags);
return SUCCESS;
- } else {
- spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
- return FAILED;
- }
+ } else
+ goto out;
}
}
}
- spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+out:
+ spin_unlock_irqrestore(&host->allocation_lock, flags);
return FAILED;
}
-/***********************************************************************
- Routine Description:
- This is the interrupt service routine for the Orchid SCSI adapter.
- It reads the interrupt register to determine if the adapter is indeed
- the source of the interrupt and clears the interrupt at the device.
- Arguments:
- HwDeviceExtension - HBA miniport driver's adapter data storage
- Return Value:
-***********************************************************************/
-static void orc_interrupt(
- ORC_HCS * hcsp
-)
+/**
+ * orc_interrupt - IRQ processing
+ * @host: Host causing the interrupt
+ *
+ * This function is called from the IRQ handler and protected
+ * by the host lock. While the controller reports that there are
+ * scb's for processing we pull them off the controller, turn the
+ * index into a host address pointer to the scb and call the scb
+ * handler.
+ *
+ * Returns IRQ_HANDLED if any SCBs were processed, IRQ_NONE otherwise
+ */
+
+static irqreturn_t orc_interrupt(struct orc_host * host)
{
- BYTE bScbIdx;
- ORC_SCB *pScb;
+ u8 scb_index;
+ struct orc_scb *scb;
- if (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT) == 0) {
- return; // 0;
+ /* Check if we have an SCB queued for servicing */
+ if (inb(host->base + ORC_RQUEUECNT) == 0)
+ return IRQ_NONE;
- }
do {
- bScbIdx = ORC_RD(hcsp->HCS_Base, ORC_RQUEUE);
+ /* Get the SCB index of the SCB to service */
+ scb_index = inb(host->base + ORC_RQUEUE);
- pScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (ULONG) (sizeof(ORC_SCB) * bScbIdx));
- pScb->SCB_Status = 0x0;
-
- inia100SCBPost((BYTE *) hcsp, (BYTE *) pScb);
- } while (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT));
- return; //1;
-
+ /* Translate it back to a host pointer */
+ scb = (struct orc_scb *) ((unsigned long) host->scb_virt + (unsigned long) (sizeof(struct orc_scb) * scb_index));
+ scb->status = 0x0;
+ /* Process the SCB */
+ inia100_scb_handler(host, scb);
+ } while (inb(host->base + ORC_RQUEUECNT));
+ return IRQ_HANDLED;
} /* End of I1060Interrupt() */
-/*****************************************************************************
- Function name : inia100BuildSCB
- Description :
- Input : pHCB - Pointer to host adapter structure
- Output : None.
- Return : pSRB - Pointer to SCSI request block.
-*****************************************************************************/
-static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, struct scsi_cmnd * SCpnt)
+/**
+ * inia100_build_scb - build SCB
+ * @host: host owing the control block
+ * @scb: control block to use
+ * @cmd: Mid layer command
+ *
+ * Build a host adapter control block from the SCSI mid layer command
+ */
+
+static void inia100_build_scb(struct orc_host * host, struct orc_scb * scb, struct scsi_cmnd * cmd)
{ /* Create corresponding SCB */
- struct scatterlist *pSrbSG;
- ORC_SG *pSG; /* Pointer to SG list */
+ struct scatterlist *sg;
+ struct orc_sgent *sgent; /* Pointer to SG list */
int i, count_sg;
- ESCB *pEScb;
+ struct orc_extended_scb *escb;
- pEScb = pSCB->SCB_EScb;
- pEScb->SCB_Srb = SCpnt;
- pSG = NULL;
+ /* Links between the escb, scb and Linux scsi midlayer cmd */
+ escb = scb->escb;
+ escb->srb = cmd;
+ sgent = NULL;
- pSCB->SCB_Opcode = ORC_EXECSCSI;
- pSCB->SCB_Flags = SCF_NO_DCHK; /* Clear done bit */
- pSCB->SCB_Target = SCpnt->device->id;
- pSCB->SCB_Lun = SCpnt->device->lun;
- pSCB->SCB_Reserved0 = 0;
- pSCB->SCB_Reserved1 = 0;
- pSCB->SCB_SGLen = 0;
+ /* Set up the SCB to do a SCSI command block */
+ scb->opcode = ORC_EXECSCSI;
+ scb->flags = SCF_NO_DCHK; /* Clear done bit */
+ scb->target = cmd->device->id;
+ scb->lun = cmd->device->lun;
+ scb->reserved0 = 0;
+ scb->reserved1 = 0;
+ scb->sg_len = 0;
- if ((pSCB->SCB_XferLen = (U32) SCpnt->request_bufflen)) {
- pSG = (ORC_SG *) & pEScb->ESCB_SGList[0];
- if (SCpnt->use_sg) {
- pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
- count_sg = pci_map_sg(pHCB->pdev, pSrbSG, SCpnt->use_sg,
- SCpnt->sc_data_direction);
- pSCB->SCB_SGLen = (U32) (count_sg * 8);
- for (i = 0; i < count_sg; i++, pSG++, pSrbSG++) {
- pSG->SG_Ptr = (U32) sg_dma_address(pSrbSG);
- pSG->SG_Len = (U32) sg_dma_len(pSrbSG);
- }
- } else if (SCpnt->request_bufflen != 0) {/* Non SG */
- pSCB->SCB_SGLen = 0x8;
- SCpnt->SCp.dma_handle = pci_map_single(pHCB->pdev,
- SCpnt->request_buffer,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- pSG->SG_Ptr = (U32) SCpnt->SCp.dma_handle;
- pSG->SG_Len = (U32) SCpnt->request_bufflen;
- } else {
- pSCB->SCB_SGLen = 0;
- pSG->SG_Ptr = 0;
- pSG->SG_Len = 0;
+ scb->xferlen = (u32) scsi_bufflen(cmd);
+ sgent = (struct orc_sgent *) & escb->sglist[0];
+
+ count_sg = scsi_dma_map(cmd);
+ BUG_ON(count_sg < 0);
+
+ /* Build the scatter gather lists */
+ if (count_sg) {
+ scb->sg_len = (u32) (count_sg * 8);
+ scsi_for_each_sg(cmd, sg, count_sg, i) {
+ sgent->base = (u32) sg_dma_address(sg);
+ sgent->length = (u32) sg_dma_len(sg);
+ sgent++;
}
- }
- pSCB->SCB_SGPAddr = (U32) pSCB->SCB_SensePAddr;
- pSCB->SCB_HaStat = 0;
- pSCB->SCB_TaStat = 0;
- pSCB->SCB_Link = 0xFF;
- pSCB->SCB_SenseLen = SENSE_SIZE;
- pSCB->SCB_CDBLen = SCpnt->cmd_len;
- if (pSCB->SCB_CDBLen >= IMAX_CDB) {
- printk("max cdb length= %x\b", SCpnt->cmd_len);
- pSCB->SCB_CDBLen = IMAX_CDB;
- }
- pSCB->SCB_Ident = SCpnt->device->lun | DISC_ALLOW;
- if (SCpnt->device->tagged_supported) { /* Tag Support */
- pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */
} else {
- pSCB->SCB_TagMsg = 0; /* No tag support */
+ scb->sg_len = 0;
+ sgent->base = 0;
+ sgent->length = 0;
}
- memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, pSCB->SCB_CDBLen);
- return;
+ scb->sg_addr = (u32) scb->sense_addr;
+ scb->hastat = 0;
+ scb->tastat = 0;
+ scb->link = 0xFF;
+ scb->sense_len = SENSE_SIZE;
+ scb->cdb_len = cmd->cmd_len;
+ if (scb->cdb_len >= IMAX_CDB) {
+ printk("max cdb length= %x\b", cmd->cmd_len);
+ scb->cdb_len = IMAX_CDB;
+ }
+ scb->ident = cmd->device->lun | DISC_ALLOW;
+ if (cmd->device->tagged_supported) { /* Tag Support */
+ scb->tag_msg = SIMPLE_QUEUE_TAG; /* Do simple tag only */
+ } else {
+ scb->tag_msg = 0; /* No tag support */
+ }
+ memcpy(&scb->cdb[0], &cmd->cmnd, scb->cdb_len);
}
-/*****************************************************************************
- Function name : inia100_queue
- Description : Queue a command and setup interrupts for a free bus.
- Input : pHCB - Pointer to host adapter structure
- Output : None.
- Return : pSRB - Pointer to SCSI request block.
-*****************************************************************************/
-static int inia100_queue(struct scsi_cmnd * SCpnt, void (*done) (struct scsi_cmnd *))
-{
- register ORC_SCB *pSCB;
- ORC_HCS *pHCB; /* Point to Host adapter control block */
+/**
+ * inia100_queue - queue command with host
+ * @cmd: Command block
+ * @done: Completion function
+ *
+ * Called by the mid layer to queue a command. Process the command
+ * block, build the host specific scb structures and if there is room
+ * queue the command down to the controller
+ */
- pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
- SCpnt->scsi_done = done;
+static int inia100_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
+{
+ struct orc_scb *scb;
+ struct orc_host *host; /* Point to Host adapter control block */
+
+ host = (struct orc_host *) cmd->device->host->hostdata;
+ cmd->scsi_done = done;
/* Get free SCSI control block */
- if ((pSCB = orc_alloc_scb(pHCB)) == NULL)
+ if ((scb = orc_alloc_scb(host)) == NULL)
return SCSI_MLQUEUE_HOST_BUSY;
- inia100BuildSCB(pHCB, pSCB, SCpnt);
- orc_exec_scb(pHCB, pSCB); /* Start execute SCB */
-
- return (0);
+ inia100_build_scb(host, scb, cmd);
+ orc_exec_scb(host, scb); /* Start execute SCB */
+ return 0;
}
/*****************************************************************************
Function name : inia100_abort
Description : Abort a queued command.
(commands that are on the bus can't be aborted easily)
- Input : pHCB - Pointer to host adapter structure
+ Input : host - Pointer to host adapter structure
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
-static int inia100_abort(struct scsi_cmnd * SCpnt)
+static int inia100_abort(struct scsi_cmnd * cmd)
{
- ORC_HCS *hcsp;
+ struct orc_host *host;
- hcsp = (ORC_HCS *) SCpnt->device->host->hostdata;
- return orc_abort_srb(hcsp, SCpnt);
+ host = (struct orc_host *) cmd->device->host->hostdata;
+ return inia100_abort_cmd(host, cmd);
}
/*****************************************************************************
Function name : inia100_reset
Description : Reset registers, reset a hanging bus and
kill active and disconnected commands for target w/o soft reset
- Input : pHCB - Pointer to host adapter structure
+ Input : host - Pointer to host adapter structure
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
-static int inia100_bus_reset(struct scsi_cmnd * SCpnt)
+static int inia100_bus_reset(struct scsi_cmnd * cmd)
{ /* I need Host Control Block Information */
- ORC_HCS *pHCB;
- pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
- return orc_reset_scsi_bus(pHCB);
+ struct orc_host *host;
+ host = (struct orc_host *) cmd->device->host->hostdata;
+ return orc_reset_scsi_bus(host);
}
/*****************************************************************************
Function name : inia100_device_reset
Description : Reset the device
- Input : pHCB - Pointer to host adapter structure
+ Input : host - Pointer to host adapter structure
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
-static int inia100_device_reset(struct scsi_cmnd * SCpnt)
+static int inia100_device_reset(struct scsi_cmnd * cmd)
{ /* I need Host Control Block Information */
- ORC_HCS *pHCB;
- pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
- return orc_device_reset(pHCB, SCpnt, scmd_id(SCpnt));
+ struct orc_host *host;
+ host = (struct orc_host *) cmd->device->host->hostdata;
+ return orc_device_reset(host, cmd, scmd_id(cmd));
}
-/*****************************************************************************
- Function name : inia100SCBPost
- Description : This is callback routine be called when orc finish one
- SCSI command.
- Input : pHCB - Pointer to host adapter control block.
- pSCB - Pointer to SCSI control block.
- Output : None.
- Return : None.
-*****************************************************************************/
-static void inia100SCBPost(BYTE * pHcb, BYTE * pScb)
-{
- struct scsi_cmnd *pSRB; /* Pointer to SCSI request block */
- ORC_HCS *pHCB;
- ORC_SCB *pSCB;
- ESCB *pEScb;
+/**
+ * inia100_scb_handler - interrupt callback
+ * @host: Host causing the interrupt
+ * @scb: SCB the controller returned as needing processing
+ *
+ * Perform completion processing on a control block. Do the conversions
+ * from host to SCSI midlayer error coding, save any sense data and
+ * the complete with the midlayer and recycle the scb.
+ */
- pHCB = (ORC_HCS *) pHcb;
- pSCB = (ORC_SCB *) pScb;
- pEScb = pSCB->SCB_EScb;
- if ((pSRB = (struct scsi_cmnd *) pEScb->SCB_Srb) == 0) {
- printk("inia100SCBPost: SRB pointer is empty\n");
- orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */
+static void inia100_scb_handler(struct orc_host *host, struct orc_scb *scb)
+{
+ struct scsi_cmnd *cmd; /* Pointer to SCSI request block */
+ struct orc_extended_scb *escb;
+
+ escb = scb->escb;
+ if ((cmd = (struct scsi_cmnd *) escb->srb) == NULL) {
+ printk(KERN_ERR "inia100_scb_handler: SRB pointer is empty\n");
+ orc_release_scb(host, scb); /* Release SCB for current channel */
return;
}
- pEScb->SCB_Srb = NULL;
+ escb->srb = NULL;
- switch (pSCB->SCB_HaStat) {
+ switch (scb->hastat) {
case 0x0:
case 0xa: /* Linked command complete without error and linked normally */
case 0xb: /* Linked command complete without error interrupt generated */
- pSCB->SCB_HaStat = 0;
+ scb->hastat = 0;
break;
case 0x11: /* Selection time out-The initiator selection or target
reselection was not complete within the SCSI Time out period */
- pSCB->SCB_HaStat = DID_TIME_OUT;
+ scb->hastat = DID_TIME_OUT;
break;
case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
phase sequence was requested by the target. The host adapter
will generate a SCSI Reset Condition, notifying the host with
a SCRD interrupt */
- pSCB->SCB_HaStat = DID_RESET;
+ scb->hastat = DID_RESET;
break;
case 0x1a: /* SCB Aborted. 07/21/98 */
- pSCB->SCB_HaStat = DID_ABORT;
+ scb->hastat = DID_ABORT;
break;
case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
@@ -984,46 +1022,41 @@
case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. */
default:
- printk("inia100: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);
- pSCB->SCB_HaStat = DID_ERROR; /* Couldn't find any better */
+ printk(KERN_DEBUG "inia100: %x %x\n", scb->hastat, scb->tastat);
+ scb->hastat = DID_ERROR; /* Couldn't find any better */
break;
}
- if (pSCB->SCB_TaStat == 2) { /* Check condition */
- memcpy((unsigned char *) &pSRB->sense_buffer[0],
- (unsigned char *) &pEScb->ESCB_SGList[0], SENSE_SIZE);
+ if (scb->tastat == 2) { /* Check condition */
+ memcpy((unsigned char *) &cmd->sense_buffer[0],
+ (unsigned char *) &escb->sglist[0], SENSE_SIZE);
}
- pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);
-
- if (pSRB->use_sg) {
- pci_unmap_sg(pHCB->pdev,
- (struct scatterlist *)pSRB->request_buffer,
- pSRB->use_sg, pSRB->sc_data_direction);
- } else if (pSRB->request_bufflen != 0) {
- pci_unmap_single(pHCB->pdev, pSRB->SCp.dma_handle,
- pSRB->request_bufflen,
- pSRB->sc_data_direction);
- }
-
- pSRB->scsi_done(pSRB); /* Notify system DONE */
-
- orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */
+ cmd->result = scb->tastat | (scb->hastat << 16);
+ scsi_dma_unmap(cmd);
+ cmd->scsi_done(cmd); /* Notify system DONE */
+ orc_release_scb(host, scb); /* Release SCB for current channel */
}
-/*
- * Interrupt handler (main routine of the driver)
+/**
+ * inia100_intr - interrupt handler
+ * @irqno: Interrupt value
+ * @devid: Host adapter
+ *
+ * Entry point for IRQ handling. All the real work is performed
+ * by orc_interrupt.
*/
static irqreturn_t inia100_intr(int irqno, void *devid)
{
- struct Scsi_Host *host = (struct Scsi_Host *)devid;
- ORC_HCS *pHcb = (ORC_HCS *)host->hostdata;
+ struct Scsi_Host *shost = (struct Scsi_Host *)devid;
+ struct orc_host *host = (struct orc_host *)shost->hostdata;
unsigned long flags;
+ irqreturn_t res;
- spin_lock_irqsave(host->host_lock, flags);
- orc_interrupt(pHcb);
- spin_unlock_irqrestore(host->host_lock, flags);
+ spin_lock_irqsave(shost->host_lock, flags);
+ res = orc_interrupt(host);
+ spin_unlock_irqrestore(shost->host_lock, flags);
- return IRQ_HANDLED;
+ return res;
}
static struct scsi_host_template inia100_template = {
@@ -1044,12 +1077,12 @@
const struct pci_device_id *id)
{
struct Scsi_Host *shost;
- ORC_HCS *pHCB;
+ struct orc_host *host;
unsigned long port, bios;
int error = -ENODEV;
u32 sz;
- unsigned long dBiosAdr;
- char *pbBiosAdr;
+ unsigned long biosaddr;
+ char *bios_phys;
if (pci_enable_device(pdev))
goto out;
@@ -1068,55 +1101,55 @@
}
/* <02> read from base address + 0x50 offset to get the bios value. */
- bios = ORC_RDWORD(port, 0x50);
+ bios = inw(port + 0x50);
- shost = scsi_host_alloc(&inia100_template, sizeof(ORC_HCS));
+ shost = scsi_host_alloc(&inia100_template, sizeof(struct orc_host));
if (!shost)
goto out_release_region;
- pHCB = (ORC_HCS *)shost->hostdata;
- pHCB->pdev = pdev;
- pHCB->HCS_Base = port;
- pHCB->HCS_BIOS = bios;
- spin_lock_init(&pHCB->BitAllocFlagLock);
+ host = (struct orc_host *)shost->hostdata;
+ host->pdev = pdev;
+ host->base = port;
+ host->BIOScfg = bios;
+ spin_lock_init(&host->allocation_lock);
/* Get total memory needed for SCB */
- sz = ORC_MAXQUEUE * sizeof(ORC_SCB);
- pHCB->HCS_virScbArray = pci_alloc_consistent(pdev, sz,
- &pHCB->HCS_physScbArray);
- if (!pHCB->HCS_virScbArray) {
+ sz = ORC_MAXQUEUE * sizeof(struct orc_scb);
+ host->scb_virt = pci_alloc_consistent(pdev, sz,
+ &host->scb_phys);
+ if (!host->scb_virt) {
printk("inia100: SCB memory allocation error\n");
goto out_host_put;
}
- memset(pHCB->HCS_virScbArray, 0, sz);
+ memset(host->scb_virt, 0, sz);
/* Get total memory needed for ESCB */
- sz = ORC_MAXQUEUE * sizeof(ESCB);
- pHCB->HCS_virEscbArray = pci_alloc_consistent(pdev, sz,
- &pHCB->HCS_physEscbArray);
- if (!pHCB->HCS_virEscbArray) {
+ sz = ORC_MAXQUEUE * sizeof(struct orc_extended_scb);
+ host->escb_virt = pci_alloc_consistent(pdev, sz,
+ &host->escb_phys);
+ if (!host->escb_virt) {
printk("inia100: ESCB memory allocation error\n");
goto out_free_scb_array;
}
- memset(pHCB->HCS_virEscbArray, 0, sz);
+ memset(host->escb_virt, 0, sz);
- dBiosAdr = pHCB->HCS_BIOS;
- dBiosAdr = (dBiosAdr << 4);
- pbBiosAdr = phys_to_virt(dBiosAdr);
- if (init_orchid(pHCB)) { /* Initialize orchid chip */
+ biosaddr = host->BIOScfg;
+ biosaddr = (biosaddr << 4);
+ bios_phys = phys_to_virt(biosaddr);
+ if (init_orchid(host)) { /* Initialize orchid chip */
printk("inia100: initial orchid fail!!\n");
goto out_free_escb_array;
}
- shost->io_port = pHCB->HCS_Base;
+ shost->io_port = host->base;
shost->n_io_port = 0xff;
shost->can_queue = ORC_MAXQUEUE;
shost->unique_id = shost->io_port;
- shost->max_id = pHCB->HCS_MaxTar;
+ shost->max_id = host->max_targets;
shost->max_lun = 16;
- shost->irq = pHCB->HCS_Intr = pdev->irq;
- shost->this_id = pHCB->HCS_SCSI_ID; /* Assign HCS index */
+ shost->irq = pdev->irq;
+ shost->this_id = host->scsi_id; /* Assign HCS index */
shost->sg_tablesize = TOTAL_SG_ENTRY;
/* Initial orc chip */
@@ -1137,36 +1170,36 @@
scsi_scan_host(shost);
return 0;
- out_free_irq:
+out_free_irq:
free_irq(shost->irq, shost);
- out_free_escb_array:
- pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ESCB),
- pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
- out_free_scb_array:
- pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
- pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
- out_host_put:
+out_free_escb_array:
+ pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_extended_scb),
+ host->escb_virt, host->escb_phys);
+out_free_scb_array:
+ pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_scb),
+ host->scb_virt, host->scb_phys);
+out_host_put:
scsi_host_put(shost);
- out_release_region:
+out_release_region:
release_region(port, 256);
- out_disable_device:
+out_disable_device:
pci_disable_device(pdev);
- out:
+out:
return error;
}
static void __devexit inia100_remove_one(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
- ORC_HCS *pHCB = (ORC_HCS *)shost->hostdata;
+ struct orc_host *host = (struct orc_host *)shost->hostdata;
scsi_remove_host(shost);
free_irq(shost->irq, shost);
- pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ESCB),
- pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
- pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
- pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
+ pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_extended_scb),
+ host->escb_virt, host->escb_phys);
+ pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_scb),
+ host->scb_virt, host->scb_phys);
release_region(shost->io_port, 256);
scsi_host_put(shost);
diff --git a/drivers/scsi/a100u2w.h b/drivers/scsi/a100u2w.h
index 6f542d2..d40e0c5 100644
--- a/drivers/scsi/a100u2w.h
+++ b/drivers/scsi/a100u2w.h
@@ -18,27 +18,6 @@
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * --------------------------------------------------------------------------
- *
- * 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, immediately at the beginning of the file.
- * 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.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * Where this Software is combined with software released under the terms of
- * the GNU General Public License ("GPL") and the terms of the GPL would require the
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
- *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -50,30 +29,19 @@
* 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.
- */
-
-/*
+ *
* Revision History:
* 06/18/98 HL, Initial production Version 1.02
* 12/19/98 bv, Use spinlocks for 2.1.95 and up
* 06/25/02 Doug Ledford <dledford@redhat.com>
* - This and the i60uscsi.h file are almost identical,
* merged them into a single header used by both .c files.
+ * 14/06/07 Alan Cox <alan@redhat.com>
+ * - Grand cleanup and Linuxisation
*/
#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02d"
-#define ULONG unsigned long
-#define USHORT unsigned short
-#define UCHAR unsigned char
-#define BYTE unsigned char
-#define WORD unsigned short
-#define DWORD unsigned long
-#define UBYTE unsigned char
-#define UWORD unsigned short
-#define UDWORD unsigned long
-#define U32 u32
-
#if 1
#define ORC_MAXQUEUE 245
#define ORC_MAXTAGS 64
@@ -90,10 +58,10 @@
/************************************************************************/
/* Scatter-Gather Element Structure */
/************************************************************************/
-typedef struct ORC_SG_Struc {
- U32 SG_Ptr; /* Data Pointer */
- U32 SG_Len; /* Data Length */
-} ORC_SG;
+struct orc_sgent {
+ u32 base; /* Data Pointer */
+ u32 length; /* Data Length */
+};
/* SCSI related definition */
#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */
@@ -165,42 +133,45 @@
#define ORC_PRGMCTR1 0xE3 /* RISC program counter */
#define ORC_RISCRAM 0xEC /* RISC RAM data port 4 bytes */
-typedef struct orc_extended_scb { /* Extended SCB */
- ORC_SG ESCB_SGList[TOTAL_SG_ENTRY]; /*0 Start of SG list */
- struct scsi_cmnd *SCB_Srb; /*50 SRB Pointer */
-} ESCB;
+struct orc_extended_scb { /* Extended SCB */
+ struct orc_sgent sglist[TOTAL_SG_ENTRY]; /*0 Start of SG list */
+ struct scsi_cmnd *srb; /*50 SRB Pointer */
+};
/***********************************************************************
SCSI Control Block
-************************************************************************/
-typedef struct orc_scb { /* Scsi_Ctrl_Blk */
- UBYTE SCB_Opcode; /*00 SCB command code&residual */
- UBYTE SCB_Flags; /*01 SCB Flags */
- UBYTE SCB_Target; /*02 Target Id */
- UBYTE SCB_Lun; /*03 Lun */
- U32 SCB_Reserved0; /*04 Reserved for ORCHID must 0 */
- U32 SCB_XferLen; /*08 Data Transfer Length */
- U32 SCB_Reserved1; /*0C Reserved for ORCHID must 0 */
- U32 SCB_SGLen; /*10 SG list # * 8 */
- U32 SCB_SGPAddr; /*14 SG List Buf physical Addr */
- U32 SCB_SGPAddrHigh; /*18 SG Buffer high physical Addr */
- UBYTE SCB_HaStat; /*1C Host Status */
- UBYTE SCB_TaStat; /*1D Target Status */
- UBYTE SCB_Status; /*1E SCB status */
- UBYTE SCB_Link; /*1F Link pointer, default 0xFF */
- UBYTE SCB_SenseLen; /*20 Sense Allocation Length */
- UBYTE SCB_CDBLen; /*21 CDB Length */
- UBYTE SCB_Ident; /*22 Identify */
- UBYTE SCB_TagMsg; /*23 Tag Message */
- UBYTE SCB_CDB[IMAX_CDB]; /*24 SCSI CDBs */
- UBYTE SCB_ScbIdx; /*3C Index for this ORCSCB */
- U32 SCB_SensePAddr; /*34 Sense Buffer physical Addr */
- ESCB *SCB_EScb; /*38 Extended SCB Pointer */
-#ifndef ALPHA
- UBYTE SCB_Reserved2[4]; /*3E Reserved for Driver use */
+ 0x40 bytes long, the last 8 are user bytes
+************************************************************************/
+struct orc_scb { /* Scsi_Ctrl_Blk */
+ u8 opcode; /*00 SCB command code&residual */
+ u8 flags; /*01 SCB Flags */
+ u8 target; /*02 Target Id */
+ u8 lun; /*03 Lun */
+ u32 reserved0; /*04 Reserved for ORCHID must 0 */
+ u32 xferlen; /*08 Data Transfer Length */
+ u32 reserved1; /*0C Reserved for ORCHID must 0 */
+ u32 sg_len; /*10 SG list # * 8 */
+ u32 sg_addr; /*14 SG List Buf physical Addr */
+ u32 sg_addrhigh; /*18 SG Buffer high physical Addr */
+ u8 hastat; /*1C Host Status */
+ u8 tastat; /*1D Target Status */
+ u8 status; /*1E SCB status */
+ u8 link; /*1F Link pointer, default 0xFF */
+ u8 sense_len; /*20 Sense Allocation Length */
+ u8 cdb_len; /*21 CDB Length */
+ u8 ident; /*22 Identify */
+ u8 tag_msg; /*23 Tag Message */
+ u8 cdb[IMAX_CDB]; /*24 SCSI CDBs */
+ u8 scbidx; /*3C Index for this ORCSCB */
+ u32 sense_addr; /*34 Sense Buffer physical Addr */
+
+ struct orc_extended_scb *escb; /*38 Extended SCB Pointer */
+ /* 64bit pointer or 32bit pointer + reserved ? */
+#ifndef CONFIG_64BIT
+ u8 reserved2[4]; /*3E Reserved for Driver use */
#endif
-} ORC_SCB;
+};
/* Opcodes of ORCSCB_Opcode */
#define ORC_EXECSCSI 0x00 /* SCSI initiator command with residual */
@@ -239,13 +210,13 @@
Target Device Control Structure
**********************************************************************/
-typedef struct ORC_Tar_Ctrl_Struc {
- UBYTE TCS_DrvDASD; /* 6 */
- UBYTE TCS_DrvSCSI; /* 7 */
- UBYTE TCS_DrvHead; /* 8 */
- UWORD TCS_DrvFlags; /* 4 */
- UBYTE TCS_DrvSector; /* 7 */
-} ORC_TCS;
+struct orc_target {
+ u8 TCS_DrvDASD; /* 6 */
+ u8 TCS_DrvSCSI; /* 7 */
+ u8 TCS_DrvHead; /* 8 */
+ u16 TCS_DrvFlags; /* 4 */
+ u8 TCS_DrvSector; /* 7 */
+};
/* Bit Definition for TCF_DrvFlags */
#define TCS_DF_NODASD_SUPT 0x20 /* Suppress OS/2 DASD Mgr support */
@@ -255,32 +226,23 @@
/***********************************************************************
Host Adapter Control Structure
************************************************************************/
-typedef struct ORC_Ha_Ctrl_Struc {
- USHORT HCS_Base; /* 00 */
- UBYTE HCS_Index; /* 02 */
- UBYTE HCS_Intr; /* 04 */
- UBYTE HCS_SCSI_ID; /* 06 H/A SCSI ID */
- UBYTE HCS_BIOS; /* 07 BIOS configuration */
-
- UBYTE HCS_Flags; /* 0B */
- UBYTE HCS_HAConfig1; /* 1B SCSI0MAXTags */
- UBYTE HCS_MaxTar; /* 1B SCSI0MAXTags */
-
- USHORT HCS_Units; /* Number of units this adapter */
- USHORT HCS_AFlags; /* Adapter info. defined flags */
- ULONG HCS_Timeout; /* Adapter timeout value */
- ORC_SCB *HCS_virScbArray; /* 28 Virtual Pointer to SCB array */
- dma_addr_t HCS_physScbArray; /* Scb Physical address */
- ESCB *HCS_virEscbArray; /* Virtual pointer to ESCB Scatter list */
- dma_addr_t HCS_physEscbArray; /* scatter list Physical address */
- UBYTE TargetFlag[16]; /* 30 target configuration, TCF_EN_TAG */
- UBYTE MaximumTags[16]; /* 40 ORC_MAX_SCBS */
- UBYTE ActiveTags[16][16]; /* 50 */
- ORC_TCS HCS_Tcs[16]; /* 28 */
- U32 BitAllocFlag[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */
- spinlock_t BitAllocFlagLock;
+struct orc_host {
+ unsigned long base; /* Base address */
+ u8 index; /* Index (Channel)*/
+ u8 scsi_id; /* H/A SCSI ID */
+ u8 BIOScfg; /*BIOS configuration */
+ u8 flags;
+ u8 max_targets; /* SCSI0MAXTags */
+ struct orc_scb *scb_virt; /* Virtual Pointer to SCB array */
+ dma_addr_t scb_phys; /* Scb Physical address */
+ struct orc_extended_scb *escb_virt; /* Virtual pointer to ESCB Scatter list */
+ dma_addr_t escb_phys; /* scatter list Physical address */
+ u8 target_flag[16]; /* target configuration, TCF_EN_TAG */
+ u8 max_tags[16]; /* ORC_MAX_SCBS */
+ u32 allocation_map[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */
+ spinlock_t allocation_lock;
struct pci_dev *pdev;
-} ORC_HCS;
+};
/* Bit Definition for HCS_Flags */
@@ -301,79 +263,79 @@
#define HCS_AF_DISABLE_RESET 0x10 /* Adapter disable reset */
#define HCS_AF_DISABLE_ADPT 0x80 /* Adapter disable */
-typedef struct _NVRAM {
+struct orc_nvram {
/*----------header ---------------*/
- UCHAR SubVendorID0; /* 00 - Sub Vendor ID */
- UCHAR SubVendorID1; /* 00 - Sub Vendor ID */
- UCHAR SubSysID0; /* 02 - Sub System ID */
- UCHAR SubSysID1; /* 02 - Sub System ID */
- UCHAR SubClass; /* 04 - Sub Class */
- UCHAR VendorID0; /* 05 - Vendor ID */
- UCHAR VendorID1; /* 05 - Vendor ID */
- UCHAR DeviceID0; /* 07 - Device ID */
- UCHAR DeviceID1; /* 07 - Device ID */
- UCHAR Reserved0[2]; /* 09 - Reserved */
- UCHAR Revision; /* 0B - Revision of data structure */
+ u8 SubVendorID0; /* 00 - Sub Vendor ID */
+ u8 SubVendorID1; /* 00 - Sub Vendor ID */
+ u8 SubSysID0; /* 02 - Sub System ID */
+ u8 SubSysID1; /* 02 - Sub System ID */
+ u8 SubClass; /* 04 - Sub Class */
+ u8 VendorID0; /* 05 - Vendor ID */
+ u8 VendorID1; /* 05 - Vendor ID */
+ u8 DeviceID0; /* 07 - Device ID */
+ u8 DeviceID1; /* 07 - Device ID */
+ u8 Reserved0[2]; /* 09 - Reserved */
+ u8 revision; /* 0B - revision of data structure */
/* ----Host Adapter Structure ---- */
- UCHAR NumOfCh; /* 0C - Number of SCSI channel */
- UCHAR BIOSConfig1; /* 0D - BIOS configuration 1 */
- UCHAR BIOSConfig2; /* 0E - BIOS boot channel&target ID */
- UCHAR BIOSConfig3; /* 0F - BIOS configuration 3 */
+ u8 NumOfCh; /* 0C - Number of SCSI channel */
+ u8 BIOSConfig1; /* 0D - BIOS configuration 1 */
+ u8 BIOSConfig2; /* 0E - BIOS boot channel&target ID */
+ u8 BIOSConfig3; /* 0F - BIOS configuration 3 */
/* ----SCSI channel Structure ---- */
/* from "CTRL-I SCSI Host Adapter SetUp menu " */
- UCHAR SCSI0Id; /* 10 - Channel 0 SCSI ID */
- UCHAR SCSI0Config; /* 11 - Channel 0 SCSI configuration */
- UCHAR SCSI0MaxTags; /* 12 - Channel 0 Maximum tags */
- UCHAR SCSI0ResetTime; /* 13 - Channel 0 Reset recovering time */
- UCHAR ReservedforChannel0[2]; /* 14 - Reserved */
+ u8 scsi_id; /* 10 - Channel 0 SCSI ID */
+ u8 SCSI0Config; /* 11 - Channel 0 SCSI configuration */
+ u8 SCSI0MaxTags; /* 12 - Channel 0 Maximum tags */
+ u8 SCSI0ResetTime; /* 13 - Channel 0 Reset recovering time */
+ u8 ReservedforChannel0[2]; /* 14 - Reserved */
/* ----SCSI target Structure ---- */
/* from "CTRL-I SCSI device SetUp menu " */
- UCHAR Target00Config; /* 16 - Channel 0 Target 0 config */
- UCHAR Target01Config; /* 17 - Channel 0 Target 1 config */
- UCHAR Target02Config; /* 18 - Channel 0 Target 2 config */
- UCHAR Target03Config; /* 19 - Channel 0 Target 3 config */
- UCHAR Target04Config; /* 1A - Channel 0 Target 4 config */
- UCHAR Target05Config; /* 1B - Channel 0 Target 5 config */
- UCHAR Target06Config; /* 1C - Channel 0 Target 6 config */
- UCHAR Target07Config; /* 1D - Channel 0 Target 7 config */
- UCHAR Target08Config; /* 1E - Channel 0 Target 8 config */
- UCHAR Target09Config; /* 1F - Channel 0 Target 9 config */
- UCHAR Target0AConfig; /* 20 - Channel 0 Target A config */
- UCHAR Target0BConfig; /* 21 - Channel 0 Target B config */
- UCHAR Target0CConfig; /* 22 - Channel 0 Target C config */
- UCHAR Target0DConfig; /* 23 - Channel 0 Target D config */
- UCHAR Target0EConfig; /* 24 - Channel 0 Target E config */
- UCHAR Target0FConfig; /* 25 - Channel 0 Target F config */
+ u8 Target00Config; /* 16 - Channel 0 Target 0 config */
+ u8 Target01Config; /* 17 - Channel 0 Target 1 config */
+ u8 Target02Config; /* 18 - Channel 0 Target 2 config */
+ u8 Target03Config; /* 19 - Channel 0 Target 3 config */
+ u8 Target04Config; /* 1A - Channel 0 Target 4 config */
+ u8 Target05Config; /* 1B - Channel 0 Target 5 config */
+ u8 Target06Config; /* 1C - Channel 0 Target 6 config */
+ u8 Target07Config; /* 1D - Channel 0 Target 7 config */
+ u8 Target08Config; /* 1E - Channel 0 Target 8 config */
+ u8 Target09Config; /* 1F - Channel 0 Target 9 config */
+ u8 Target0AConfig; /* 20 - Channel 0 Target A config */
+ u8 Target0BConfig; /* 21 - Channel 0 Target B config */
+ u8 Target0CConfig; /* 22 - Channel 0 Target C config */
+ u8 Target0DConfig; /* 23 - Channel 0 Target D config */
+ u8 Target0EConfig; /* 24 - Channel 0 Target E config */
+ u8 Target0FConfig; /* 25 - Channel 0 Target F config */
- UCHAR SCSI1Id; /* 26 - Channel 1 SCSI ID */
- UCHAR SCSI1Config; /* 27 - Channel 1 SCSI configuration */
- UCHAR SCSI1MaxTags; /* 28 - Channel 1 Maximum tags */
- UCHAR SCSI1ResetTime; /* 29 - Channel 1 Reset recovering time */
- UCHAR ReservedforChannel1[2]; /* 2A - Reserved */
+ u8 SCSI1Id; /* 26 - Channel 1 SCSI ID */
+ u8 SCSI1Config; /* 27 - Channel 1 SCSI configuration */
+ u8 SCSI1MaxTags; /* 28 - Channel 1 Maximum tags */
+ u8 SCSI1ResetTime; /* 29 - Channel 1 Reset recovering time */
+ u8 ReservedforChannel1[2]; /* 2A - Reserved */
/* ----SCSI target Structure ---- */
/* from "CTRL-I SCSI device SetUp menu " */
- UCHAR Target10Config; /* 2C - Channel 1 Target 0 config */
- UCHAR Target11Config; /* 2D - Channel 1 Target 1 config */
- UCHAR Target12Config; /* 2E - Channel 1 Target 2 config */
- UCHAR Target13Config; /* 2F - Channel 1 Target 3 config */
- UCHAR Target14Config; /* 30 - Channel 1 Target 4 config */
- UCHAR Target15Config; /* 31 - Channel 1 Target 5 config */
- UCHAR Target16Config; /* 32 - Channel 1 Target 6 config */
- UCHAR Target17Config; /* 33 - Channel 1 Target 7 config */
- UCHAR Target18Config; /* 34 - Channel 1 Target 8 config */
- UCHAR Target19Config; /* 35 - Channel 1 Target 9 config */
- UCHAR Target1AConfig; /* 36 - Channel 1 Target A config */
- UCHAR Target1BConfig; /* 37 - Channel 1 Target B config */
- UCHAR Target1CConfig; /* 38 - Channel 1 Target C config */
- UCHAR Target1DConfig; /* 39 - Channel 1 Target D config */
- UCHAR Target1EConfig; /* 3A - Channel 1 Target E config */
- UCHAR Target1FConfig; /* 3B - Channel 1 Target F config */
- UCHAR reserved[3]; /* 3C - Reserved */
+ u8 Target10Config; /* 2C - Channel 1 Target 0 config */
+ u8 Target11Config; /* 2D - Channel 1 Target 1 config */
+ u8 Target12Config; /* 2E - Channel 1 Target 2 config */
+ u8 Target13Config; /* 2F - Channel 1 Target 3 config */
+ u8 Target14Config; /* 30 - Channel 1 Target 4 config */
+ u8 Target15Config; /* 31 - Channel 1 Target 5 config */
+ u8 Target16Config; /* 32 - Channel 1 Target 6 config */
+ u8 Target17Config; /* 33 - Channel 1 Target 7 config */
+ u8 Target18Config; /* 34 - Channel 1 Target 8 config */
+ u8 Target19Config; /* 35 - Channel 1 Target 9 config */
+ u8 Target1AConfig; /* 36 - Channel 1 Target A config */
+ u8 Target1BConfig; /* 37 - Channel 1 Target B config */
+ u8 Target1CConfig; /* 38 - Channel 1 Target C config */
+ u8 Target1DConfig; /* 39 - Channel 1 Target D config */
+ u8 Target1EConfig; /* 3A - Channel 1 Target E config */
+ u8 Target1FConfig; /* 3B - Channel 1 Target F config */
+ u8 reserved[3]; /* 3C - Reserved */
/* ---------- CheckSum ---------- */
- UCHAR CheckSum; /* 3F - Checksum of NVRam */
-} NVRAM, *PNVRAM;
+ u8 CheckSum; /* 3F - Checksum of NVRam */
+};
/* Bios Configuration for nvram->BIOSConfig1 */
#define NBC_BIOSENABLE 0x01 /* BIOS enable */
@@ -407,10 +369,3 @@
#define NCC_RESET_TIME 0x0A /* SCSI RESET recovering time */
#define NTC_DEFAULT (NTC_1GIGA | NTC_NO_WIDESYNC | NTC_DISC_ENABLE)
-#define ORC_RD(x,y) (UCHAR)(inb( (int)((ULONG)((ULONG)x+(UCHAR)y)) ))
-#define ORC_RDWORD(x,y) (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
-#define ORC_RDLONG(x,y) (long)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
-
-#define ORC_WR( adr,data) outb( (UCHAR)(data), (int)(adr))
-#define ORC_WRSHORT(adr,data) outw( (UWORD)(data), (int)(adr))
-#define ORC_WRLONG( adr,data) outl( (ULONG)(data), (int)(adr))
diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c
new file mode 100644
index 0000000..6a57846
--- /dev/null
+++ b/drivers/scsi/a4000t.c
@@ -0,0 +1,143 @@
+/*
+ * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
+ * Amiga Technologies A4000T SCSI controller.
+ *
+ * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * plus modifications of the 53c7xx.c driver to support the Amiga.
+ *
+ * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org>
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+
+MODULE_AUTHOR("Alan Hourihane <alanh@fairlite.demon.co.uk> / Kars de Jong <jongk@linux-m68k.org>");
+MODULE_DESCRIPTION("Amiga A4000T NCR53C710 driver");
+MODULE_LICENSE("GPL");
+
+
+static struct scsi_host_template a4000t_scsi_driver_template = {
+ .name = "A4000T builtin SCSI",
+ .proc_name = "A4000t",
+ .this_id = 7,
+ .module = THIS_MODULE,
+};
+
+static struct platform_device *a4000t_scsi_device;
+
+#define A4000T_SCSI_ADDR 0xdd0040
+
+static int __devinit a4000t_probe(struct device *dev)
+{
+ struct Scsi_Host * host = NULL;
+ struct NCR_700_Host_Parameters *hostdata;
+
+ if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(A4000_SCSI)))
+ goto out;
+
+ if (!request_mem_region(A4000T_SCSI_ADDR, 0x1000,
+ "A4000T builtin SCSI"))
+ goto out;
+
+ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (hostdata == NULL) {
+ printk(KERN_ERR "a4000t-scsi: Failed to allocate host data\n");
+ goto out_release;
+ }
+ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
+
+ /* Fill in the required pieces of hostdata */
+ hostdata->base = (void __iomem *)ZTWO_VADDR(A4000T_SCSI_ADDR);
+ hostdata->clock = 50;
+ hostdata->chip710 = 1;
+ hostdata->dmode_extra = DMODE_FC2;
+ hostdata->dcntl_extra = EA_710;
+
+ /* and register the chip */
+ host = NCR_700_detect(&a4000t_scsi_driver_template, hostdata, dev);
+ if (!host) {
+ printk(KERN_ERR "a4000t-scsi: No host detected; "
+ "board configuration problem?\n");
+ goto out_free;
+ }
+
+ host->this_id = 7;
+ host->base = A4000T_SCSI_ADDR;
+ host->irq = IRQ_AMIGA_PORTS;
+
+ if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "a4000t-scsi",
+ host)) {
+ printk(KERN_ERR "a4000t-scsi: request_irq failed\n");
+ goto out_put_host;
+ }
+
+ scsi_scan_host(host);
+
+ return 0;
+
+ out_put_host:
+ scsi_host_put(host);
+ out_free:
+ kfree(hostdata);
+ out_release:
+ release_mem_region(A4000T_SCSI_ADDR, 0x1000);
+ out:
+ return -ENODEV;
+}
+
+static __devexit int a4000t_device_remove(struct device *dev)
+{
+ struct Scsi_Host *host = dev_to_shost(dev);
+ struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
+
+ scsi_remove_host(host);
+
+ NCR_700_release(host);
+ kfree(hostdata);
+ free_irq(host->irq, host);
+ release_mem_region(A4000T_SCSI_ADDR, 0x1000);
+
+ return 0;
+}
+
+static struct device_driver a4000t_scsi_driver = {
+ .name = "a4000t-scsi",
+ .bus = &platform_bus_type,
+ .probe = a4000t_probe,
+ .remove = __devexit_p(a4000t_device_remove),
+};
+
+static int __init a4000t_scsi_init(void)
+{
+ int err;
+
+ err = driver_register(&a4000t_scsi_driver);
+ if (err)
+ return err;
+
+ a4000t_scsi_device = platform_device_register_simple("a4000t-scsi",
+ -1, NULL, 0);
+ if (IS_ERR(a4000t_scsi_device)) {
+ driver_unregister(&a4000t_scsi_driver);
+ return PTR_ERR(a4000t_scsi_device);
+ }
+
+ return err;
+}
+
+static void __exit a4000t_scsi_exit(void)
+{
+ platform_device_unregister(a4000t_scsi_device);
+ driver_unregister(&a4000t_scsi_driver);
+}
+
+module_init(a4000t_scsi_init);
+module_exit(a4000t_scsi_exit);
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 8dcfe4e..0b6fd0b 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -169,6 +169,18 @@
module_param(acbsize, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware.");
+int update_interval = 30 * 60;
+module_param(update_interval, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync updates issued to adapter.");
+
+int check_interval = 24 * 60 * 60;
+module_param(check_interval, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health checks.");
+
+int check_reset = 1;
+module_param(check_reset, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the adapter.");
+
int expose_physicals = -1;
module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on");
@@ -312,11 +324,10 @@
if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
- fsa_dev_ptr = kmalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers,
+ fsa_dev_ptr = kzalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers,
GFP_KERNEL);
if (!fsa_dev_ptr)
return -ENOMEM;
- memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers);
dev->fsa_dev = fsa_dev_ptr;
dev->maximum_num_containers = maximum_num_containers;
@@ -344,21 +355,16 @@
{
void *buf;
int transfer_len;
- struct scatterlist *sg = scsicmd->request_buffer;
+ struct scatterlist *sg = scsi_sglist(scsicmd);
- if (scsicmd->use_sg) {
- buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- transfer_len = min(sg->length, len + offset);
- } else {
- buf = scsicmd->request_buffer;
- transfer_len = min(scsicmd->request_bufflen, len + offset);
- }
+ buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ transfer_len = min(sg->length, len + offset);
+
transfer_len -= offset;
if (buf && transfer_len > 0)
memcpy(buf + offset, data, transfer_len);
- if (scsicmd->use_sg)
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
}
@@ -451,7 +457,7 @@
{
struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
- if (fsa_dev_ptr[scmd_id(scsicmd)].valid)
+ if ((fsa_dev_ptr[scmd_id(scsicmd)].valid & 1))
return aac_scsi_cmd(scsicmd);
scsicmd->result = DID_NO_CONNECT << 16;
@@ -459,18 +465,18 @@
return 0;
}
-static int _aac_probe_container2(void * context, struct fib * fibptr)
+static void _aac_probe_container2(void * context, struct fib * fibptr)
{
struct fsa_dev_info *fsa_dev_ptr;
int (*callback)(struct scsi_cmnd *);
struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context;
- if (!aac_valid_context(scsicmd, fibptr))
- return 0;
- fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
scsicmd->SCp.Status = 0;
+ fsa_dev_ptr = fibptr->dev->fsa_dev;
if (fsa_dev_ptr) {
struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr);
fsa_dev_ptr += scmd_id(scsicmd);
@@ -493,10 +499,11 @@
aac_fib_free(fibptr);
callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr);
scsicmd->SCp.ptr = NULL;
- return (*callback)(scsicmd);
+ (*callback)(scsicmd);
+ return;
}
-static int _aac_probe_container1(void * context, struct fib * fibptr)
+static void _aac_probe_container1(void * context, struct fib * fibptr)
{
struct scsi_cmnd * scsicmd;
struct aac_mount * dresp;
@@ -506,13 +513,14 @@
dresp = (struct aac_mount *) fib_data(fibptr);
dresp->mnt[0].capacityhigh = 0;
if ((le32_to_cpu(dresp->status) != ST_OK) ||
- (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE))
- return _aac_probe_container2(context, fibptr);
+ (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) {
+ _aac_probe_container2(context, fibptr);
+ return;
+ }
scsicmd = (struct scsi_cmnd *) context;
- scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
if (!aac_valid_context(scsicmd, fibptr))
- return 0;
+ return;
aac_fib_init(fibptr);
@@ -527,21 +535,18 @@
sizeof(struct aac_query_mount),
FsaNormal,
0, 1,
- (fib_callback) _aac_probe_container2,
+ _aac_probe_container2,
(void *) scsicmd);
/*
* Check that the command queued to the controller
*/
- if (status == -EINPROGRESS) {
+ if (status == -EINPROGRESS)
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
- return 0;
- }
- if (status < 0) {
+ else if (status < 0) {
/* Inherit results from VM_NameServe, if any */
dresp->status = cpu_to_le32(ST_OK);
- return _aac_probe_container2(context, fibptr);
+ _aac_probe_container2(context, fibptr);
}
- return 0;
}
static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *))
@@ -566,7 +571,7 @@
sizeof(struct aac_query_mount),
FsaNormal,
0, 1,
- (fib_callback) _aac_probe_container1,
+ _aac_probe_container1,
(void *) scsicmd);
/*
* Check that the command queued to the controller
@@ -620,7 +625,7 @@
return -ENOMEM;
}
scsicmd->list.next = NULL;
- scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))_aac_probe_container1;
+ scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))aac_probe_container_callback1;
scsicmd->device = scsidev;
scsidev->sdev_state = 0;
@@ -825,7 +830,7 @@
readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
readcmd->count = cpu_to_le32(count<<9);
readcmd->cid = cpu_to_le16(scmd_id(cmd));
- readcmd->flags = cpu_to_le16(1);
+ readcmd->flags = cpu_to_le16(IO_TYPE_READ);
readcmd->bpTotal = 0;
readcmd->bpComplete = 0;
@@ -904,7 +909,7 @@
(void *) cmd);
}
-static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
+static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
{
u16 fibsize;
struct aac_raw_io *writecmd;
@@ -914,7 +919,9 @@
writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
writecmd->count = cpu_to_le32(count<<9);
writecmd->cid = cpu_to_le16(scmd_id(cmd));
- writecmd->flags = 0;
+ writecmd->flags = fua ?
+ cpu_to_le16(IO_TYPE_WRITE|IO_SUREWRITE) :
+ cpu_to_le16(IO_TYPE_WRITE);
writecmd->bpTotal = 0;
writecmd->bpComplete = 0;
@@ -933,7 +940,7 @@
(void *) cmd);
}
-static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
+static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
{
u16 fibsize;
struct aac_write64 *writecmd;
@@ -964,7 +971,7 @@
(void *) cmd);
}
-static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
+static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
{
u16 fibsize;
struct aac_write *writecmd;
@@ -1041,7 +1048,7 @@
struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
aac_build_sg64(cmd, (struct sgmap64*) &srbcmd->sg);
- srbcmd->count = cpu_to_le32(cmd->request_bufflen);
+ srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
@@ -1069,7 +1076,7 @@
struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
aac_build_sg(cmd, (struct sgmap*)&srbcmd->sg);
- srbcmd->count = cpu_to_le32(cmd->request_bufflen);
+ srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
@@ -1172,6 +1179,7 @@
}
if (!dev->in_reset) {
+ char buffer[16];
tmp = le32_to_cpu(dev->adapter_info.kernelrev);
printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
dev->name,
@@ -1192,16 +1200,23 @@
dev->name, dev->id,
tmp>>24,(tmp>>16)&0xff,tmp&0xff,
le32_to_cpu(dev->adapter_info.biosbuild));
- if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
- printk(KERN_INFO "%s%d: serial %x\n",
- dev->name, dev->id,
- le32_to_cpu(dev->adapter_info.serial[0]));
+ buffer[0] = '\0';
+ if (aac_show_serial_number(
+ shost_to_class(dev->scsi_host_ptr), buffer))
+ printk(KERN_INFO "%s%d: serial %s",
+ dev->name, dev->id, buffer);
if (dev->supplement_adapter_info.VpdInfo.Tsid[0]) {
printk(KERN_INFO "%s%d: TSID %.*s\n",
dev->name, dev->id,
(int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
dev->supplement_adapter_info.VpdInfo.Tsid);
}
+ if (!check_reset ||
+ (dev->supplement_adapter_info.SupportedOptions2 &
+ le32_to_cpu(AAC_OPTION_IGNORE_RESET))) {
+ printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
+ dev->name, dev->id);
+ }
}
dev->nondasd_support = 0;
@@ -1332,7 +1347,7 @@
if (!aac_valid_context(scsicmd, fibptr))
return;
- dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+ dev = fibptr->dev;
cid = scmd_id(scsicmd);
if (nblank(dprintk(x))) {
@@ -1371,16 +1386,9 @@
}
BUG_ON(fibptr == NULL);
-
- if(scsicmd->use_sg)
- pci_unmap_sg(dev->pdev,
- (struct scatterlist *)scsicmd->request_buffer,
- scsicmd->use_sg,
- scsicmd->sc_data_direction);
- else if(scsicmd->request_bufflen)
- pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle,
- scsicmd->request_bufflen,
- scsicmd->sc_data_direction);
+
+ scsi_dma_unmap(scsicmd);
+
readreply = (struct aac_read_reply *)fib_data(fibptr);
if (le32_to_cpu(readreply->status) == ST_OK)
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
@@ -1498,6 +1506,7 @@
{
u64 lba;
u32 count;
+ int fua;
int status;
struct aac_dev *dev;
struct fib * cmd_fibcontext;
@@ -1512,6 +1521,7 @@
count = scsicmd->cmnd[4];
if (count == 0)
count = 256;
+ fua = 0;
} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
@@ -1524,6 +1534,7 @@
(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
+ fua = scsicmd->cmnd[1] & 0x8;
} else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */
dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd)));
@@ -1531,10 +1542,12 @@
| (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
| (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+ fua = scsicmd->cmnd[1] & 0x8;
} else {
dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
+ fua = scsicmd->cmnd[1] & 0x8;
}
dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
smp_processor_id(), (unsigned long long)lba, jiffies));
@@ -1549,7 +1562,7 @@
return 0;
}
- status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count);
+ status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua);
/*
* Check that the command queued to the controller
@@ -1592,7 +1605,7 @@
COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
else {
struct scsi_device *sdev = cmd->device;
- struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+ struct aac_dev *dev = fibptr->dev;
u32 cid = sdev_id(sdev);
printk(KERN_WARNING
"synchronize_callback: synchronize failed, status = %d\n",
@@ -1699,7 +1712,7 @@
int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
{
- u32 cid = 0;
+ u32 cid;
struct Scsi_Host *host = scsicmd->device->host;
struct aac_dev *dev = (struct aac_dev *)host->hostdata;
struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
@@ -1711,15 +1724,15 @@
* Test does not apply to ID 16, the pseudo id for the controller
* itself.
*/
- if (scmd_id(scsicmd) != host->this_id) {
- if ((scmd_channel(scsicmd) == CONTAINER_CHANNEL)) {
- if((scmd_id(scsicmd) >= dev->maximum_num_containers) ||
+ cid = scmd_id(scsicmd);
+ if (cid != host->this_id) {
+ if (scmd_channel(scsicmd) == CONTAINER_CHANNEL) {
+ if((cid >= dev->maximum_num_containers) ||
(scsicmd->device->lun != 0)) {
scsicmd->result = DID_NO_CONNECT << 16;
scsicmd->scsi_done(scsicmd);
return 0;
}
- cid = scmd_id(scsicmd);
/*
* If the target container doesn't exist, it may have
@@ -1782,7 +1795,7 @@
{
struct inquiry_data inq_data;
- dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scmd_id(scsicmd)));
+ dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
memset(&inq_data, 0, sizeof (struct inquiry_data));
inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */
@@ -1794,7 +1807,7 @@
* Set the Vendor, Product, and Revision Level
* see: <vendor>.c i.e. aac.c
*/
- if (scmd_id(scsicmd) == host->this_id) {
+ if (cid == host->this_id) {
setinqstr(dev, (void *) (inq_data.inqd_vid), ARRAY_SIZE(container_types));
inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */
aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
@@ -1886,15 +1899,29 @@
case MODE_SENSE:
{
- char mode_buf[4];
+ char mode_buf[7];
+ int mode_buf_length = 4;
dprintk((KERN_DEBUG "MODE SENSE command.\n"));
mode_buf[0] = 3; /* Mode data length */
mode_buf[1] = 0; /* Medium type - default */
- mode_buf[2] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected */
+ mode_buf[2] = 0; /* Device-specific param,
+ bit 8: 0/1 = write enabled/protected
+ bit 4: 0/1 = FUA enabled */
+ if (dev->raw_io_interface)
+ mode_buf[2] = 0x10;
mode_buf[3] = 0; /* Block descriptor length */
-
- aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf));
+ if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
+ ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) {
+ mode_buf[0] = 6;
+ mode_buf[4] = 8;
+ mode_buf[5] = 1;
+ mode_buf[6] = 0x04; /* WCE */
+ mode_buf_length = 7;
+ if (mode_buf_length > scsicmd->cmnd[4])
+ mode_buf_length = scsicmd->cmnd[4];
+ }
+ aac_internal_transfer(scsicmd, mode_buf, 0, mode_buf_length);
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
@@ -1902,18 +1929,33 @@
}
case MODE_SENSE_10:
{
- char mode_buf[8];
+ char mode_buf[11];
+ int mode_buf_length = 8;
dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n"));
mode_buf[0] = 0; /* Mode data length (MSB) */
mode_buf[1] = 6; /* Mode data length (LSB) */
mode_buf[2] = 0; /* Medium type - default */
- mode_buf[3] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected */
+ mode_buf[3] = 0; /* Device-specific param,
+ bit 8: 0/1 = write enabled/protected
+ bit 4: 0/1 = FUA enabled */
+ if (dev->raw_io_interface)
+ mode_buf[3] = 0x10;
mode_buf[4] = 0; /* reserved */
mode_buf[5] = 0; /* reserved */
mode_buf[6] = 0; /* Block descriptor length (MSB) */
mode_buf[7] = 0; /* Block descriptor length (LSB) */
- aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf));
+ if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
+ ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) {
+ mode_buf[1] = 9;
+ mode_buf[8] = 8;
+ mode_buf[9] = 1;
+ mode_buf[10] = 0x04; /* WCE */
+ mode_buf_length = 11;
+ if (mode_buf_length > scsicmd->cmnd[8])
+ mode_buf_length = scsicmd->cmnd[8];
+ }
+ aac_internal_transfer(scsicmd, mode_buf, 0, mode_buf_length);
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
@@ -2136,28 +2178,21 @@
if (!aac_valid_context(scsicmd, fibptr))
return;
- dev = (struct aac_dev *)scsicmd->device->host->hostdata;
-
BUG_ON(fibptr == NULL);
+ dev = fibptr->dev;
+
srbreply = (struct aac_srb_reply *) fib_data(fibptr);
scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */
/*
* Calculate resid for sg
*/
-
- scsicmd->resid = scsicmd->request_bufflen -
- le32_to_cpu(srbreply->data_xfer_length);
- if(scsicmd->use_sg)
- pci_unmap_sg(dev->pdev,
- (struct scatterlist *)scsicmd->request_buffer,
- scsicmd->use_sg,
- scsicmd->sc_data_direction);
- else if(scsicmd->request_bufflen)
- pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, scsicmd->request_bufflen,
- scsicmd->sc_data_direction);
+ scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
+ - le32_to_cpu(srbreply->data_xfer_length));
+
+ scsi_dma_unmap(scsicmd);
/*
* First check the fib status
@@ -2233,7 +2268,7 @@
break;
case SRB_STATUS_BUSY:
- scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+ scsicmd->result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
break;
case SRB_STATUS_BUS_RESET:
@@ -2343,34 +2378,33 @@
{
struct aac_dev *dev;
unsigned long byte_count = 0;
+ int nseg;
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
// Get rid of old data
psg->count = 0;
psg->sg[0].addr = 0;
- psg->sg[0].count = 0;
- if (scsicmd->use_sg) {
+ psg->sg[0].count = 0;
+
+ nseg = scsi_dma_map(scsicmd);
+ BUG_ON(nseg < 0);
+ if (nseg) {
struct scatterlist *sg;
int i;
- int sg_count;
- sg = (struct scatterlist *) scsicmd->request_buffer;
- sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
- scsicmd->sc_data_direction);
- psg->count = cpu_to_le32(sg_count);
+ psg->count = cpu_to_le32(nseg);
- for (i = 0; i < sg_count; i++) {
+ scsi_for_each_sg(scsicmd, sg, nseg, i) {
psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg));
psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
byte_count += sg_dma_len(sg);
- sg++;
}
/* hba wants the size to be exact */
- if(byte_count > scsicmd->request_bufflen){
- u32 temp = le32_to_cpu(psg->sg[i-1].count) -
- (byte_count - scsicmd->request_bufflen);
+ if (byte_count > scsi_bufflen(scsicmd)) {
+ u32 temp = le32_to_cpu(psg->sg[i-1].count) -
+ (byte_count - scsi_bufflen(scsicmd));
psg->sg[i-1].count = cpu_to_le32(temp);
- byte_count = scsicmd->request_bufflen;
+ byte_count = scsi_bufflen(scsicmd);
}
/* Check for command underflow */
if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
@@ -2378,18 +2412,6 @@
byte_count, scsicmd->underflow);
}
}
- else if(scsicmd->request_bufflen) {
- u32 addr;
- scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
- scsicmd->request_buffer,
- scsicmd->request_bufflen,
- scsicmd->sc_data_direction);
- addr = scsicmd->SCp.dma_handle;
- psg->count = cpu_to_le32(1);
- psg->sg[0].addr = cpu_to_le32(addr);
- psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);
- byte_count = scsicmd->request_bufflen;
- }
return byte_count;
}
@@ -2399,6 +2421,7 @@
struct aac_dev *dev;
unsigned long byte_count = 0;
u64 addr;
+ int nseg;
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
// Get rid of old data
@@ -2406,31 +2429,28 @@
psg->sg[0].addr[0] = 0;
psg->sg[0].addr[1] = 0;
psg->sg[0].count = 0;
- if (scsicmd->use_sg) {
+
+ nseg = scsi_dma_map(scsicmd);
+ BUG_ON(nseg < 0);
+ if (nseg) {
struct scatterlist *sg;
int i;
- int sg_count;
- sg = (struct scatterlist *) scsicmd->request_buffer;
- sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
- scsicmd->sc_data_direction);
-
- for (i = 0; i < sg_count; i++) {
+ scsi_for_each_sg(scsicmd, sg, nseg, i) {
int count = sg_dma_len(sg);
addr = sg_dma_address(sg);
psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
psg->sg[i].count = cpu_to_le32(count);
byte_count += count;
- sg++;
}
- psg->count = cpu_to_le32(sg_count);
+ psg->count = cpu_to_le32(nseg);
/* hba wants the size to be exact */
- if(byte_count > scsicmd->request_bufflen){
- u32 temp = le32_to_cpu(psg->sg[i-1].count) -
- (byte_count - scsicmd->request_bufflen);
+ if (byte_count > scsi_bufflen(scsicmd)) {
+ u32 temp = le32_to_cpu(psg->sg[i-1].count) -
+ (byte_count - scsi_bufflen(scsicmd));
psg->sg[i-1].count = cpu_to_le32(temp);
- byte_count = scsicmd->request_bufflen;
+ byte_count = scsi_bufflen(scsicmd);
}
/* Check for command underflow */
if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
@@ -2438,26 +2458,13 @@
byte_count, scsicmd->underflow);
}
}
- else if(scsicmd->request_bufflen) {
- scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
- scsicmd->request_buffer,
- scsicmd->request_bufflen,
- scsicmd->sc_data_direction);
- addr = scsicmd->SCp.dma_handle;
- psg->count = cpu_to_le32(1);
- psg->sg[0].addr[0] = cpu_to_le32(addr & 0xffffffff);
- psg->sg[0].addr[1] = cpu_to_le32(addr >> 32);
- psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);
- byte_count = scsicmd->request_bufflen;
- }
return byte_count;
}
static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg)
{
- struct Scsi_Host *host = scsicmd->device->host;
- struct aac_dev *dev = (struct aac_dev *)host->hostdata;
unsigned long byte_count = 0;
+ int nseg;
// Get rid of old data
psg->count = 0;
@@ -2467,16 +2474,14 @@
psg->sg[0].addr[1] = 0;
psg->sg[0].count = 0;
psg->sg[0].flags = 0;
- if (scsicmd->use_sg) {
+
+ nseg = scsi_dma_map(scsicmd);
+ BUG_ON(nseg < 0);
+ if (nseg) {
struct scatterlist *sg;
int i;
- int sg_count;
- sg = (struct scatterlist *) scsicmd->request_buffer;
- sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
- scsicmd->sc_data_direction);
-
- for (i = 0; i < sg_count; i++) {
+ scsi_for_each_sg(scsicmd, sg, nseg, i) {
int count = sg_dma_len(sg);
u64 addr = sg_dma_address(sg);
psg->sg[i].next = 0;
@@ -2486,15 +2491,14 @@
psg->sg[i].count = cpu_to_le32(count);
psg->sg[i].flags = 0;
byte_count += count;
- sg++;
}
- psg->count = cpu_to_le32(sg_count);
+ psg->count = cpu_to_le32(nseg);
/* hba wants the size to be exact */
- if(byte_count > scsicmd->request_bufflen){
- u32 temp = le32_to_cpu(psg->sg[i-1].count) -
- (byte_count - scsicmd->request_bufflen);
+ if (byte_count > scsi_bufflen(scsicmd)) {
+ u32 temp = le32_to_cpu(psg->sg[i-1].count) -
+ (byte_count - scsi_bufflen(scsicmd));
psg->sg[i-1].count = cpu_to_le32(temp);
- byte_count = scsicmd->request_bufflen;
+ byte_count = scsi_bufflen(scsicmd);
}
/* Check for command underflow */
if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
@@ -2502,24 +2506,6 @@
byte_count, scsicmd->underflow);
}
}
- else if(scsicmd->request_bufflen) {
- int count;
- u64 addr;
- scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
- scsicmd->request_buffer,
- scsicmd->request_bufflen,
- scsicmd->sc_data_direction);
- addr = scsicmd->SCp.dma_handle;
- count = scsicmd->request_bufflen;
- psg->count = cpu_to_le32(1);
- psg->sg[0].next = 0;
- psg->sg[0].prev = 0;
- psg->sg[0].addr[1] = cpu_to_le32((u32)(addr>>32));
- psg->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
- psg->sg[0].count = cpu_to_le32(count);
- psg->sg[0].flags = 0;
- byte_count = scsicmd->request_bufflen;
- }
return byte_count;
}
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index c81edf3..f1d3b66a 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,8 +12,8 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2437
-# define AAC_DRIVER_BRANCH "-mh4"
+# define AAC_DRIVER_BUILD 2447
+# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -464,12 +464,12 @@
int (*adapter_restart)(struct aac_dev *dev, int bled);
/* Transport operations */
int (*adapter_ioremap)(struct aac_dev * dev, u32 size);
- irqreturn_t (*adapter_intr)(int irq, void *dev_id);
+ irq_handler_t adapter_intr;
/* Packet operations */
int (*adapter_deliver)(struct fib * fib);
int (*adapter_bounds)(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba);
int (*adapter_read)(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count);
- int (*adapter_write)(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count);
+ int (*adapter_write)(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua);
int (*adapter_scsi)(struct fib * fib, struct scsi_cmnd * cmd);
/* Administrative operations */
int (*adapter_comm)(struct aac_dev * dev, int comm);
@@ -860,10 +860,12 @@
__le32 FlashFirmwareBootBuild;
u8 MfgPcbaSerialNo[12];
u8 MfgWWNName[8];
- __le32 MoreFeatureBits;
+ __le32 SupportedOptions2;
__le32 ReservedGrowth[1];
};
#define AAC_FEATURE_FALCON 0x00000010
+#define AAC_OPTION_MU_RESET 0x00000001
+#define AAC_OPTION_IGNORE_RESET 0x00000002
#define AAC_SIS_VERSION_V3 3
#define AAC_SIS_SLOT_UNKNOWN 0xFF
@@ -1054,8 +1056,8 @@
#define aac_adapter_read(fib,cmd,lba,count) \
((fib)->dev)->a_ops.adapter_read(fib,cmd,lba,count)
-#define aac_adapter_write(fib,cmd,lba,count) \
- ((fib)->dev)->a_ops.adapter_write(fib,cmd,lba,count)
+#define aac_adapter_write(fib,cmd,lba,count,fua) \
+ ((fib)->dev)->a_ops.adapter_write(fib,cmd,lba,count,fua)
#define aac_adapter_scsi(fib,cmd) \
((fib)->dev)->a_ops.adapter_scsi(fib,cmd)
@@ -1213,6 +1215,9 @@
__le32 block;
__le16 pad;
__le16 flags;
+#define IO_TYPE_WRITE 0x00000000
+#define IO_TYPE_READ 0x00000001
+#define IO_SUREWRITE 0x00000008
struct sgmap64 sg; // Must be last in struct because it is variable
};
struct aac_write_reply
@@ -1257,6 +1262,19 @@
u8 data[16];
};
+#define CT_PAUSE_IO 65
+#define CT_RELEASE_IO 66
+struct aac_pause {
+ __le32 command; /* VM_ContainerConfig */
+ __le32 type; /* CT_PAUSE_IO */
+ __le32 timeout; /* 10ms ticks */
+ __le32 min;
+ __le32 noRescan;
+ __le32 parm3;
+ __le32 parm4;
+ __le32 count; /* sizeof(((struct aac_pause_reply *)NULL)->data) */
+};
+
struct aac_srb
{
__le32 function;
@@ -1804,6 +1822,10 @@
int aac_get_containers(struct aac_dev *dev);
int aac_scsi_cmd(struct scsi_cmnd *cmd);
int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg);
+#ifndef shost_to_class
+#define shost_to_class(shost) &shost->shost_classdev
+#endif
+ssize_t aac_show_serial_number(struct class_device *class_dev, char *buf);
int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg);
int aac_rx_init(struct aac_dev *dev);
int aac_rkt_init(struct aac_dev *dev);
@@ -1813,6 +1835,7 @@
unsigned int aac_response_normal(struct aac_queue * q);
unsigned int aac_command_normal(struct aac_queue * q);
unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
+int aac_reset_adapter(struct aac_dev * dev, int forced);
int aac_check_health(struct aac_dev * dev);
int aac_command_thread(void *data);
int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
@@ -1832,3 +1855,6 @@
extern int expose_physicals;
extern int aac_reset_devices;
extern int aac_commit;
+extern int update_interval;
+extern int check_interval;
+extern int check_reset;
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 9aca57e..d510839 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1021,7 +1021,7 @@
}
-static int _aac_reset_adapter(struct aac_dev *aac)
+static int _aac_reset_adapter(struct aac_dev *aac, int forced)
{
int index, quirks;
int retval;
@@ -1029,25 +1029,32 @@
struct scsi_device *dev;
struct scsi_cmnd *command;
struct scsi_cmnd *command_list;
+ int jafo = 0;
/*
* Assumptions:
- * - host is locked.
+ * - host is locked, unless called by the aacraid thread.
+ * (a matter of convenience, due to legacy issues surrounding
+ * eh_host_adapter_reset).
* - in_reset is asserted, so no new i/o is getting to the
* card.
- * - The card is dead.
+ * - The card is dead, or will be very shortly ;-/ so no new
+ * commands are completing in the interrupt service.
*/
host = aac->scsi_host_ptr;
scsi_block_requests(host);
aac_adapter_disable_int(aac);
- spin_unlock_irq(host->host_lock);
- kthread_stop(aac->thread);
+ if (aac->thread->pid != current->pid) {
+ spin_unlock_irq(host->host_lock);
+ kthread_stop(aac->thread);
+ jafo = 1;
+ }
/*
* If a positive health, means in a known DEAD PANIC
* state and the adapter could be reset to `try again'.
*/
- retval = aac_adapter_restart(aac, aac_adapter_check_health(aac));
+ retval = aac_adapter_restart(aac, forced ? 0 : aac_adapter_check_health(aac));
if (retval)
goto out;
@@ -1104,10 +1111,12 @@
if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT)
if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
goto out;
- aac->thread = kthread_run(aac_command_thread, aac, aac->name);
- if (IS_ERR(aac->thread)) {
- retval = PTR_ERR(aac->thread);
- goto out;
+ if (jafo) {
+ aac->thread = kthread_run(aac_command_thread, aac, aac->name);
+ if (IS_ERR(aac->thread)) {
+ retval = PTR_ERR(aac->thread);
+ goto out;
+ }
}
(void)aac_get_adapter_info(aac);
quirks = aac_get_driver_ident(index)->quirks;
@@ -1150,7 +1159,98 @@
out:
aac->in_reset = 0;
scsi_unblock_requests(host);
- spin_lock_irq(host->host_lock);
+ if (jafo) {
+ spin_lock_irq(host->host_lock);
+ }
+ return retval;
+}
+
+int aac_reset_adapter(struct aac_dev * aac, int forced)
+{
+ unsigned long flagv = 0;
+ int retval;
+ struct Scsi_Host * host;
+
+ if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0)
+ return -EBUSY;
+
+ if (aac->in_reset) {
+ spin_unlock_irqrestore(&aac->fib_lock, flagv);
+ return -EBUSY;
+ }
+ aac->in_reset = 1;
+ spin_unlock_irqrestore(&aac->fib_lock, flagv);
+
+ /*
+ * Wait for all commands to complete to this specific
+ * target (block maximum 60 seconds). Although not necessary,
+ * it does make us a good storage citizen.
+ */
+ host = aac->scsi_host_ptr;
+ scsi_block_requests(host);
+ if (forced < 2) for (retval = 60; retval; --retval) {
+ struct scsi_device * dev;
+ struct scsi_cmnd * command;
+ int active = 0;
+
+ __shost_for_each_device(dev, host) {
+ spin_lock_irqsave(&dev->list_lock, flagv);
+ list_for_each_entry(command, &dev->cmd_list, list) {
+ if (command->SCp.phase == AAC_OWNER_FIRMWARE) {
+ active++;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&dev->list_lock, flagv);
+ if (active)
+ break;
+
+ }
+ /*
+ * We can exit If all the commands are complete
+ */
+ if (active == 0)
+ break;
+ ssleep(1);
+ }
+
+ /* Quiesce build, flush cache, write through mode */
+ aac_send_shutdown(aac);
+ spin_lock_irqsave(host->host_lock, flagv);
+ retval = _aac_reset_adapter(aac, forced);
+ spin_unlock_irqrestore(host->host_lock, flagv);
+
+ if (retval == -ENODEV) {
+ /* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */
+ struct fib * fibctx = aac_fib_alloc(aac);
+ if (fibctx) {
+ struct aac_pause *cmd;
+ int status;
+
+ aac_fib_init(fibctx);
+
+ cmd = (struct aac_pause *) fib_data(fibctx);
+
+ cmd->command = cpu_to_le32(VM_ContainerConfig);
+ cmd->type = cpu_to_le32(CT_PAUSE_IO);
+ cmd->timeout = cpu_to_le32(1);
+ cmd->min = cpu_to_le32(1);
+ cmd->noRescan = cpu_to_le32(1);
+ cmd->count = cpu_to_le32(0);
+
+ status = aac_fib_send(ContainerCommand,
+ fibctx,
+ sizeof(struct aac_pause),
+ FsaNormal,
+ -2 /* Timeout silently */, 1,
+ NULL, NULL);
+
+ if (status >= 0)
+ aac_fib_complete(fibctx);
+ aac_fib_free(fibctx);
+ }
+ }
+
return retval;
}
@@ -1270,10 +1370,15 @@
printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
+ if (!check_reset || (aac->supplement_adapter_info.SupportedOptions2 &
+ le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
+ goto out;
host = aac->scsi_host_ptr;
- spin_lock_irqsave(host->host_lock, flagv);
- BlinkLED = _aac_reset_adapter(aac);
- spin_unlock_irqrestore(host->host_lock, flagv);
+ if (aac->thread->pid != current->pid)
+ spin_lock_irqsave(host->host_lock, flagv);
+ BlinkLED = _aac_reset_adapter(aac, 0);
+ if (aac->thread->pid != current->pid)
+ spin_unlock_irqrestore(host->host_lock, flagv);
return BlinkLED;
out:
@@ -1300,6 +1405,9 @@
struct aac_fib_context *fibctx;
unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
+ unsigned long next_jiffies = jiffies + HZ;
+ unsigned long next_check_jiffies = next_jiffies;
+ long difference = HZ;
/*
* We can only have one thread per adapter for AIF's.
@@ -1368,7 +1476,7 @@
cpu_to_le32(AifCmdJobProgress))) {
aac_handle_aif(dev, fib);
}
-
+
time_now = jiffies/HZ;
/*
@@ -1507,11 +1615,79 @@
* There are no more AIF's
*/
spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
- schedule();
+
+ /*
+ * Background activity
+ */
+ if ((time_before(next_check_jiffies,next_jiffies))
+ && ((difference = next_check_jiffies - jiffies) <= 0)) {
+ next_check_jiffies = next_jiffies;
+ if (aac_check_health(dev) == 0) {
+ difference = ((long)(unsigned)check_interval)
+ * HZ;
+ next_check_jiffies = jiffies + difference;
+ } else if (!dev->queues)
+ break;
+ }
+ if (!time_before(next_check_jiffies,next_jiffies)
+ && ((difference = next_jiffies - jiffies) <= 0)) {
+ struct timeval now;
+ int ret;
+
+ /* Don't even try to talk to adapter if its sick */
+ ret = aac_check_health(dev);
+ if (!ret && !dev->queues)
+ break;
+ next_check_jiffies = jiffies
+ + ((long)(unsigned)check_interval)
+ * HZ;
+ do_gettimeofday(&now);
+
+ /* Synchronize our watches */
+ if (((1000000 - (1000000 / HZ)) > now.tv_usec)
+ && (now.tv_usec > (1000000 / HZ)))
+ difference = (((1000000 - now.tv_usec) * HZ)
+ + 500000) / 1000000;
+ else if (ret == 0) {
+ struct fib *fibptr;
+
+ if ((fibptr = aac_fib_alloc(dev))) {
+ u32 * info;
+
+ aac_fib_init(fibptr);
+
+ info = (u32 *) fib_data(fibptr);
+ if (now.tv_usec > 500000)
+ ++now.tv_sec;
+
+ *info = cpu_to_le32(now.tv_sec);
+
+ (void)aac_fib_send(SendHostTime,
+ fibptr,
+ sizeof(*info),
+ FsaNormal,
+ 1, 1,
+ NULL,
+ NULL);
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ }
+ difference = (long)(unsigned)update_interval*HZ;
+ } else {
+ /* retry shortly */
+ difference = 10 * HZ;
+ }
+ next_jiffies = jiffies + difference;
+ if (time_before(next_check_jiffies,next_jiffies))
+ difference = next_check_jiffies - jiffies;
+ }
+ if (difference <= 0)
+ difference = 1;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(difference);
if (kthread_should_stop())
break;
- set_current_state(TASK_INTERRUPTIBLE);
}
if (dev->queues)
remove_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait);
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 5c487ff..d76e1a8 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -39,10 +39,8 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/dma-mapping.h>
#include <linux/syscalls.h>
#include <linux/delay.h>
-#include <linux/smp_lock.h>
#include <linux/kthread.h>
#include <asm/semaphore.h>
@@ -223,12 +221,12 @@
{ aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/
{ aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/
{ aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/
- { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell PERC2/QC */
+ { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_34SG }, /* Dell PERC2/QC */
{ aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */
{ aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */
{ aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */
- { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec Catch All */
+ { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Catch All */
{ aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */
{ aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec NEMER/ARK Catch All */
};
@@ -403,10 +401,6 @@
static int aac_slave_configure(struct scsi_device *sdev)
{
- if (sdev_channel(sdev) == CONTAINER_CHANNEL) {
- sdev->skip_ms_page_8 = 1;
- sdev->skip_ms_page_3f = 1;
- }
if ((sdev->type == TYPE_DISK) &&
(sdev_channel(sdev) != CONTAINER_CHANNEL)) {
if (expose_physicals == 0)
@@ -450,6 +444,43 @@
return 0;
}
+/**
+ * aac_change_queue_depth - alter queue depths
+ * @sdev: SCSI device we are considering
+ * @depth: desired queue depth
+ *
+ * Alters queue depths for target device based on the host adapter's
+ * total capacity and the queue depth supported by the target device.
+ */
+
+static int aac_change_queue_depth(struct scsi_device *sdev, int depth)
+{
+ if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
+ (sdev_channel(sdev) == CONTAINER_CHANNEL)) {
+ struct scsi_device * dev;
+ struct Scsi_Host *host = sdev->host;
+ unsigned num = 0;
+
+ __shost_for_each_device(dev, host) {
+ if (dev->tagged_supported && (dev->type == TYPE_DISK) &&
+ (sdev_channel(dev) == CONTAINER_CHANNEL))
+ ++num;
+ ++num;
+ }
+ if (num >= host->can_queue)
+ num = host->can_queue - 1;
+ if (depth > (host->can_queue - num))
+ depth = host->can_queue - num;
+ if (depth > 256)
+ depth = 256;
+ else if (depth < 2)
+ depth = 2;
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth);
+ } else
+ scsi_adjust_queue_depth(sdev, 0, 1);
+ return sdev->queue_depth;
+}
+
static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg)
{
struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
@@ -548,6 +579,14 @@
ssleep(1);
}
printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
+ /*
+ * This adapter needs a blind reset, only do so for Adapters that
+ * support a register, instead of a commanded, reset.
+ */
+ if ((aac->supplement_adapter_info.SupportedOptions2 &
+ le32_to_cpu(AAC_OPTION_MU_RESET|AAC_OPTION_IGNORE_RESET)) ==
+ le32_to_cpu(AAC_OPTION_MU_RESET))
+ aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */
return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
}
@@ -731,15 +770,21 @@
return len;
}
-static ssize_t aac_show_serial_number(struct class_device *class_dev,
- char *buf)
+ssize_t aac_show_serial_number(struct class_device *class_dev, char *buf)
{
struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
int len = 0;
if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
- len = snprintf(buf, PAGE_SIZE, "%x\n",
+ len = snprintf(buf, PAGE_SIZE, "%06X\n",
le32_to_cpu(dev->adapter_info.serial[0]));
+ if (len &&
+ !memcmp(&dev->supplement_adapter_info.MfgPcbaSerialNo[
+ sizeof(dev->supplement_adapter_info.MfgPcbaSerialNo)+2-len],
+ buf, len))
+ len = snprintf(buf, PAGE_SIZE, "%.*s\n",
+ (int)sizeof(dev->supplement_adapter_info.MfgPcbaSerialNo),
+ dev->supplement_adapter_info.MfgPcbaSerialNo);
return len;
}
@@ -755,6 +800,31 @@
class_to_shost(class_dev)->max_id);
}
+static ssize_t aac_store_reset_adapter(struct class_device *class_dev,
+ const char *buf, size_t count)
+{
+ int retval = -EACCES;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return retval;
+ retval = aac_reset_adapter((struct aac_dev*)class_to_shost(class_dev)->hostdata, buf[0] == '!');
+ if (retval >= 0)
+ retval = count;
+ return retval;
+}
+
+static ssize_t aac_show_reset_adapter(struct class_device *class_dev,
+ char *buf)
+{
+ struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
+ int len, tmp;
+
+ tmp = aac_adapter_check_health(dev);
+ if ((tmp == 0) && dev->in_reset)
+ tmp = -EBUSY;
+ len = snprintf(buf, PAGE_SIZE, "0x%x", tmp);
+ return len;
+}
static struct class_device_attribute aac_model = {
.attr = {
@@ -812,6 +882,14 @@
},
.show = aac_show_max_id,
};
+static struct class_device_attribute aac_reset = {
+ .attr = {
+ .name = "reset_host",
+ .mode = S_IWUSR|S_IRUGO,
+ },
+ .store = aac_store_reset_adapter,
+ .show = aac_show_reset_adapter,
+};
static struct class_device_attribute *aac_attrs[] = {
&aac_model,
@@ -822,6 +900,7 @@
&aac_serial_number,
&aac_max_channel,
&aac_max_id,
+ &aac_reset,
NULL
};
@@ -848,6 +927,7 @@
.bios_param = aac_biosparm,
.shost_attrs = aac_attrs,
.slave_configure = aac_slave_configure,
+ .change_queue_depth = aac_change_queue_depth,
.eh_abort_handler = aac_eh_abort,
.eh_host_reset_handler = aac_eh_reset,
.can_queue = AAC_NUM_IO_FIB,
@@ -1086,7 +1166,7 @@
{
int error;
- printk(KERN_INFO "Adaptec %s driver (%s)\n",
+ printk(KERN_INFO "Adaptec %s driver %s\n",
AAC_DRIVERNAME, aac_driver_version);
error = pci_register_driver(&aac_pci_driver);
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index ae978a3..ebc65b9 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -464,21 +464,24 @@
{
u32 var;
- if (bled)
- printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
- dev->name, dev->id, bled);
- else {
- bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
- 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
- if (!bled && (var != 0x00000001))
- bled = -EINVAL;
- }
- if (bled && (bled != -ETIMEDOUT))
- bled = aac_adapter_sync_cmd(dev, IOP_RESET,
- 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
+ if (!(dev->supplement_adapter_info.SupportedOptions2 &
+ le32_to_cpu(AAC_OPTION_MU_RESET)) || (bled >= 0) || (bled == -2)) {
+ if (bled)
+ printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
+ dev->name, dev->id, bled);
+ else {
+ bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
+ 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
+ if (!bled && (var != 0x00000001))
+ bled = -EINVAL;
+ }
+ if (bled && (bled != -ETIMEDOUT))
+ bled = aac_adapter_sync_cmd(dev, IOP_RESET,
+ 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
- if (bled && (bled != -ETIMEDOUT))
- return -EINVAL;
+ if (bled && (bled != -ETIMEDOUT))
+ return -EINVAL;
+ }
if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */
rx_writel(dev, MUnit.reserved2, 3);
msleep(5000); /* Delay 5 seconds */
@@ -596,7 +599,7 @@
}
msleep(1);
}
- if (restart)
+ if (restart && aac_commit)
aac_commit = 1;
/*
* Fill in the common function dispatch table.
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 9b3303b..2b66897 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -798,7 +798,6 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
-#include "advansys.h"
#ifdef CONFIG_PCI
#include <linux/pci.h>
#endif /* CONFIG_PCI */
@@ -2014,7 +2013,7 @@
STATIC void AscEnableIsaDma(uchar);
#endif /* CONFIG_ISA */
STATIC ASC_DCNT AscGetMaxDmaCount(ushort);
-
+static const char *advansys_info(struct Scsi_Host *shp);
/*
* --- Adv Library Constants and Macros
@@ -3970,10 +3969,6 @@
ASC_IS_PCI,
};
-/*
- * Used with the LILO 'advansys' option to eliminate or
- * limit I/O port probing at boot time, cf. advansys_setup().
- */
STATIC int asc_iopflag = ASC_FALSE;
STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
@@ -4055,10 +4050,6 @@
#endif /* ADVANSYS_DEBUG */
-/*
- * --- Linux 'struct scsi_host_template' and advansys_setup() Functions
- */
-
#ifdef CONFIG_PROC_FS
/*
* advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
@@ -4080,7 +4071,7 @@
* if 'prtbuf' is too small it will not be overwritten. Instead the
* user just won't get all the available statistics.
*/
-int
+static int
advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
off_t offset, int length, int inout)
{
@@ -4296,7 +4287,7 @@
* it must not call SCSI mid-level functions including scsi_malloc()
* and scsi_free().
*/
-int __init
+static int __init
advansys_detect(struct scsi_host_template *tpnt)
{
static int detect_called = ASC_FALSE;
@@ -5428,7 +5419,7 @@
*
* Release resources allocated for a single AdvanSys adapter.
*/
-int
+static int
advansys_release(struct Scsi_Host *shp)
{
asc_board_t *boardp;
@@ -5475,7 +5466,7 @@
* Note: The information line should not exceed ASC_INFO_SIZE bytes,
* otherwise the static 'info' array will be overrun.
*/
-const char *
+static const char *
advansys_info(struct Scsi_Host *shp)
{
static char info[ASC_INFO_SIZE];
@@ -5568,7 +5559,7 @@
* This function always returns 0. Command return status is saved
* in the 'scp' result field.
*/
-int
+static int
advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
{
struct Scsi_Host *shp;
@@ -5656,7 +5647,7 @@
* sleeping is allowed and no locking other than for host structures is
* required. Returns SUCCESS or FAILED.
*/
-int
+static int
advansys_reset(struct scsi_cmnd *scp)
{
struct Scsi_Host *shp;
@@ -5841,7 +5832,7 @@
* ip[1]: sectors
* ip[2]: cylinders
*/
-int
+static int
advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int ip[])
{
@@ -5875,82 +5866,6 @@
}
/*
- * advansys_setup()
- *
- * This function is called from init/main.c at boot time.
- * It it passed LILO parameters that can be set from the
- * LILO command line or in /etc/lilo.conf.
- *
- * It is used by the AdvanSys driver to either disable I/O
- * port scanning or to limit scanning to 1 - 4 I/O ports.
- * Regardless of the option setting EISA and PCI boards
- * will still be searched for and detected. This option
- * only affects searching for ISA and VL boards.
- *
- * If ADVANSYS_DEBUG is defined the driver debug level may
- * be set using the 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port.
- *
- * Examples:
- * 1. Eliminate I/O port scanning:
- * boot: linux advansys=
- * or
- * boot: linux advansys=0x0
- * 2. Limit I/O port scanning to one I/O port:
- * boot: linux advansys=0x110
- * 3. Limit I/O port scanning to four I/O ports:
- * boot: linux advansys=0x110,0x210,0x230,0x330
- * 4. If ADVANSYS_DEBUG, limit I/O port scanning to four I/O ports and
- * set the driver debug level to 2.
- * boot: linux advansys=0x110,0x210,0x230,0x330,0xdeb2
- *
- * ints[0] - number of arguments
- * ints[1] - first argument
- * ints[2] - second argument
- * ...
- */
-void __init
-advansys_setup(char *str, int *ints)
-{
- int i;
-
- if (asc_iopflag == ASC_TRUE) {
- printk("AdvanSys SCSI: 'advansys' LILO option may appear only once\n");
- return;
- }
-
- asc_iopflag = ASC_TRUE;
-
- if (ints[0] > ASC_NUM_IOPORT_PROBE) {
-#ifdef ADVANSYS_DEBUG
- if ((ints[0] == ASC_NUM_IOPORT_PROBE + 1) &&
- (ints[ASC_NUM_IOPORT_PROBE + 1] >> 4 == 0xdeb)) {
- asc_dbglvl = ints[ASC_NUM_IOPORT_PROBE + 1] & 0xf;
- } else {
-#endif /* ADVANSYS_DEBUG */
- printk("AdvanSys SCSI: only %d I/O ports accepted\n",
- ASC_NUM_IOPORT_PROBE);
-#ifdef ADVANSYS_DEBUG
- }
-#endif /* ADVANSYS_DEBUG */
- }
-
-#ifdef ADVANSYS_DEBUG
- ASC_DBG1(1, "advansys_setup: ints[0] %d\n", ints[0]);
- for (i = 1; i < ints[0]; i++) {
- ASC_DBG2(1, " ints[%d] 0x%x", i, ints[i]);
- }
- ASC_DBG(1, "\n");
-#endif /* ADVANSYS_DEBUG */
-
- for (i = 1; i <= ints[0] && i <= ASC_NUM_IOPORT_PROBE; i++) {
- asc_ioport[i-1] = ints[i];
- ASC_DBG2(1, "advansys_setup: asc_ioport[%d] 0x%x\n",
- i - 1, asc_ioport[i-1]);
- }
-}
-
-
-/*
* --- Loadable Driver Support
*/
diff --git a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h
deleted file mode 100644
index 8ee7fb1..0000000
--- a/drivers/scsi/advansys.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
- *
- * Copyright (c) 1995-2000 Advanced System Products, Inc.
- * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that redistributions of source
- * code retain the above copyright notice and this comment without
- * modification.
- *
- * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
- * changed its name to ConnectCom Solutions, Inc.
- *
- */
-
-#ifndef _ADVANSYS_H
-#define _ADVANSYS_H
-
-/*
- * struct scsi_host_template function prototypes.
- */
-int advansys_detect(struct scsi_host_template *);
-int advansys_release(struct Scsi_Host *);
-const char *advansys_info(struct Scsi_Host *);
-int advansys_queuecommand(struct scsi_cmnd *, void (* done)(struct scsi_cmnd *));
-int advansys_reset(struct scsi_cmnd *);
-int advansys_biosparam(struct scsi_device *, struct block_device *,
- sector_t, int[]);
-static int advansys_slave_configure(struct scsi_device *);
-
-/* init/main.c setup function */
-void advansys_setup(char *, int *);
-
-#endif /* _ADVANSYS_H */
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 4b4d123..85f2394 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -240,6 +240,7 @@
#include <linux/io.h>
#include <linux/blkdev.h>
#include <asm/system.h>
+#include <linux/completion.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/wait.h>
@@ -253,7 +254,6 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/list.h>
-#include <asm/semaphore.h>
#include <scsi/scsicam.h>
#include "scsi.h"
@@ -551,7 +551,7 @@
*/
struct aha152x_scdata {
Scsi_Cmnd *next; /* next sc in queue */
- struct semaphore *sem; /* semaphore to block on */
+ struct completion *done;/* semaphore to block on */
unsigned char cmd_len;
unsigned char cmnd[MAX_COMMAND_SIZE];
unsigned short use_sg;
@@ -608,7 +608,7 @@
#define SCDATA(SCpnt) ((struct aha152x_scdata *) (SCpnt)->host_scribble)
#define SCNEXT(SCpnt) SCDATA(SCpnt)->next
-#define SCSEM(SCpnt) SCDATA(SCpnt)->sem
+#define SCSEM(SCpnt) SCDATA(SCpnt)->done
#define SG_ADDRESS(buffer) ((char *) (page_address((buffer)->page)+(buffer)->offset))
@@ -969,7 +969,8 @@
/*
* Queue a command and setup interrupts for a free bus.
*/
-static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, void (*done)(Scsi_Cmnd *))
+static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
+ int phase, void (*done)(Scsi_Cmnd *))
{
struct Scsi_Host *shpnt = SCpnt->device->host;
unsigned long flags;
@@ -1013,7 +1014,7 @@
}
SCNEXT(SCpnt) = NULL;
- SCSEM(SCpnt) = sem;
+ SCSEM(SCpnt) = complete;
/* setup scratch area
SCp.ptr : buffer pointer
@@ -1084,9 +1085,9 @@
DPRINTK(debug_eh, INFO_LEAD "reset_done called\n", CMDINFO(SCpnt));
#endif
if(SCSEM(SCpnt)) {
- up(SCSEM(SCpnt));
+ complete(SCSEM(SCpnt));
} else {
- printk(KERN_ERR "aha152x: reset_done w/o semaphore\n");
+ printk(KERN_ERR "aha152x: reset_done w/o completion\n");
}
}
@@ -1139,21 +1140,6 @@
return FAILED;
}
-static void timer_expired(unsigned long p)
-{
- Scsi_Cmnd *SCp = (Scsi_Cmnd *)p;
- struct semaphore *sem = SCSEM(SCp);
- struct Scsi_Host *shpnt = SCp->device->host;
- unsigned long flags;
-
- /* remove command from issue queue */
- DO_LOCK(flags);
- remove_SC(&ISSUE_SC, SCp);
- DO_UNLOCK(flags);
-
- up(sem);
-}
-
/*
* Reset a device
*
@@ -1161,14 +1147,14 @@
static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
{
struct Scsi_Host *shpnt = SCpnt->device->host;
- DECLARE_MUTEX_LOCKED(sem);
- struct timer_list timer;
+ DECLARE_COMPLETION(done);
int ret, issued, disconnected;
unsigned char old_cmd_len = SCpnt->cmd_len;
unsigned short old_use_sg = SCpnt->use_sg;
void *old_buffer = SCpnt->request_buffer;
unsigned old_bufflen = SCpnt->request_bufflen;
unsigned long flags;
+ unsigned long timeleft;
#if defined(AHA152X_DEBUG)
if(HOSTDATA(shpnt)->debug & debug_eh) {
@@ -1192,15 +1178,15 @@
SCpnt->request_buffer = NULL;
SCpnt->request_bufflen = 0;
- init_timer(&timer);
- timer.data = (unsigned long) SCpnt;
- timer.expires = jiffies + 100*HZ; /* 10s */
- timer.function = (void (*)(unsigned long)) timer_expired;
+ aha152x_internal_queue(SCpnt, &done, resetting, reset_done);
- aha152x_internal_queue(SCpnt, &sem, resetting, reset_done);
- add_timer(&timer);
- down(&sem);
- del_timer(&timer);
+ timeleft = wait_for_completion_timeout(&done, 100*HZ);
+ if (!timeleft) {
+ /* remove command from issue queue */
+ DO_LOCK(flags);
+ remove_SC(&ISSUE_SC, SCpnt);
+ DO_UNLOCK(flags);
+ }
SCpnt->cmd_len = old_cmd_len;
SCpnt->use_sg = old_use_sg;
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index d7af9c6..e4a4f3a 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -271,20 +271,8 @@
continue;
}
sgptr = (struct aha1740_sg *) SCtmp->host_scribble;
- if (SCtmp->use_sg) {
- /* We used scatter-gather.
- Do the unmapping dance. */
- dma_unmap_sg (&edev->dev,
- (struct scatterlist *) SCtmp->request_buffer,
- SCtmp->use_sg,
- SCtmp->sc_data_direction);
- } else {
- dma_unmap_single (&edev->dev,
- sgptr->buf_dma_addr,
- SCtmp->request_bufflen,
- DMA_BIDIRECTIONAL);
- }
-
+ scsi_dma_unmap(SCtmp);
+
/* Free the sg block */
dma_free_coherent (&edev->dev,
sizeof (struct aha1740_sg),
@@ -349,11 +337,9 @@
unchar target = scmd_id(SCpnt);
struct aha1740_hostdata *host = HOSTDATA(SCpnt->device->host);
unsigned long flags;
- void *buff = SCpnt->request_buffer;
- int bufflen = SCpnt->request_bufflen;
dma_addr_t sg_dma;
struct aha1740_sg *sgptr;
- int ecbno;
+ int ecbno, nseg;
DEB(int i);
if(*cmd == REQUEST_SENSE) {
@@ -423,24 +409,23 @@
}
sgptr = (struct aha1740_sg *) SCpnt->host_scribble;
sgptr->sg_dma_addr = sg_dma;
-
- if (SCpnt->use_sg) {
- struct scatterlist * sgpnt;
+
+ nseg = scsi_dma_map(SCpnt);
+ BUG_ON(nseg < 0);
+ if (nseg) {
+ struct scatterlist *sg;
struct aha1740_chain * cptr;
- int i, count;
+ int i;
DEB(unsigned char * ptr);
host->ecb[ecbno].sg = 1; /* SCSI Initiator Command
* w/scatter-gather*/
- sgpnt = (struct scatterlist *) SCpnt->request_buffer;
cptr = sgptr->sg_chain;
- count = dma_map_sg (&host->edev->dev, sgpnt, SCpnt->use_sg,
- SCpnt->sc_data_direction);
- for(i=0; i < count; i++) {
- cptr[i].datalen = sg_dma_len (sgpnt + i);
- cptr[i].dataptr = sg_dma_address (sgpnt + i);
+ scsi_for_each_sg(SCpnt, sg, nseg, i) {
+ cptr[i].datalen = sg_dma_len (sg);
+ cptr[i].dataptr = sg_dma_address (sg);
}
- host->ecb[ecbno].datalen = count*sizeof(struct aha1740_chain);
+ host->ecb[ecbno].datalen = nseg * sizeof(struct aha1740_chain);
host->ecb[ecbno].dataptr = sg_dma;
#ifdef DEBUG
printk("cptr %x: ",cptr);
@@ -448,11 +433,8 @@
for(i=0;i<24;i++) printk("%02x ", ptr[i]);
#endif
} else {
- host->ecb[ecbno].datalen = bufflen;
- sgptr->buf_dma_addr = dma_map_single (&host->edev->dev,
- buff, bufflen,
- DMA_BIDIRECTIONAL);
- host->ecb[ecbno].dataptr = sgptr->buf_dma_addr;
+ host->ecb[ecbno].datalen = 0;
+ host->ecb[ecbno].dataptr = 0;
}
host->ecb[ecbno].lun = SCpnt->device->lun;
host->ecb[ecbno].ses = 1; /* Suppress underrun errors */
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 6054881..286ab83 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -376,21 +376,10 @@
ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb)
{
struct scsi_cmnd *cmd;
- int direction;
cmd = scb->io_ctx;
- direction = cmd->sc_data_direction;
ahd_sync_sglist(ahd, scb, BUS_DMASYNC_POSTWRITE);
- if (cmd->use_sg != 0) {
- struct scatterlist *sg;
-
- sg = (struct scatterlist *)cmd->request_buffer;
- pci_unmap_sg(ahd->dev_softc, sg, cmd->use_sg, direction);
- } else if (cmd->request_bufflen != 0) {
- pci_unmap_single(ahd->dev_softc,
- scb->platform_data->buf_busaddr,
- cmd->request_bufflen, direction);
- }
+ scsi_dma_unmap(cmd);
}
/******************************** Macros **************************************/
@@ -1422,6 +1411,7 @@
u_int col_idx;
uint16_t mask;
unsigned long flags;
+ int nseg;
ahd_lock(ahd, &flags);
@@ -1494,18 +1484,17 @@
ahd_set_residual(scb, 0);
ahd_set_sense_residual(scb, 0);
scb->sg_count = 0;
- if (cmd->use_sg != 0) {
- void *sg;
- struct scatterlist *cur_seg;
- u_int nseg;
- int dir;
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- dir = cmd->sc_data_direction;
- nseg = pci_map_sg(ahd->dev_softc, cur_seg,
- cmd->use_sg, dir);
+ nseg = scsi_dma_map(cmd);
+ BUG_ON(nseg < 0);
+ if (nseg > 0) {
+ void *sg = scb->sg_list;
+ struct scatterlist *cur_seg;
+ int i;
+
scb->platform_data->xfer_len = 0;
- for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) {
+
+ scsi_for_each_sg(cmd, cur_seg, nseg, i) {
dma_addr_t addr;
bus_size_t len;
@@ -1513,22 +1502,8 @@
len = sg_dma_len(cur_seg);
scb->platform_data->xfer_len += len;
sg = ahd_sg_setup(ahd, scb, sg, addr, len,
- /*last*/nseg == 1);
+ i == (nseg - 1));
}
- } else if (cmd->request_bufflen != 0) {
- void *sg;
- dma_addr_t addr;
- int dir;
-
- sg = scb->sg_list;
- dir = cmd->sc_data_direction;
- addr = pci_map_single(ahd->dev_softc,
- cmd->request_buffer,
- cmd->request_bufflen, dir);
- scb->platform_data->xfer_len = cmd->request_bufflen;
- scb->platform_data->buf_busaddr = addr;
- sg = ahd_sg_setup(ahd, scb, sg, addr,
- cmd->request_bufflen, /*last*/TRUE);
}
LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index ad9761b..853998b 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -781,7 +781,7 @@
static __inline
void ahd_set_residual(struct scb *scb, u_long resid)
{
- scb->io_ctx->resid = resid;
+ scsi_set_resid(scb->io_ctx, resid);
}
static __inline
@@ -793,7 +793,7 @@
static __inline
u_long ahd_get_residual(struct scb *scb)
{
- return (scb->io_ctx->resid);
+ return scsi_get_resid(scb->io_ctx);
}
static __inline
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 660f26e..1803ab6 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -402,18 +402,8 @@
cmd = scb->io_ctx;
ahc_sync_sglist(ahc, scb, BUS_DMASYNC_POSTWRITE);
- if (cmd->use_sg != 0) {
- struct scatterlist *sg;
- sg = (struct scatterlist *)cmd->request_buffer;
- pci_unmap_sg(ahc->dev_softc, sg, cmd->use_sg,
- cmd->sc_data_direction);
- } else if (cmd->request_bufflen != 0) {
- pci_unmap_single(ahc->dev_softc,
- scb->platform_data->buf_busaddr,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
}
static __inline int
@@ -1381,6 +1371,7 @@
struct ahc_tmode_tstate *tstate;
uint16_t mask;
struct scb_tailq *untagged_q = NULL;
+ int nseg;
/*
* Schedule us to run later. The only reason we are not
@@ -1472,23 +1463,21 @@
ahc_set_residual(scb, 0);
ahc_set_sense_residual(scb, 0);
scb->sg_count = 0;
- if (cmd->use_sg != 0) {
+
+ nseg = scsi_dma_map(cmd);
+ BUG_ON(nseg < 0);
+ if (nseg > 0) {
struct ahc_dma_seg *sg;
struct scatterlist *cur_seg;
- struct scatterlist *end_seg;
- int nseg;
+ int i;
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg,
- cmd->sc_data_direction);
- end_seg = cur_seg + nseg;
/* Copy the segments into the SG list. */
sg = scb->sg_list;
/*
* The sg_count may be larger than nseg if
* a transfer crosses a 32bit page.
- */
- while (cur_seg < end_seg) {
+ */
+ scsi_for_each_sg(cmd, cur_seg, nseg, i) {
dma_addr_t addr;
bus_size_t len;
int consumed;
@@ -1499,7 +1488,6 @@
sg, addr, len);
sg += consumed;
scb->sg_count += consumed;
- cur_seg++;
}
sg--;
sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
@@ -1516,33 +1504,6 @@
*/
scb->hscb->dataptr = scb->sg_list->addr;
scb->hscb->datacnt = scb->sg_list->len;
- } else if (cmd->request_bufflen != 0) {
- struct ahc_dma_seg *sg;
- dma_addr_t addr;
-
- sg = scb->sg_list;
- addr = pci_map_single(ahc->dev_softc,
- cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- scb->platform_data->buf_busaddr = addr;
- scb->sg_count = ahc_linux_map_seg(ahc, scb,
- sg, addr,
- cmd->request_bufflen);
- sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
-
- /*
- * Reset the sg list pointer.
- */
- scb->hscb->sgptr =
- ahc_htole32(scb->sg_list_phys | SG_FULL_RESID);
-
- /*
- * Copy the first SG into the "current"
- * data pointer area.
- */
- scb->hscb->dataptr = sg->addr;
- scb->hscb->datacnt = sg->len;
} else {
scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL);
scb->hscb->dataptr = 0;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index 8fee7ed..b48dab4 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -751,7 +751,7 @@
static __inline
void ahc_set_residual(struct scb *scb, u_long resid)
{
- scb->io_ctx->resid = resid;
+ scsi_set_resid(scb->io_ctx, resid);
}
static __inline
@@ -763,7 +763,7 @@
static __inline
u_long ahc_get_residual(struct scb *scb)
{
- return (scb->io_ctx->resid);
+ return scsi_get_resid(scb->io_ctx);
}
static __inline
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index a988d5a..4998bb8 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -2690,17 +2690,8 @@
struct aic7xxx_scb *scbp;
unsigned char queue_depth;
- if (cmd->use_sg > 1)
- {
- struct scatterlist *sg;
+ scsi_dma_unmap(cmd);
- sg = (struct scatterlist *)cmd->request_buffer;
- pci_unmap_sg(p->pdev, sg, cmd->use_sg, cmd->sc_data_direction);
- }
- else if (cmd->request_bufflen)
- pci_unmap_single(p->pdev, aic7xxx_mapping(cmd),
- cmd->request_bufflen,
- cmd->sc_data_direction);
if (scb->flags & SCB_SENSE)
{
pci_unmap_single(p->pdev,
@@ -3869,7 +3860,7 @@
* the mid layer didn't check residual data counts to see if the
* command needs retried.
*/
- cmd->resid = scb->sg_length - actual;
+ scsi_set_resid(cmd, scb->sg_length - actual);
aic7xxx_status(cmd) = hscb->target_status;
}
}
@@ -6581,7 +6572,7 @@
struct aic7xxx_host *p = (struct aic7xxx_host *)SDptr->host->hostdata;
struct aic_dev_data *aic_dev;
- aic_dev = kmalloc(sizeof(struct aic_dev_data), GFP_ATOMIC | GFP_KERNEL);
+ aic_dev = kmalloc(sizeof(struct aic_dev_data), GFP_KERNEL);
if(!aic_dev)
return 1;
/*
@@ -10137,6 +10128,7 @@
struct scsi_device *sdptr = cmd->device;
unsigned char tindex = TARGET_INDEX(cmd);
struct request *req = cmd->request;
+ int use_sg;
mask = (0x01 << tindex);
hscb = scb->hscb;
@@ -10209,8 +10201,10 @@
memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len);
hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd));
- if (cmd->use_sg)
- {
+ use_sg = scsi_dma_map(cmd);
+ BUG_ON(use_sg < 0);
+
+ if (use_sg) {
struct scatterlist *sg; /* Must be mid-level SCSI code scatterlist */
/*
@@ -10219,11 +10213,11 @@
* differences and the kernel SG list uses virtual addresses where
* we need physical addresses.
*/
- int i, use_sg;
+ int i;
- sg = (struct scatterlist *)cmd->request_buffer;
scb->sg_length = 0;
- use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, cmd->sc_data_direction);
+
+
/*
* Copy the segments into the SG array. NOTE!!! - We used to
* have the first entry both in the data_pointer area and the first
@@ -10231,10 +10225,9 @@
* entry in both places, but now we download the address of
* scb->sg_list[1] instead of 0 to the sg pointer in the hscb.
*/
- for (i = 0; i < use_sg; i++)
- {
- unsigned int len = sg_dma_len(sg+i);
- scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg+i));
+ scsi_for_each_sg(cmd, sg, use_sg, i) {
+ unsigned int len = sg_dma_len(sg);
+ scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg));
scb->sg_list[i].length = cpu_to_le32(len);
scb->sg_length += len;
}
@@ -10244,33 +10237,13 @@
scb->sg_count = i;
hscb->SG_segment_count = i;
hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1]));
- }
- else
- {
- if (cmd->request_bufflen)
- {
- unsigned int address = pci_map_single(p->pdev, cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- aic7xxx_mapping(cmd) = address;
- scb->sg_list[0].address = cpu_to_le32(address);
- scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
- scb->sg_count = 1;
- scb->sg_length = cmd->request_bufflen;
- hscb->SG_segment_count = 1;
- hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[0]));
- hscb->data_count = scb->sg_list[0].length;
- hscb->data_pointer = scb->sg_list[0].address;
- }
- else
- {
+ } else {
scb->sg_count = 0;
scb->sg_length = 0;
hscb->SG_segment_count = 0;
hscb->SG_list_pointer = 0;
hscb->data_count = 0;
hscb->data_pointer = 0;
- }
}
}
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
deleted file mode 100644
index d5d3c4d..0000000
--- a/drivers/scsi/amiga7xx.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
- * Amiga MacroSystemUS WarpEngine SCSI controller.
- * Amiga Technologies A4000T SCSI controller.
- * Amiga Technologies/DKB A4091 SCSI controller.
- *
- * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
- * plus modifications of the 53c7xx.c driver to support the Amiga.
- */
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/blkdev.h>
-#include <linux/zorro.h>
-#include <linux/stat.h>
-
-#include <asm/setup.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-#include <asm/dma.h>
-#include <asm/irq.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "53c7xx.h"
-#include "amiga7xx.h"
-
-
-static int amiga7xx_register_one(struct scsi_host_template *tpnt,
- unsigned long address)
-{
- long long options;
- int clock;
-
- if (!request_mem_region(address, 0x1000, "ncr53c710"))
- return 0;
-
- address = (unsigned long)z_ioremap(address, 0x1000);
- options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 | OPTION_INTFLY |
- OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS |
- OPTION_DISCONNECT;
- clock = 50000000; /* 50 MHz SCSI Clock */
- ncr53c7xx_init(tpnt, 0, 710, address, 0, IRQ_AMIGA_PORTS, DMA_NONE,
- options, clock);
- return 1;
-}
-
-
-#ifdef CONFIG_ZORRO
-
-static struct {
- zorro_id id;
- unsigned long offset;
- int absolute; /* offset is absolute address */
-} amiga7xx_table[] = {
- { .id = ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS, .offset = 0xf40000,
- .absolute = 1 },
- { .id = ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx, .offset = 0x40000 },
- { .id = ZORRO_PROD_CBM_A4091_1, .offset = 0x800000 },
- { .id = ZORRO_PROD_CBM_A4091_2, .offset = 0x800000 },
- { .id = ZORRO_PROD_GVP_GFORCE_040_060, .offset = 0x40000 },
- { 0 }
-};
-
-static int __init amiga7xx_zorro_detect(struct scsi_host_template *tpnt)
-{
- int num = 0, i;
- struct zorro_dev *z = NULL;
- unsigned long address;
-
- while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
- for (i = 0; amiga7xx_table[i].id; i++)
- if (z->id == amiga7xx_table[i].id)
- break;
- if (!amiga7xx_table[i].id)
- continue;
- if (amiga7xx_table[i].absolute)
- address = amiga7xx_table[i].offset;
- else
- address = z->resource.start + amiga7xx_table[i].offset;
- num += amiga7xx_register_one(tpnt, address);
- }
- return num;
-}
-
-#endif /* CONFIG_ZORRO */
-
-
-int __init amiga7xx_detect(struct scsi_host_template *tpnt)
-{
- static unsigned char called = 0;
- int num = 0;
-
- if (called || !MACH_IS_AMIGA)
- return 0;
-
- tpnt->proc_name = "Amiga7xx";
-
- if (AMIGAHW_PRESENT(A4000_SCSI))
- num += amiga7xx_register_one(tpnt, 0xdd0040);
-
-#ifdef CONFIG_ZORRO
- num += amiga7xx_zorro_detect(tpnt);
-#endif
-
- called = 1;
- return num;
-}
-
-static int amiga7xx_release(struct Scsi_Host *shost)
-{
- if (shost->irq)
- free_irq(shost->irq, NULL);
- if (shost->dma_channel != 0xff)
- free_dma(shost->dma_channel);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
- scsi_unregister(shost);
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .name = "Amiga NCR53c710 SCSI",
- .detect = amiga7xx_detect,
- .release = amiga7xx_release,
- .queuecommand = NCR53c7xx_queue_command,
- .abort = NCR53c7xx_abort,
- .reset = NCR53c7xx_reset,
- .can_queue = 24,
- .this_id = 7,
- .sg_tablesize = 63,
- .cmd_per_lun = 3,
- .use_clustering = DISABLE_CLUSTERING
-};
-
-
-#include "scsi_module.c"
diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h
deleted file mode 100644
index 7cd63a9..0000000
--- a/drivers/scsi/amiga7xx.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef AMIGA7XX_H
-
-#include <linux/types.h>
-
-int amiga7xx_detect(struct scsi_host_template *);
-const char *NCR53c7x0_info(void);
-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int NCR53c7xx_abort(Scsi_Cmnd *);
-int NCR53c7x0_release (struct Scsi_Host *);
-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
-void NCR53c7x0_intr(int irq, void *dev_id);
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 3
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 24
-#endif
-
-#include <scsi/scsicam.h>
-
-#endif /* AMIGA7XX_H */
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index aff96db..f0b8bf4 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -48,9 +48,10 @@
#define ARCMSR_MAX_OUTSTANDING_CMD 256
#define ARCMSR_MAX_FREECCB_NUM 288
-#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.13"
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.14"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
+#define ARCMSR_MAX_XFER_SECTORS_B 4096
#define ARCMSR_MAX_TARGETID 17
#define ARCMSR_MAX_TARGETLUN 8
#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD
@@ -469,4 +470,3 @@
extern struct class_device_attribute *arcmsr_host_attrs[];
extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb);
void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb);
-
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 8b46158..0ddfc21 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -57,6 +57,7 @@
#include <linux/dma-mapping.h>
#include <linux/timer.h>
#include <linux/pci.h>
+#include <linux/aer.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -71,7 +72,7 @@
#include "arcmsr.h"
MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>");
-MODULE_DESCRIPTION("ARECA (ARC11xx/12xx) SATA RAID HOST Adapter");
+MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(ARCMSR_DRIVER_VERSION);
@@ -93,7 +94,9 @@
static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
-
+static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state);
+static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);
static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
{
if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
@@ -104,7 +107,8 @@
static struct scsi_host_template arcmsr_scsi_host_template = {
.module = THIS_MODULE,
- .name = "ARCMSR ARECA SATA RAID HOST Adapter" ARCMSR_DRIVER_VERSION,
+ .name = "ARCMSR ARECA SATA/SAS RAID HOST Adapter"
+ ARCMSR_DRIVER_VERSION,
.info = arcmsr_info,
.queuecommand = arcmsr_queue_command,
.eh_abort_handler = arcmsr_abort,
@@ -119,6 +123,10 @@
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = arcmsr_host_attrs,
};
+static struct pci_error_handlers arcmsr_pci_error_handlers = {
+ .error_detected = arcmsr_pci_error_detected,
+ .slot_reset = arcmsr_pci_slot_reset,
+};
static struct pci_device_id arcmsr_device_id_table[] = {
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
@@ -144,7 +152,8 @@
.id_table = arcmsr_device_id_table,
.probe = arcmsr_probe,
.remove = arcmsr_remove,
- .shutdown = arcmsr_shutdown
+ .shutdown = arcmsr_shutdown,
+ .err_handler = &arcmsr_pci_error_handlers,
};
static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
@@ -328,6 +337,8 @@
arcmsr_iop_init(acb);
pci_set_drvdata(pdev, host);
+ if (strncmp(acb->firm_version, "V1.42", 5) >= 0)
+ host->max_sectors= ARCMSR_MAX_XFER_SECTORS_B;
error = scsi_add_host(host, &pdev->dev);
if (error)
@@ -338,6 +349,7 @@
goto out_free_sysfs;
scsi_scan_host(host);
+ pci_enable_pcie_error_reporting(pdev);
return 0;
out_free_sysfs:
out_free_irq:
@@ -369,19 +381,9 @@
static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
{
- struct AdapterControlBlock *acb = ccb->acb;
struct scsi_cmnd *pcmd = ccb->pcmd;
- if (pcmd->use_sg != 0) {
- struct scatterlist *sl;
-
- sl = (struct scatterlist *)pcmd->request_buffer;
- pci_unmap_sg(acb->pdev, sl, pcmd->use_sg, pcmd->sc_data_direction);
- }
- else if (pcmd->request_bufflen != 0)
- pci_unmap_single(acb->pdev,
- pcmd->SCp.dma_handle,
- pcmd->request_bufflen, pcmd->sc_data_direction);
+ scsi_dma_unmap(pcmd);
}
static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag)
@@ -498,7 +500,7 @@
static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg=acb->pmu;
+ struct MessageUnit __iomem *reg = acb->pmu;
writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0);
if (arcmsr_wait_msgint_ready(acb))
@@ -551,6 +553,7 @@
int8_t *psge = (int8_t *)&arcmsr_cdb->u;
uint32_t address_lo, address_hi;
int arccdbsize = 0x30;
+ int nseg;
ccb->pcmd = pcmd;
memset(arcmsr_cdb, 0, sizeof (struct ARCMSR_CDB));
@@ -561,20 +564,20 @@
arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
arcmsr_cdb->Context = (unsigned long)arcmsr_cdb;
memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
- if (pcmd->use_sg) {
- int length, sgcount, i, cdb_sgcount = 0;
- struct scatterlist *sl;
- /* Get Scatter Gather List from scsiport. */
- sl = (struct scatterlist *) pcmd->request_buffer;
- sgcount = pci_map_sg(acb->pdev, sl, pcmd->use_sg,
- pcmd->sc_data_direction);
+ nseg = scsi_dma_map(pcmd);
+ BUG_ON(nseg < 0);
+
+ if (nseg) {
+ int length, i, cdb_sgcount = 0;
+ struct scatterlist *sg;
+
/* map stor port SG list to our iop SG List. */
- for (i = 0; i < sgcount; i++) {
+ scsi_for_each_sg(pcmd, sg, nseg, i) {
/* Get the physical address of the current data pointer */
- length = cpu_to_le32(sg_dma_len(sl));
- address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sl)));
- address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sl)));
+ length = cpu_to_le32(sg_dma_len(sg));
+ address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg)));
+ address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg)));
if (address_hi == 0) {
struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
@@ -591,32 +594,12 @@
psge += sizeof (struct SG64ENTRY);
arccdbsize += sizeof (struct SG64ENTRY);
}
- sl++;
cdb_sgcount++;
}
arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
- arcmsr_cdb->DataLength = pcmd->request_bufflen;
+ arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
if ( arccdbsize > 256)
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
- } else if (pcmd->request_bufflen) {
- dma_addr_t dma_addr;
- dma_addr = pci_map_single(acb->pdev, pcmd->request_buffer,
- pcmd->request_bufflen, pcmd->sc_data_direction);
- pcmd->SCp.dma_handle = dma_addr;
- address_lo = cpu_to_le32(dma_addr_lo32(dma_addr));
- address_hi = cpu_to_le32(dma_addr_hi32(dma_addr));
- if (address_hi == 0) {
- struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
- pdma_sg->address = address_lo;
- pdma_sg->length = pcmd->request_bufflen;
- } else {
- struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
- pdma_sg->addresshigh = address_hi;
- pdma_sg->address = address_lo;
- pdma_sg->length = pcmd->request_bufflen|IS_SG64_ADDR;
- }
- arcmsr_cdb->sgcount = 1;
- arcmsr_cdb->DataLength = pcmd->request_bufflen;
}
if (pcmd->sc_data_direction == DMA_TO_DEVICE ) {
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
@@ -747,7 +730,7 @@
int id, lun;
/*
****************************************************************
- ** areca cdb command done
+ ** areca cdb command done
****************************************************************
*/
while (1) {
@@ -758,20 +741,20 @@
(flag_ccb << 5));
if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
if (ccb->startdone == ARCMSR_CCB_ABORTED) {
- struct scsi_cmnd *abortcmd=ccb->pcmd;
+ struct scsi_cmnd *abortcmd = ccb->pcmd;
if (abortcmd) {
abortcmd->result |= DID_ABORT >> 16;
arcmsr_ccb_complete(ccb, 1);
printk(KERN_NOTICE
- "arcmsr%d: ccb='0x%p' isr got aborted command \n"
+ "arcmsr%d: ccb ='0x%p' isr got aborted command \n"
, acb->host->host_no, ccb);
}
continue;
}
printk(KERN_NOTICE
- "arcmsr%d: isr get an illegal ccb command done acb='0x%p'"
- "ccb='0x%p' ccbacb='0x%p' startdone = 0x%x"
- " ccboutstandingcount=%d \n"
+ "arcmsr%d: isr get an illegal ccb command done acb = '0x%p'"
+ "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x"
+ " ccboutstandingcount = %d \n"
, acb->host->host_no
, acb
, ccb
@@ -791,7 +774,7 @@
switch(ccb->arcmsr_cdb.DeviceStatus) {
case ARCMSR_DEV_SELECT_TIMEOUT: {
acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_TIME_OUT << 16;
+ ccb->pcmd->result = DID_NO_CONNECT << 16;
arcmsr_ccb_complete(ccb, 1);
}
break;
@@ -810,8 +793,8 @@
break;
default:
printk(KERN_NOTICE
- "arcmsr%d: scsi id=%d lun=%d"
- " isr get command error done,"
+ "arcmsr%d: scsi id = %d lun = %d"
+ " isr get command error done, "
"but got unknown DeviceStatus = 0x%x \n"
, acb->host->host_no
, id
@@ -848,24 +831,21 @@
struct CMD_MESSAGE_FIELD *pcmdmessagefld;
int retvalue = 0, transfer_len = 0;
char *buffer;
+ struct scatterlist *sg;
uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 |
(uint32_t ) cmd->cmnd[6] << 16 |
(uint32_t ) cmd->cmnd[7] << 8 |
(uint32_t ) cmd->cmnd[8];
/* 4 bytes: Areca io control code */
- if (cmd->use_sg) {
- struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer;
- buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- if (cmd->use_sg > 1) {
- retvalue = ARCMSR_MESSAGE_FAIL;
- goto message_out;
- }
- transfer_len += sg->length;
- } else {
- buffer = cmd->request_buffer;
- transfer_len = cmd->request_bufflen;
+ sg = scsi_sglist(cmd);
+ buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ if (scsi_sg_count(cmd) > 1) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
}
+ transfer_len += sg->length;
+
if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) {
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
@@ -1057,12 +1037,9 @@
retvalue = ARCMSR_MESSAGE_FAIL;
}
message_out:
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ sg = scsi_sglist(cmd);
+ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
- sg = (struct scatterlist *) cmd->request_buffer;
- kunmap_atomic(buffer - sg->offset, KM_IRQ0);
- }
return retvalue;
}
@@ -1085,6 +1062,7 @@
case INQUIRY: {
unsigned char inqdata[36];
char *buffer;
+ struct scatterlist *sg;
if (cmd->device->lun) {
cmd->result = (DID_TIME_OUT << 16);
@@ -1096,7 +1074,7 @@
inqdata[1] = 0;
/* rem media bit & Dev Type Modifier */
inqdata[2] = 0;
- /* ISO,ECMA,& ANSI versions */
+ /* ISO, ECMA, & ANSI versions */
inqdata[4] = 31;
/* length of additional data */
strncpy(&inqdata[8], "Areca ", 8);
@@ -1104,21 +1082,14 @@
strncpy(&inqdata[16], "RAID controller ", 16);
/* Product Identification */
strncpy(&inqdata[32], "R001", 4); /* Product Revision */
- if (cmd->use_sg) {
- struct scatterlist *sg;
- sg = (struct scatterlist *) cmd->request_buffer;
- buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- } else {
- buffer = cmd->request_buffer;
- }
+ sg = scsi_sglist(cmd);
+ buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+
memcpy(buffer, inqdata, sizeof(inqdata));
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ sg = scsi_sglist(cmd);
+ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
- sg = (struct scatterlist *) cmd->request_buffer;
- kunmap_atomic(buffer - sg->offset, KM_IRQ0);
- }
cmd->scsi_done(cmd);
}
break;
@@ -1153,7 +1124,7 @@
, acb->host->host_no);
return SCSI_MLQUEUE_HOST_BUSY;
}
- if(target == 16) {
+ if (target == 16) {
/* virtual device for iop message transfer */
arcmsr_handle_virtual_command(acb, cmd);
return 0;
@@ -1166,7 +1137,7 @@
printk(KERN_NOTICE
"arcmsr%d: block 'read/write'"
"command with gone raid volume"
- " Cmd=%2x, TargetId=%d, Lun=%d \n"
+ " Cmd = %2x, TargetId = %d, Lun = %d \n"
, acb->host->host_no
, cmd->cmnd[0]
, target, lun);
@@ -1257,7 +1228,7 @@
if ((ccb->startdone == ARCMSR_CCB_ABORTED) ||
(ccb == poll_ccb)) {
printk(KERN_NOTICE
- "arcmsr%d: scsi id=%d lun=%d ccb='0x%p'"
+ "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
" poll command abort successfully \n"
, acb->host->host_no
, ccb->pcmd->device->id
@@ -1270,8 +1241,8 @@
}
printk(KERN_NOTICE
"arcmsr%d: polling get an illegal ccb"
- " command done ccb='0x%p'"
- "ccboutstandingcount=%d \n"
+ " command done ccb ='0x%p'"
+ "ccboutstandingcount = %d \n"
, acb->host->host_no
, ccb
, atomic_read(&acb->ccboutstandingcount));
@@ -1288,7 +1259,7 @@
switch(ccb->arcmsr_cdb.DeviceStatus) {
case ARCMSR_DEV_SELECT_TIMEOUT: {
acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_TIME_OUT << 16;
+ ccb->pcmd->result = DID_NO_CONNECT << 16;
arcmsr_ccb_complete(ccb, 1);
}
break;
@@ -1307,7 +1278,7 @@
break;
default:
printk(KERN_NOTICE
- "arcmsr%d: scsi id=%d lun=%d"
+ "arcmsr%d: scsi id = %d lun = %d"
" polling and getting command error done"
"but got unknown DeviceStatus = 0x%x \n"
, acb->host->host_no
@@ -1322,6 +1293,94 @@
}
}
}
+static void arcmsr_done4_abort_postqueue(struct AdapterControlBlock *acb)
+{
+ int i = 0, found = 0;
+ int id, lun;
+ uint32_t flag_ccb, outbound_intstatus;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CommandControlBlock *ccb;
+ /*clear and abort all outbound posted Q*/
+
+ while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) &&
+(i++ < 256)){
+ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
+(flag_ccb << 5));
+ if (ccb){
+ if ((ccb->acb != acb)||(ccb->startdone != \
+ARCMSR_CCB_START)){
+ printk(KERN_NOTICE "arcmsr%d: polling get \
+an illegal ccb" "command done ccb = '0x%p'""ccboutstandingcount = %d \n",
+ acb->host->host_no, ccb,
+ atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+
+ id = ccb->pcmd->device->id;
+ lun = ccb->pcmd->device->lun;
+ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)){
+ if (acb->devstate[id][lun] == ARECA_RAID_GONE)
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ ccb->pcmd->result = DID_OK << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ else {
+ switch(ccb->arcmsr_cdb.DeviceStatus) {
+ case ARCMSR_DEV_SELECT_TIMEOUT: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_ABORTED:
+
+ case ARCMSR_DEV_INIT_FAIL: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_CHECK_CONDITION: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GOOD;
+ arcmsr_report_sense_info(ccb);
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ default:
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi id = %d \
+ lun = %d""polling and \
+ getting command error \
+ done""but got unknown \
+ DeviceStatus = 0x%x \n",
+ acb->host->host_no, id,
+ lun, ccb->arcmsr_cdb.DeviceStatus);
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ break;
+ }
+ }
+ found = 1;
+ }
+ }
+ if (found){
+ outbound_intstatus = readl(®->outbound_intstatus) & \
+ acb->outbound_int_enable;
+ writel(outbound_intstatus, ®->outbound_intstatus);
+ /*clear interrupt*/
+ }
+ return;
+}
+
static void arcmsr_iop_init(struct AdapterControlBlock *acb)
{
@@ -1355,7 +1414,6 @@
static void arcmsr_iop_reset(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
struct CommandControlBlock *ccb;
uint32_t intmask_org;
int i = 0;
@@ -1368,21 +1426,17 @@
/* disable all outbound interrupt */
intmask_org = arcmsr_disable_outbound_ints(acb);
/* clear all outbound posted Q */
- for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
- readl(®->outbound_queueport);
+ arcmsr_done4_abort_postqueue(acb);
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
ccb = acb->pccb_pool[i];
- if ((ccb->startdone == ARCMSR_CCB_START) ||
- (ccb->startdone == ARCMSR_CCB_ABORTED)) {
+ if (ccb->startdone == ARCMSR_CCB_START) {
ccb->startdone = ARCMSR_CCB_ABORTED;
- ccb->pcmd->result = DID_ABORT << 16;
- arcmsr_ccb_complete(ccb, 1);
}
}
/* enable all outbound interrupt */
arcmsr_enable_outbound_ints(acb, intmask_org);
}
- atomic_set(&acb->ccboutstandingcount, 0);
+
}
static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
@@ -1428,10 +1482,9 @@
int i = 0;
printk(KERN_NOTICE
- "arcmsr%d: abort device command of scsi id=%d lun=%d \n",
+ "arcmsr%d: abort device command of scsi id = %d lun = %d \n",
acb->host->host_no, cmd->device->id, cmd->device->lun);
acb->num_aborts++;
-
/*
************************************************
** the all interrupt service routine is locked
@@ -1486,10 +1539,306 @@
type = "X-TYPE";
break;
}
- sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s",
+ sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s",
type, raid6 ? "( RAID6 capable)" : "",
ARCMSR_DRIVER_VERSION);
return buf;
}
+static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host;
+ struct AdapterControlBlock *acb;
+ uint8_t bus, dev_fun;
+ int error;
+ error = pci_enable_device(pdev);
+ if (error)
+ return PCI_ERS_RESULT_DISCONNECT;
+ pci_set_master(pdev);
+
+ host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof \
+(struct AdapterControlBlock));
+ if (!host)
+ return PCI_ERS_RESULT_DISCONNECT;
+ acb = (struct AdapterControlBlock *)host->hostdata;
+ memset(acb, 0, sizeof (struct AdapterControlBlock));
+
+ error = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ if (error) {
+ error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (error) {
+ printk(KERN_WARNING
+ "scsi%d: No suitable DMA mask available\n",
+ host->host_no);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ }
+ bus = pdev->bus->number;
+ dev_fun = pdev->devfn;
+ acb = (struct AdapterControlBlock *) host->hostdata;
+ memset(acb, 0, sizeof(struct AdapterControlBlock));
+ acb->pdev = pdev;
+ acb->host = host;
+ host->max_sectors = ARCMSR_MAX_XFER_SECTORS;
+ host->max_lun = ARCMSR_MAX_TARGETLUN;
+ host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/
+ host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/
+ host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES;
+ host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */
+ host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
+ host->this_id = ARCMSR_SCSI_INITIATOR_ID;
+ host->unique_id = (bus << 8) | dev_fun;
+ host->irq = pdev->irq;
+ error = pci_request_regions(pdev, "arcmsr");
+ if (error)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ acb->pmu = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (!acb->pmu) {
+ printk(KERN_NOTICE "arcmsr%d: memory"
+ " mapping region fail \n", acb->host->host_no);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
+ ACB_F_MESSAGE_RQBUFFER_CLEARED |
+ ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
+ INIT_LIST_HEAD(&acb->ccb_free_list);
+
+ error = arcmsr_alloc_ccb_pool(acb);
+ if (error)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ error = request_irq(pdev->irq, arcmsr_do_interrupt,
+ IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb);
+ if (error)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ arcmsr_iop_init(acb);
+ if (strncmp(acb->firm_version, "V1.42", 5) >= 0)
+ host->max_sectors = ARCMSR_MAX_XFER_SECTORS_B;
+
+ pci_set_drvdata(pdev, host);
+
+ error = scsi_add_host(host, &pdev->dev);
+ if (error)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ error = arcmsr_alloc_sysfs_attr(acb);
+ if (error)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ scsi_scan_host(host);
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void arcmsr_pci_ers_need_reset_forepart(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CommandControlBlock *ccb;
+ /*clear and abort all outbound posted Q*/
+ int i = 0, found = 0;
+ int id, lun;
+ uint32_t flag_ccb, outbound_intstatus;
+
+ while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) &&
+ (i++ < 256)){
+ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset
+ + (flag_ccb << 5));
+ if (ccb){
+ if ((ccb->acb != acb)||(ccb->startdone !=
+ ARCMSR_CCB_START)){
+ printk(KERN_NOTICE "arcmsr%d: polling \
+ get an illegal ccb"" command done ccb = '0x%p'"
+ "ccboutstandingcount = %d \n",
+ acb->host->host_no, ccb,
+ atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+
+ id = ccb->pcmd->device->id;
+ lun = ccb->pcmd->device->lun;
+ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (acb->devstate[id][lun] ==
+ ARECA_RAID_GONE)
+ acb->devstate[id][lun] =
+ ARECA_RAID_GOOD;
+ ccb->pcmd->result = DID_OK << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ else {
+ switch(ccb->arcmsr_cdb.DeviceStatus) {
+ case ARCMSR_DEV_SELECT_TIMEOUT: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_ABORTED:
+
+ case ARCMSR_DEV_INIT_FAIL: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_CHECK_CONDITION: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GOOD;
+ arcmsr_report_sense_info(ccb);
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ default:
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi \
+ id = %d lun = %d"
+ " polling and \
+ getting command \
+ error done"
+ "but got unknown \
+ DeviceStatus = 0x%x \n"
+ , acb->host->host_no,
+ id, lun,
+ ccb->arcmsr_cdb.DeviceStatus);
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ break;
+ }
+ }
+ found = 1;
+ }
+ }
+ if (found){
+ outbound_intstatus = readl(®->outbound_intstatus) &
+ acb->outbound_int_enable;
+ writel(outbound_intstatus, ®->outbound_intstatus);
+ /*clear interrupt*/
+ }
+ return;
+}
+
+
+static void arcmsr_pci_ers_disconnect_forepart(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CommandControlBlock *ccb;
+ /*clear and abort all outbound posted Q*/
+ int i = 0, found = 0;
+ int id, lun;
+ uint32_t flag_ccb, outbound_intstatus;
+
+ while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) &&
+ (i++ < 256)){
+ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
+ (flag_ccb << 5));
+ if (ccb){
+ if ((ccb->acb != acb)||(ccb->startdone !=
+ ARCMSR_CCB_START)){
+ printk(KERN_NOTICE
+ "arcmsr%d: polling get an illegal ccb"
+ " command done ccb = '0x%p'"
+ "ccboutstandingcount = %d \n",
+ acb->host->host_no, ccb,
+ atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+
+ id = ccb->pcmd->device->id;
+ lun = ccb->pcmd->device->lun;
+ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (acb->devstate[id][lun] == ARECA_RAID_GONE)
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ ccb->pcmd->result = DID_OK << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ else {
+ switch(ccb->arcmsr_cdb.DeviceStatus) {
+ case ARCMSR_DEV_SELECT_TIMEOUT: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_ABORTED:
+
+ case ARCMSR_DEV_INIT_FAIL: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_CHECK_CONDITION: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GOOD;
+ arcmsr_report_sense_info(ccb);
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ default:
+ printk(KERN_NOTICE "arcmsr%d: \
+ scsi id = %d lun = %d"
+ " polling and \
+ getting command error done"
+ "but got unknown \
+ DeviceStatus = 0x%x \n"
+ , acb->host->host_no,
+ id, lun, ccb->arcmsr_cdb.DeviceStatus);
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ break;
+ }
+ }
+ found = 1;
+ }
+ }
+ if (found){
+ outbound_intstatus = readl(®->outbound_intstatus) &
+ acb->outbound_int_enable;
+ writel(outbound_intstatus, ®->outbound_intstatus);
+ /*clear interrupt*/
+ }
+ return;
+}
+
+static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ switch (state) {
+ case pci_channel_io_frozen:
+ arcmsr_pci_ers_need_reset_forepart(pdev);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ arcmsr_pci_ers_disconnect_forepart(pdev);
+ return PCI_ERS_RESULT_DISCONNECT;
+ break;
+ default:
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
+}
diff --git a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c
deleted file mode 100644
index 599b400..0000000
--- a/drivers/scsi/bvme6000.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux.
- *
- * Based on work by Alan Hourihane
- */
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/blkdev.h>
-#include <linux/zorro.h>
-
-#include <asm/setup.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/bvme6000hw.h>
-#include <asm/irq.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "53c7xx.h"
-#include "bvme6000.h"
-
-#include<linux/stat.h>
-
-
-int bvme6000_scsi_detect(struct scsi_host_template *tpnt)
-{
- static unsigned char called = 0;
- int clock;
- long long options;
-
- if (called)
- return 0;
- if (!MACH_IS_BVME6000)
- return 0;
-
- tpnt->proc_name = "BVME6000";
-
- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
-
- clock = 40000000; /* 66MHz SCSI Clock */
-
- ncr53c7xx_init(tpnt, 0, 710, (unsigned long)BVME_NCR53C710_BASE,
- 0, BVME_IRQ_SCSI, DMA_NONE,
- options, clock);
- called = 1;
- return 1;
-}
-
-static int bvme6000_scsi_release(struct Scsi_Host *shost)
-{
- if (shost->irq)
- free_irq(shost->irq, NULL);
- if (shost->dma_channel != 0xff)
- free_dma(shost->dma_channel);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
- scsi_unregister(shost);
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .name = "BVME6000 NCR53c710 SCSI",
- .detect = bvme6000_scsi_detect,
- .release = bvme6000_scsi_release,
- .queuecommand = NCR53c7xx_queue_command,
- .abort = NCR53c7xx_abort,
- .reset = NCR53c7xx_reset,
- .can_queue = 24,
- .this_id = 7,
- .sg_tablesize = 63,
- .cmd_per_lun = 3,
- .use_clustering = DISABLE_CLUSTERING
-};
-
-
-#include "scsi_module.c"
diff --git a/drivers/scsi/bvme6000.h b/drivers/scsi/bvme6000.h
deleted file mode 100644
index ea3e4b2..0000000
--- a/drivers/scsi/bvme6000.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef BVME6000_SCSI_H
-#define BVME6000_SCSI_H
-
-#include <linux/types.h>
-
-int bvme6000_scsi_detect(struct scsi_host_template *);
-const char *NCR53c7x0_info(void);
-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int NCR53c7xx_abort(Scsi_Cmnd *);
-int NCR53c7x0_release (struct Scsi_Host *);
-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
-void NCR53c7x0_intr(int irq, void *dev_id);
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 3
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 24
-#endif
-
-#include <scsi/scsicam.h>
-
-#endif /* BVME6000_SCSI_H */
diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c
new file mode 100644
index 0000000..012cdea
--- /dev/null
+++ b/drivers/scsi/bvme6000_scsi.c
@@ -0,0 +1,135 @@
+/*
+ * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux.
+ *
+ * Based on work by Alan Hourihane and Kars de Jong
+ *
+ * Rewritten to use 53c700.c by Richard Hirst <richard@sleepie.demon.co.uk>
+ */
+
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/bvme6000hw.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+
+MODULE_AUTHOR("Richard Hirst <richard@sleepie.demon.co.uk>");
+MODULE_DESCRIPTION("BVME6000 NCR53C710 driver");
+MODULE_LICENSE("GPL");
+
+static struct scsi_host_template bvme6000_scsi_driver_template = {
+ .name = "BVME6000 NCR53c710 SCSI",
+ .proc_name = "BVME6000",
+ .this_id = 7,
+ .module = THIS_MODULE,
+};
+
+static struct platform_device *bvme6000_scsi_device;
+
+static __devinit int
+bvme6000_probe(struct device *dev)
+{
+ struct Scsi_Host * host = NULL;
+ struct NCR_700_Host_Parameters *hostdata;
+
+ if (!MACH_IS_BVME6000)
+ goto out;
+
+ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (hostdata == NULL) {
+ printk(KERN_ERR "bvme6000-scsi: "
+ "Failed to allocate host data\n");
+ goto out;
+ }
+ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
+
+ /* Fill in the required pieces of hostdata */
+ hostdata->base = (void __iomem *)BVME_NCR53C710_BASE;
+ hostdata->clock = 40; /* XXX - depends on the CPU clock! */
+ hostdata->chip710 = 1;
+ hostdata->dmode_extra = DMODE_FC2;
+ hostdata->dcntl_extra = EA_710;
+ hostdata->ctest7_extra = CTEST7_TT1;
+
+ /* and register the chip */
+ host = NCR_700_detect(&bvme6000_scsi_driver_template, hostdata, dev);
+ if (!host) {
+ printk(KERN_ERR "bvme6000-scsi: No host detected; "
+ "board configuration problem?\n");
+ goto out_free;
+ }
+ host->base = BVME_NCR53C710_BASE;
+ host->this_id = 7;
+ host->irq = BVME_IRQ_SCSI;
+ if (request_irq(BVME_IRQ_SCSI, NCR_700_intr, 0, "bvme6000-scsi",
+ host)) {
+ printk(KERN_ERR "bvme6000-scsi: request_irq failed\n");
+ goto out_put_host;
+ }
+
+ scsi_scan_host(host);
+
+ return 0;
+
+ out_put_host:
+ scsi_host_put(host);
+ out_free:
+ kfree(hostdata);
+ out:
+ return -ENODEV;
+}
+
+static __devexit int
+bvme6000_device_remove(struct device *dev)
+{
+ struct Scsi_Host *host = dev_to_shost(dev);
+ struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
+
+ scsi_remove_host(host);
+ NCR_700_release(host);
+ kfree(hostdata);
+ free_irq(host->irq, host);
+
+ return 0;
+}
+
+static struct device_driver bvme6000_scsi_driver = {
+ .name = "bvme6000-scsi",
+ .bus = &platform_bus_type,
+ .probe = bvme6000_probe,
+ .remove = __devexit_p(bvme6000_device_remove),
+};
+
+static int __init bvme6000_scsi_init(void)
+{
+ int err;
+
+ err = driver_register(&bvme6000_scsi_driver);
+ if (err)
+ return err;
+
+ bvme6000_scsi_device = platform_device_register_simple("bvme6000-scsi",
+ -1, NULL, 0);
+ if (IS_ERR(bvme6000_scsi_device)) {
+ driver_unregister(&bvme6000_scsi_driver);
+ return PTR_ERR(bvme6000_scsi_device);
+ }
+
+ return 0;
+}
+
+static void __exit bvme6000_scsi_exit(void)
+{
+ platform_device_unregister(bvme6000_scsi_device);
+ driver_unregister(&bvme6000_scsi_driver);
+}
+
+module_init(bvme6000_scsi_init);
+module_exit(bvme6000_scsi_exit);
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 564ea90..7b8a345 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -979,6 +979,7 @@
static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
+ int nseg;
enum dma_data_direction dir = cmd->sc_data_direction;
dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n",
cmd->pid, dcb->target_id, dcb->target_lun);
@@ -1000,27 +1001,30 @@
srb->scsi_phase = PH_BUS_FREE; /* initial phase */
srb->end_message = 0;
- if (dir == PCI_DMA_NONE || !cmd->request_buffer) {
+ nseg = scsi_dma_map(cmd);
+ BUG_ON(nseg < 0);
+
+ if (dir == PCI_DMA_NONE || !nseg) {
dprintkdbg(DBG_0,
"build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n",
- cmd->bufflen, cmd->request_buffer,
- cmd->use_sg, srb->segment_x[0].address);
- } else if (cmd->use_sg) {
+ cmd->bufflen, scsi_sglist(cmd), scsi_sg_count(cmd),
+ srb->segment_x[0].address);
+ } else {
int i;
- u32 reqlen = cmd->request_bufflen;
- struct scatterlist *sl = (struct scatterlist *)
- cmd->request_buffer;
+ u32 reqlen = scsi_bufflen(cmd);
+ struct scatterlist *sg;
struct SGentry *sgp = srb->segment_x;
- srb->sg_count = pci_map_sg(dcb->acb->dev, sl, cmd->use_sg,
- dir);
- dprintkdbg(DBG_0,
- "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n",
- reqlen, cmd->request_buffer, cmd->use_sg,
- srb->sg_count);
- for (i = 0; i < srb->sg_count; i++) {
- u32 busaddr = (u32)sg_dma_address(&sl[i]);
- u32 seglen = (u32)sl[i].length;
+ srb->sg_count = nseg;
+
+ dprintkdbg(DBG_0,
+ "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n",
+ reqlen, scsi_sglist(cmd), scsi_sg_count(cmd),
+ srb->sg_count);
+
+ scsi_for_each_sg(cmd, sg, srb->sg_count, i) {
+ u32 busaddr = (u32)sg_dma_address(sg);
+ u32 seglen = (u32)sg->length;
sgp[i].address = busaddr;
sgp[i].length = seglen;
srb->total_xfer_length += seglen;
@@ -1050,23 +1054,6 @@
dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n",
srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN);
- } else {
- srb->total_xfer_length = cmd->request_bufflen;
- srb->sg_count = 1;
- srb->segment_x[0].address =
- pci_map_single(dcb->acb->dev, cmd->request_buffer,
- srb->total_xfer_length, dir);
-
- /* Fixup for WIDE padding - make sure length is even */
- if (dcb->sync_period & WIDE_SYNC && srb->total_xfer_length % 2)
- srb->total_xfer_length++;
-
- srb->segment_x[0].length = srb->total_xfer_length;
-
- dprintkdbg(DBG_0,
- "build_srb: [1] len=%d buf=%p use_sg=%d map=%08x\n",
- srb->total_xfer_length, cmd->request_buffer,
- cmd->use_sg, srb->segment_x[0].address);
}
srb->request_length = srb->total_xfer_length;
@@ -2128,7 +2115,7 @@
/*clear_fifo(acb, "DOP1"); */
/* KG: What is this supposed to be useful for? WIDE padding stuff? */
if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC
- && srb->cmd->request_bufflen % 2) {
+ && scsi_bufflen(srb->cmd) % 2) {
d_left_counter = 0;
dprintkl(KERN_INFO,
"data_out_phase0: Discard 1 byte (0x%02x)\n",
@@ -2159,7 +2146,7 @@
sg_update_list(srb, d_left_counter);
/* KG: Most ugly hack! Apparently, this works around a chip bug */
if ((srb->segment_x[srb->sg_index].length ==
- diff && srb->cmd->use_sg)
+ diff && scsi_sg_count(srb->cmd))
|| ((oldxferred & ~PAGE_MASK) ==
(PAGE_SIZE - diff))
) {
@@ -2289,19 +2276,15 @@
unsigned char *virt, *base = NULL;
unsigned long flags = 0;
size_t len = left_io;
+ size_t offset = srb->request_length - left_io;
- if (srb->cmd->use_sg) {
- size_t offset = srb->request_length - left_io;
- local_irq_save(flags);
- /* Assumption: it's inside one page as it's at most 4 bytes and
- I just assume it's on a 4-byte boundary */
- base = scsi_kmap_atomic_sg((struct scatterlist *)srb->cmd->request_buffer,
- srb->sg_count, &offset, &len);
- virt = base + offset;
- } else {
- virt = srb->cmd->request_buffer + srb->cmd->request_bufflen - left_io;
- len = left_io;
- }
+ local_irq_save(flags);
+ /* Assumption: it's inside one page as it's at most 4 bytes and
+ I just assume it's on a 4-byte boundary */
+ base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd),
+ srb->sg_count, &offset, &len);
+ virt = base + offset;
+
left_io -= len;
while (len) {
@@ -2341,10 +2324,8 @@
DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
}
- if (srb->cmd->use_sg) {
- scsi_kunmap_atomic_sg(base);
- local_irq_restore(flags);
- }
+ scsi_kunmap_atomic_sg(base);
+ local_irq_restore(flags);
}
/*printk(" %08x", *(u32*)(bus_to_virt (addr))); */
/*srb->total_xfer_length = 0; */
@@ -2455,7 +2436,7 @@
*/
srb->state |= SRB_DATA_XFER;
DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0);
- if (srb->cmd->use_sg) { /* with S/G */
+ if (scsi_sg_count(srb->cmd)) { /* with S/G */
io_dir |= DMACMD_SG;
DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
srb->sg_bus_addr +
@@ -2513,18 +2494,14 @@
unsigned char *virt, *base = NULL;
unsigned long flags = 0;
size_t len = left_io;
+ size_t offset = srb->request_length - left_io;
- if (srb->cmd->use_sg) {
- size_t offset = srb->request_length - left_io;
- local_irq_save(flags);
- /* Again, max 4 bytes */
- base = scsi_kmap_atomic_sg((struct scatterlist *)srb->cmd->request_buffer,
- srb->sg_count, &offset, &len);
- virt = base + offset;
- } else {
- virt = srb->cmd->request_buffer + srb->cmd->request_bufflen - left_io;
- len = left_io;
- }
+ local_irq_save(flags);
+ /* Again, max 4 bytes */
+ base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd),
+ srb->sg_count, &offset, &len);
+ virt = base + offset;
+
left_io -= len;
while (len--) {
@@ -2536,10 +2513,8 @@
sg_subtract_one(srb);
}
- if (srb->cmd->use_sg) {
- scsi_kunmap_atomic_sg(base);
- local_irq_restore(flags);
- }
+ scsi_kunmap_atomic_sg(base);
+ local_irq_restore(flags);
}
if (srb->dcb->sync_period & WIDE_SYNC) {
if (ln % 2) {
@@ -3295,7 +3270,8 @@
{
struct scsi_cmnd *cmd = srb->cmd;
enum dma_data_direction dir = cmd->sc_data_direction;
- if (cmd->use_sg && dir != PCI_DMA_NONE) {
+
+ if (scsi_sg_count(cmd) && dir != PCI_DMA_NONE) {
/* unmap DC395x SG list */
dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n",
srb->sg_bus_addr, SEGMENTX_LEN);
@@ -3303,16 +3279,9 @@
SEGMENTX_LEN,
PCI_DMA_TODEVICE);
dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n",
- cmd->use_sg, cmd->request_buffer);
+ scsi_sg_count(cmd), scsi_bufflen(cmd));
/* unmap the sg segments */
- pci_unmap_sg(acb->dev,
- (struct scatterlist *)cmd->request_buffer,
- cmd->use_sg, dir);
- } else if (cmd->request_buffer && dir != PCI_DMA_NONE) {
- dprintkdbg(DBG_SG, "pci_unmap_srb: buffer=%08x(%05x)\n",
- srb->segment_x[0].address, cmd->request_bufflen);
- pci_unmap_single(acb->dev, srb->segment_x[0].address,
- cmd->request_bufflen, dir);
+ scsi_dma_unmap(cmd);
}
}
@@ -3352,8 +3321,8 @@
dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid,
srb->cmd->device->id, srb->cmd->device->lun);
dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n",
- srb, cmd->use_sg, srb->sg_index, srb->sg_count,
- cmd->request_buffer);
+ srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count,
+ scsi_sgtalbe(cmd));
status = srb->target_status;
if (srb->flag & AUTO_REQSENSE) {
dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n");
@@ -3482,16 +3451,10 @@
}
}
- if (dir != PCI_DMA_NONE) {
- if (cmd->use_sg)
- pci_dma_sync_sg_for_cpu(acb->dev,
- (struct scatterlist *)cmd->
- request_buffer, cmd->use_sg, dir);
- else if (cmd->request_buffer)
- pci_dma_sync_single_for_cpu(acb->dev,
- srb->segment_x[0].address,
- cmd->request_bufflen, dir);
- }
+ if (dir != PCI_DMA_NONE && scsi_sg_count(cmd))
+ pci_dma_sync_sg_for_cpu(acb->dev, scsi_sglist(cmd),
+ scsi_sg_count(cmd), dir);
+
ckc_only = 0;
/* Check Error Conditions */
ckc_e:
@@ -3500,19 +3463,15 @@
unsigned char *base = NULL;
struct ScsiInqData *ptr;
unsigned long flags = 0;
+ struct scatterlist* sg = scsi_sglist(cmd);
+ size_t offset = 0, len = sizeof(struct ScsiInqData);
- if (cmd->use_sg) {
- struct scatterlist* sg = (struct scatterlist *)cmd->request_buffer;
- size_t offset = 0, len = sizeof(struct ScsiInqData);
-
- local_irq_save(flags);
- base = scsi_kmap_atomic_sg(sg, cmd->use_sg, &offset, &len);
- ptr = (struct ScsiInqData *)(base + offset);
- } else
- ptr = (struct ScsiInqData *)(cmd->request_buffer);
+ local_irq_save(flags);
+ base = scsi_kmap_atomic_sg(sg, scsi_sg_count(cmd), &offset, &len);
+ ptr = (struct ScsiInqData *)(base + offset);
if (!ckc_only && (cmd->result & RES_DID) == 0
- && cmd->cmnd[2] == 0 && cmd->request_bufflen >= 8
+ && cmd->cmnd[2] == 0 && scsi_bufflen(cmd) >= 8
&& dir != PCI_DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2)
dcb->inquiry7 = ptr->Flags;
@@ -3527,14 +3486,12 @@
}
}
- if (cmd->use_sg) {
- scsi_kunmap_atomic_sg(base);
- local_irq_restore(flags);
- }
+ scsi_kunmap_atomic_sg(base);
+ local_irq_restore(flags);
}
/* Here is the info for Doug Gilbert's sg3 ... */
- cmd->resid = srb->total_xfer_length;
+ scsi_set_resid(cmd, srb->total_xfer_length);
/* This may be interpreted by sb. or not ... */
cmd->SCp.this_residual = srb->total_xfer_length;
cmd->SCp.buffers_residual = 0;
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 8c7d2bb..2e2362d 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -2078,12 +2078,13 @@
u32 *lenptr;
int direction;
int scsidir;
+ int nseg;
u32 len;
u32 reqlen;
s32 rcode;
memset(msg, 0 , sizeof(msg));
- len = cmd->request_bufflen;
+ len = scsi_bufflen(cmd);
direction = 0x00000000;
scsidir = 0x00000000; // DATA NO XFER
@@ -2140,21 +2141,21 @@
lenptr=mptr++; /* Remember me - fill in when we know */
reqlen = 14; // SINGLE SGE
/* Now fill in the SGList and command */
- if(cmd->use_sg) {
- struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer;
- int sg_count = pci_map_sg(pHba->pDev, sg, cmd->use_sg,
- cmd->sc_data_direction);
+ nseg = scsi_dma_map(cmd);
+ BUG_ON(nseg < 0);
+ if (nseg) {
+ struct scatterlist *sg;
len = 0;
- for(i = 0 ; i < sg_count; i++) {
+ scsi_for_each_sg(cmd, sg, nseg, i) {
*mptr++ = direction|0x10000000|sg_dma_len(sg);
len+=sg_dma_len(sg);
*mptr++ = sg_dma_address(sg);
- sg++;
+ /* Make this an end of list */
+ if (i == nseg - 1)
+ mptr[-2] = direction|0xD0000000|sg_dma_len(sg);
}
- /* Make this an end of list */
- mptr[-2] = direction|0xD0000000|sg_dma_len(sg-1);
reqlen = mptr - msg;
*lenptr = len;
@@ -2163,16 +2164,8 @@
len, cmd->underflow);
}
} else {
- *lenptr = len = cmd->request_bufflen;
- if(len == 0) {
- reqlen = 12;
- } else {
- *mptr++ = 0xD0000000|direction|cmd->request_bufflen;
- *mptr++ = pci_map_single(pHba->pDev,
- cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- }
+ *lenptr = len = 0;
+ reqlen = 12;
}
/* Stick the headers on */
@@ -2232,7 +2225,7 @@
hba_status = detailed_status >> 8;
// calculate resid for sg
- cmd->resid = cmd->request_bufflen - readl(reply+5);
+ scsi_set_resid(cmd, scsi_bufflen(cmd) - readl(reply+5));
pHba = (adpt_hba*) cmd->device->host->hostdata[0];
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 2d38025..a83e9f1 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1609,8 +1609,9 @@
static void map_dma(unsigned int i, struct hostdata *ha)
{
- unsigned int k, count, pci_dir;
- struct scatterlist *sgpnt;
+ unsigned int k, pci_dir;
+ int count;
+ struct scatterlist *sg;
struct mscp *cpp;
struct scsi_cmnd *SCpnt;
@@ -1625,38 +1626,19 @@
cpp->sense_len = sizeof SCpnt->sense_buffer;
- if (!SCpnt->use_sg) {
-
- /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */
- if (!SCpnt->request_bufflen)
- pci_dir = PCI_DMA_BIDIRECTIONAL;
-
- if (SCpnt->request_buffer)
- cpp->data_address = H2DEV(pci_map_single(ha->pdev,
- SCpnt->
- request_buffer,
- SCpnt->
- request_bufflen,
- pci_dir));
-
- cpp->data_len = H2DEV(SCpnt->request_bufflen);
- return;
- }
-
- sgpnt = (struct scatterlist *)SCpnt->request_buffer;
- count = pci_map_sg(ha->pdev, sgpnt, SCpnt->use_sg, pci_dir);
-
- for (k = 0; k < count; k++) {
- cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k]));
- cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k]));
+ count = scsi_dma_map(SCpnt);
+ BUG_ON(count < 0);
+ scsi_for_each_sg(SCpnt, sg, count, k) {
+ cpp->sglist[k].address = H2DEV(sg_dma_address(sg));
+ cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(sg));
}
cpp->sg = 1;
cpp->data_address = H2DEV(pci_map_single(ha->pdev, cpp->sglist,
- SCpnt->use_sg *
+ scsi_sg_count(SCpnt) *
sizeof(struct sg_list),
pci_dir));
- cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list)));
+ cpp->data_len = H2DEV((scsi_sg_count(SCpnt) * sizeof(struct sg_list)));
}
static void unmap_dma(unsigned int i, struct hostdata *ha)
@@ -1673,9 +1655,7 @@
pci_unmap_single(ha->pdev, DEV2H(cpp->sense_addr),
DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
- if (SCpnt->use_sg)
- pci_unmap_sg(ha->pdev, SCpnt->request_buffer, SCpnt->use_sg,
- pci_dir);
+ scsi_dma_unmap(SCpnt);
if (!DEV2H(cpp->data_len))
pci_dir = PCI_DMA_BIDIRECTIONAL;
@@ -1700,9 +1680,9 @@
DEV2H(cpp->sense_len),
PCI_DMA_FROMDEVICE);
- if (SCpnt->use_sg)
- pci_dma_sync_sg_for_cpu(ha->pdev, SCpnt->request_buffer,
- SCpnt->use_sg, pci_dir);
+ if (scsi_sg_count(SCpnt))
+ pci_dma_sync_sg_for_cpu(ha->pdev, scsi_sglist(SCpnt),
+ scsi_sg_count(SCpnt), pci_dir);
if (!DEV2H(cpp->data_len))
pci_dir = PCI_DMA_BIDIRECTIONAL;
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 71caf2d..77b06a9 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -324,17 +324,14 @@
static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd)
{
struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
- struct scatterlist *sg = cmd->request_buffer;
+ struct scatterlist *sg = scsi_sglist(cmd);
int dir = cmd->sc_data_direction;
int total, i;
if (dir == DMA_NONE)
return;
- BUG_ON(cmd->use_sg == 0);
-
- spriv->u.num_sg = esp->ops->map_sg(esp, sg,
- cmd->use_sg, dir);
+ spriv->u.num_sg = esp->ops->map_sg(esp, sg, scsi_sg_count(cmd), dir);
spriv->cur_residue = sg_dma_len(sg);
spriv->cur_sg = sg;
@@ -407,8 +404,7 @@
if (dir == DMA_NONE)
return;
- esp->ops->unmap_sg(esp, cmd->request_buffer,
- spriv->u.num_sg, dir);
+ esp->ops->unmap_sg(esp, scsi_sglist(cmd), spriv->u.num_sg, dir);
}
static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent)
@@ -921,7 +917,7 @@
static int esp_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct scsi_device *dev = cmd->device;
- struct esp *esp = host_to_esp(dev->host);
+ struct esp *esp = shost_priv(dev->host);
struct esp_cmd_priv *spriv;
struct esp_cmd_entry *ent;
@@ -2357,7 +2353,7 @@
static int esp_slave_alloc(struct scsi_device *dev)
{
- struct esp *esp = host_to_esp(dev->host);
+ struct esp *esp = shost_priv(dev->host);
struct esp_target_data *tp = &esp->target[dev->id];
struct esp_lun_data *lp;
@@ -2381,7 +2377,7 @@
static int esp_slave_configure(struct scsi_device *dev)
{
- struct esp *esp = host_to_esp(dev->host);
+ struct esp *esp = shost_priv(dev->host);
struct esp_target_data *tp = &esp->target[dev->id];
int goal_tags, queue_depth;
@@ -2423,7 +2419,7 @@
static int esp_eh_abort_handler(struct scsi_cmnd *cmd)
{
- struct esp *esp = host_to_esp(cmd->device->host);
+ struct esp *esp = shost_priv(cmd->device->host);
struct esp_cmd_entry *ent, *tmp;
struct completion eh_done;
unsigned long flags;
@@ -2539,7 +2535,7 @@
static int esp_eh_bus_reset_handler(struct scsi_cmnd *cmd)
{
- struct esp *esp = host_to_esp(cmd->device->host);
+ struct esp *esp = shost_priv(cmd->device->host);
struct completion eh_reset;
unsigned long flags;
@@ -2575,7 +2571,7 @@
/* All bets are off, reset the entire device. */
static int esp_eh_host_reset_handler(struct scsi_cmnd *cmd)
{
- struct esp *esp = host_to_esp(cmd->device->host);
+ struct esp *esp = shost_priv(cmd->device->host);
unsigned long flags;
spin_lock_irqsave(esp->host->host_lock, flags);
@@ -2615,7 +2611,7 @@
static void esp_get_signalling(struct Scsi_Host *host)
{
- struct esp *esp = host_to_esp(host);
+ struct esp *esp = shost_priv(host);
enum spi_signal_type type;
if (esp->flags & ESP_FLAG_DIFFERENTIAL)
@@ -2629,7 +2625,7 @@
static void esp_set_offset(struct scsi_target *target, int offset)
{
struct Scsi_Host *host = dev_to_shost(target->dev.parent);
- struct esp *esp = host_to_esp(host);
+ struct esp *esp = shost_priv(host);
struct esp_target_data *tp = &esp->target[target->id];
tp->nego_goal_offset = offset;
@@ -2639,7 +2635,7 @@
static void esp_set_period(struct scsi_target *target, int period)
{
struct Scsi_Host *host = dev_to_shost(target->dev.parent);
- struct esp *esp = host_to_esp(host);
+ struct esp *esp = shost_priv(host);
struct esp_target_data *tp = &esp->target[target->id];
tp->nego_goal_period = period;
@@ -2649,7 +2645,7 @@
static void esp_set_width(struct scsi_target *target, int width)
{
struct Scsi_Host *host = dev_to_shost(target->dev.parent);
- struct esp *esp = host_to_esp(host);
+ struct esp *esp = shost_priv(host);
struct esp_target_data *tp = &esp->target[target->id];
tp->nego_goal_width = (width ? 1 : 0);
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
index 8d4a669..d5576d5 100644
--- a/drivers/scsi/esp_scsi.h
+++ b/drivers/scsi/esp_scsi.h
@@ -517,8 +517,6 @@
struct sbus_dma *dma;
};
-#define host_to_esp(host) ((struct esp *)(host)->hostdata)
-
/* A front-end driver for the ESP chip should do the following in
* it's device probe routine:
* 1) Allocate the host and private area using scsi_host_alloc()
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 5d4ea6f..36169d5 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -410,6 +410,8 @@
static char * fdomain = NULL;
module_param(fdomain, charp, 0);
+#ifndef PCMCIA
+
static unsigned long addresses[] = {
0xc8000,
0xca000,
@@ -426,6 +428,8 @@
static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
+#endif /* !PCMCIA */
+
/*
READ THIS BEFORE YOU ADD A SIGNATURE!
@@ -458,6 +462,8 @@
*/
+#ifndef PCMCIA
+
static struct signature {
const char *signature;
int sig_offset;
@@ -503,6 +509,8 @@
#define SIGNATURE_COUNT ARRAY_SIZE(signatures)
+#endif /* !PCMCIA */
+
static void print_banner( struct Scsi_Host *shpnt )
{
if (!shpnt) return; /* This won't ever happen */
@@ -633,6 +641,8 @@
return 0;
}
+#ifndef PCMCIA
+
/* fdomain_get_irq assumes that we have a valid MCA ID for a
TMC-1660/TMC-1680 Future Domain board. Now, check to be sure the
bios_base matches these ports. If someone was unlucky enough to have
@@ -667,7 +677,6 @@
static int fdomain_isa_detect( int *irq, int *iobase )
{
-#ifndef PCMCIA
int i, j;
int base = 0xdeadbeef;
int flag = 0;
@@ -786,11 +795,22 @@
*iobase = base;
return 1; /* success */
-#else
- return 0;
-#endif
}
+#else /* PCMCIA */
+
+static int fdomain_isa_detect( int *irq, int *iobase )
+{
+ if (irq)
+ *irq = 0;
+ if (iobase)
+ *iobase = 0;
+ return 0;
+}
+
+#endif /* !PCMCIA */
+
+
/* PCI detection function: int fdomain_pci_bios_detect(int* irq, int*
iobase) This function gets the Interrupt Level and I/O base address from
the PCI configuration registers. */
@@ -1345,16 +1365,15 @@
#if ERRORS_ONLY
if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
- if ((unsigned char)(*((char *)current_SC->request_buffer+2)) & 0x0f) {
+ char *buf = scsi_sglist(current_SC);
+ if ((unsigned char)(*(buf + 2)) & 0x0f) {
unsigned char key;
unsigned char code;
unsigned char qualifier;
- key = (unsigned char)(*((char *)current_SC->request_buffer + 2))
- & 0x0f;
- code = (unsigned char)(*((char *)current_SC->request_buffer + 12));
- qualifier = (unsigned char)(*((char *)current_SC->request_buffer
- + 13));
+ key = (unsigned char)(*(buf + 2)) & 0x0f;
+ code = (unsigned char)(*(buf + 12));
+ qualifier = (unsigned char)(*(buf + 13));
if (key != UNIT_ATTENTION
&& !(key == NOT_READY
@@ -1405,8 +1424,8 @@
printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
SCpnt->target,
*(unsigned char *)SCpnt->cmnd,
- SCpnt->use_sg,
- SCpnt->request_bufflen );
+ scsi_sg_count(SCpnt),
+ scsi_bufflen(SCpnt));
#endif
fdomain_make_bus_idle();
@@ -1416,20 +1435,19 @@
/* Initialize static data */
- if (current_SC->use_sg) {
- current_SC->SCp.buffer =
- (struct scatterlist *)current_SC->request_buffer;
- current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
- current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
- current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
+ if (scsi_sg_count(current_SC)) {
+ current_SC->SCp.buffer = scsi_sglist(current_SC);
+ current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page)
+ + current_SC->SCp.buffer->offset;
+ current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
+ current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1;
} else {
- current_SC->SCp.ptr = (char *)current_SC->request_buffer;
- current_SC->SCp.this_residual = current_SC->request_bufflen;
- current_SC->SCp.buffer = NULL;
- current_SC->SCp.buffers_residual = 0;
+ current_SC->SCp.ptr = 0;
+ current_SC->SCp.this_residual = 0;
+ current_SC->SCp.buffer = NULL;
+ current_SC->SCp.buffers_residual = 0;
}
-
-
+
current_SC->SCp.Status = 0;
current_SC->SCp.Message = 0;
current_SC->SCp.have_data_in = 0;
@@ -1472,8 +1490,8 @@
SCpnt->SCp.phase,
SCpnt->device->id,
*(unsigned char *)SCpnt->cmnd,
- SCpnt->use_sg,
- SCpnt->request_bufflen );
+ scsi_sg_count(SCpnt),
+ scsi_bufflen(SCpnt));
printk( "sent_command = %d, have_data_in = %d, timeout = %d\n",
SCpnt->SCp.sent_command,
SCpnt->SCp.have_data_in,
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 60446b8..d0b95ce 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -876,7 +876,7 @@
/* Vortex only makes RAID controllers.
* We do not really want to specify all 550 ids here, so wildcard match.
*/
-static struct pci_device_id gdthtable[] __attribute_used__ = {
+static struct pci_device_id gdthtable[] __maybe_unused = {
{PCI_VENDOR_ID_VORTEX,PCI_ANY_ID,PCI_ANY_ID, PCI_ANY_ID},
{PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC,PCI_ANY_ID,PCI_ANY_ID},
{PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC_XSCALE,PCI_ANY_ID,PCI_ANY_ID},
@@ -1955,7 +1955,7 @@
for (j = 0; j < 12; ++j)
rtc[j] = CMOS_READ(j);
} while (rtc[0] != CMOS_READ(0));
- spin_lock_irqrestore(&rtc_lock, flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0],
*(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]));
/* 3. send to controller firmware */
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index bec83cb..0e579ca 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -339,20 +339,8 @@
scp = hba->reqs[tag].scp;
- if (HPT_SCP(scp)->mapped) {
- if (scp->use_sg)
- pci_unmap_sg(hba->pcidev,
- (struct scatterlist *)scp->request_buffer,
- scp->use_sg,
- scp->sc_data_direction
- );
- else
- pci_unmap_single(hba->pcidev,
- HPT_SCP(scp)->dma_handle,
- scp->request_bufflen,
- scp->sc_data_direction
- );
- }
+ if (HPT_SCP(scp)->mapped)
+ scsi_dma_unmap(scp);
switch (le32_to_cpu(req->header.result)) {
case IOP_RESULT_SUCCESS:
@@ -448,43 +436,26 @@
{
struct Scsi_Host *host = scp->device->host;
struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
- struct scatterlist *sglist = (struct scatterlist *)scp->request_buffer;
+ struct scatterlist *sg;
+ int idx, nseg;
- /*
- * though we'll not get non-use_sg fields anymore,
- * keep use_sg checking anyway
- */
- if (scp->use_sg) {
- int idx;
+ nseg = scsi_dma_map(scp);
+ BUG_ON(nseg < 0);
+ if (!nseg)
+ return 0;
- HPT_SCP(scp)->sgcnt = pci_map_sg(hba->pcidev,
- sglist, scp->use_sg,
- scp->sc_data_direction);
- HPT_SCP(scp)->mapped = 1;
- BUG_ON(HPT_SCP(scp)->sgcnt > hba->max_sg_descriptors);
+ HPT_SCP(scp)->sgcnt = nseg;
+ HPT_SCP(scp)->mapped = 1;
- for (idx = 0; idx < HPT_SCP(scp)->sgcnt; idx++) {
- psg[idx].pci_address =
- cpu_to_le64(sg_dma_address(&sglist[idx]));
- psg[idx].size = cpu_to_le32(sg_dma_len(&sglist[idx]));
- psg[idx].eot = (idx == HPT_SCP(scp)->sgcnt - 1) ?
- cpu_to_le32(1) : 0;
- }
+ BUG_ON(HPT_SCP(scp)->sgcnt > hba->max_sg_descriptors);
- return HPT_SCP(scp)->sgcnt;
- } else {
- HPT_SCP(scp)->dma_handle = pci_map_single(
- hba->pcidev,
- scp->request_buffer,
- scp->request_bufflen,
- scp->sc_data_direction
- );
- HPT_SCP(scp)->mapped = 1;
- psg->pci_address = cpu_to_le64(HPT_SCP(scp)->dma_handle);
- psg->size = cpu_to_le32(scp->request_bufflen);
- psg->eot = cpu_to_le32(1);
- return 1;
+ scsi_for_each_sg(scp, sg, HPT_SCP(scp)->sgcnt, idx) {
+ psg[idx].pci_address = cpu_to_le64(sg_dma_address(sg));
+ psg[idx].size = cpu_to_le32(sg_dma_len(sg));
+ psg[idx].eot = (idx == HPT_SCP(scp)->sgcnt - 1) ?
+ cpu_to_le32(1) : 0;
}
+ return HPT_SCP(scp)->sgcnt;
}
static int hptiop_queuecommand(struct scsi_cmnd *scp,
@@ -529,9 +500,8 @@
req = (struct hpt_iop_request_scsi_command *)_req->req_virt;
/* build S/G table */
- if (scp->request_bufflen)
- sg_count = hptiop_buildsgl(scp, req->sg_list);
- else
+ sg_count = hptiop_buildsgl(scp, req->sg_list);
+ if (!sg_count)
HPT_SCP(scp)->mapped = 0;
req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
@@ -540,7 +510,7 @@
req->header.context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
(u32)_req->index);
req->header.context_hi32 = 0;
- req->dataxfer_length = cpu_to_le32(scp->request_bufflen);
+ req->dataxfer_length = cpu_to_le32(scsi_bufflen(scp));
req->channel = scp->device->channel;
req->target = scp->device->id;
req->lun = scp->device->lun;
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 0e57fb6..4275d1b 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -31,14 +31,21 @@
#include <linux/mca.h>
#include <linux/spinlock.h>
#include <linux/init.h>
-#include <linux/mca-legacy.h>
#include <asm/system.h>
#include <asm/io.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
-#include "ibmmca.h"
+
+/* Common forward declarations for all Linux-versions: */
+static int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int ibmmca_abort (Scsi_Cmnd *);
+static int ibmmca_host_reset (Scsi_Cmnd *);
+static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *);
+static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout);
+
+
/* current version of this driver-source: */
#define IBMMCA_SCSI_DRIVER_VERSION "4.0b-ac"
@@ -65,11 +72,11 @@
#define IM_DEBUG_CMD_DEVICE TYPE_TAPE
/* relative addresses of hardware registers on a subsystem */
-#define IM_CMD_REG(hi) (hosts[(hi)]->io_port) /*Command Interface, (4 bytes long) */
-#define IM_ATTN_REG(hi) (hosts[(hi)]->io_port+4) /*Attention (1 byte) */
-#define IM_CTR_REG(hi) (hosts[(hi)]->io_port+5) /*Basic Control (1 byte) */
-#define IM_INTR_REG(hi) (hosts[(hi)]->io_port+6) /*Interrupt Status (1 byte, r/o) */
-#define IM_STAT_REG(hi) (hosts[(hi)]->io_port+7) /*Basic Status (1 byte, read only) */
+#define IM_CMD_REG(h) ((h)->io_port) /*Command Interface, (4 bytes long) */
+#define IM_ATTN_REG(h) ((h)->io_port+4) /*Attention (1 byte) */
+#define IM_CTR_REG(h) ((h)->io_port+5) /*Basic Control (1 byte) */
+#define IM_INTR_REG(h) ((h)->io_port+6) /*Interrupt Status (1 byte, r/o) */
+#define IM_STAT_REG(h) ((h)->io_port+7) /*Basic Status (1 byte, read only) */
/* basic I/O-port of first adapter */
#define IM_IO_PORT 0x3540
@@ -266,30 +273,36 @@
if ((display_mode & LED_ACTIVITY)||(!display_mode)) \
outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); }
-/*list of supported subsystems */
-struct subsys_list_struct {
- unsigned short mca_id;
- char *description;
-};
-
/* types of different supported hardware that goes to hostdata special */
#define IBM_SCSI2_FW 0
#define IBM_7568_WCACHE 1
#define IBM_EXP_UNIT 2
#define IBM_SCSI_WCACHE 3
#define IBM_SCSI 4
+#define IBM_INTEGSCSI 5
/* other special flags for hostdata structure */
#define FORCED_DETECTION 100
#define INTEGRATED_SCSI 101
/* List of possible IBM-SCSI-adapters */
-static struct subsys_list_struct subsys_list[] = {
- {0x8efc, "IBM SCSI-2 F/W Adapter"}, /* special = 0 */
- {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/Cache"}, /* special = 1 */
- {0x8ef8, "IBM Expansion Unit SCSI Controller"}, /* special = 2 */
- {0x8eff, "IBM SCSI Adapter w/Cache"}, /* special = 3 */
- {0x8efe, "IBM SCSI Adapter"}, /* special = 4 */
+static short ibmmca_id_table[] = {
+ 0x8efc,
+ 0x8efd,
+ 0x8ef8,
+ 0x8eff,
+ 0x8efe,
+ /* No entry for integrated SCSI, that's part of the register */
+ 0
+};
+
+static const char *ibmmca_description[] = {
+ "IBM SCSI-2 F/W Adapter", /* special = 0 */
+ "IBM 7568 Industrial Computer SCSI Adapter w/Cache", /* special = 1 */
+ "IBM Expansion Unit SCSI Controller", /* special = 2 */
+ "IBM SCSI Adapter w/Cache", /* special = 3 */
+ "IBM SCSI Adapter", /* special = 4 */
+ "IBM Integrated SCSI Controller", /* special = 5 */
};
/* Max number of logical devices (can be up from 0 to 14). 15 is the address
@@ -375,30 +388,30 @@
};
/* macros to access host data structure */
-#define subsystem_pun(hi) (hosts[(hi)]->this_id)
-#define subsystem_maxid(hi) (hosts[(hi)]->max_id)
-#define ld(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_ld)
-#define get_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_ldn)
-#define get_scsi(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_scsi)
-#define local_checking_phase_flag(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_local_checking_phase_flag)
-#define got_interrupt(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_got_interrupt)
-#define stat_result(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_stat_result)
-#define reset_status(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_reset_status)
-#define last_scsi_command(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_command)
-#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)
-#define last_scsi_blockcount(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_blockcount)
-#define last_scsi_logical_block(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_logical_block)
-#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)
-#define next_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_next_ldn)
-#define IBM_DS(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_IBM_DS)
-#define special(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_special)
-#define subsystem_connector_size(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_connector_size)
-#define adapter_speed(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_adapter_speed)
-#define pos2(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[2])
-#define pos3(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[3])
-#define pos4(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[4])
-#define pos5(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[5])
-#define pos6(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[6])
+#define subsystem_pun(h) ((h)->this_id)
+#define subsystem_maxid(h) ((h)->max_id)
+#define ld(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_ld)
+#define get_ldn(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_get_ldn)
+#define get_scsi(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_get_scsi)
+#define local_checking_phase_flag(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_local_checking_phase_flag)
+#define got_interrupt(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_got_interrupt)
+#define stat_result(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_stat_result)
+#define reset_status(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_reset_status)
+#define last_scsi_command(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_command)
+#define last_scsi_type(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_type)
+#define last_scsi_blockcount(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_blockcount)
+#define last_scsi_logical_block(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_logical_block)
+#define last_scsi_type(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_type)
+#define next_ldn(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_next_ldn)
+#define IBM_DS(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_IBM_DS)
+#define special(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_special)
+#define subsystem_connector_size(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_connector_size)
+#define adapter_speed(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_adapter_speed)
+#define pos2(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[2])
+#define pos3(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[3])
+#define pos4(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[4])
+#define pos5(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[5])
+#define pos6(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[6])
/* Define a arbitrary number as subsystem-marker-type. This number is, as
described in the ANSI-SCSI-standard, not occupied by other device-types. */
@@ -459,11 +472,6 @@
/*counter of concurrent disk read/writes, to turn on/off disk led */
static int disk_rw_in_progress = 0;
-/* host information */
-static int found = 0;
-static struct Scsi_Host *hosts[IM_MAX_HOSTS + 1] = {
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
static unsigned int pos[8]; /* whole pos register-line for diagnosis */
/* Taking into account the additions, made by ZP Gu.
* This selects now the preset value from the configfile and
@@ -474,70 +482,68 @@
static char ibm_ansi_order = 0;
#endif
-static void issue_cmd(int, unsigned long, unsigned char);
+static void issue_cmd(struct Scsi_Host *, unsigned long, unsigned char);
static void internal_done(Scsi_Cmnd * cmd);
-static void check_devices(int, int);
-static int immediate_assign(int, unsigned int, unsigned int, unsigned int, unsigned int);
-static int immediate_feature(int, unsigned int, unsigned int);
+static void check_devices(struct Scsi_Host *, int);
+static int immediate_assign(struct Scsi_Host *, unsigned int, unsigned int, unsigned int, unsigned int);
+static int immediate_feature(struct Scsi_Host *, unsigned int, unsigned int);
#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
-static int immediate_reset(int, unsigned int);
+static int immediate_reset(struct Scsi_Host *, unsigned int);
#endif
-static int device_inquiry(int, int);
-static int read_capacity(int, int);
-static int get_pos_info(int);
+static int device_inquiry(struct Scsi_Host *, int);
+static int read_capacity(struct Scsi_Host *, int);
+static int get_pos_info(struct Scsi_Host *);
static char *ti_p(int);
static char *ti_l(int);
static char *ibmrate(unsigned int, int);
static int probe_display(int);
-static int probe_bus_mode(int);
-static int device_exists(int, int, int *, int *);
-static struct Scsi_Host *ibmmca_register(struct scsi_host_template *, int, int, int, char *);
+static int probe_bus_mode(struct Scsi_Host *);
+static int device_exists(struct Scsi_Host *, int, int *, int *);
static int option_setup(char *);
/* local functions needed for proc_info */
-static int ldn_access_load(int, int);
-static int ldn_access_total_read_write(int);
+static int ldn_access_load(struct Scsi_Host *, int);
+static int ldn_access_total_read_write(struct Scsi_Host *);
static irqreturn_t interrupt_handler(int irq, void *dev_id)
{
- int host_index, ihost_index;
unsigned int intr_reg;
unsigned int cmd_result;
unsigned int ldn;
+ unsigned long flags;
Scsi_Cmnd *cmd;
int lastSCSI;
- struct Scsi_Host *dev = dev_id;
+ struct device *dev = dev_id;
+ struct Scsi_Host *shpnt = dev_get_drvdata(dev);
- spin_lock(dev->host_lock);
- /* search for one adapter-response on shared interrupt */
- for (host_index = 0; hosts[host_index] && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST); host_index++);
- /* return if some other device on this IRQ caused the interrupt */
- if (!hosts[host_index]) {
- spin_unlock(dev->host_lock);
+ spin_lock_irqsave(shpnt->host_lock, flags);
+
+ if(!(inb(IM_STAT_REG(shpnt)) & IM_INTR_REQUEST)) {
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_NONE;
}
/* the reset-function already did all the job, even ints got
renabled on the subsystem, so just return */
- if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT) || (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT)) {
- reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS;
- spin_unlock(dev->host_lock);
+ if ((reset_status(shpnt) == IM_RESET_NOT_IN_PROGRESS_NO_INT) || (reset_status(shpnt) == IM_RESET_FINISHED_OK_NO_INT)) {
+ reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS;
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
}
/*must wait for attention reg not busy, then send EOI to subsystem */
while (1) {
- if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+ if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
break;
cpu_relax();
}
- ihost_index = host_index;
+
/*get command result and logical device */
- intr_reg = (unsigned char) (inb(IM_INTR_REG(ihost_index)));
+ intr_reg = (unsigned char) (inb(IM_INTR_REG(shpnt)));
cmd_result = intr_reg & 0xf0;
ldn = intr_reg & 0x0f;
/* get the last_scsi_command here */
- lastSCSI = last_scsi_command(ihost_index)[ldn];
- outb(IM_EOI | ldn, IM_ATTN_REG(ihost_index));
+ lastSCSI = last_scsi_command(shpnt)[ldn];
+ outb(IM_EOI | ldn, IM_ATTN_REG(shpnt));
/*these should never happen (hw fails, or a local programming bug) */
if (!global_command_error_excuse) {
@@ -547,38 +553,38 @@
case IM_SOFTWARE_SEQUENCING_ERROR:
case IM_CMD_ERROR:
printk(KERN_ERR "IBM MCA SCSI: Fatal Subsystem ERROR!\n");
- printk(KERN_ERR " Last cmd=0x%x, ena=%x, len=", lastSCSI, ld(ihost_index)[ldn].scb.enable);
- if (ld(ihost_index)[ldn].cmd)
- printk("%ld/%ld,", (long) (ld(ihost_index)[ldn].cmd->request_bufflen), (long) (ld(ihost_index)[ldn].scb.sys_buf_length));
+ printk(KERN_ERR " Last cmd=0x%x, ena=%x, len=", lastSCSI, ld(shpnt)[ldn].scb.enable);
+ if (ld(shpnt)[ldn].cmd)
+ printk("%ld/%ld,", (long) (scsi_bufflen(ld(shpnt)[ldn].cmd)), (long) (ld(shpnt)[ldn].scb.sys_buf_length));
else
printk("none,");
- if (ld(ihost_index)[ldn].cmd)
- printk("Blocksize=%d", ld(ihost_index)[ldn].scb.u2.blk.length);
+ if (ld(shpnt)[ldn].cmd)
+ printk("Blocksize=%d", ld(shpnt)[ldn].scb.u2.blk.length);
else
printk("Blocksize=none");
- printk(", host=0x%x, ldn=0x%x\n", ihost_index, ldn);
- if (ld(ihost_index)[ldn].cmd) {
- printk(KERN_ERR "Blockcount=%d/%d\n", last_scsi_blockcount(ihost_index)[ldn], ld(ihost_index)[ldn].scb.u2.blk.count);
- printk(KERN_ERR "Logical block=%lx/%lx\n", last_scsi_logical_block(ihost_index)[ldn], ld(ihost_index)[ldn].scb.u1.log_blk_adr);
+ printk(", host=%p, ldn=0x%x\n", shpnt, ldn);
+ if (ld(shpnt)[ldn].cmd) {
+ printk(KERN_ERR "Blockcount=%d/%d\n", last_scsi_blockcount(shpnt)[ldn], ld(shpnt)[ldn].scb.u2.blk.count);
+ printk(KERN_ERR "Logical block=%lx/%lx\n", last_scsi_logical_block(shpnt)[ldn], ld(shpnt)[ldn].scb.u1.log_blk_adr);
}
printk(KERN_ERR "Reason given: %s\n", (cmd_result == IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" : (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" : (cmd_result == IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN");
/* if errors appear, enter this section to give detailed info */
printk(KERN_ERR "IBM MCA SCSI: Subsystem Error-Status follows:\n");
- printk(KERN_ERR " Command Type................: %x\n", last_scsi_type(ihost_index)[ldn]);
- printk(KERN_ERR " Attention Register..........: %x\n", inb(IM_ATTN_REG(ihost_index)));
- printk(KERN_ERR " Basic Control Register......: %x\n", inb(IM_CTR_REG(ihost_index)));
+ printk(KERN_ERR " Command Type................: %x\n", last_scsi_type(shpnt)[ldn]);
+ printk(KERN_ERR " Attention Register..........: %x\n", inb(IM_ATTN_REG(shpnt)));
+ printk(KERN_ERR " Basic Control Register......: %x\n", inb(IM_CTR_REG(shpnt)));
printk(KERN_ERR " Interrupt Status Register...: %x\n", intr_reg);
- printk(KERN_ERR " Basic Status Register.......: %x\n", inb(IM_STAT_REG(ihost_index)));
- if ((last_scsi_type(ihost_index)[ldn] == IM_SCB) || (last_scsi_type(ihost_index)[ldn] == IM_LONG_SCB)) {
- printk(KERN_ERR " SCB-Command.................: %x\n", ld(ihost_index)[ldn].scb.command);
- printk(KERN_ERR " SCB-Enable..................: %x\n", ld(ihost_index)[ldn].scb.enable);
- printk(KERN_ERR " SCB-logical block address...: %lx\n", ld(ihost_index)[ldn].scb.u1.log_blk_adr);
- printk(KERN_ERR " SCB-system buffer address...: %lx\n", ld(ihost_index)[ldn].scb.sys_buf_adr);
- printk(KERN_ERR " SCB-system buffer length....: %lx\n", ld(ihost_index)[ldn].scb.sys_buf_length);
- printk(KERN_ERR " SCB-tsb address.............: %lx\n", ld(ihost_index)[ldn].scb.tsb_adr);
- printk(KERN_ERR " SCB-Chain address...........: %lx\n", ld(ihost_index)[ldn].scb.scb_chain_adr);
- printk(KERN_ERR " SCB-block count.............: %x\n", ld(ihost_index)[ldn].scb.u2.blk.count);
- printk(KERN_ERR " SCB-block length............: %x\n", ld(ihost_index)[ldn].scb.u2.blk.length);
+ printk(KERN_ERR " Basic Status Register.......: %x\n", inb(IM_STAT_REG(shpnt)));
+ if ((last_scsi_type(shpnt)[ldn] == IM_SCB) || (last_scsi_type(shpnt)[ldn] == IM_LONG_SCB)) {
+ printk(KERN_ERR " SCB-Command.................: %x\n", ld(shpnt)[ldn].scb.command);
+ printk(KERN_ERR " SCB-Enable..................: %x\n", ld(shpnt)[ldn].scb.enable);
+ printk(KERN_ERR " SCB-logical block address...: %lx\n", ld(shpnt)[ldn].scb.u1.log_blk_adr);
+ printk(KERN_ERR " SCB-system buffer address...: %lx\n", ld(shpnt)[ldn].scb.sys_buf_adr);
+ printk(KERN_ERR " SCB-system buffer length....: %lx\n", ld(shpnt)[ldn].scb.sys_buf_length);
+ printk(KERN_ERR " SCB-tsb address.............: %lx\n", ld(shpnt)[ldn].scb.tsb_adr);
+ printk(KERN_ERR " SCB-Chain address...........: %lx\n", ld(shpnt)[ldn].scb.scb_chain_adr);
+ printk(KERN_ERR " SCB-block count.............: %x\n", ld(shpnt)[ldn].scb.u2.blk.count);
+ printk(KERN_ERR " SCB-block length............: %x\n", ld(shpnt)[ldn].scb.u2.blk.length);
}
printk(KERN_ERR " Send this report to the maintainer.\n");
panic("IBM MCA SCSI: Fatal error message from the subsystem (0x%X,0x%X)!\n", lastSCSI, cmd_result);
@@ -600,72 +606,73 @@
}
}
/* if no panic appeared, increase the interrupt-counter */
- IBM_DS(ihost_index).total_interrupts++;
+ IBM_DS(shpnt).total_interrupts++;
/*only for local checking phase */
- if (local_checking_phase_flag(ihost_index)) {
- stat_result(ihost_index) = cmd_result;
- got_interrupt(ihost_index) = 1;
- reset_status(ihost_index) = IM_RESET_FINISHED_OK;
- last_scsi_command(ihost_index)[ldn] = NO_SCSI;
- spin_unlock(dev->host_lock);
+ if (local_checking_phase_flag(shpnt)) {
+ stat_result(shpnt) = cmd_result;
+ got_interrupt(shpnt) = 1;
+ reset_status(shpnt) = IM_RESET_FINISHED_OK;
+ last_scsi_command(shpnt)[ldn] = NO_SCSI;
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
}
/* handling of commands coming from upper level of scsi driver */
- if (last_scsi_type(ihost_index)[ldn] == IM_IMM_CMD) {
+ if (last_scsi_type(shpnt)[ldn] == IM_IMM_CMD) {
/* verify ldn, and may handle rare reset immediate command */
- if ((reset_status(ihost_index) == IM_RESET_IN_PROGRESS) && (last_scsi_command(ihost_index)[ldn] == IM_RESET_IMM_CMD)) {
+ if ((reset_status(shpnt) == IM_RESET_IN_PROGRESS) && (last_scsi_command(shpnt)[ldn] == IM_RESET_IMM_CMD)) {
if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
disk_rw_in_progress = 0;
PS2_DISK_LED_OFF();
- reset_status(ihost_index) = IM_RESET_FINISHED_FAIL;
+ reset_status(shpnt) = IM_RESET_FINISHED_FAIL;
} else {
/*reset disk led counter, turn off disk led */
disk_rw_in_progress = 0;
PS2_DISK_LED_OFF();
- reset_status(ihost_index) = IM_RESET_FINISHED_OK;
+ reset_status(shpnt) = IM_RESET_FINISHED_OK;
}
- stat_result(ihost_index) = cmd_result;
- last_scsi_command(ihost_index)[ldn] = NO_SCSI;
- last_scsi_type(ihost_index)[ldn] = 0;
- spin_unlock(dev->host_lock);
+ stat_result(shpnt) = cmd_result;
+ last_scsi_command(shpnt)[ldn] = NO_SCSI;
+ last_scsi_type(shpnt)[ldn] = 0;
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
- } else if (last_scsi_command(ihost_index)[ldn] == IM_ABORT_IMM_CMD) {
+ } else if (last_scsi_command(shpnt)[ldn] == IM_ABORT_IMM_CMD) {
/* react on SCSI abort command */
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n");
#endif
disk_rw_in_progress = 0;
PS2_DISK_LED_OFF();
- cmd = ld(ihost_index)[ldn].cmd;
- ld(ihost_index)[ldn].cmd = NULL;
+ cmd = ld(shpnt)[ldn].cmd;
+ ld(shpnt)[ldn].cmd = NULL;
if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
cmd->result = DID_NO_CONNECT << 16;
else
cmd->result = DID_ABORT << 16;
- stat_result(ihost_index) = cmd_result;
- last_scsi_command(ihost_index)[ldn] = NO_SCSI;
- last_scsi_type(ihost_index)[ldn] = 0;
+ stat_result(shpnt) = cmd_result;
+ last_scsi_command(shpnt)[ldn] = NO_SCSI;
+ last_scsi_type(shpnt)[ldn] = 0;
if (cmd->scsi_done)
(cmd->scsi_done) (cmd); /* should be the internal_done */
- spin_unlock(dev->host_lock);
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
} else {
disk_rw_in_progress = 0;
PS2_DISK_LED_OFF();
- reset_status(ihost_index) = IM_RESET_FINISHED_OK;
- stat_result(ihost_index) = cmd_result;
- last_scsi_command(ihost_index)[ldn] = NO_SCSI;
- spin_unlock(dev->host_lock);
+ reset_status(shpnt) = IM_RESET_FINISHED_OK;
+ stat_result(shpnt) = cmd_result;
+ last_scsi_command(shpnt)[ldn] = NO_SCSI;
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
}
}
- last_scsi_command(ihost_index)[ldn] = NO_SCSI;
- last_scsi_type(ihost_index)[ldn] = 0;
- cmd = ld(ihost_index)[ldn].cmd;
- ld(ihost_index)[ldn].cmd = NULL;
+ last_scsi_command(shpnt)[ldn] = NO_SCSI;
+ last_scsi_type(shpnt)[ldn] = 0;
+ cmd = ld(shpnt)[ldn].cmd;
+ ld(shpnt)[ldn].cmd = NULL;
#ifdef IM_DEBUG_TIMEOUT
if (cmd) {
if ((cmd->target == TIMEOUT_PUN) && (cmd->device->lun == TIMEOUT_LUN)) {
+ spin_unlock_irqsave(shpnt->host_lock, flags);
printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n", cmd->target, cmd->device->lun);
return IRQ_HANDLED;
}
@@ -674,15 +681,15 @@
/*if no command structure, just return, else clear cmd */
if (!cmd)
{
- spin_unlock(dev->host_lock);
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
}
#ifdef IM_DEBUG_INT
- printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", cmd->cmnd[0], intr_reg, ld(ihost_index)[ldn].tsb.dev_status, ld(ihost_index)[ldn].tsb.cmd_status, ld(ihost_index)[ldn].tsb.dev_error, ld(ihost_index)[ldn].tsb.cmd_error);
+ printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", cmd->cmnd[0], intr_reg, ld(shpnt)[ldn].tsb.dev_status, ld(shpnt)[ldn].tsb.cmd_status, ld(shpnt)[ldn].tsb.dev_error, ld(shpnt)[ldn].tsb.cmd_error);
#endif
/*if this is end of media read/write, may turn off PS/2 disk led */
- if ((ld(ihost_index)[ldn].device_type != TYPE_NO_LUN) && (ld(ihost_index)[ldn].device_type != TYPE_NO_DEVICE)) {
+ if ((ld(shpnt)[ldn].device_type != TYPE_NO_LUN) && (ld(shpnt)[ldn].device_type != TYPE_NO_DEVICE)) {
/* only access this, if there was a valid device addressed */
if (--disk_rw_in_progress == 0)
PS2_DISK_LED_OFF();
@@ -693,8 +700,8 @@
* adapters do not support CMD_TERMINATED, TASK_SET_FULL and
* ACA_ACTIVE as returning statusbyte information. (ML) */
if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
- cmd->result = (unsigned char) (ld(ihost_index)[ldn].tsb.dev_status & 0x1e);
- IBM_DS(ihost_index).total_errors++;
+ cmd->result = (unsigned char) (ld(shpnt)[ldn].tsb.dev_status & 0x1e);
+ IBM_DS(shpnt).total_errors++;
} else
cmd->result = 0;
/* write device status into cmd->result, and call done function */
@@ -705,24 +712,25 @@
cmd->result |= DID_OK << 16;
if (cmd->scsi_done)
(cmd->scsi_done) (cmd);
- spin_unlock(dev->host_lock);
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
}
-static void issue_cmd(int host_index, unsigned long cmd_reg, unsigned char attn_reg)
+static void issue_cmd(struct Scsi_Host *shpnt, unsigned long cmd_reg,
+ unsigned char attn_reg)
{
unsigned long flags;
/* must wait for attention reg not busy */
while (1) {
- spin_lock_irqsave(hosts[host_index]->host_lock, flags);
- if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+ spin_lock_irqsave(shpnt->host_lock, flags);
+ if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
break;
- spin_unlock_irqrestore(hosts[host_index]->host_lock, flags);
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
}
/* write registers and enable system interrupts */
- outl(cmd_reg, IM_CMD_REG(host_index));
- outb(attn_reg, IM_ATTN_REG(host_index));
- spin_unlock_irqrestore(hosts[host_index]->host_lock, flags);
+ outl(cmd_reg, IM_CMD_REG(shpnt));
+ outb(attn_reg, IM_ATTN_REG(shpnt));
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
}
static void internal_done(Scsi_Cmnd * cmd)
@@ -732,34 +740,34 @@
}
/* SCSI-SCB-command for device_inquiry */
-static int device_inquiry(int host_index, int ldn)
+static int device_inquiry(struct Scsi_Host *shpnt, int ldn)
{
int retr;
struct im_scb *scb;
struct im_tsb *tsb;
unsigned char *buf;
- scb = &(ld(host_index)[ldn].scb);
- tsb = &(ld(host_index)[ldn].tsb);
- buf = (unsigned char *) (&(ld(host_index)[ldn].buf));
- ld(host_index)[ldn].tsb.dev_status = 0; /* prepare statusblock */
+ scb = &(ld(shpnt)[ldn].scb);
+ tsb = &(ld(shpnt)[ldn].tsb);
+ buf = (unsigned char *) (&(ld(shpnt)[ldn].buf));
+ ld(shpnt)[ldn].tsb.dev_status = 0; /* prepare statusblock */
for (retr = 0; retr < 3; retr++) {
/* fill scb with inquiry command */
scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT;
scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
- last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD;
- last_scsi_type(host_index)[ldn] = IM_SCB;
+ last_scsi_command(shpnt)[ldn] = IM_DEVICE_INQUIRY_CMD;
+ last_scsi_type(shpnt)[ldn] = IM_SCB;
scb->sys_buf_adr = isa_virt_to_bus(buf);
scb->sys_buf_length = 255; /* maximum bufferlength gives max info */
scb->tsb_adr = isa_virt_to_bus(tsb);
/* issue scb to passed ldn, and busy wait for interrupt */
- got_interrupt(host_index) = 0;
- issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
- while (!got_interrupt(host_index))
+ got_interrupt(shpnt) = 0;
+ issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn);
+ while (!got_interrupt(shpnt))
barrier();
/*if command successful, break */
- if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+ if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
return 1;
}
/*if all three retries failed, return "no device at this ldn" */
@@ -769,34 +777,34 @@
return 1;
}
-static int read_capacity(int host_index, int ldn)
+static int read_capacity(struct Scsi_Host *shpnt, int ldn)
{
int retr;
struct im_scb *scb;
struct im_tsb *tsb;
unsigned char *buf;
- scb = &(ld(host_index)[ldn].scb);
- tsb = &(ld(host_index)[ldn].tsb);
- buf = (unsigned char *) (&(ld(host_index)[ldn].buf));
- ld(host_index)[ldn].tsb.dev_status = 0;
+ scb = &(ld(shpnt)[ldn].scb);
+ tsb = &(ld(shpnt)[ldn].tsb);
+ buf = (unsigned char *) (&(ld(shpnt)[ldn].buf));
+ ld(shpnt)[ldn].tsb.dev_status = 0;
for (retr = 0; retr < 3; retr++) {
/*fill scb with read capacity command */
scb->command = IM_READ_CAPACITY_CMD;
scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
- last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD;
- last_scsi_type(host_index)[ldn] = IM_SCB;
+ last_scsi_command(shpnt)[ldn] = IM_READ_CAPACITY_CMD;
+ last_scsi_type(shpnt)[ldn] = IM_SCB;
scb->sys_buf_adr = isa_virt_to_bus(buf);
scb->sys_buf_length = 8;
scb->tsb_adr = isa_virt_to_bus(tsb);
/*issue scb to passed ldn, and busy wait for interrupt */
- got_interrupt(host_index) = 0;
- issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
- while (!got_interrupt(host_index))
+ got_interrupt(shpnt) = 0;
+ issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn);
+ while (!got_interrupt(shpnt))
barrier();
/*if got capacity, get block length and return one device found */
- if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+ if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
return 1;
}
/*if all three retries failed, return "no device at this ldn" */
@@ -806,39 +814,39 @@
return 1;
}
-static int get_pos_info(int host_index)
+static int get_pos_info(struct Scsi_Host *shpnt)
{
int retr;
struct im_scb *scb;
struct im_tsb *tsb;
unsigned char *buf;
- scb = &(ld(host_index)[MAX_LOG_DEV].scb);
- tsb = &(ld(host_index)[MAX_LOG_DEV].tsb);
- buf = (unsigned char *) (&(ld(host_index)[MAX_LOG_DEV].buf));
- ld(host_index)[MAX_LOG_DEV].tsb.dev_status = 0;
+ scb = &(ld(shpnt)[MAX_LOG_DEV].scb);
+ tsb = &(ld(shpnt)[MAX_LOG_DEV].tsb);
+ buf = (unsigned char *) (&(ld(shpnt)[MAX_LOG_DEV].buf));
+ ld(shpnt)[MAX_LOG_DEV].tsb.dev_status = 0;
for (retr = 0; retr < 3; retr++) {
/*fill scb with get_pos_info command */
scb->command = IM_GET_POS_INFO_CMD;
scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
- last_scsi_command(host_index)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD;
- last_scsi_type(host_index)[MAX_LOG_DEV] = IM_SCB;
+ last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD;
+ last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_SCB;
scb->sys_buf_adr = isa_virt_to_bus(buf);
- if (special(host_index) == IBM_SCSI2_FW)
+ if (special(shpnt) == IBM_SCSI2_FW)
scb->sys_buf_length = 256; /* get all info from F/W adapter */
else
scb->sys_buf_length = 18; /* get exactly 18 bytes for other SCSI */
scb->tsb_adr = isa_virt_to_bus(tsb);
/*issue scb to ldn=15, and busy wait for interrupt */
- got_interrupt(host_index) = 0;
- issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | MAX_LOG_DEV);
+ got_interrupt(shpnt) = 0;
+ issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | MAX_LOG_DEV);
/* FIXME: timeout */
- while (!got_interrupt(host_index))
+ while (!got_interrupt(shpnt))
barrier();
/*if got POS-stuff, get block length and return one device found */
- if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+ if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
return 1;
}
/* if all three retries failed, return "no device at this ldn" */
@@ -851,14 +859,16 @@
/* SCSI-immediate-command for assign. This functions maps/unmaps specific
ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the
subsystem and for dynamical remapping od ldns. */
-static int immediate_assign(int host_index, unsigned int pun, unsigned int lun, unsigned int ldn, unsigned int operation)
+static int immediate_assign(struct Scsi_Host *shpnt, unsigned int pun,
+ unsigned int lun, unsigned int ldn,
+ unsigned int operation)
{
int retr;
unsigned long imm_cmd;
for (retr = 0; retr < 3; retr++) {
/* select mutation level of the SCSI-adapter */
- switch (special(host_index)) {
+ switch (special(shpnt)) {
case IBM_SCSI2_FW:
imm_cmd = (unsigned long) (IM_ASSIGN_IMM_CMD);
imm_cmd |= (unsigned long) ((lun & 7) << 24);
@@ -867,7 +877,7 @@
imm_cmd |= (unsigned long) ((ldn & 15) << 16);
break;
default:
- imm_cmd = inl(IM_CMD_REG(host_index));
+ imm_cmd = inl(IM_CMD_REG(shpnt));
imm_cmd &= (unsigned long) (0xF8000000); /* keep reserved bits */
imm_cmd |= (unsigned long) (IM_ASSIGN_IMM_CMD);
imm_cmd |= (unsigned long) ((lun & 7) << 24);
@@ -876,15 +886,15 @@
imm_cmd |= (unsigned long) ((ldn & 15) << 16);
break;
}
- last_scsi_command(host_index)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD;
- last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
- got_interrupt(host_index) = 0;
- issue_cmd(host_index, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
- while (!got_interrupt(host_index))
+ last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD;
+ last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_IMM_CMD;
+ got_interrupt(shpnt) = 0;
+ issue_cmd(shpnt, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
+ while (!got_interrupt(shpnt))
barrier();
/*if command successful, break */
- if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+ if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED)
return 1;
}
if (retr >= 3)
@@ -893,7 +903,7 @@
return 1;
}
-static int immediate_feature(int host_index, unsigned int speed, unsigned int timeout)
+static int immediate_feature(struct Scsi_Host *shpnt, unsigned int speed, unsigned int timeout)
{
int retr;
unsigned long imm_cmd;
@@ -903,16 +913,16 @@
imm_cmd = IM_FEATURE_CTR_IMM_CMD;
imm_cmd |= (unsigned long) ((speed & 0x7) << 29);
imm_cmd |= (unsigned long) ((timeout & 0x1fff) << 16);
- last_scsi_command(host_index)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD;
- last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
- got_interrupt(host_index) = 0;
+ last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD;
+ last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_IMM_CMD;
+ got_interrupt(shpnt) = 0;
/* we need to run into command errors in order to probe for the
* right speed! */
global_command_error_excuse = 1;
- issue_cmd(host_index, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
+ issue_cmd(shpnt, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
/* FIXME: timeout */
- while (!got_interrupt(host_index))
+ while (!got_interrupt(shpnt))
barrier();
if (global_command_error_excuse == CMD_FAIL) {
global_command_error_excuse = 0;
@@ -920,7 +930,7 @@
} else
global_command_error_excuse = 0;
/*if command successful, break */
- if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+ if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED)
return 1;
}
if (retr >= 3)
@@ -930,35 +940,35 @@
}
#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
-static int immediate_reset(int host_index, unsigned int ldn)
+static int immediate_reset(struct Scsi_Host *shpnt, unsigned int ldn)
{
int retries;
int ticks;
unsigned long imm_command;
for (retries = 0; retries < 3; retries++) {
- imm_command = inl(IM_CMD_REG(host_index));
+ imm_command = inl(IM_CMD_REG(shpnt));
imm_command &= (unsigned long) (0xFFFF0000); /* keep reserved bits */
imm_command |= (unsigned long) (IM_RESET_IMM_CMD);
- last_scsi_command(host_index)[ldn] = IM_RESET_IMM_CMD;
- last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
- got_interrupt(host_index) = 0;
- reset_status(host_index) = IM_RESET_IN_PROGRESS;
- issue_cmd(host_index, (unsigned long) (imm_command), IM_IMM_CMD | ldn);
+ last_scsi_command(shpnt)[ldn] = IM_RESET_IMM_CMD;
+ last_scsi_type(shpnt)[ldn] = IM_IMM_CMD;
+ got_interrupt(shpnt) = 0;
+ reset_status(shpnt) = IM_RESET_IN_PROGRESS;
+ issue_cmd(shpnt, (unsigned long) (imm_command), IM_IMM_CMD | ldn);
ticks = IM_RESET_DELAY * HZ;
- while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks) {
+ while (reset_status(shpnt) == IM_RESET_IN_PROGRESS && --ticks) {
udelay((1 + 999 / HZ) * 1000);
barrier();
}
/* if reset did not complete, just complain */
if (!ticks) {
printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY);
- reset_status(host_index) = IM_RESET_FINISHED_OK;
+ reset_status(shpnt) = IM_RESET_FINISHED_OK;
/* did not work, finish */
return 1;
}
/*if command successful, break */
- if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+ if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED)
return 1;
}
if (retries >= 3)
@@ -1060,35 +1070,35 @@
return 0;
}
-static int probe_bus_mode(int host_index)
+static int probe_bus_mode(struct Scsi_Host *shpnt)
{
struct im_pos_info *info;
int num_bus = 0;
int ldn;
- info = (struct im_pos_info *) (&(ld(host_index)[MAX_LOG_DEV].buf));
- if (get_pos_info(host_index)) {
+ info = (struct im_pos_info *) (&(ld(shpnt)[MAX_LOG_DEV].buf));
+ if (get_pos_info(shpnt)) {
if (info->connector_size & 0xf000)
- subsystem_connector_size(host_index) = 16;
+ subsystem_connector_size(shpnt) = 16;
else
- subsystem_connector_size(host_index) = 32;
+ subsystem_connector_size(shpnt) = 32;
num_bus |= (info->pos_4b & 8) >> 3;
for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
- if ((special(host_index) == IBM_SCSI_WCACHE) || (special(host_index) == IBM_7568_WCACHE)) {
+ if ((special(shpnt) == IBM_SCSI_WCACHE) || (special(shpnt) == IBM_7568_WCACHE)) {
if (!((info->cache_stat >> ldn) & 1))
- ld(host_index)[ldn].cache_flag = 0;
+ ld(shpnt)[ldn].cache_flag = 0;
}
if (!((info->retry_stat >> ldn) & 1))
- ld(host_index)[ldn].retry_flag = 0;
+ ld(shpnt)[ldn].retry_flag = 0;
}
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: SCSI-Cache bits: ");
for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
- printk("%d", ld(host_index)[ldn].cache_flag);
+ printk("%d", ld(shpnt)[ldn].cache_flag);
}
printk("\nIBM MCA SCSI: SCSI-Retry bits: ");
for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
- printk("%d", ld(host_index)[ldn].retry_flag);
+ printk("%d", ld(shpnt)[ldn].retry_flag);
}
printk("\n");
#endif
@@ -1097,7 +1107,7 @@
}
/* probing scsi devices */
-static void check_devices(int host_index, int adaptertype)
+static void check_devices(struct Scsi_Host *shpnt, int adaptertype)
{
int id, lun, ldn, ticks;
int count_devices; /* local counter for connected device */
@@ -1108,24 +1118,24 @@
/* assign default values to certain variables */
ticks = 0;
count_devices = 0;
- IBM_DS(host_index).dyn_flag = 0; /* normally no need for dynamical ldn management */
- IBM_DS(host_index).total_errors = 0; /* set errorcounter to 0 */
- next_ldn(host_index) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired' */
+ IBM_DS(shpnt).dyn_flag = 0; /* normally no need for dynamical ldn management */
+ IBM_DS(shpnt).total_errors = 0; /* set errorcounter to 0 */
+ next_ldn(shpnt) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired' */
/* initialize the very important driver-informational arrays/structs */
- memset(ld(host_index), 0, sizeof(ld(host_index)));
+ memset(ld(shpnt), 0, sizeof(ld(shpnt)));
for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
- last_scsi_command(host_index)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */
- last_scsi_type(host_index)[ldn] = 0;
- ld(host_index)[ldn].cache_flag = 1;
- ld(host_index)[ldn].retry_flag = 1;
+ last_scsi_command(shpnt)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */
+ last_scsi_type(shpnt)[ldn] = 0;
+ ld(shpnt)[ldn].cache_flag = 1;
+ ld(shpnt)[ldn].retry_flag = 1;
}
- memset(get_ldn(host_index), TYPE_NO_DEVICE, sizeof(get_ldn(host_index))); /* this is essential ! */
- memset(get_scsi(host_index), TYPE_NO_DEVICE, sizeof(get_scsi(host_index))); /* this is essential ! */
+ memset(get_ldn(shpnt), TYPE_NO_DEVICE, sizeof(get_ldn(shpnt))); /* this is essential ! */
+ memset(get_scsi(shpnt), TYPE_NO_DEVICE, sizeof(get_scsi(shpnt))); /* this is essential ! */
for (lun = 0; lun < 8; lun++) {
/* mark the adapter at its pun on all luns */
- get_scsi(host_index)[subsystem_pun(host_index)][lun] = TYPE_IBM_SCSI_ADAPTER;
- get_ldn(host_index)[subsystem_pun(host_index)][lun] = MAX_LOG_DEV; /* make sure, the subsystem
+ get_scsi(shpnt)[subsystem_pun(shpnt)][lun] = TYPE_IBM_SCSI_ADAPTER;
+ get_ldn(shpnt)[subsystem_pun(shpnt)][lun] = MAX_LOG_DEV; /* make sure, the subsystem
ldn is active for all
luns. */
}
@@ -1134,9 +1144,9 @@
/* monitor connected on model XX95. */
/* STEP 1: */
- adapter_speed(host_index) = global_adapter_speed;
- speedrun = adapter_speed(host_index);
- while (immediate_feature(host_index, speedrun, adapter_timeout) == 2) {
+ adapter_speed(shpnt) = global_adapter_speed;
+ speedrun = adapter_speed(shpnt);
+ while (immediate_feature(shpnt, speedrun, adapter_timeout) == 2) {
probe_display(1);
if (speedrun == 7)
panic("IBM MCA SCSI: Cannot set Synchronous-Transfer-Rate!\n");
@@ -1144,30 +1154,30 @@
if (speedrun > 7)
speedrun = 7;
}
- adapter_speed(host_index) = speedrun;
+ adapter_speed(shpnt) = speedrun;
/* Get detailed information about the current adapter, necessary for
* device operations: */
- num_bus = probe_bus_mode(host_index);
+ num_bus = probe_bus_mode(shpnt);
/* num_bus contains only valid data for the F/W adapter! */
if (adaptertype == IBM_SCSI2_FW) { /* F/W SCSI adapter: */
/* F/W adapter PUN-space extension evaluation: */
if (num_bus) {
printk(KERN_INFO "IBM MCA SCSI: Separate bus mode (wide-addressing enabled)\n");
- subsystem_maxid(host_index) = 16;
+ subsystem_maxid(shpnt) = 16;
} else {
printk(KERN_INFO "IBM MCA SCSI: Combined bus mode (wide-addressing disabled)\n");
- subsystem_maxid(host_index) = 8;
+ subsystem_maxid(shpnt) = 8;
}
printk(KERN_INFO "IBM MCA SCSI: Sync.-Rate (F/W: 20, Int.: 10, Ext.: %s) MBytes/s\n", ibmrate(speedrun, adaptertype));
} else /* all other IBM SCSI adapters: */
printk(KERN_INFO "IBM MCA SCSI: Synchronous-SCSI-Transfer-Rate: %s MBytes/s\n", ibmrate(speedrun, adaptertype));
/* assign correct PUN device space */
- max_pun = subsystem_maxid(host_index);
+ max_pun = subsystem_maxid(shpnt);
#ifdef IM_DEBUG_PROBE
- printk("IBM MCA SCSI: Current SCSI-host index: %d\n", host_index);
+ printk("IBM MCA SCSI: Current SCSI-host index: %d\n", shpnt);
printk("IBM MCA SCSI: Removing default logical SCSI-device mapping.");
#else
printk(KERN_INFO "IBM MCA SCSI: Dev. Order: %s, Mapping (takes <2min): ", (ibm_ansi_order) ? "ANSI" : "New");
@@ -1177,7 +1187,7 @@
#ifdef IM_DEBUG_PROBE
printk(".");
#endif
- immediate_assign(host_index, 0, 0, ldn, REMOVE_LDN); /* remove ldn (wherever) */
+ immediate_assign(shpnt, 0, 0, ldn, REMOVE_LDN); /* remove ldn (wherever) */
}
lun = 0; /* default lun is 0 */
#ifndef IM_DEBUG_PROBE
@@ -1196,18 +1206,18 @@
#ifdef IM_DEBUG_PROBE
printk(".");
#endif
- if (id != subsystem_pun(host_index)) {
+ if (id != subsystem_pun(shpnt)) {
/* if pun is not the adapter: */
/* set ldn=0 to pun,lun */
- immediate_assign(host_index, id, lun, PROBE_LDN, SET_LDN);
- if (device_inquiry(host_index, PROBE_LDN)) { /* probe device */
- get_scsi(host_index)[id][lun] = (unsigned char) (ld(host_index)[PROBE_LDN].buf[0]);
+ immediate_assign(shpnt, id, lun, PROBE_LDN, SET_LDN);
+ if (device_inquiry(shpnt, PROBE_LDN)) { /* probe device */
+ get_scsi(shpnt)[id][lun] = (unsigned char) (ld(shpnt)[PROBE_LDN].buf[0]);
/* entry, even for NO_LUN */
- if (ld(host_index)[PROBE_LDN].buf[0] != TYPE_NO_LUN)
+ if (ld(shpnt)[PROBE_LDN].buf[0] != TYPE_NO_LUN)
count_devices++; /* a existing device is found */
}
/* remove ldn */
- immediate_assign(host_index, id, lun, PROBE_LDN, REMOVE_LDN);
+ immediate_assign(shpnt, id, lun, PROBE_LDN, REMOVE_LDN);
}
}
#ifndef IM_DEBUG_PROBE
@@ -1227,16 +1237,16 @@
#ifdef IM_DEBUG_PROBE
printk(".");
#endif
- if (id != subsystem_pun(host_index)) {
- if (get_scsi(host_index)[id][lun] != TYPE_NO_LUN && get_scsi(host_index)[id][lun] != TYPE_NO_DEVICE) {
+ if (id != subsystem_pun(shpnt)) {
+ if (get_scsi(shpnt)[id][lun] != TYPE_NO_LUN && get_scsi(shpnt)[id][lun] != TYPE_NO_DEVICE) {
/* Only map if accepted type. Always enter for
lun == 0 to get no gaps into ldn-mapping for ldn<7. */
- immediate_assign(host_index, id, lun, ldn, SET_LDN);
- get_ldn(host_index)[id][lun] = ldn; /* map ldn */
- if (device_exists(host_index, ldn, &ld(host_index)[ldn].block_length, &ld(host_index)[ldn].device_type)) {
+ immediate_assign(shpnt, id, lun, ldn, SET_LDN);
+ get_ldn(shpnt)[id][lun] = ldn; /* map ldn */
+ if (device_exists(shpnt, ldn, &ld(shpnt)[ldn].block_length, &ld(shpnt)[ldn].device_type)) {
#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
printk("resetting device at ldn=%x ... ", ldn);
- immediate_reset(host_index, ldn);
+ immediate_reset(shpnt, ldn);
#endif
ldn++;
} else {
@@ -1244,15 +1254,15 @@
* handle it or because it has problems */
if (lun > 0) {
/* remove mapping */
- get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE;
- immediate_assign(host_index, 0, 0, ldn, REMOVE_LDN);
+ get_ldn(shpnt)[id][lun] = TYPE_NO_DEVICE;
+ immediate_assign(shpnt, 0, 0, ldn, REMOVE_LDN);
} else
ldn++;
}
} else if (lun == 0) {
/* map lun == 0, even if no device exists */
- immediate_assign(host_index, id, lun, ldn, SET_LDN);
- get_ldn(host_index)[id][lun] = ldn; /* map ldn */
+ immediate_assign(shpnt, id, lun, ldn, SET_LDN);
+ get_ldn(shpnt)[id][lun] = ldn; /* map ldn */
ldn++;
}
}
@@ -1262,14 +1272,14 @@
/* map remaining ldns to non-existing devices */
for (lun = 1; lun < 8 && ldn < MAX_LOG_DEV; lun++)
for (id = 0; id < max_pun && ldn < MAX_LOG_DEV; id++) {
- if (get_scsi(host_index)[id][lun] == TYPE_NO_LUN || get_scsi(host_index)[id][lun] == TYPE_NO_DEVICE) {
+ if (get_scsi(shpnt)[id][lun] == TYPE_NO_LUN || get_scsi(shpnt)[id][lun] == TYPE_NO_DEVICE) {
probe_display(1);
/* Map remaining ldns only to NON-existing pun,lun
combinations to make sure an inquiry will fail.
For MULTI_LUN, it is needed to avoid adapter autonome
SCSI-remapping. */
- immediate_assign(host_index, id, lun, ldn, SET_LDN);
- get_ldn(host_index)[id][lun] = ldn;
+ immediate_assign(shpnt, id, lun, ldn, SET_LDN);
+ get_ldn(shpnt)[id][lun] = ldn;
ldn++;
}
}
@@ -1292,51 +1302,51 @@
for (id = 0; id < max_pun; id++) {
printk("%2d ", id);
for (lun = 0; lun < 8; lun++)
- printk("%2s ", ti_p(get_scsi(host_index)[id][lun]));
+ printk("%2s ", ti_p(get_scsi(shpnt)[id][lun]));
printk(" %2d ", id);
for (lun = 0; lun < 8; lun++)
- printk("%2s ", ti_l(get_ldn(host_index)[id][lun]));
+ printk("%2s ", ti_l(get_ldn(shpnt)[id][lun]));
printk("\n");
}
#endif
/* assign total number of found SCSI-devices to the statistics struct */
- IBM_DS(host_index).total_scsi_devices = count_devices;
+ IBM_DS(shpnt).total_scsi_devices = count_devices;
/* decide for output in /proc-filesystem, if the configuration of
SCSI-devices makes dynamical reassignment of devices necessary */
if (count_devices >= MAX_LOG_DEV)
- IBM_DS(host_index).dyn_flag = 1; /* dynamical assignment is necessary */
+ IBM_DS(shpnt).dyn_flag = 1; /* dynamical assignment is necessary */
else
- IBM_DS(host_index).dyn_flag = 0; /* dynamical assignment is not necessary */
+ IBM_DS(shpnt).dyn_flag = 0; /* dynamical assignment is not necessary */
/* If no SCSI-devices are assigned, return 1 in order to cause message. */
if (ldn == 0)
printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n");
/* reset the counters for statistics on the current adapter */
- IBM_DS(host_index).scbs = 0;
- IBM_DS(host_index).long_scbs = 0;
- IBM_DS(host_index).total_accesses = 0;
- IBM_DS(host_index).total_interrupts = 0;
- IBM_DS(host_index).dynamical_assignments = 0;
- memset(IBM_DS(host_index).ldn_access, 0x0, sizeof(IBM_DS(host_index).ldn_access));
- memset(IBM_DS(host_index).ldn_read_access, 0x0, sizeof(IBM_DS(host_index).ldn_read_access));
- memset(IBM_DS(host_index).ldn_write_access, 0x0, sizeof(IBM_DS(host_index).ldn_write_access));
- memset(IBM_DS(host_index).ldn_inquiry_access, 0x0, sizeof(IBM_DS(host_index).ldn_inquiry_access));
- memset(IBM_DS(host_index).ldn_modeselect_access, 0x0, sizeof(IBM_DS(host_index).ldn_modeselect_access));
- memset(IBM_DS(host_index).ldn_assignments, 0x0, sizeof(IBM_DS(host_index).ldn_assignments));
+ IBM_DS(shpnt).scbs = 0;
+ IBM_DS(shpnt).long_scbs = 0;
+ IBM_DS(shpnt).total_accesses = 0;
+ IBM_DS(shpnt).total_interrupts = 0;
+ IBM_DS(shpnt).dynamical_assignments = 0;
+ memset(IBM_DS(shpnt).ldn_access, 0x0, sizeof(IBM_DS(shpnt).ldn_access));
+ memset(IBM_DS(shpnt).ldn_read_access, 0x0, sizeof(IBM_DS(shpnt).ldn_read_access));
+ memset(IBM_DS(shpnt).ldn_write_access, 0x0, sizeof(IBM_DS(shpnt).ldn_write_access));
+ memset(IBM_DS(shpnt).ldn_inquiry_access, 0x0, sizeof(IBM_DS(shpnt).ldn_inquiry_access));
+ memset(IBM_DS(shpnt).ldn_modeselect_access, 0x0, sizeof(IBM_DS(shpnt).ldn_modeselect_access));
+ memset(IBM_DS(shpnt).ldn_assignments, 0x0, sizeof(IBM_DS(shpnt).ldn_assignments));
probe_display(0);
return;
}
-static int device_exists(int host_index, int ldn, int *block_length, int *device_type)
+static int device_exists(struct Scsi_Host *shpnt, int ldn, int *block_length, int *device_type)
{
unsigned char *buf;
/* if no valid device found, return immediately with 0 */
- if (!(device_inquiry(host_index, ldn)))
+ if (!(device_inquiry(shpnt, ldn)))
return 0;
- buf = (unsigned char *) (&(ld(host_index)[ldn].buf));
+ buf = (unsigned char *) (&(ld(shpnt)[ldn].buf));
if (*buf == TYPE_ROM) {
*device_type = TYPE_ROM;
*block_length = 2048; /* (standard blocksize for yellow-/red-book) */
@@ -1349,7 +1359,7 @@
}
if (*buf == TYPE_DISK) {
*device_type = TYPE_DISK;
- if (read_capacity(host_index, ldn)) {
+ if (read_capacity(shpnt, ldn)) {
*block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24);
return 1;
} else
@@ -1357,7 +1367,7 @@
}
if (*buf == TYPE_MOD) {
*device_type = TYPE_MOD;
- if (read_capacity(host_index, ldn)) {
+ if (read_capacity(shpnt, ldn)) {
*block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24);
return 1;
} else
@@ -1430,6 +1440,9 @@
return;
}
+#if 0
+ FIXME NEED TO MOVE TO SYSFS
+
static int ibmmca_getinfo(char *buf, int slot, void *dev_id)
{
struct Scsi_Host *shpnt;
@@ -1480,58 +1493,34 @@
return len;
}
+#endif
-int ibmmca_detect(struct scsi_host_template * scsi_template)
+static struct scsi_host_template ibmmca_driver_template = {
+ .proc_name = "ibmmca",
+ .proc_info = ibmmca_proc_info,
+ .name = "IBM SCSI-Subsystem",
+ .queuecommand = ibmmca_queuecommand,
+ .eh_abort_handler = ibmmca_abort,
+ .eh_host_reset_handler = ibmmca_host_reset,
+ .bios_param = ibmmca_biosparam,
+ .can_queue = 16,
+ .this_id = 7,
+ .sg_tablesize = 16,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING,
+};
+
+static int ibmmca_probe(struct device *dev)
{
struct Scsi_Host *shpnt;
- int port, id, i, j, k, slot;
- int devices_on_irq_11 = 0;
- int devices_on_irq_14 = 0;
- int IRQ14_registered = 0;
- int IRQ11_registered = 0;
-
- found = 0; /* make absolutely sure, that found is set to 0 */
+ int port, id, i, j, k, irq, enabled, ret = -EINVAL;
+ struct mca_device *mca_dev = to_mca_device(dev);
+ const char *description = ibmmca_description[mca_dev->index];
/* First of all, print the version number of the driver. This is
* important to allow better user bugreports in case of already
* having problems with the MCA_bus probing. */
printk(KERN_INFO "IBM MCA SCSI: Version %s\n", IBMMCA_SCSI_DRIVER_VERSION);
- /* if this is not MCA machine, return "nothing found" */
- if (!MCA_bus) {
- printk(KERN_INFO "IBM MCA SCSI: No Microchannel-bus present --> Aborting.\n" " This machine does not have any IBM MCA-bus\n" " or the MCA-Kernel-support is not enabled!\n");
- return 0;
- }
-
-#ifdef MODULE
- /* If the driver is run as module, read from conf.modules or cmd-line */
- if (boot_options)
- option_setup(boot_options);
-#endif
-
- /* get interrupt request level */
- if (request_irq(IM_IRQ, interrupt_handler, IRQF_SHARED, "ibmmcascsi", hosts)) {
- printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ);
- return 0;
- } else
- IRQ14_registered++;
-
- /* if ibmmcascsi setup option was passed to kernel, return "found" */
- for (i = 0; i < IM_MAX_HOSTS; i++)
- if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8) {
- printk("IBM MCA SCSI: forced detected SCSI Adapter, io=0x%x, scsi id=%d.\n", io_port[i], scsi_id[i]);
- if ((shpnt = ibmmca_register(scsi_template, io_port[i], scsi_id[i], FORCED_DETECTION, "forced detected SCSI Adapter"))) {
- for (k = 2; k < 7; k++)
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = 0;
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_special = FORCED_DETECTION;
- mca_set_adapter_name(MCA_INTEGSCSI, "forced detected SCSI Adapter");
- mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt);
- mca_mark_as_used(MCA_INTEGSCSI);
- devices_on_irq_14++;
- }
- }
- if (found)
- return found;
-
/* The POS2-register of all PS/2 model SCSI-subsystems has the following
* interpretation of bits:
* Bit 7 - 4 : Chip Revision ID (Release)
@@ -1558,7 +1547,14 @@
/* first look for the IBM SCSI integrated subsystem on the motherboard */
for (j = 0; j < 8; j++) /* read the pos-information */
- pos[j] = mca_read_stored_pos(MCA_INTEGSCSI, j);
+ pos[j] = mca_device_read_pos(mca_dev, j);
+ id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */
+ enabled = (pos[2] &0x01);
+ if (!enabled) {
+ printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
+ printk(KERN_WARNING " SCSI-operations may not work.\n");
+ }
+
/* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present, but
* if we ignore the settings of all surrounding pos registers, it is not
* completely sufficient to only check pos2 and pos3. */
@@ -1566,232 +1562,137 @@
* make sure, we see a real integrated onboard SCSI-interface and no
* internal system information, which gets mapped to some pos registers
* on models 95xx. */
- if ((!pos[0] && !pos[1] && pos[2] > 0 && pos[3] > 0 && !pos[4] && !pos[5] && !pos[6] && !pos[7]) || (pos[0] == 0xff && pos[1] == 0xff && pos[2] < 0xff && pos[3] < 0xff && pos[4] == 0xff && pos[5] == 0xff && pos[6] == 0xff && pos[7] == 0xff)) {
- if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
- port = IM_IO_PORT;
- else { /* if disabled, no IRQs will be generated, as the chip won't
- * listen to the incoming commands and will do really nothing,
- * except for listening to the pos-register settings. If this
- * happens, I need to hugely think about it, as one has to
- * write something to the MCA-Bus pos register in order to
- * enable the chip. Normally, IBM-SCSI won't pass the POST,
- * when the chip is disabled (see IBM tech. ref.). */
- port = IM_IO_PORT; /* anyway, set the portnumber and warn */
- printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n" " SCSI-operations may not work.\n");
+ if (mca_dev->slot == MCA_INTEGSCSI &&
+ ((!pos[0] && !pos[1] && pos[2] > 0 &&
+ pos[3] > 0 && !pos[4] && !pos[5] &&
+ !pos[6] && !pos[7]) ||
+ (pos[0] == 0xff && pos[1] == 0xff &&
+ pos[2] < 0xff && pos[3] < 0xff &&
+ pos[4] == 0xff && pos[5] == 0xff &&
+ pos[6] == 0xff && pos[7] == 0xff))) {
+ irq = IM_IRQ;
+ port = IM_IO_PORT;
+ } else {
+ irq = IM_IRQ;
+ port = IM_IO_PORT + ((pos[2] &0x0e) << 2);
+ if ((mca_dev->index == IBM_SCSI2_FW) && (pos[6] != 0)) {
+ printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
+ printk(KERN_ERR " Impossible to determine adapter PUN!\n");
+ printk(KERN_ERR " Guessing adapter PUN = 7.\n");
+ id = 7;
+ } else {
+ id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
+ if (mca_dev->index == IBM_SCSI2_FW) {
+ id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
+ * for F/W adapters */
+ }
}
- id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */
- /* give detailed information on the subsystem. This helps me
- * additionally during debugging and analyzing bug-reports. */
- printk(KERN_INFO "IBM MCA SCSI: IBM Integrated SCSI Controller ffound, io=0x%x, scsi id=%d,\n", port, id);
+ if ((mca_dev->index == IBM_SCSI2_FW) &&
+ (pos[4] & 0x01) && (pos[6] == 0)) {
+ /* IRQ11 is used by SCSI-2 F/W Adapter/A */
+ printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
+ irq = IM_IRQ_FW;
+ }
+ }
+
+
+
+ /* give detailed information on the subsystem. This helps me
+ * additionally during debugging and analyzing bug-reports. */
+ printk(KERN_INFO "IBM MCA SCSI: %s found, io=0x%x, scsi id=%d,\n",
+ description, port, id);
+ if (mca_dev->slot == MCA_INTEGSCSI)
printk(KERN_INFO " chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible", (pos[2] & 1) ? "enabled." : "disabled.");
+ else {
+ if ((pos[2] & 0xf0) == 0xf0)
+ printk(KERN_DEBUG " ROM Addr.=off,");
+ else
+ printk(KERN_DEBUG " ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000);
- /* register the found integrated SCSI-subsystem */
- if ((shpnt = ibmmca_register(scsi_template, port, id, INTEGRATED_SCSI, "IBM Integrated SCSI Controller")))
- {
- for (k = 2; k < 7; k++)
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_special = INTEGRATED_SCSI;
- mca_set_adapter_name(MCA_INTEGSCSI, "IBM Integrated SCSI Controller");
- mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt);
- mca_mark_as_used(MCA_INTEGSCSI);
- devices_on_irq_14++;
- }
+ printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled.");
}
- /* now look for other adapters in MCA slots, */
- /* determine the number of known IBM-SCSI-subsystem types */
- /* see the pos[2] dependence to get the adapter port-offset. */
- for (i = 0; i < ARRAY_SIZE(subsys_list); i++) {
- /* scan each slot for a fitting adapter id */
- slot = 0; /* start at slot 0 */
- while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot))
- != MCA_NOTFOUND) { /* scan through all slots */
- for (j = 0; j < 8; j++) /* read the pos-information */
- pos[j] = mca_read_stored_pos(slot, j);
- if ((pos[2] & 1) == 1)
- /* is the subsystem chip enabled ? */
- /* (explanations see above) */
- port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
- else {
- /* anyway, set the portnumber and warn */
- port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
- printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
- printk(KERN_WARNING " SCSI-operations may not work.\n");
- }
- if ((i == IBM_SCSI2_FW) && (pos[6] != 0)) {
- printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
- printk(KERN_ERR " Impossible to determine adapter PUN!\n");
- printk(KERN_ERR " Guessing adapter PUN = 7.\n");
- id = 7;
- } else {
- id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
- if (i == IBM_SCSI2_FW) {
- id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
- * for F/W adapters */
- }
- }
- if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0)) {
- /* IRQ11 is used by SCSI-2 F/W Adapter/A */
- printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
- /* get interrupt request level */
- if (request_irq(IM_IRQ_FW, interrupt_handler, IRQF_SHARED, "ibmmcascsi", hosts)) {
- printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ_FW);
- } else
- IRQ11_registered++;
- }
- printk(KERN_INFO "IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", subsys_list[i].description, slot + 1, port, id);
- if ((pos[2] & 0xf0) == 0xf0)
- printk(KERN_DEBUG" ROM Addr.=off,");
- else
- printk(KERN_DEBUG " ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000);
- printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled.");
-
- /* register the hostadapter */
- if ((shpnt = ibmmca_register(scsi_template, port, id, i, subsys_list[i].description))) {
- for (k = 2; k < 8; k++)
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_special = i;
- mca_set_adapter_name(slot, subsys_list[i].description);
- mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmmca_getinfo, shpnt);
- mca_mark_as_used(slot);
- if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0))
- devices_on_irq_11++;
- else
- devices_on_irq_14++;
- }
- slot++; /* advance to next slot */
- } /* advance to next adapter id in the list of IBM-SCSI-subsystems */
- }
-
- /* now check for SCSI-adapters, mapped to the integrated SCSI
- * area. E.g. a W/Cache in MCA-slot 9(!). Do the check correct here,
- * as this is a known effect on some models 95xx. */
- for (i = 0; i < ARRAY_SIZE(subsys_list); i++) {
- /* scan each slot for a fitting adapter id */
- slot = mca_find_adapter(subsys_list[i].mca_id, MCA_INTEGSCSI);
- if (slot != MCA_NOTFOUND) { /* scan through all slots */
- for (j = 0; j < 8; j++) /* read the pos-information */
- pos[j] = mca_read_stored_pos(slot, j);
- if ((pos[2] & 1) == 1) { /* is the subsystem chip enabled ? */
- /* (explanations see above) */
- port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
- } else { /* anyway, set the portnumber and warn */
- port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
- printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
- printk(KERN_WARNING " SCSI-operations may not work.\n");
- }
- if ((i == IBM_SCSI2_FW) && (pos[6] != 0)) {
- printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
- printk(KERN_ERR " Impossible to determine adapter PUN!\n");
- printk(KERN_ERR " Guessing adapter PUN = 7.\n");
- id = 7;
- } else {
- id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
- if (i == IBM_SCSI2_FW)
- id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
- * for F/W adapters */
- }
- if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0)) {
- /* IRQ11 is used by SCSI-2 F/W Adapter/A */
- printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
- /* get interrupt request level */
- if (request_irq(IM_IRQ_FW, interrupt_handler, IRQF_SHARED, "ibmmcascsi", hosts))
- printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ_FW);
- else
- IRQ11_registered++;
- }
- printk(KERN_INFO "IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", subsys_list[i].description, slot + 1, port, id);
- if ((pos[2] & 0xf0) == 0xf0)
- printk(KERN_DEBUG " ROM Addr.=off,");
- else
- printk(KERN_DEBUG " ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000);
- printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled.");
-
- /* register the hostadapter */
- if ((shpnt = ibmmca_register(scsi_template, port, id, i, subsys_list[i].description))) {
- for (k = 2; k < 7; k++)
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_special = i;
- mca_set_adapter_name(slot, subsys_list[i].description);
- mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmmca_getinfo, shpnt);
- mca_mark_as_used(slot);
- if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0))
- devices_on_irq_11++;
- else
- devices_on_irq_14++;
- }
- slot++; /* advance to next slot */
- } /* advance to next adapter id in the list of IBM-SCSI-subsystems */
- }
- if (IRQ11_registered && !devices_on_irq_11)
- free_irq(IM_IRQ_FW, hosts); /* no devices on IRQ 11 */
- if (IRQ14_registered && !devices_on_irq_14)
- free_irq(IM_IRQ, hosts); /* no devices on IRQ 14 */
- if (!devices_on_irq_11 && !devices_on_irq_14)
- printk(KERN_WARNING "IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n");
- return found; /* return the number of found SCSI hosts. Should be 1 or 0. */
-}
-
-static struct Scsi_Host *ibmmca_register(struct scsi_host_template * scsi_template, int port, int id, int adaptertype, char *hostname)
-{
- struct Scsi_Host *shpnt;
- int i, j;
- unsigned int ctrl;
-
/* check I/O region */
- if (!request_region(port, IM_N_IO_PORT, hostname)) {
+ if (!request_region(port, IM_N_IO_PORT, description)) {
printk(KERN_ERR "IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n", port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT);
- return NULL;
+ goto out_fail;
}
/* register host */
- shpnt = scsi_register(scsi_template, sizeof(struct ibmmca_hostdata));
+ shpnt = scsi_host_alloc(&ibmmca_driver_template,
+ sizeof(struct ibmmca_hostdata));
if (!shpnt) {
printk(KERN_ERR "IBM MCA SCSI: Unable to register host.\n");
- release_region(port, IM_N_IO_PORT);
- return NULL;
+ goto out_release;
+ }
+
+ dev_set_drvdata(dev, shpnt);
+ if(request_irq(irq, interrupt_handler, IRQF_SHARED, description, dev)) {
+ printk(KERN_ERR "IBM MCA SCSI: failed to request interrupt %d\n", irq);
+ goto out_free_host;
}
/* request I/O region */
- hosts[found] = shpnt; /* add new found hostadapter to the list */
- special(found) = adaptertype; /* important assignment or else crash! */
- subsystem_connector_size(found) = 0; /* preset slot-size */
- shpnt->irq = IM_IRQ; /* assign necessary stuff for the adapter */
+ special(shpnt) = mca_dev->index; /* important assignment or else crash! */
+ subsystem_connector_size(shpnt) = 0; /* preset slot-size */
+ shpnt->irq = irq; /* assign necessary stuff for the adapter */
shpnt->io_port = port;
shpnt->n_io_port = IM_N_IO_PORT;
shpnt->this_id = id;
shpnt->max_id = 8; /* 8 PUNs are default */
/* now, the SCSI-subsystem is connected to Linux */
- ctrl = (unsigned int) (inb(IM_CTR_REG(found))); /* get control-register status */
#ifdef IM_DEBUG_PROBE
+ ctrl = (unsigned int) (inb(IM_CTR_REG(found))); /* get control-register status */
printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n", ctrl, inb(IM_STAT_REG(found)));
printk("IBM MCA SCSI: This adapters' POS-registers: ");
for (i = 0; i < 8; i++)
printk("%x ", pos[i]);
printk("\n");
#endif
- reset_status(found) = IM_RESET_NOT_IN_PROGRESS;
+ reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS;
for (i = 0; i < 16; i++) /* reset the tables */
for (j = 0; j < 8; j++)
- get_ldn(found)[i][j] = MAX_LOG_DEV;
+ get_ldn(shpnt)[i][j] = MAX_LOG_DEV;
/* check which logical devices exist */
/* after this line, local interrupting is possible: */
- local_checking_phase_flag(found) = 1;
- check_devices(found, adaptertype); /* call by value, using the global variable hosts */
- local_checking_phase_flag(found) = 0;
- found++; /* now increase index to be prepared for next found subsystem */
+ local_checking_phase_flag(shpnt) = 1;
+ check_devices(shpnt, mca_dev->index); /* call by value, using the global variable hosts */
+ local_checking_phase_flag(shpnt) = 0;
+
/* an ibm mca subsystem has been detected */
- return shpnt;
+
+ for (k = 2; k < 7; k++)
+ ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
+ ((struct ibmmca_hostdata *) shpnt->hostdata)->_special = INTEGRATED_SCSI;
+ mca_device_set_name(mca_dev, description);
+ /* FIXME: NEED TO REPLUMB TO SYSFS
+ mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt);
+ */
+ mca_device_set_claim(mca_dev, 1);
+ if (scsi_add_host(shpnt, dev)) {
+ dev_printk(KERN_ERR, dev, "IBM MCA SCSI: scsi_add_host failed\n");
+ goto out_free_host;
+ }
+ scsi_scan_host(shpnt);
+
+ return 0;
+ out_free_host:
+ scsi_host_put(shpnt);
+ out_release:
+ release_region(port, IM_N_IO_PORT);
+ out_fail:
+ return ret;
}
-static int ibmmca_release(struct Scsi_Host *shpnt)
+static int __devexit ibmmca_remove(struct device *dev)
{
+ struct Scsi_Host *shpnt = dev_get_drvdata(dev);
+ scsi_remove_host(shpnt);
release_region(shpnt->io_port, shpnt->n_io_port);
- if (!(--found))
- free_irq(shpnt->irq, hosts);
+ free_irq(shpnt->irq, dev);
return 0;
}
@@ -1805,33 +1706,24 @@
int current_ldn;
int id, lun;
int target;
- int host_index;
int max_pun;
int i;
- struct scatterlist *sl;
+ struct scatterlist *sg;
shpnt = cmd->device->host;
- /* search for the right hostadapter */
- for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
- if (!hosts[host_index]) { /* invalid hostadapter descriptor address */
- cmd->result = DID_NO_CONNECT << 16;
- if (done)
- done(cmd);
- return 0;
- }
- max_pun = subsystem_maxid(host_index);
+ max_pun = subsystem_maxid(shpnt);
if (ibm_ansi_order) {
target = max_pun - 1 - cmd->device->id;
- if ((target <= subsystem_pun(host_index)) && (cmd->device->id <= subsystem_pun(host_index)))
+ if ((target <= subsystem_pun(shpnt)) && (cmd->device->id <= subsystem_pun(shpnt)))
target--;
- else if ((target >= subsystem_pun(host_index)) && (cmd->device->id >= subsystem_pun(host_index)))
+ else if ((target >= subsystem_pun(shpnt)) && (cmd->device->id >= subsystem_pun(shpnt)))
target++;
} else
target = cmd->device->id;
/* if (target,lun) is NO LUN or not existing at all, return error */
- if ((get_scsi(host_index)[target][cmd->device->lun] == TYPE_NO_LUN) || (get_scsi(host_index)[target][cmd->device->lun] == TYPE_NO_DEVICE)) {
+ if ((get_scsi(shpnt)[target][cmd->device->lun] == TYPE_NO_LUN) || (get_scsi(shpnt)[target][cmd->device->lun] == TYPE_NO_DEVICE)) {
cmd->result = DID_NO_CONNECT << 16;
if (done)
done(cmd);
@@ -1839,16 +1731,16 @@
}
/*if (target,lun) unassigned, do further checks... */
- ldn = get_ldn(host_index)[target][cmd->device->lun];
+ ldn = get_ldn(shpnt)[target][cmd->device->lun];
if (ldn >= MAX_LOG_DEV) { /* on invalid ldn do special stuff */
if (ldn > MAX_LOG_DEV) { /* dynamical remapping if ldn unassigned */
- current_ldn = next_ldn(host_index); /* stop-value for one circle */
- while (ld(host_index)[next_ldn(host_index)].cmd) { /* search for a occupied, but not in */
+ current_ldn = next_ldn(shpnt); /* stop-value for one circle */
+ while (ld(shpnt)[next_ldn(shpnt)].cmd) { /* search for a occupied, but not in */
/* command-processing ldn. */
- next_ldn(host_index)++;
- if (next_ldn(host_index) >= MAX_LOG_DEV)
- next_ldn(host_index) = 7;
- if (current_ldn == next_ldn(host_index)) { /* One circle done ? */
+ next_ldn(shpnt)++;
+ if (next_ldn(shpnt) >= MAX_LOG_DEV)
+ next_ldn(shpnt) = 7;
+ if (current_ldn == next_ldn(shpnt)) { /* One circle done ? */
/* no non-processing ldn found */
scmd_printk(KERN_WARNING, cmd,
"IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n"
@@ -1864,56 +1756,56 @@
/* unmap non-processing ldn */
for (id = 0; id < max_pun; id++)
for (lun = 0; lun < 8; lun++) {
- if (get_ldn(host_index)[id][lun] == next_ldn(host_index)) {
- get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE;
- get_scsi(host_index)[id][lun] = TYPE_NO_DEVICE;
+ if (get_ldn(shpnt)[id][lun] == next_ldn(shpnt)) {
+ get_ldn(shpnt)[id][lun] = TYPE_NO_DEVICE;
+ get_scsi(shpnt)[id][lun] = TYPE_NO_DEVICE;
/* unmap entry */
}
}
/* set reduced interrupt_handler-mode for checking */
- local_checking_phase_flag(host_index) = 1;
+ local_checking_phase_flag(shpnt) = 1;
/* map found ldn to pun,lun */
- get_ldn(host_index)[target][cmd->device->lun] = next_ldn(host_index);
+ get_ldn(shpnt)[target][cmd->device->lun] = next_ldn(shpnt);
/* change ldn to the right value, that is now next_ldn */
- ldn = next_ldn(host_index);
+ ldn = next_ldn(shpnt);
/* unassign all ldns (pun,lun,ldn does not matter for remove) */
- immediate_assign(host_index, 0, 0, 0, REMOVE_LDN);
+ immediate_assign(shpnt, 0, 0, 0, REMOVE_LDN);
/* set only LDN for remapped device */
- immediate_assign(host_index, target, cmd->device->lun, ldn, SET_LDN);
+ immediate_assign(shpnt, target, cmd->device->lun, ldn, SET_LDN);
/* get device information for ld[ldn] */
- if (device_exists(host_index, ldn, &ld(host_index)[ldn].block_length, &ld(host_index)[ldn].device_type)) {
- ld(host_index)[ldn].cmd = NULL; /* To prevent panic set 0, because
+ if (device_exists(shpnt, ldn, &ld(shpnt)[ldn].block_length, &ld(shpnt)[ldn].device_type)) {
+ ld(shpnt)[ldn].cmd = NULL; /* To prevent panic set 0, because
devices that were not assigned,
should have nothing in progress. */
- get_scsi(host_index)[target][cmd->device->lun] = ld(host_index)[ldn].device_type;
+ get_scsi(shpnt)[target][cmd->device->lun] = ld(shpnt)[ldn].device_type;
/* increase assignment counters for statistics in /proc */
- IBM_DS(host_index).dynamical_assignments++;
- IBM_DS(host_index).ldn_assignments[ldn]++;
+ IBM_DS(shpnt).dynamical_assignments++;
+ IBM_DS(shpnt).ldn_assignments[ldn]++;
} else
/* panic here, because a device, found at boottime has
vanished */
panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n", ldn, target, cmd->device->lun);
/* unassign again all ldns (pun,lun,ldn does not matter for remove) */
- immediate_assign(host_index, 0, 0, 0, REMOVE_LDN);
+ immediate_assign(shpnt, 0, 0, 0, REMOVE_LDN);
/* remap all ldns, as written in the pun/lun table */
lun = 0;
#ifdef CONFIG_SCSI_MULTI_LUN
for (lun = 0; lun < 8; lun++)
#endif
for (id = 0; id < max_pun; id++) {
- if (get_ldn(host_index)[id][lun] <= MAX_LOG_DEV)
- immediate_assign(host_index, id, lun, get_ldn(host_index)[id][lun], SET_LDN);
+ if (get_ldn(shpnt)[id][lun] <= MAX_LOG_DEV)
+ immediate_assign(shpnt, id, lun, get_ldn(shpnt)[id][lun], SET_LDN);
}
/* set back to normal interrupt_handling */
- local_checking_phase_flag(host_index) = 0;
+ local_checking_phase_flag(shpnt) = 0;
#ifdef IM_DEBUG_PROBE
/* Information on syslog terminal */
printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n", ldn, target, cmd->device->lun);
#endif
/* increase next_ldn for next dynamical assignment */
- next_ldn(host_index)++;
- if (next_ldn(host_index) >= MAX_LOG_DEV)
- next_ldn(host_index) = 7;
+ next_ldn(shpnt)++;
+ if (next_ldn(shpnt) >= MAX_LOG_DEV)
+ next_ldn(shpnt) = 7;
} else { /* wall against Linux accesses to the subsystem adapter */
cmd->result = DID_BAD_TARGET << 16;
if (done)
@@ -1923,34 +1815,32 @@
}
/*verify there is no command already in progress for this log dev */
- if (ld(host_index)[ldn].cmd)
+ if (ld(shpnt)[ldn].cmd)
panic("IBM MCA SCSI: cmd already in progress for this ldn.\n");
/*save done in cmd, and save cmd for the interrupt handler */
cmd->scsi_done = done;
- ld(host_index)[ldn].cmd = cmd;
+ ld(shpnt)[ldn].cmd = cmd;
/*fill scb information independent of the scsi command */
- scb = &(ld(host_index)[ldn].scb);
- ld(host_index)[ldn].tsb.dev_status = 0;
+ scb = &(ld(shpnt)[ldn].scb);
+ ld(shpnt)[ldn].tsb.dev_status = 0;
scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE;
- scb->tsb_adr = isa_virt_to_bus(&(ld(host_index)[ldn].tsb));
+ scb->tsb_adr = isa_virt_to_bus(&(ld(shpnt)[ldn].tsb));
scsi_cmd = cmd->cmnd[0];
- if (cmd->use_sg) {
- i = cmd->use_sg;
- sl = (struct scatterlist *) (cmd->request_buffer);
- if (i > 16)
- panic("IBM MCA SCSI: scatter-gather list too long.\n");
- while (--i >= 0) {
- ld(host_index)[ldn].sge[i].address = (void *) (isa_page_to_bus(sl[i].page) + sl[i].offset);
- ld(host_index)[ldn].sge[i].byte_length = sl[i].length;
+ if (scsi_sg_count(cmd)) {
+ BUG_ON(scsi_sg_count(cmd) > 16);
+
+ scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
+ ld(shpnt)[ldn].sge[i].address = (void *) (isa_page_to_bus(sg->page) + sg->offset);
+ ld(shpnt)[ldn].sge[i].byte_length = sg->length;
}
scb->enable |= IM_POINTER_TO_LIST;
- scb->sys_buf_adr = isa_virt_to_bus(&(ld(host_index)[ldn].sge[0]));
- scb->sys_buf_length = cmd->use_sg * sizeof(struct im_sge);
+ scb->sys_buf_adr = isa_virt_to_bus(&(ld(shpnt)[ldn].sge[0]));
+ scb->sys_buf_length = scsi_sg_count(cmd) * sizeof(struct im_sge);
} else {
- scb->sys_buf_adr = isa_virt_to_bus(cmd->request_buffer);
+ scb->sys_buf_adr = isa_virt_to_bus(scsi_sglist(cmd));
/* recent Linux midlevel SCSI places 1024 byte for inquiry
* command. Far too much for old PS/2 hardware. */
switch (scsi_cmd) {
@@ -1961,16 +1851,16 @@
case REQUEST_SENSE:
case MODE_SENSE:
case MODE_SELECT:
- if (cmd->request_bufflen > 255)
+ if (scsi_bufflen(cmd) > 255)
scb->sys_buf_length = 255;
else
- scb->sys_buf_length = cmd->request_bufflen;
+ scb->sys_buf_length = scsi_bufflen(cmd);
break;
case TEST_UNIT_READY:
scb->sys_buf_length = 0;
break;
default:
- scb->sys_buf_length = cmd->request_bufflen;
+ scb->sys_buf_length = scsi_bufflen(cmd);
break;
}
}
@@ -1982,16 +1872,16 @@
/* for specific device-type debugging: */
#ifdef IM_DEBUG_CMD_SPEC_DEV
- if (ld(host_index)[ldn].device_type == IM_DEBUG_CMD_DEVICE)
- printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", ld(host_index)[ldn].device_type, scsi_cmd, ldn);
+ if (ld(shpnt)[ldn].device_type == IM_DEBUG_CMD_DEVICE)
+ printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", ld(shpnt)[ldn].device_type, scsi_cmd, ldn);
#endif
/* for possible panics store current command */
- last_scsi_command(host_index)[ldn] = scsi_cmd;
- last_scsi_type(host_index)[ldn] = IM_SCB;
+ last_scsi_command(shpnt)[ldn] = scsi_cmd;
+ last_scsi_type(shpnt)[ldn] = IM_SCB;
/* update statistical info */
- IBM_DS(host_index).total_accesses++;
- IBM_DS(host_index).ldn_access[ldn]++;
+ IBM_DS(shpnt).total_accesses++;
+ IBM_DS(shpnt).ldn_access[ldn]++;
switch (scsi_cmd) {
case READ_6:
@@ -2003,17 +1893,17 @@
/* Distinguish between disk and other devices. Only disks (that are the
most frequently accessed devices) should be supported by the
IBM-SCSI-Subsystem commands. */
- switch (ld(host_index)[ldn].device_type) {
+ switch (ld(shpnt)[ldn].device_type) {
case TYPE_DISK: /* for harddisks enter here ... */
case TYPE_MOD: /* ... try it also for MO-drives (send flames as */
/* you like, if this won't work.) */
if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12) {
/* read command preparations */
scb->enable |= IM_READ_CONTROL;
- IBM_DS(host_index).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
+ IBM_DS(shpnt).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
scb->command = IM_READ_DATA_CMD | IM_NO_DISCONNECT;
} else { /* write command preparations */
- IBM_DS(host_index).ldn_write_access[ldn]++; /* increase write-count on ldn stat. */
+ IBM_DS(shpnt).ldn_write_access[ldn]++; /* increase write-count on ldn stat. */
scb->command = IM_WRITE_DATA_CMD | IM_NO_DISCONNECT;
}
if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6) {
@@ -2023,9 +1913,9 @@
scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) | (((unsigned) cmd->cmnd[4]) << 8) | (((unsigned) cmd->cmnd[3]) << 16) | (((unsigned) cmd->cmnd[2]) << 24);
scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) | (((unsigned) cmd->cmnd[7]) << 8);
}
- last_scsi_logical_block(host_index)[ldn] = scb->u1.log_blk_adr;
- last_scsi_blockcount(host_index)[ldn] = scb->u2.blk.count;
- scb->u2.blk.length = ld(host_index)[ldn].block_length;
+ last_scsi_logical_block(shpnt)[ldn] = scb->u1.log_blk_adr;
+ last_scsi_blockcount(shpnt)[ldn] = scb->u2.blk.count;
+ scb->u2.blk.length = ld(shpnt)[ldn].block_length;
break;
/* for other devices, enter here. Other types are not known by
Linux! TYPE_NO_LUN is forbidden as valid device. */
@@ -2046,14 +1936,14 @@
scb->enable |= IM_BYPASS_BUFFER;
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
- last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+ last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
/* Read/write on this non-disk devices is also displayworthy,
so flash-up the LED/display. */
break;
}
break;
case INQUIRY:
- IBM_DS(host_index).ldn_inquiry_access[ldn]++;
+ IBM_DS(shpnt).ldn_inquiry_access[ldn]++;
scb->command = IM_DEVICE_INQUIRY_CMD;
scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
scb->u1.log_blk_adr = 0;
@@ -2064,7 +1954,7 @@
scb->u1.log_blk_adr = 0;
scb->u1.scsi_cmd_length = 6;
memcpy(scb->u2.scsi_command, cmd->cmnd, 6);
- last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+ last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
break;
case READ_CAPACITY:
/* the length of system memory buffer must be exactly 8 bytes */
@@ -2081,12 +1971,12 @@
/* Commands that need write-only-mode (system -> device): */
case MODE_SELECT:
case MODE_SELECT_10:
- IBM_DS(host_index).ldn_modeselect_access[ldn]++;
+ IBM_DS(shpnt).ldn_modeselect_access[ldn]++;
scb->command = IM_OTHER_SCSI_CMD_CMD;
scb->enable |= IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; /*Select needs WRITE-enabled */
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
- last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+ last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
break;
/* For other commands, read-only is useful. Most other commands are
running without an input-data-block. */
@@ -2095,19 +1985,19 @@
scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
- last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+ last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
break;
}
/*issue scb command, and return */
if (++disk_rw_in_progress == 1)
PS2_DISK_LED_ON(shpnt->host_no, target);
- if (last_scsi_type(host_index)[ldn] == IM_LONG_SCB) {
- issue_cmd(host_index, isa_virt_to_bus(scb), IM_LONG_SCB | ldn);
- IBM_DS(host_index).long_scbs++;
+ if (last_scsi_type(shpnt)[ldn] == IM_LONG_SCB) {
+ issue_cmd(shpnt, isa_virt_to_bus(scb), IM_LONG_SCB | ldn);
+ IBM_DS(shpnt).long_scbs++;
} else {
- issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
- IBM_DS(host_index).scbs++;
+ issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn);
+ IBM_DS(shpnt).scbs++;
}
return 0;
}
@@ -2122,7 +2012,6 @@
unsigned int ldn;
void (*saved_done) (Scsi_Cmnd *);
int target;
- int host_index;
int max_pun;
unsigned long imm_command;
@@ -2131,35 +2020,23 @@
#endif
shpnt = cmd->device->host;
- /* search for the right hostadapter */
- for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
- if (!hosts[host_index]) { /* invalid hostadapter descriptor address */
- cmd->result = DID_NO_CONNECT << 16;
- if (cmd->scsi_done)
- (cmd->scsi_done) (cmd);
- shpnt = cmd->device->host;
-#ifdef IM_DEBUG_PROBE
- printk(KERN_DEBUG "IBM MCA SCSI: Abort adapter selection failed!\n");
-#endif
- return SUCCESS;
- }
- max_pun = subsystem_maxid(host_index);
+ max_pun = subsystem_maxid(shpnt);
if (ibm_ansi_order) {
target = max_pun - 1 - cmd->device->id;
- if ((target <= subsystem_pun(host_index)) && (cmd->device->id <= subsystem_pun(host_index)))
+ if ((target <= subsystem_pun(shpnt)) && (cmd->device->id <= subsystem_pun(shpnt)))
target--;
- else if ((target >= subsystem_pun(host_index)) && (cmd->device->id >= subsystem_pun(host_index)))
+ else if ((target >= subsystem_pun(shpnt)) && (cmd->device->id >= subsystem_pun(shpnt)))
target++;
} else
target = cmd->device->id;
/* get logical device number, and disable system interrupts */
printk(KERN_WARNING "IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n", target, cmd->device->lun);
- ldn = get_ldn(host_index)[target][cmd->device->lun];
+ ldn = get_ldn(shpnt)[target][cmd->device->lun];
/*if cmd for this ldn has already finished, no need to abort */
- if (!ld(host_index)[ldn].cmd) {
+ if (!ld(shpnt)[ldn].cmd) {
return SUCCESS;
}
@@ -2170,20 +2047,20 @@
saved_done = cmd->scsi_done;
cmd->scsi_done = internal_done;
cmd->SCp.Status = 0;
- last_scsi_command(host_index)[ldn] = IM_ABORT_IMM_CMD;
- last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
- imm_command = inl(IM_CMD_REG(host_index));
+ last_scsi_command(shpnt)[ldn] = IM_ABORT_IMM_CMD;
+ last_scsi_type(shpnt)[ldn] = IM_IMM_CMD;
+ imm_command = inl(IM_CMD_REG(shpnt));
imm_command &= (unsigned long) (0xffff0000); /* mask reserved stuff */
imm_command |= (unsigned long) (IM_ABORT_IMM_CMD);
/* must wait for attention reg not busy */
/* FIXME - timeout, politeness */
while (1) {
- if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+ if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
break;
}
/* write registers and enable system interrupts */
- outl(imm_command, IM_CMD_REG(host_index));
- outb(IM_IMM_CMD | ldn, IM_ATTN_REG(host_index));
+ outl(imm_command, IM_CMD_REG(shpnt));
+ outb(IM_IMM_CMD | ldn, IM_ATTN_REG(shpnt));
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Abort queued to adapter...\n");
#endif
@@ -2202,7 +2079,7 @@
cmd->result |= DID_ABORT << 16;
if (cmd->scsi_done)
(cmd->scsi_done) (cmd);
- ld(host_index)[ldn].cmd = NULL;
+ ld(shpnt)[ldn].cmd = NULL;
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Abort finished with success.\n");
#endif
@@ -2211,7 +2088,7 @@
cmd->result |= DID_NO_CONNECT << 16;
if (cmd->scsi_done)
(cmd->scsi_done) (cmd);
- ld(host_index)[ldn].cmd = NULL;
+ ld(shpnt)[ldn].cmd = NULL;
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Abort failed.\n");
#endif
@@ -2236,71 +2113,65 @@
struct Scsi_Host *shpnt;
Scsi_Cmnd *cmd_aid;
int ticks, i;
- int host_index;
unsigned long imm_command;
BUG_ON(cmd == NULL);
ticks = IM_RESET_DELAY * HZ;
shpnt = cmd->device->host;
- /* search for the right hostadapter */
- for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
- if (!hosts[host_index]) /* invalid hostadapter descriptor address */
- return FAILED;
-
- if (local_checking_phase_flag(host_index)) {
+ if (local_checking_phase_flag(shpnt)) {
printk(KERN_WARNING "IBM MCA SCSI: unable to reset while checking devices.\n");
return FAILED;
}
/* issue reset immediate command to subsystem, and wait for interrupt */
printk("IBM MCA SCSI: resetting all devices.\n");
- reset_status(host_index) = IM_RESET_IN_PROGRESS;
- last_scsi_command(host_index)[0xf] = IM_RESET_IMM_CMD;
- last_scsi_type(host_index)[0xf] = IM_IMM_CMD;
- imm_command = inl(IM_CMD_REG(host_index));
+ reset_status(shpnt) = IM_RESET_IN_PROGRESS;
+ last_scsi_command(shpnt)[0xf] = IM_RESET_IMM_CMD;
+ last_scsi_type(shpnt)[0xf] = IM_IMM_CMD;
+ imm_command = inl(IM_CMD_REG(shpnt));
imm_command &= (unsigned long) (0xffff0000); /* mask reserved stuff */
imm_command |= (unsigned long) (IM_RESET_IMM_CMD);
/* must wait for attention reg not busy */
while (1) {
- if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+ if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
break;
spin_unlock_irq(shpnt->host_lock);
yield();
spin_lock_irq(shpnt->host_lock);
}
/*write registers and enable system interrupts */
- outl(imm_command, IM_CMD_REG(host_index));
- outb(IM_IMM_CMD | 0xf, IM_ATTN_REG(host_index));
+ outl(imm_command, IM_CMD_REG(shpnt));
+ outb(IM_IMM_CMD | 0xf, IM_ATTN_REG(shpnt));
/* wait for interrupt finished or intr_stat register to be set, as the
* interrupt will not be executed, while we are in here! */
/* FIXME: This is really really icky we so want a sleeping version of this ! */
- while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks && ((inb(IM_INTR_REG(host_index)) & 0x8f) != 0x8f)) {
+ while (reset_status(shpnt) == IM_RESET_IN_PROGRESS && --ticks && ((inb(IM_INTR_REG(shpnt)) & 0x8f) != 0x8f)) {
udelay((1 + 999 / HZ) * 1000);
barrier();
}
/* if reset did not complete, just return an error */
if (!ticks) {
printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY);
- reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+ reset_status(shpnt) = IM_RESET_FINISHED_FAIL;
return FAILED;
}
- if ((inb(IM_INTR_REG(host_index)) & 0x8f) == 0x8f) {
+ if ((inb(IM_INTR_REG(shpnt)) & 0x8f) == 0x8f) {
/* analysis done by this routine and not by the intr-routine */
- if (inb(IM_INTR_REG(host_index)) == 0xaf)
- reset_status(host_index) = IM_RESET_FINISHED_OK_NO_INT;
- else if (inb(IM_INTR_REG(host_index)) == 0xcf)
- reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+ if (inb(IM_INTR_REG(shpnt)) == 0xaf)
+ reset_status(shpnt) = IM_RESET_FINISHED_OK_NO_INT;
+ else if (inb(IM_INTR_REG(shpnt)) == 0xcf)
+ reset_status(shpnt) = IM_RESET_FINISHED_FAIL;
else /* failed, 4get it */
- reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS_NO_INT;
- outb(IM_EOI | 0xf, IM_ATTN_REG(host_index));
+ reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS_NO_INT;
+ outb(IM_EOI | 0xf, IM_ATTN_REG(shpnt));
}
/* if reset failed, just return an error */
- if (reset_status(host_index) == IM_RESET_FINISHED_FAIL) {
+ if (reset_status(shpnt) == IM_RESET_FINISHED_FAIL) {
printk(KERN_ERR "IBM MCA SCSI: reset failed.\n");
return FAILED;
}
@@ -2308,9 +2179,9 @@
/* so reset finished ok - call outstanding done's, and return success */
printk(KERN_INFO "IBM MCA SCSI: Reset successfully completed.\n");
for (i = 0; i < MAX_LOG_DEV; i++) {
- cmd_aid = ld(host_index)[i].cmd;
+ cmd_aid = ld(shpnt)[i].cmd;
if (cmd_aid && cmd_aid->scsi_done) {
- ld(host_index)[i].cmd = NULL;
+ ld(shpnt)[i].cmd = NULL;
cmd_aid->result = DID_RESET << 16;
}
}
@@ -2351,46 +2222,46 @@
}
/* calculate percentage of total accesses on a ldn */
-static int ldn_access_load(int host_index, int ldn)
+static int ldn_access_load(struct Scsi_Host *shpnt, int ldn)
{
- if (IBM_DS(host_index).total_accesses == 0)
+ if (IBM_DS(shpnt).total_accesses == 0)
return (0);
- if (IBM_DS(host_index).ldn_access[ldn] == 0)
+ if (IBM_DS(shpnt).ldn_access[ldn] == 0)
return (0);
- return (IBM_DS(host_index).ldn_access[ldn] * 100) / IBM_DS(host_index).total_accesses;
+ return (IBM_DS(shpnt).ldn_access[ldn] * 100) / IBM_DS(shpnt).total_accesses;
}
/* calculate total amount of r/w-accesses */
-static int ldn_access_total_read_write(int host_index)
+static int ldn_access_total_read_write(struct Scsi_Host *shpnt)
{
int a;
int i;
a = 0;
for (i = 0; i <= MAX_LOG_DEV; i++)
- a += IBM_DS(host_index).ldn_read_access[i] + IBM_DS(host_index).ldn_write_access[i];
+ a += IBM_DS(shpnt).ldn_read_access[i] + IBM_DS(shpnt).ldn_write_access[i];
return (a);
}
-static int ldn_access_total_inquiry(int host_index)
+static int ldn_access_total_inquiry(struct Scsi_Host *shpnt)
{
int a;
int i;
a = 0;
for (i = 0; i <= MAX_LOG_DEV; i++)
- a += IBM_DS(host_index).ldn_inquiry_access[i];
+ a += IBM_DS(shpnt).ldn_inquiry_access[i];
return (a);
}
-static int ldn_access_total_modeselect(int host_index)
+static int ldn_access_total_modeselect(struct Scsi_Host *shpnt)
{
int a;
int i;
a = 0;
for (i = 0; i <= MAX_LOG_DEV; i++)
- a += IBM_DS(host_index).ldn_modeselect_access[i];
+ a += IBM_DS(shpnt).ldn_modeselect_access[i];
return (a);
}
@@ -2398,19 +2269,14 @@
static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
{
int len = 0;
- int i, id, lun, host_index;
+ int i, id, lun;
unsigned long flags;
int max_pun;
- for (i = 0; hosts[i] && hosts[i] != shpnt; i++);
- spin_lock_irqsave(hosts[i]->host_lock, flags); /* Check it */
- host_index = i;
- if (!shpnt) {
- len += sprintf(buffer + len, "\nIBM MCA SCSI: Can't find adapter");
- return len;
- }
- max_pun = subsystem_maxid(host_index);
+ spin_lock_irqsave(shpnt->host_lock, flags); /* Check it */
+
+ max_pun = subsystem_maxid(shpnt);
len += sprintf(buffer + len, "\n IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n", IBMMCA_SCSI_DRIVER_VERSION);
len += sprintf(buffer + len, " SCSI Access-Statistics:\n");
@@ -2421,40 +2287,40 @@
len += sprintf(buffer + len, " Multiple LUN probing.....: No\n");
#endif
len += sprintf(buffer + len, " This Hostnumber..........: %d\n", shpnt->host_no);
- len += sprintf(buffer + len, " Base I/O-Port............: 0x%x\n", (unsigned int) (IM_CMD_REG(host_index)));
+ len += sprintf(buffer + len, " Base I/O-Port............: 0x%x\n", (unsigned int) (IM_CMD_REG(shpnt)));
len += sprintf(buffer + len, " (Shared) IRQ.............: %d\n", IM_IRQ);
- len += sprintf(buffer + len, " Total Interrupts.........: %d\n", IBM_DS(host_index).total_interrupts);
- len += sprintf(buffer + len, " Total SCSI Accesses......: %d\n", IBM_DS(host_index).total_accesses);
- len += sprintf(buffer + len, " Total short SCBs.........: %d\n", IBM_DS(host_index).scbs);
- len += sprintf(buffer + len, " Total long SCBs..........: %d\n", IBM_DS(host_index).long_scbs);
- len += sprintf(buffer + len, " Total SCSI READ/WRITE..: %d\n", ldn_access_total_read_write(host_index));
- len += sprintf(buffer + len, " Total SCSI Inquiries...: %d\n", ldn_access_total_inquiry(host_index));
- len += sprintf(buffer + len, " Total SCSI Modeselects.: %d\n", ldn_access_total_modeselect(host_index));
- len += sprintf(buffer + len, " Total SCSI other cmds..: %d\n", IBM_DS(host_index).total_accesses - ldn_access_total_read_write(host_index)
- - ldn_access_total_modeselect(host_index)
- - ldn_access_total_inquiry(host_index));
- len += sprintf(buffer + len, " Total SCSI command fails.: %d\n\n", IBM_DS(host_index).total_errors);
+ len += sprintf(buffer + len, " Total Interrupts.........: %d\n", IBM_DS(shpnt).total_interrupts);
+ len += sprintf(buffer + len, " Total SCSI Accesses......: %d\n", IBM_DS(shpnt).total_accesses);
+ len += sprintf(buffer + len, " Total short SCBs.........: %d\n", IBM_DS(shpnt).scbs);
+ len += sprintf(buffer + len, " Total long SCBs..........: %d\n", IBM_DS(shpnt).long_scbs);
+ len += sprintf(buffer + len, " Total SCSI READ/WRITE..: %d\n", ldn_access_total_read_write(shpnt));
+ len += sprintf(buffer + len, " Total SCSI Inquiries...: %d\n", ldn_access_total_inquiry(shpnt));
+ len += sprintf(buffer + len, " Total SCSI Modeselects.: %d\n", ldn_access_total_modeselect(shpnt));
+ len += sprintf(buffer + len, " Total SCSI other cmds..: %d\n", IBM_DS(shpnt).total_accesses - ldn_access_total_read_write(shpnt)
+ - ldn_access_total_modeselect(shpnt)
+ - ldn_access_total_inquiry(shpnt));
+ len += sprintf(buffer + len, " Total SCSI command fails.: %d\n\n", IBM_DS(shpnt).total_errors);
len += sprintf(buffer + len, " Logical-Device-Number (LDN) Access-Statistics:\n");
len += sprintf(buffer + len, " LDN | Accesses [%%] | READ | WRITE | ASSIGNMENTS\n");
len += sprintf(buffer + len, " -----|--------------|-----------|-----------|--------------\n");
for (i = 0; i <= MAX_LOG_DEV; i++)
- len += sprintf(buffer + len, " %2X | %3d | %8d | %8d | %8d\n", i, ldn_access_load(host_index, i), IBM_DS(host_index).ldn_read_access[i], IBM_DS(host_index).ldn_write_access[i], IBM_DS(host_index).ldn_assignments[i]);
+ len += sprintf(buffer + len, " %2X | %3d | %8d | %8d | %8d\n", i, ldn_access_load(shpnt, i), IBM_DS(shpnt).ldn_read_access[i], IBM_DS(shpnt).ldn_write_access[i], IBM_DS(shpnt).ldn_assignments[i]);
len += sprintf(buffer + len, " -----------------------------------------------------------\n\n");
len += sprintf(buffer + len, " Dynamical-LDN-Assignment-Statistics:\n");
- len += sprintf(buffer + len, " Number of physical SCSI-devices..: %d (+ Adapter)\n", IBM_DS(host_index).total_scsi_devices);
- len += sprintf(buffer + len, " Dynamical Assignment necessary...: %s\n", IBM_DS(host_index).dyn_flag ? "Yes" : "No ");
- len += sprintf(buffer + len, " Next LDN to be assigned..........: 0x%x\n", next_ldn(host_index));
- len += sprintf(buffer + len, " Dynamical assignments done yet...: %d\n", IBM_DS(host_index).dynamical_assignments);
+ len += sprintf(buffer + len, " Number of physical SCSI-devices..: %d (+ Adapter)\n", IBM_DS(shpnt).total_scsi_devices);
+ len += sprintf(buffer + len, " Dynamical Assignment necessary...: %s\n", IBM_DS(shpnt).dyn_flag ? "Yes" : "No ");
+ len += sprintf(buffer + len, " Next LDN to be assigned..........: 0x%x\n", next_ldn(shpnt));
+ len += sprintf(buffer + len, " Dynamical assignments done yet...: %d\n", IBM_DS(shpnt).dynamical_assignments);
len += sprintf(buffer + len, "\n Current SCSI-Device-Mapping:\n");
len += sprintf(buffer + len, " Physical SCSI-Device Map Logical SCSI-Device Map\n");
len += sprintf(buffer + len, " ID\\LUN 0 1 2 3 4 5 6 7 ID\\LUN 0 1 2 3 4 5 6 7\n");
for (id = 0; id < max_pun; id++) {
len += sprintf(buffer + len, " %2d ", id);
for (lun = 0; lun < 8; lun++)
- len += sprintf(buffer + len, "%2s ", ti_p(get_scsi(host_index)[id][lun]));
+ len += sprintf(buffer + len, "%2s ", ti_p(get_scsi(shpnt)[id][lun]));
len += sprintf(buffer + len, " %2d ", id);
for (lun = 0; lun < 8; lun++)
- len += sprintf(buffer + len, "%2s ", ti_l(get_ldn(host_index)[id][lun]));
+ len += sprintf(buffer + len, "%2s ", ti_l(get_ldn(shpnt)[id][lun]));
len += sprintf(buffer + len, "\n");
}
@@ -2488,20 +2354,31 @@
__setup("ibmmcascsi=", option_setup);
-static struct scsi_host_template driver_template = {
- .proc_name = "ibmmca",
- .proc_info = ibmmca_proc_info,
- .name = "IBM SCSI-Subsystem",
- .detect = ibmmca_detect,
- .release = ibmmca_release,
- .queuecommand = ibmmca_queuecommand,
- .eh_abort_handler = ibmmca_abort,
- .eh_host_reset_handler = ibmmca_host_reset,
- .bios_param = ibmmca_biosparam,
- .can_queue = 16,
- .this_id = 7,
- .sg_tablesize = 16,
- .cmd_per_lun = 1,
- .use_clustering = ENABLE_CLUSTERING,
+static struct mca_driver ibmmca_driver = {
+ .id_table = ibmmca_id_table,
+ .driver = {
+ .name = "ibmmca",
+ .bus = &mca_bus_type,
+ .probe = ibmmca_probe,
+ .remove = __devexit_p(ibmmca_remove),
+ },
};
-#include "scsi_module.c"
+
+static int __init ibmmca_init(void)
+{
+#ifdef MODULE
+ /* If the driver is run as module, read from conf.modules or cmd-line */
+ if (boot_options)
+ option_setup(boot_options);
+#endif
+
+ return mca_register_driver_integrated(&ibmmca_driver, MCA_INTEGSCSI);
+}
+
+static void __exit ibmmca_exit(void)
+{
+ mca_unregister_driver(&ibmmca_driver);
+}
+
+module_init(ibmmca_init);
+module_exit(ibmmca_exit);
diff --git a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h
deleted file mode 100644
index 017ee2f..0000000
--- a/drivers/scsi/ibmmca.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Low Level Driver for the IBM Microchannel SCSI Subsystem
- * (Headerfile, see Documentation/scsi/ibmmca.txt for description of the
- * IBM MCA SCSI-driver.
- * For use under the GNU General Public License within the Linux-kernel project.
- * This include file works only correctly with kernel 2.4.0 or higher!!! */
-
-#ifndef _IBMMCA_H
-#define _IBMMCA_H
-
-/* Common forward declarations for all Linux-versions: */
-
-/* Interfaces to the midlevel Linux SCSI driver */
-static int ibmmca_detect (struct scsi_host_template *);
-static int ibmmca_release (struct Scsi_Host *);
-static int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-static int ibmmca_abort (Scsi_Cmnd *);
-static int ibmmca_host_reset (Scsi_Cmnd *);
-static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *);
-
-#endif /* _IBMMCA_H */
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index b10eefe..5870866 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -173,9 +173,8 @@
}
}
if (in_use)
- printk(KERN_WARNING
- "ibmvscsi: releasing event pool with %d "
- "events still in use?\n", in_use);
+ dev_warn(hostdata->dev, "releasing event pool with %d "
+ "events still in use?\n", in_use);
kfree(pool->events);
dma_free_coherent(hostdata->dev,
pool->size * sizeof(*pool->iu_storage),
@@ -210,15 +209,13 @@
struct srp_event_struct *evt)
{
if (!valid_event_struct(pool, evt)) {
- printk(KERN_ERR
- "ibmvscsi: Freeing invalid event_struct %p "
- "(not in pool %p)\n", evt, pool->events);
+ dev_err(evt->hostdata->dev, "Freeing invalid event_struct %p "
+ "(not in pool %p)\n", evt, pool->events);
return;
}
if (atomic_inc_return(&evt->free) != 1) {
- printk(KERN_ERR
- "ibmvscsi: Freeing event_struct %p "
- "which is not in use!\n", evt);
+ dev_err(evt->hostdata->dev, "Freeing event_struct %p "
+ "which is not in use!\n", evt);
return;
}
}
@@ -353,20 +350,19 @@
}
}
-static int map_sg_list(int num_entries,
- struct scatterlist *sg,
+static int map_sg_list(struct scsi_cmnd *cmd, int nseg,
struct srp_direct_buf *md)
{
int i;
+ struct scatterlist *sg;
u64 total_length = 0;
- for (i = 0; i < num_entries; ++i) {
+ scsi_for_each_sg(cmd, sg, nseg, i) {
struct srp_direct_buf *descr = md + i;
- struct scatterlist *sg_entry = &sg[i];
- descr->va = sg_dma_address(sg_entry);
- descr->len = sg_dma_len(sg_entry);
+ descr->va = sg_dma_address(sg);
+ descr->len = sg_dma_len(sg);
descr->key = 0;
- total_length += sg_dma_len(sg_entry);
+ total_length += sg_dma_len(sg);
}
return total_length;
}
@@ -387,40 +383,37 @@
int sg_mapped;
u64 total_length = 0;
- struct scatterlist *sg = cmd->request_buffer;
struct srp_direct_buf *data =
(struct srp_direct_buf *) srp_cmd->add_data;
struct srp_indirect_buf *indirect =
(struct srp_indirect_buf *) data;
- sg_mapped = dma_map_sg(dev, sg, cmd->use_sg, DMA_BIDIRECTIONAL);
-
- if (sg_mapped == 0)
+ sg_mapped = scsi_dma_map(cmd);
+ if (!sg_mapped)
+ return 1;
+ else if (sg_mapped < 0)
return 0;
+ else if (sg_mapped > SG_ALL) {
+ printk(KERN_ERR
+ "ibmvscsi: More than %d mapped sg entries, got %d\n",
+ SG_ALL, sg_mapped);
+ return 0;
+ }
set_srp_direction(cmd, srp_cmd, sg_mapped);
/* special case; we can use a single direct descriptor */
if (sg_mapped == 1) {
- data->va = sg_dma_address(&sg[0]);
- data->len = sg_dma_len(&sg[0]);
- data->key = 0;
+ map_sg_list(cmd, sg_mapped, data);
return 1;
}
- if (sg_mapped > SG_ALL) {
- printk(KERN_ERR
- "ibmvscsi: More than %d mapped sg entries, got %d\n",
- SG_ALL, sg_mapped);
- return 0;
- }
-
indirect->table_desc.va = 0;
indirect->table_desc.len = sg_mapped * sizeof(struct srp_direct_buf);
indirect->table_desc.key = 0;
if (sg_mapped <= MAX_INDIRECT_BUFS) {
- total_length = map_sg_list(sg_mapped, sg,
+ total_length = map_sg_list(cmd, sg_mapped,
&indirect->desc_list[0]);
indirect->len = total_length;
return 1;
@@ -429,61 +422,27 @@
/* get indirect table */
if (!evt_struct->ext_list) {
evt_struct->ext_list = (struct srp_direct_buf *)
- dma_alloc_coherent(dev,
+ dma_alloc_coherent(dev,
SG_ALL * sizeof(struct srp_direct_buf),
&evt_struct->ext_list_token, 0);
if (!evt_struct->ext_list) {
- printk(KERN_ERR
- "ibmvscsi: Can't allocate memory for indirect table\n");
+ sdev_printk(KERN_ERR, cmd->device,
+ "Can't allocate memory for indirect table\n");
return 0;
-
}
}
- total_length = map_sg_list(sg_mapped, sg, evt_struct->ext_list);
+ total_length = map_sg_list(cmd, sg_mapped, evt_struct->ext_list);
indirect->len = total_length;
indirect->table_desc.va = evt_struct->ext_list_token;
indirect->table_desc.len = sg_mapped * sizeof(indirect->desc_list[0]);
memcpy(indirect->desc_list, evt_struct->ext_list,
MAX_INDIRECT_BUFS * sizeof(struct srp_direct_buf));
-
return 1;
}
/**
- * map_single_data: - Maps memory and initializes memory decriptor fields
- * @cmd: struct scsi_cmnd with the memory to be mapped
- * @srp_cmd: srp_cmd that contains the memory descriptor
- * @dev: device for which to map dma memory
- *
- * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd.
- * Returns 1 on success.
-*/
-static int map_single_data(struct scsi_cmnd *cmd,
- struct srp_cmd *srp_cmd, struct device *dev)
-{
- struct srp_direct_buf *data =
- (struct srp_direct_buf *) srp_cmd->add_data;
-
- data->va =
- dma_map_single(dev, cmd->request_buffer,
- cmd->request_bufflen,
- DMA_BIDIRECTIONAL);
- if (dma_mapping_error(data->va)) {
- printk(KERN_ERR
- "ibmvscsi: Unable to map request_buffer for command!\n");
- return 0;
- }
- data->len = cmd->request_bufflen;
- data->key = 0;
-
- set_srp_direction(cmd, srp_cmd, 1);
-
- return 1;
-}
-
-/**
* map_data_for_srp_cmd: - Calls functions to map data for srp cmds
* @cmd: struct scsi_cmnd with the memory to be mapped
* @srp_cmd: srp_cmd that contains the memory descriptor
@@ -503,23 +462,83 @@
case DMA_NONE:
return 1;
case DMA_BIDIRECTIONAL:
- printk(KERN_ERR
- "ibmvscsi: Can't map DMA_BIDIRECTIONAL to read/write\n");
+ sdev_printk(KERN_ERR, cmd->device,
+ "Can't map DMA_BIDIRECTIONAL to read/write\n");
return 0;
default:
- printk(KERN_ERR
- "ibmvscsi: Unknown data direction 0x%02x; can't map!\n",
- cmd->sc_data_direction);
+ sdev_printk(KERN_ERR, cmd->device,
+ "Unknown data direction 0x%02x; can't map!\n",
+ cmd->sc_data_direction);
return 0;
}
- if (!cmd->request_buffer)
- return 1;
- if (cmd->use_sg)
- return map_sg_data(cmd, evt_struct, srp_cmd, dev);
- return map_single_data(cmd, srp_cmd, dev);
+ return map_sg_data(cmd, evt_struct, srp_cmd, dev);
}
+/**
+ * purge_requests: Our virtual adapter just shut down. purge any sent requests
+ * @hostdata: the adapter
+ */
+static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
+{
+ struct srp_event_struct *tmp_evt, *pos;
+ unsigned long flags;
+
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
+ list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
+ list_del(&tmp_evt->list);
+ del_timer(&tmp_evt->timer);
+ if (tmp_evt->cmnd) {
+ tmp_evt->cmnd->result = (error_code << 16);
+ unmap_cmd_data(&tmp_evt->iu.srp.cmd,
+ tmp_evt,
+ tmp_evt->hostdata->dev);
+ if (tmp_evt->cmnd_done)
+ tmp_evt->cmnd_done(tmp_evt->cmnd);
+ } else if (tmp_evt->done)
+ tmp_evt->done(tmp_evt);
+ free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
+ }
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+}
+
+/**
+ * ibmvscsi_reset_host - Reset the connection to the server
+ * @hostdata: struct ibmvscsi_host_data to reset
+*/
+static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
+{
+ scsi_block_requests(hostdata->host);
+ atomic_set(&hostdata->request_limit, 0);
+
+ purge_requests(hostdata, DID_ERROR);
+ if ((ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata)) ||
+ (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0)) ||
+ (vio_enable_interrupts(to_vio_dev(hostdata->dev)))) {
+ atomic_set(&hostdata->request_limit, -1);
+ dev_err(hostdata->dev, "error after reset\n");
+ }
+
+ scsi_unblock_requests(hostdata->host);
+}
+
+/**
+ * ibmvscsi_timeout - Internal command timeout handler
+ * @evt_struct: struct srp_event_struct that timed out
+ *
+ * Called when an internally generated command times out
+*/
+static void ibmvscsi_timeout(struct srp_event_struct *evt_struct)
+{
+ struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+
+ dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n",
+ evt_struct->iu.srp.cmd.opcode);
+
+ ibmvscsi_reset_host(hostdata);
+}
+
+
/* ------------------------------------------------------------
* Routines for sending and receiving SRPs
*/
@@ -527,12 +546,14 @@
* ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq()
* @evt_struct: evt_struct to be sent
* @hostdata: ibmvscsi_host_data of host
+ * @timeout: timeout in seconds - 0 means do not time command
*
* Returns the value returned from ibmvscsi_send_crq(). (Zero for success)
* Note that this routine assumes that host_lock is held for synchronization
*/
static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
- struct ibmvscsi_host_data *hostdata)
+ struct ibmvscsi_host_data *hostdata,
+ unsigned long timeout)
{
u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
int request_status;
@@ -588,12 +609,20 @@
*/
list_add_tail(&evt_struct->list, &hostdata->sent);
+ init_timer(&evt_struct->timer);
+ if (timeout) {
+ evt_struct->timer.data = (unsigned long) evt_struct;
+ evt_struct->timer.expires = jiffies + (timeout * HZ);
+ evt_struct->timer.function = (void (*)(unsigned long))ibmvscsi_timeout;
+ add_timer(&evt_struct->timer);
+ }
+
if ((rc =
ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
list_del(&evt_struct->list);
+ del_timer(&evt_struct->timer);
- printk(KERN_ERR "ibmvscsi: send error %d\n",
- rc);
+ dev_err(hostdata->dev, "send error %d\n", rc);
atomic_inc(&hostdata->request_limit);
goto send_error;
}
@@ -634,9 +663,8 @@
if (unlikely(rsp->opcode != SRP_RSP)) {
if (printk_ratelimit())
- printk(KERN_WARNING
- "ibmvscsi: bad SRP RSP type %d\n",
- rsp->opcode);
+ dev_warn(evt_struct->hostdata->dev,
+ "bad SRP RSP type %d\n", rsp->opcode);
}
if (cmnd) {
@@ -650,9 +678,9 @@
evt_struct->hostdata->dev);
if (rsp->flags & SRP_RSP_FLAG_DOOVER)
- cmnd->resid = rsp->data_out_res_cnt;
+ scsi_set_resid(cmnd, rsp->data_out_res_cnt);
else if (rsp->flags & SRP_RSP_FLAG_DIOVER)
- cmnd->resid = rsp->data_in_res_cnt;
+ scsi_set_resid(cmnd, rsp->data_in_res_cnt);
}
if (evt_struct->cmnd_done)
@@ -697,7 +725,7 @@
srp_cmd->lun = ((u64) lun) << 48;
if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
- printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n");
+ sdev_printk(KERN_ERR, cmnd->device, "couldn't convert cmd to srp_cmd\n");
free_event_struct(&hostdata->pool, evt_struct);
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -722,7 +750,7 @@
offsetof(struct srp_indirect_buf, desc_list);
}
- return ibmvscsi_send_srp_event(evt_struct, hostdata);
+ return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
}
/* ------------------------------------------------------------
@@ -744,16 +772,16 @@
DMA_BIDIRECTIONAL);
if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
- printk("ibmvscsi: error %d getting adapter info\n",
- evt_struct->xfer_iu->mad.adapter_info.common.status);
+ dev_err(hostdata->dev, "error %d getting adapter info\n",
+ evt_struct->xfer_iu->mad.adapter_info.common.status);
} else {
- printk("ibmvscsi: host srp version: %s, "
- "host partition %s (%d), OS %d, max io %u\n",
- hostdata->madapter_info.srp_version,
- hostdata->madapter_info.partition_name,
- hostdata->madapter_info.partition_number,
- hostdata->madapter_info.os_type,
- hostdata->madapter_info.port_max_txu[0]);
+ dev_info(hostdata->dev, "host srp version: %s, "
+ "host partition %s (%d), OS %d, max io %u\n",
+ hostdata->madapter_info.srp_version,
+ hostdata->madapter_info.partition_name,
+ hostdata->madapter_info.partition_number,
+ hostdata->madapter_info.os_type,
+ hostdata->madapter_info.port_max_txu[0]);
if (hostdata->madapter_info.port_max_txu[0])
hostdata->host->max_sectors =
@@ -761,11 +789,10 @@
if (hostdata->madapter_info.os_type == 3 &&
strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
- printk("ibmvscsi: host (Ver. %s) doesn't support large"
- "transfers\n",
- hostdata->madapter_info.srp_version);
- printk("ibmvscsi: limiting scatterlists to %d\n",
- MAX_INDIRECT_BUFS);
+ dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
+ hostdata->madapter_info.srp_version);
+ dev_err(hostdata->dev, "limiting scatterlists to %d\n",
+ MAX_INDIRECT_BUFS);
hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
}
}
@@ -784,19 +811,20 @@
{
struct viosrp_adapter_info *req;
struct srp_event_struct *evt_struct;
+ unsigned long flags;
dma_addr_t addr;
evt_struct = get_event_struct(&hostdata->pool);
if (!evt_struct) {
- printk(KERN_ERR "ibmvscsi: couldn't allocate an event "
- "for ADAPTER_INFO_REQ!\n");
+ dev_err(hostdata->dev,
+ "couldn't allocate an event for ADAPTER_INFO_REQ!\n");
return;
}
init_event_struct(evt_struct,
adapter_info_rsp,
VIOSRP_MAD_FORMAT,
- init_timeout * HZ);
+ init_timeout);
req = &evt_struct->iu.mad.adapter_info;
memset(req, 0x00, sizeof(*req));
@@ -809,20 +837,20 @@
DMA_BIDIRECTIONAL);
if (dma_mapping_error(req->buffer)) {
- printk(KERN_ERR
- "ibmvscsi: Unable to map request_buffer "
- "for adapter_info!\n");
+ dev_err(hostdata->dev, "Unable to map request_buffer for adapter_info!\n");
free_event_struct(&hostdata->pool, evt_struct);
return;
}
- if (ibmvscsi_send_srp_event(evt_struct, hostdata)) {
- printk(KERN_ERR "ibmvscsi: couldn't send ADAPTER_INFO_REQ!\n");
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
+ if (ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2)) {
+ dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
dma_unmap_single(hostdata->dev,
addr,
sizeof(hostdata->madapter_info),
DMA_BIDIRECTIONAL);
}
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
};
/**
@@ -839,24 +867,23 @@
case SRP_LOGIN_RSP: /* it worked! */
break;
case SRP_LOGIN_REJ: /* refused! */
- printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REJ reason %u\n",
- evt_struct->xfer_iu->srp.login_rej.reason);
+ dev_info(hostdata->dev, "SRP_LOGIN_REJ reason %u\n",
+ evt_struct->xfer_iu->srp.login_rej.reason);
/* Login failed. */
atomic_set(&hostdata->request_limit, -1);
return;
default:
- printk(KERN_ERR
- "ibmvscsi: Invalid login response typecode 0x%02x!\n",
- evt_struct->xfer_iu->srp.login_rsp.opcode);
+ dev_err(hostdata->dev, "Invalid login response typecode 0x%02x!\n",
+ evt_struct->xfer_iu->srp.login_rsp.opcode);
/* Login failed. */
atomic_set(&hostdata->request_limit, -1);
return;
}
- printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n");
+ dev_info(hostdata->dev, "SRP_LOGIN succeeded\n");
if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta < 0)
- printk(KERN_ERR "ibmvscsi: Invalid request_limit.\n");
+ dev_err(hostdata->dev, "Invalid request_limit.\n");
/* Now we know what the real request-limit is.
* This value is set rather than added to request_limit because
@@ -885,15 +912,14 @@
struct srp_login_req *login;
struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool);
if (!evt_struct) {
- printk(KERN_ERR
- "ibmvscsi: couldn't allocate an event for login req!\n");
+ dev_err(hostdata->dev, "couldn't allocate an event for login req!\n");
return FAILED;
}
init_event_struct(evt_struct,
login_rsp,
VIOSRP_SRP_FORMAT,
- init_timeout * HZ);
+ init_timeout);
login = &evt_struct->iu.srp.login_req;
memset(login, 0x00, sizeof(struct srp_login_req));
@@ -907,9 +933,9 @@
*/
atomic_set(&hostdata->request_limit, 1);
- rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
+ rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- printk("ibmvscsic: sent SRP login\n");
+ dev_info(hostdata->dev, "sent SRP login\n");
return rc;
};
@@ -958,20 +984,20 @@
if (!found_evt) {
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- return FAILED;
+ return SUCCESS;
}
evt = get_event_struct(&hostdata->pool);
if (evt == NULL) {
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- printk(KERN_ERR "ibmvscsi: failed to allocate abort event\n");
+ sdev_printk(KERN_ERR, cmd->device, "failed to allocate abort event\n");
return FAILED;
}
init_event_struct(evt,
sync_completion,
VIOSRP_SRP_FORMAT,
- init_timeout * HZ);
+ init_timeout);
tsk_mgmt = &evt->iu.srp.tsk_mgmt;
@@ -982,15 +1008,16 @@
tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
tsk_mgmt->task_tag = (u64) found_evt;
- printk(KERN_INFO "ibmvscsi: aborting command. lun 0x%lx, tag 0x%lx\n",
- tsk_mgmt->lun, tsk_mgmt->task_tag);
+ sdev_printk(KERN_INFO, cmd->device, "aborting command. lun 0x%lx, tag 0x%lx\n",
+ tsk_mgmt->lun, tsk_mgmt->task_tag);
evt->sync_srp = &srp_rsp;
init_completion(&evt->comp);
- rsp_rc = ibmvscsi_send_srp_event(evt, hostdata);
+ rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
if (rsp_rc != 0) {
- printk(KERN_ERR "ibmvscsi: failed to send abort() event\n");
+ sdev_printk(KERN_ERR, cmd->device,
+ "failed to send abort() event. rc=%d\n", rsp_rc);
return FAILED;
}
@@ -999,9 +1026,8 @@
/* make sure we got a good response */
if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
if (printk_ratelimit())
- printk(KERN_WARNING
- "ibmvscsi: abort bad SRP RSP type %d\n",
- srp_rsp.srp.rsp.opcode);
+ sdev_printk(KERN_WARNING, cmd->device, "abort bad SRP RSP type %d\n",
+ srp_rsp.srp.rsp.opcode);
return FAILED;
}
@@ -1012,10 +1038,9 @@
if (rsp_rc) {
if (printk_ratelimit())
- printk(KERN_WARNING
- "ibmvscsi: abort code %d for task tag 0x%lx\n",
- rsp_rc,
- tsk_mgmt->task_tag);
+ sdev_printk(KERN_WARNING, cmd->device,
+ "abort code %d for task tag 0x%lx\n",
+ rsp_rc, tsk_mgmt->task_tag);
return FAILED;
}
@@ -1034,15 +1059,13 @@
if (found_evt == NULL) {
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- printk(KERN_INFO
- "ibmvscsi: aborted task tag 0x%lx completed\n",
- tsk_mgmt->task_tag);
+ sdev_printk(KERN_INFO, cmd->device, "aborted task tag 0x%lx completed\n",
+ tsk_mgmt->task_tag);
return SUCCESS;
}
- printk(KERN_INFO
- "ibmvscsi: successfully aborted task tag 0x%lx\n",
- tsk_mgmt->task_tag);
+ sdev_printk(KERN_INFO, cmd->device, "successfully aborted task tag 0x%lx\n",
+ tsk_mgmt->task_tag);
cmd->result = (DID_ABORT << 16);
list_del(&found_evt->list);
@@ -1076,14 +1099,14 @@
evt = get_event_struct(&hostdata->pool);
if (evt == NULL) {
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- printk(KERN_ERR "ibmvscsi: failed to allocate reset event\n");
+ sdev_printk(KERN_ERR, cmd->device, "failed to allocate reset event\n");
return FAILED;
}
init_event_struct(evt,
sync_completion,
VIOSRP_SRP_FORMAT,
- init_timeout * HZ);
+ init_timeout);
tsk_mgmt = &evt->iu.srp.tsk_mgmt;
@@ -1093,15 +1116,16 @@
tsk_mgmt->lun = ((u64) lun) << 48;
tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
- printk(KERN_INFO "ibmvscsi: resetting device. lun 0x%lx\n",
- tsk_mgmt->lun);
+ sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
+ tsk_mgmt->lun);
evt->sync_srp = &srp_rsp;
init_completion(&evt->comp);
- rsp_rc = ibmvscsi_send_srp_event(evt, hostdata);
+ rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
if (rsp_rc != 0) {
- printk(KERN_ERR "ibmvscsi: failed to send reset event\n");
+ sdev_printk(KERN_ERR, cmd->device,
+ "failed to send reset event. rc=%d\n", rsp_rc);
return FAILED;
}
@@ -1110,9 +1134,8 @@
/* make sure we got a good response */
if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
if (printk_ratelimit())
- printk(KERN_WARNING
- "ibmvscsi: reset bad SRP RSP type %d\n",
- srp_rsp.srp.rsp.opcode);
+ sdev_printk(KERN_WARNING, cmd->device, "reset bad SRP RSP type %d\n",
+ srp_rsp.srp.rsp.opcode);
return FAILED;
}
@@ -1123,9 +1146,9 @@
if (rsp_rc) {
if (printk_ratelimit())
- printk(KERN_WARNING
- "ibmvscsi: reset code %d for task tag 0x%lx\n",
- rsp_rc, tsk_mgmt->task_tag);
+ sdev_printk(KERN_WARNING, cmd->device,
+ "reset code %d for task tag 0x%lx\n",
+ rsp_rc, tsk_mgmt->task_tag);
return FAILED;
}
@@ -1154,32 +1177,30 @@
}
/**
- * purge_requests: Our virtual adapter just shut down. purge any sent requests
- * @hostdata: the adapter
- */
-static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
+ * ibmvscsi_eh_host_reset_handler - Reset the connection to the server
+ * @cmd: struct scsi_cmnd having problems
+*/
+static int ibmvscsi_eh_host_reset_handler(struct scsi_cmnd *cmd)
{
- struct srp_event_struct *tmp_evt, *pos;
- unsigned long flags;
+ unsigned long wait_switch = 0;
+ struct ibmvscsi_host_data *hostdata =
+ (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
- spin_lock_irqsave(hostdata->host->host_lock, flags);
- list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
- list_del(&tmp_evt->list);
- if (tmp_evt->cmnd) {
- tmp_evt->cmnd->result = (error_code << 16);
- unmap_cmd_data(&tmp_evt->iu.srp.cmd,
- tmp_evt,
- tmp_evt->hostdata->dev);
- if (tmp_evt->cmnd_done)
- tmp_evt->cmnd_done(tmp_evt->cmnd);
- } else {
- if (tmp_evt->done) {
- tmp_evt->done(tmp_evt);
- }
- }
- free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
+ dev_err(hostdata->dev, "Resetting connection due to error recovery\n");
+
+ ibmvscsi_reset_host(hostdata);
+
+ for (wait_switch = jiffies + (init_timeout * HZ);
+ time_before(jiffies, wait_switch) &&
+ atomic_read(&hostdata->request_limit) < 2;) {
+
+ msleep(10);
}
- spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
+ if (atomic_read(&hostdata->request_limit) <= 0)
+ return FAILED;
+
+ return SUCCESS;
}
/**
@@ -1191,6 +1212,7 @@
void ibmvscsi_handle_crq(struct viosrp_crq *crq,
struct ibmvscsi_host_data *hostdata)
{
+ long rc;
unsigned long flags;
struct srp_event_struct *evt_struct =
(struct srp_event_struct *)crq->IU_data_ptr;
@@ -1198,27 +1220,25 @@
case 0xC0: /* initialization */
switch (crq->format) {
case 0x01: /* Initialization message */
- printk(KERN_INFO "ibmvscsi: partner initialized\n");
+ dev_info(hostdata->dev, "partner initialized\n");
/* Send back a response */
- if (ibmvscsi_send_crq(hostdata,
- 0xC002000000000000LL, 0) == 0) {
+ if ((rc = ibmvscsi_send_crq(hostdata,
+ 0xC002000000000000LL, 0)) == 0) {
/* Now login */
send_srp_login(hostdata);
} else {
- printk(KERN_ERR
- "ibmvscsi: Unable to send init rsp\n");
+ dev_err(hostdata->dev, "Unable to send init rsp. rc=%ld\n", rc);
}
break;
case 0x02: /* Initialization response */
- printk(KERN_INFO
- "ibmvscsi: partner initialization complete\n");
+ dev_info(hostdata->dev, "partner initialization complete\n");
/* Now login */
send_srp_login(hostdata);
break;
default:
- printk(KERN_ERR "ibmvscsi: unknown crq message type\n");
+ dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format);
}
return;
case 0xFF: /* Hypervisor telling us the connection is closed */
@@ -1226,8 +1246,7 @@
atomic_set(&hostdata->request_limit, 0);
if (crq->format == 0x06) {
/* We need to re-setup the interpartition connection */
- printk(KERN_INFO
- "ibmvscsi: Re-enabling adapter!\n");
+ dev_info(hostdata->dev, "Re-enabling adapter!\n");
purge_requests(hostdata, DID_REQUEUE);
if ((ibmvscsi_reenable_crq_queue(&hostdata->queue,
hostdata)) ||
@@ -1235,14 +1254,11 @@
0xC001000000000000LL, 0))) {
atomic_set(&hostdata->request_limit,
-1);
- printk(KERN_ERR
- "ibmvscsi: error after"
- " enable\n");
+ dev_err(hostdata->dev, "error after enable\n");
}
} else {
- printk(KERN_INFO
- "ibmvscsi: Virtual adapter failed rc %d!\n",
- crq->format);
+ dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n",
+ crq->format);
purge_requests(hostdata, DID_ERROR);
if ((ibmvscsi_reset_crq_queue(&hostdata->queue,
@@ -1251,8 +1267,7 @@
0xC001000000000000LL, 0))) {
atomic_set(&hostdata->request_limit,
-1);
- printk(KERN_ERR
- "ibmvscsi: error after reset\n");
+ dev_err(hostdata->dev, "error after reset\n");
}
}
scsi_unblock_requests(hostdata->host);
@@ -1260,9 +1275,8 @@
case 0x80: /* real payload */
break;
default:
- printk(KERN_ERR
- "ibmvscsi: got an invalid message type 0x%02x\n",
- crq->valid);
+ dev_err(hostdata->dev, "got an invalid message type 0x%02x\n",
+ crq->valid);
return;
}
@@ -1271,16 +1285,14 @@
* actually sent
*/
if (!valid_event_struct(&hostdata->pool, evt_struct)) {
- printk(KERN_ERR
- "ibmvscsi: returned correlation_token 0x%p is invalid!\n",
+ dev_err(hostdata->dev, "returned correlation_token 0x%p is invalid!\n",
(void *)crq->IU_data_ptr);
return;
}
if (atomic_read(&evt_struct->free)) {
- printk(KERN_ERR
- "ibmvscsi: received duplicate correlation_token 0x%p!\n",
- (void *)crq->IU_data_ptr);
+ dev_err(hostdata->dev, "received duplicate correlation_token 0x%p!\n",
+ (void *)crq->IU_data_ptr);
return;
}
@@ -1288,11 +1300,12 @@
atomic_add(evt_struct->xfer_iu->srp.rsp.req_lim_delta,
&hostdata->request_limit);
+ del_timer(&evt_struct->timer);
+
if (evt_struct->done)
evt_struct->done(evt_struct);
else
- printk(KERN_ERR
- "ibmvscsi: returned done() is NULL; not running it!\n");
+ dev_err(hostdata->dev, "returned done() is NULL; not running it!\n");
/*
* Lock the host_lock before messing with these structures, since we
@@ -1313,20 +1326,20 @@
{
struct viosrp_host_config *host_config;
struct srp_event_struct *evt_struct;
+ unsigned long flags;
dma_addr_t addr;
int rc;
evt_struct = get_event_struct(&hostdata->pool);
if (!evt_struct) {
- printk(KERN_ERR
- "ibmvscsi: could't allocate event for HOST_CONFIG!\n");
+ dev_err(hostdata->dev, "couldn't allocate event for HOST_CONFIG!\n");
return -1;
}
init_event_struct(evt_struct,
sync_completion,
VIOSRP_MAD_FORMAT,
- init_timeout * HZ);
+ init_timeout);
host_config = &evt_struct->iu.mad.host_config;
@@ -1339,14 +1352,15 @@
DMA_BIDIRECTIONAL);
if (dma_mapping_error(host_config->buffer)) {
- printk(KERN_ERR
- "ibmvscsi: dma_mapping error " "getting host config\n");
+ dev_err(hostdata->dev, "dma_mapping error getting host config\n");
free_event_struct(&hostdata->pool, evt_struct);
return -1;
}
init_completion(&evt_struct->comp);
- rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
+ rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
if (rc == 0)
wait_for_completion(&evt_struct->comp);
dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL);
@@ -1375,6 +1389,23 @@
return 0;
}
+/**
+ * ibmvscsi_change_queue_depth - Change the device's queue depth
+ * @sdev: scsi device struct
+ * @qdepth: depth to set
+ *
+ * Return value:
+ * actual depth set
+ **/
+static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
+{
+ if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN)
+ qdepth = IBMVSCSI_MAX_CMDS_PER_LUN;
+
+ scsi_adjust_queue_depth(sdev, 0, qdepth);
+ return sdev->queue_depth;
+}
+
/* ------------------------------------------------------------
* sysfs attributes
*/
@@ -1520,7 +1551,9 @@
.queuecommand = ibmvscsi_queuecommand,
.eh_abort_handler = ibmvscsi_eh_abort_handler,
.eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
+ .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
.slave_configure = ibmvscsi_slave_configure,
+ .change_queue_depth = ibmvscsi_change_queue_depth,
.cmd_per_lun = 16,
.can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
.this_id = -1,
@@ -1545,7 +1578,7 @@
driver_template.can_queue = max_requests;
host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
if (!host) {
- printk(KERN_ERR "ibmvscsi: couldn't allocate host data\n");
+ dev_err(&vdev->dev, "couldn't allocate host data\n");
goto scsi_host_alloc_failed;
}
@@ -1559,11 +1592,11 @@
rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests);
if (rc != 0 && rc != H_RESOURCE) {
- printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n");
+ dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
goto init_crq_failed;
}
if (initialize_event_pool(&hostdata->pool, max_requests, hostdata) != 0) {
- printk(KERN_ERR "ibmvscsi: couldn't initialize event pool\n");
+ dev_err(&vdev->dev, "couldn't initialize event pool\n");
goto init_pool_failed;
}
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 77cc1d4..b19c2e2 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -45,6 +45,7 @@
#define MAX_INDIRECT_BUFS 10
#define IBMVSCSI_MAX_REQUESTS_DEFAULT 100
+#define IBMVSCSI_MAX_CMDS_PER_LUN 64
/* ------------------------------------------------------------
* Data Structures
@@ -69,6 +70,7 @@
union viosrp_iu iu;
void (*cmnd_done) (struct scsi_cmnd *);
struct completion comp;
+ struct timer_list timer;
union viosrp_iu *sync_srp;
struct srp_direct_buf *ext_list;
dma_addr_t ext_list_token;
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index d8700aa..9c14e78 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -177,7 +177,7 @@
memset(&hostdata->madapter_info, 0x00,
sizeof(hostdata->madapter_info));
- printk(KERN_INFO "rpa_vscsi: SPR_VERSION: %s\n", SRP_VERSION);
+ dev_info(hostdata->dev, "SRP_VERSION: %s\n", SRP_VERSION);
strcpy(hostdata->madapter_info.srp_version, SRP_VERSION);
strncpy(hostdata->madapter_info.partition_name, partition_name,
@@ -232,25 +232,24 @@
if (rc == 2) {
/* Adapter is good, but other end is not ready */
- printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n");
+ dev_warn(hostdata->dev, "Partner adapter not ready\n");
retrc = 0;
} else if (rc != 0) {
- printk(KERN_WARNING "ibmvscsi: Error %d opening adapter\n", rc);
+ dev_warn(hostdata->dev, "Error %d opening adapter\n", rc);
goto reg_crq_failed;
}
if (request_irq(vdev->irq,
ibmvscsi_handle_event,
0, "ibmvscsi", (void *)hostdata) != 0) {
- printk(KERN_ERR "ibmvscsi: couldn't register irq 0x%x\n",
- vdev->irq);
+ dev_err(hostdata->dev, "couldn't register irq 0x%x\n",
+ vdev->irq);
goto req_irq_failed;
}
rc = vio_enable_interrupts(vdev);
if (rc != 0) {
- printk(KERN_ERR "ibmvscsi: Error %d enabling interrupts!!!\n",
- rc);
+ dev_err(hostdata->dev, "Error %d enabling interrupts!!!\n", rc);
goto req_irq_failed;
}
@@ -294,7 +293,7 @@
} while ((rc == H_IN_PROGRESS) || (rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
if (rc)
- printk(KERN_ERR "ibmvscsi: Error %d enabling adapter\n", rc);
+ dev_err(hostdata->dev, "Error %d enabling adapter\n", rc);
return rc;
}
@@ -327,10 +326,9 @@
queue->msg_token, PAGE_SIZE);
if (rc == 2) {
/* Adapter is good, but other end is not ready */
- printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n");
+ dev_warn(hostdata->dev, "Partner adapter not ready\n");
} else if (rc != 0) {
- printk(KERN_WARNING
- "ibmvscsi: couldn't register crq--rc 0x%x\n", rc);
+ dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
}
return rc;
}
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 7e7635c..d9dfb69 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -3,7 +3,8 @@
*
* Copyright (c) 1994-1998 Initio Corporation
* Copyright (c) 1998 Bas Vermeulen <bvermeul@blackstar.xs4all.nl>
- * All rights reserved.
+ * Copyright (c) 2004 Christoph Hellwig <hch@lst.de>
+ * Copyright (c) 2007 Red Hat <alan@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,38 +20,6 @@
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * --------------------------------------------------------------------------
- *
- * 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, immediately at the beginning of the file.
- * 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.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * Where this Software is combined with software released under the terms of
- * the GNU General Public License ("GPL") and the terms of the GPL would require the
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * 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.
*
*************************************************************************
*
@@ -70,14 +39,14 @@
* - Fix memory allocation problem
* 03/04/98 hc - v1.01l
* - Fix tape rewind which will hang the system problem
- * - Set can_queue to tul_num_scb
+ * - Set can_queue to initio_num_scb
* 06/25/98 hc - v1.01m
* - Get it work for kernel version >= 2.1.75
- * - Dynamic assign SCSI bus reset holding time in init_tulip()
+ * - Dynamic assign SCSI bus reset holding time in initio_init()
* 07/02/98 hc - v1.01n
* - Support 0002134A
* 08/07/98 hc - v1.01o
- * - Change the tul_abort_srb routine to use scsi_done. <01>
+ * - Change the initio_abort_srb routine to use scsi_done. <01>
* 09/07/98 hl - v1.02
* - Change the INI9100U define and proc_dir_entry to
* reflect the newer Kernel 2.1.118, but the v1.o1o
@@ -150,23 +119,13 @@
static unsigned int i91u_debug = DEBUG_DEFAULT;
#endif
-#define TUL_RDWORD(x,y) (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
-
-typedef struct PCI_ID_Struc {
- unsigned short vendor_id;
- unsigned short device_id;
-} PCI_ID;
-
-static int tul_num_ch = 4; /* Maximum 4 adapters */
-static int tul_num_scb;
-static int tul_tag_enable = 1;
-static SCB *tul_scb;
+static int initio_tag_enable = 1;
#ifdef DEBUG_i91u
static int setup_debug = 0;
#endif
-static void i91uSCBPost(BYTE * pHcb, BYTE * pScb);
+static void i91uSCBPost(u8 * pHcb, u8 * pScb);
/* PCI Devices supported by this driver */
static struct pci_device_id i91u_pci_devices[] = {
@@ -184,74 +143,66 @@
#define DEBUG_STATE 0
#define INT_DISC 0
-/*--- external functions --*/
-static void tul_se2_wait(void);
+/*--- forward references ---*/
+static struct scsi_ctrl_blk *initio_find_busy_scb(struct initio_host * host, u16 tarlun);
+static struct scsi_ctrl_blk *initio_find_done_scb(struct initio_host * host);
-/*--- forward refrence ---*/
-static SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun);
-static SCB *tul_find_done_scb(HCS * pCurHcb);
+static int tulip_main(struct initio_host * host);
-static int tulip_main(HCS * pCurHcb);
+static int initio_next_state(struct initio_host * host);
+static int initio_state_1(struct initio_host * host);
+static int initio_state_2(struct initio_host * host);
+static int initio_state_3(struct initio_host * host);
+static int initio_state_4(struct initio_host * host);
+static int initio_state_5(struct initio_host * host);
+static int initio_state_6(struct initio_host * host);
+static int initio_state_7(struct initio_host * host);
+static int initio_xfer_data_in(struct initio_host * host);
+static int initio_xfer_data_out(struct initio_host * host);
+static int initio_xpad_in(struct initio_host * host);
+static int initio_xpad_out(struct initio_host * host);
+static int initio_status_msg(struct initio_host * host);
-static int tul_next_state(HCS * pCurHcb);
-static int tul_state_1(HCS * pCurHcb);
-static int tul_state_2(HCS * pCurHcb);
-static int tul_state_3(HCS * pCurHcb);
-static int tul_state_4(HCS * pCurHcb);
-static int tul_state_5(HCS * pCurHcb);
-static int tul_state_6(HCS * pCurHcb);
-static int tul_state_7(HCS * pCurHcb);
-static int tul_xfer_data_in(HCS * pCurHcb);
-static int tul_xfer_data_out(HCS * pCurHcb);
-static int tul_xpad_in(HCS * pCurHcb);
-static int tul_xpad_out(HCS * pCurHcb);
-static int tul_status_msg(HCS * pCurHcb);
+static int initio_msgin(struct initio_host * host);
+static int initio_msgin_sync(struct initio_host * host);
+static int initio_msgin_accept(struct initio_host * host);
+static int initio_msgout_reject(struct initio_host * host);
+static int initio_msgin_extend(struct initio_host * host);
-static int tul_msgin(HCS * pCurHcb);
-static int tul_msgin_sync(HCS * pCurHcb);
-static int tul_msgin_accept(HCS * pCurHcb);
-static int tul_msgout_reject(HCS * pCurHcb);
-static int tul_msgin_extend(HCS * pCurHcb);
+static int initio_msgout_ide(struct initio_host * host);
+static int initio_msgout_abort_targ(struct initio_host * host);
+static int initio_msgout_abort_tag(struct initio_host * host);
-static int tul_msgout_ide(HCS * pCurHcb);
-static int tul_msgout_abort_targ(HCS * pCurHcb);
-static int tul_msgout_abort_tag(HCS * pCurHcb);
+static int initio_bus_device_reset(struct initio_host * host);
+static void initio_select_atn(struct initio_host * host, struct scsi_ctrl_blk * scb);
+static void initio_select_atn3(struct initio_host * host, struct scsi_ctrl_blk * scb);
+static void initio_select_atn_stop(struct initio_host * host, struct scsi_ctrl_blk * scb);
+static int int_initio_busfree(struct initio_host * host);
+static int int_initio_scsi_rst(struct initio_host * host);
+static int int_initio_bad_seq(struct initio_host * host);
+static int int_initio_resel(struct initio_host * host);
+static int initio_sync_done(struct initio_host * host);
+static int wdtr_done(struct initio_host * host);
+static int wait_tulip(struct initio_host * host);
+static int initio_wait_done_disc(struct initio_host * host);
+static int initio_wait_disc(struct initio_host * host);
+static void tulip_scsi(struct initio_host * host);
+static int initio_post_scsi_rst(struct initio_host * host);
-static int tul_bus_device_reset(HCS * pCurHcb);
-static void tul_select_atn(HCS * pCurHcb, SCB * pCurScb);
-static void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb);
-static void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb);
-static int int_tul_busfree(HCS * pCurHcb);
-static int int_tul_scsi_rst(HCS * pCurHcb);
-static int int_tul_bad_seq(HCS * pCurHcb);
-static int int_tul_resel(HCS * pCurHcb);
-static int tul_sync_done(HCS * pCurHcb);
-static int wdtr_done(HCS * pCurHcb);
-static int wait_tulip(HCS * pCurHcb);
-static int tul_wait_done_disc(HCS * pCurHcb);
-static int tul_wait_disc(HCS * pCurHcb);
-static void tulip_scsi(HCS * pCurHcb);
-static int tul_post_scsi_rst(HCS * pCurHcb);
+static void initio_se2_ew_en(unsigned long base);
+static void initio_se2_ew_ds(unsigned long base);
+static int initio_se2_rd_all(unsigned long base);
+static void initio_se2_update_all(unsigned long base); /* setup default pattern */
+static void initio_read_eeprom(unsigned long base);
-static void tul_se2_ew_en(WORD CurBase);
-static void tul_se2_ew_ds(WORD CurBase);
-static int tul_se2_rd_all(WORD CurBase);
-static void tul_se2_update_all(WORD CurBase); /* setup default pattern */
-static void tul_read_eeprom(WORD CurBase);
+/* ---- INTERNAL VARIABLES ---- */
- /* ---- INTERNAL VARIABLES ---- */
-static HCS tul_hcs[MAX_SUPPORTED_ADAPTERS];
-static INI_ADPT_STRUCT i91u_adpt[MAX_SUPPORTED_ADAPTERS];
-
-/*NVRAM nvram, *nvramp = &nvram; */
static NVRAM i91unvram;
static NVRAM *i91unvramp;
-
-
-static UCHAR i91udftNvRam[64] =
+static u8 i91udftNvRam[64] =
{
-/*----------- header -----------*/
+ /*----------- header -----------*/
0x25, 0xc9, /* Signature */
0x40, /* Size */
0x01, /* Revision */
@@ -289,7 +240,7 @@
0, 0}; /* - CheckSum - */
-static UCHAR tul_rate_tbl[8] = /* fast 20 */
+static u8 initio_rate_tbl[8] = /* fast 20 */
{
/* nanosecond devide by 4 */
12, /* 50ns, 20M */
@@ -302,53 +253,17 @@
62 /* 250ns, 4M */
};
-static void tul_do_pause(unsigned amount)
-{ /* Pause for amount jiffies */
+static void initio_do_pause(unsigned amount)
+{
+ /* Pause for amount jiffies */
unsigned long the_time = jiffies + amount;
- while (time_before_eq(jiffies, the_time));
+ while (time_before_eq(jiffies, the_time))
+ cpu_relax();
}
/*-- forward reference --*/
-/*******************************************************************
- Use memeory refresh time ~ 15us * 2
-********************************************************************/
-void tul_se2_wait(void)
-{
-#if 1
- udelay(30);
-#else
- UCHAR readByte;
-
- readByte = TUL_RD(0, 0x61);
- if ((readByte & 0x10) == 0x10) {
- for (;;) {
- readByte = TUL_RD(0, 0x61);
- if ((readByte & 0x10) == 0x10)
- break;
- }
- for (;;) {
- readByte = TUL_RD(0, 0x61);
- if ((readByte & 0x10) != 0x10)
- break;
- }
- } else {
- for (;;) {
- readByte = TUL_RD(0, 0x61);
- if ((readByte & 0x10) == 0x10)
- break;
- }
- for (;;) {
- readByte = TUL_RD(0, 0x61);
- if ((readByte & 0x10) != 0x10)
- break;
- }
- }
-#endif
-}
-
-
/******************************************************************
Input: instruction for Serial E2PROM
@@ -379,1174 +294,1019 @@
******************************************************************/
-static void tul_se2_instr(WORD CurBase, UCHAR instr)
+
+/**
+ * initio_se2_instr - bitbang an instruction
+ * @base: Base of InitIO controller
+ * @instr: Instruction for serial E2PROM
+ *
+ * Bitbang an instruction out to the serial E2Prom
+ */
+
+static void initio_se2_instr(unsigned long base, u8 instr)
{
int i;
- UCHAR b;
+ u8 b;
- TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2DO); /* cs+start bit */
- tul_se2_wait();
- TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK | SE2DO); /* +CLK */
- tul_se2_wait();
+ outb(SE2CS | SE2DO, base + TUL_NVRAM); /* cs+start bit */
+ udelay(30);
+ outb(SE2CS | SE2CLK | SE2DO, base + TUL_NVRAM); /* +CLK */
+ udelay(30);
for (i = 0; i < 8; i++) {
if (instr & 0x80)
- b = SE2CS | SE2DO; /* -CLK+dataBit */
+ b = SE2CS | SE2DO; /* -CLK+dataBit */
else
- b = SE2CS; /* -CLK */
- TUL_WR(CurBase + TUL_NVRAM, b);
- tul_se2_wait();
- TUL_WR(CurBase + TUL_NVRAM, b | SE2CLK); /* +CLK */
- tul_se2_wait();
+ b = SE2CS; /* -CLK */
+ outb(b, base + TUL_NVRAM);
+ udelay(30);
+ outb(b | SE2CLK, base + TUL_NVRAM); /* +CLK */
+ udelay(30);
instr <<= 1;
}
- TUL_WR(CurBase + TUL_NVRAM, SE2CS); /* -CLK */
- tul_se2_wait();
- return;
+ outb(SE2CS, base + TUL_NVRAM); /* -CLK */
+ udelay(30);
}
-/******************************************************************
- Function name : tul_se2_ew_en
- Description : Enable erase/write state of serial EEPROM
-******************************************************************/
-void tul_se2_ew_en(WORD CurBase)
+/**
+ * initio_se2_ew_en - Enable erase/write
+ * @base: Base address of InitIO controller
+ *
+ * Enable erase/write state of serial EEPROM
+ */
+void initio_se2_ew_en(unsigned long base)
{
- tul_se2_instr(CurBase, 0x30); /* EWEN */
- TUL_WR(CurBase + TUL_NVRAM, 0); /* -CS */
- tul_se2_wait();
- return;
+ initio_se2_instr(base, 0x30); /* EWEN */
+ outb(0, base + TUL_NVRAM); /* -CS */
+ udelay(30);
}
-/************************************************************************
- Disable erase/write state of serial EEPROM
-*************************************************************************/
-void tul_se2_ew_ds(WORD CurBase)
+/**
+ * initio_se2_ew_ds - Disable erase/write
+ * @base: Base address of InitIO controller
+ *
+ * Disable erase/write state of serial EEPROM
+ */
+void initio_se2_ew_ds(unsigned long base)
{
- tul_se2_instr(CurBase, 0); /* EWDS */
- TUL_WR(CurBase + TUL_NVRAM, 0); /* -CS */
- tul_se2_wait();
- return;
+ initio_se2_instr(base, 0); /* EWDS */
+ outb(0, base + TUL_NVRAM); /* -CS */
+ udelay(30);
}
-/******************************************************************
- Input :address of Serial E2PROM
- Output :value stored in Serial E2PROM
-*******************************************************************/
-static USHORT tul_se2_rd(WORD CurBase, ULONG adr)
+/**
+ * initio_se2_rd - read E2PROM word
+ * @base: Base of InitIO controller
+ * @addr: Address of word in E2PROM
+ *
+ * Read a word from the NV E2PROM device
+ */
+static u16 initio_se2_rd(unsigned long base, u8 addr)
{
- UCHAR instr, readByte;
- USHORT readWord;
+ u8 instr, rb;
+ u16 val = 0;
int i;
- instr = (UCHAR) (adr | 0x80);
- tul_se2_instr(CurBase, instr); /* READ INSTR */
- readWord = 0;
+ instr = (u8) (addr | 0x80);
+ initio_se2_instr(base, instr); /* READ INSTR */
for (i = 15; i >= 0; i--) {
- TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK); /* +CLK */
- tul_se2_wait();
- TUL_WR(CurBase + TUL_NVRAM, SE2CS); /* -CLK */
+ outb(SE2CS | SE2CLK, base + TUL_NVRAM); /* +CLK */
+ udelay(30);
+ outb(SE2CS, base + TUL_NVRAM); /* -CLK */
/* sample data after the following edge of clock */
- readByte = TUL_RD(CurBase, TUL_NVRAM);
- readByte &= SE2DI;
- readWord += (readByte << i);
- tul_se2_wait(); /* 6/20/95 */
+ rb = inb(base + TUL_NVRAM);
+ rb &= SE2DI;
+ val += (rb << i);
+ udelay(30); /* 6/20/95 */
}
- TUL_WR(CurBase + TUL_NVRAM, 0); /* no chip select */
- tul_se2_wait();
- return readWord;
+ outb(0, base + TUL_NVRAM); /* no chip select */
+ udelay(30);
+ return val;
}
-
-/******************************************************************
- Input: new value in Serial E2PROM, address of Serial E2PROM
-*******************************************************************/
-static void tul_se2_wr(WORD CurBase, UCHAR adr, USHORT writeWord)
+/**
+ * initio_se2_wr - read E2PROM word
+ * @base: Base of InitIO controller
+ * @addr: Address of word in E2PROM
+ * @val: Value to write
+ *
+ * Write a word to the NV E2PROM device. Used when recovering from
+ * a problem with the NV.
+ */
+static void initio_se2_wr(unsigned long base, u8 addr, u16 val)
{
- UCHAR readByte;
- UCHAR instr;
+ u8 rb;
+ u8 instr;
int i;
- instr = (UCHAR) (adr | 0x40);
- tul_se2_instr(CurBase, instr); /* WRITE INSTR */
+ instr = (u8) (addr | 0x40);
+ initio_se2_instr(base, instr); /* WRITE INSTR */
for (i = 15; i >= 0; i--) {
- if (writeWord & 0x8000)
- TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2DO); /* -CLK+dataBit 1 */
+ if (val & 0x8000)
+ outb(SE2CS | SE2DO, base + TUL_NVRAM); /* -CLK+dataBit 1 */
else
- TUL_WR(CurBase + TUL_NVRAM, SE2CS); /* -CLK+dataBit 0 */
- tul_se2_wait();
- TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK); /* +CLK */
- tul_se2_wait();
- writeWord <<= 1;
+ outb(SE2CS, base + TUL_NVRAM); /* -CLK+dataBit 0 */
+ udelay(30);
+ outb(SE2CS | SE2CLK, base + TUL_NVRAM); /* +CLK */
+ udelay(30);
+ val <<= 1;
}
- TUL_WR(CurBase + TUL_NVRAM, SE2CS); /* -CLK */
- tul_se2_wait();
- TUL_WR(CurBase + TUL_NVRAM, 0); /* -CS */
- tul_se2_wait();
+ outb(SE2CS, base + TUL_NVRAM); /* -CLK */
+ udelay(30);
+ outb(0, base + TUL_NVRAM); /* -CS */
+ udelay(30);
- TUL_WR(CurBase + TUL_NVRAM, SE2CS); /* +CS */
- tul_se2_wait();
+ outb(SE2CS, base + TUL_NVRAM); /* +CS */
+ udelay(30);
for (;;) {
- TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK); /* +CLK */
- tul_se2_wait();
- TUL_WR(CurBase + TUL_NVRAM, SE2CS); /* -CLK */
- tul_se2_wait();
- if ((readByte = TUL_RD(CurBase, TUL_NVRAM)) & SE2DI)
+ outb(SE2CS | SE2CLK, base + TUL_NVRAM); /* +CLK */
+ udelay(30);
+ outb(SE2CS, base + TUL_NVRAM); /* -CLK */
+ udelay(30);
+ if ((rb = inb(base + TUL_NVRAM)) & SE2DI)
break; /* write complete */
}
- TUL_WR(CurBase + TUL_NVRAM, 0); /* -CS */
- return;
+ outb(0, base + TUL_NVRAM); /* -CS */
}
+/**
+ * initio_se2_rd_all - read hostadapter NV configuration
+ * @base: Base address of InitIO controller
+ *
+ * Reads the E2PROM data into main memory. Ensures that the checksum
+ * and header marker are valid. Returns 1 on success -1 on error.
+ */
-/***********************************************************************
- Read SCSI H/A configuration parameters from serial EEPROM
-************************************************************************/
-int tul_se2_rd_all(WORD CurBase)
+static int initio_se2_rd_all(unsigned long base)
{
int i;
- ULONG chksum = 0;
- USHORT *np;
+ u16 chksum = 0;
+ u16 *np;
i91unvramp = &i91unvram;
- np = (USHORT *) i91unvramp;
- for (i = 0; i < 32; i++) {
- *np++ = tul_se2_rd(CurBase, i);
- }
+ np = (u16 *) i91unvramp;
+ for (i = 0; i < 32; i++)
+ *np++ = initio_se2_rd(base, i);
-/*--------------------Is signature "ini" ok ? ----------------*/
+ /* Is signature "ini" ok ? */
if (i91unvramp->NVM_Signature != INI_SIGNATURE)
return -1;
-/*---------------------- Is ckecksum ok ? ----------------------*/
- np = (USHORT *) i91unvramp;
+ /* Is ckecksum ok ? */
+ np = (u16 *) i91unvramp;
for (i = 0; i < 31; i++)
chksum += *np++;
- if (i91unvramp->NVM_CheckSum != (USHORT) chksum)
+ if (i91unvramp->NVM_CheckSum != chksum)
return -1;
return 1;
}
-
-/***********************************************************************
- Update SCSI H/A configuration parameters from serial EEPROM
-************************************************************************/
-void tul_se2_update_all(WORD CurBase)
+/**
+ * initio_se2_update_all - Update E2PROM
+ * @base: Base of InitIO controller
+ *
+ * Update the E2PROM by wrting any changes into the E2PROM
+ * chip, rewriting the checksum.
+ */
+static void initio_se2_update_all(unsigned long base)
{ /* setup default pattern */
int i;
- ULONG chksum = 0;
- USHORT *np, *np1;
+ u16 chksum = 0;
+ u16 *np, *np1;
i91unvramp = &i91unvram;
/* Calculate checksum first */
- np = (USHORT *) i91udftNvRam;
+ np = (u16 *) i91udftNvRam;
for (i = 0; i < 31; i++)
chksum += *np++;
- *np = (USHORT) chksum;
- tul_se2_ew_en(CurBase); /* Enable write */
+ *np = chksum;
+ initio_se2_ew_en(base); /* Enable write */
- np = (USHORT *) i91udftNvRam;
- np1 = (USHORT *) i91unvramp;
+ np = (u16 *) i91udftNvRam;
+ np1 = (u16 *) i91unvramp;
for (i = 0; i < 32; i++, np++, np1++) {
- if (*np != *np1) {
- tul_se2_wr(CurBase, i, *np);
- }
+ if (*np != *np1)
+ initio_se2_wr(base, i, *np);
}
-
- tul_se2_ew_ds(CurBase); /* Disable write */
- return;
+ initio_se2_ew_ds(base); /* Disable write */
}
-/*************************************************************************
- Function name : read_eeprom
-**************************************************************************/
-void tul_read_eeprom(WORD CurBase)
+/**
+ * initio_read_eeprom - Retrieve configuration
+ * @base: Base of InitIO Host Adapter
+ *
+ * Retrieve the host adapter configuration data from E2Prom. If the
+ * data is invalid then the defaults are used and are also restored
+ * into the E2PROM. This forms the access point for the SCSI driver
+ * into the E2PROM layer, the other functions for the E2PROM are all
+ * internal use.
+ *
+ * Must be called single threaded, uses a shared global area.
+ */
+
+static void initio_read_eeprom(unsigned long base)
{
- UCHAR gctrl;
+ u8 gctrl;
i91unvramp = &i91unvram;
-/*------Enable EEProm programming ---*/
- gctrl = TUL_RD(CurBase, TUL_GCTRL);
- TUL_WR(CurBase + TUL_GCTRL, gctrl | TUL_GCTRL_EEPROM_BIT);
- if (tul_se2_rd_all(CurBase) != 1) {
- tul_se2_update_all(CurBase); /* setup default pattern */
- tul_se2_rd_all(CurBase); /* load again */
+ /* Enable EEProm programming */
+ gctrl = inb(base + TUL_GCTRL);
+ outb(gctrl | TUL_GCTRL_EEPROM_BIT, base + TUL_GCTRL);
+ if (initio_se2_rd_all(base) != 1) {
+ initio_se2_update_all(base); /* setup default pattern */
+ initio_se2_rd_all(base); /* load again */
}
-/*------ Disable EEProm programming ---*/
- gctrl = TUL_RD(CurBase, TUL_GCTRL);
- TUL_WR(CurBase + TUL_GCTRL, gctrl & ~TUL_GCTRL_EEPROM_BIT);
-} /* read_eeprom */
-
-static int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
- BYTE bBus, BYTE bDevice)
-{
- int i, j;
-
- for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {
- if (i91u_adpt[i].ADPT_BIOS < wBIOS)
- continue;
- if (i91u_adpt[i].ADPT_BIOS == wBIOS) {
- if (i91u_adpt[i].ADPT_BASE == wBASE) {
- if (i91u_adpt[i].ADPT_Bus != 0xFF)
- return 1;
- } else if (i91u_adpt[i].ADPT_BASE < wBASE)
- continue;
- }
- for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) {
- i91u_adpt[j].ADPT_BASE = i91u_adpt[j - 1].ADPT_BASE;
- i91u_adpt[j].ADPT_INTR = i91u_adpt[j - 1].ADPT_INTR;
- i91u_adpt[j].ADPT_BIOS = i91u_adpt[j - 1].ADPT_BIOS;
- i91u_adpt[j].ADPT_Bus = i91u_adpt[j - 1].ADPT_Bus;
- i91u_adpt[j].ADPT_Device = i91u_adpt[j - 1].ADPT_Device;
- }
- i91u_adpt[i].ADPT_BASE = wBASE;
- i91u_adpt[i].ADPT_INTR = bInterrupt;
- i91u_adpt[i].ADPT_BIOS = wBIOS;
- i91u_adpt[i].ADPT_Bus = bBus;
- i91u_adpt[i].ADPT_Device = bDevice;
- return 0;
- }
- return 1;
+ /* Disable EEProm programming */
+ gctrl = inb(base + TUL_GCTRL);
+ outb(gctrl & ~TUL_GCTRL_EEPROM_BIT, base + TUL_GCTRL);
}
-static void init_i91uAdapter_table(void)
-{
- int i;
+/**
+ * initio_stop_bm - stop bus master
+ * @host: InitIO we are stopping
+ *
+ * Stop any pending DMA operation, aborting the DMA if neccessary
+ */
- for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) { /* Initialize adapter structure */
- i91u_adpt[i].ADPT_BIOS = 0xffff;
- i91u_adpt[i].ADPT_BASE = 0xffff;
- i91u_adpt[i].ADPT_INTR = 0xff;
- i91u_adpt[i].ADPT_Bus = 0xff;
- i91u_adpt[i].ADPT_Device = 0xff;
- }
- return;
-}
-
-static void tul_stop_bm(HCS * pCurHcb)
+static void initio_stop_bm(struct initio_host * host)
{
- if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT | TAX_X_CLR_FIFO);
+ if (inb(host->addr + TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */
+ outb(TAX_X_ABT | TAX_X_CLR_FIFO, host->addr + TUL_XCmd);
/* wait Abort DMA xfer done */
- while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);
+ while ((inb(host->addr + TUL_Int) & XABT) == 0)
+ cpu_relax();
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
}
-/***************************************************************************/
-static void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx)
-{
- pCurHcb->HCS_Base = i91u_adpt[ch_idx].ADPT_BASE; /* Supply base address */
- pCurHcb->HCS_BIOS = i91u_adpt[ch_idx].ADPT_BIOS; /* Supply BIOS address */
- pCurHcb->HCS_Intr = i91u_adpt[ch_idx].ADPT_INTR; /* Supply interrupt line */
- return;
-}
+/**
+ * initio_reset_scsi - Reset SCSI host controller
+ * @host: InitIO host to reset
+ * @seconds: Recovery time
+ *
+ * Perform a full reset of the SCSI subsystem.
+ */
-/***************************************************************************/
-static int tul_reset_scsi(HCS * pCurHcb, int seconds)
+static int initio_reset_scsi(struct initio_host * host, int seconds)
{
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_BUS);
+ outb(TSC_RST_BUS, host->addr + TUL_SCtrl0);
- while (!((pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt)) & TSS_SCSIRST_INT));
+ while (!((host->jsint = inb(host->addr + TUL_SInt)) & TSS_SCSIRST_INT))
+ cpu_relax();
+
/* reset tulip chip */
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, 0);
+ outb(0, host->addr + TUL_SSignal);
/* Stall for a while, wait for target's firmware ready,make it 2 sec ! */
/* SONY 5200 tape drive won't work if only stall for 1 sec */
- tul_do_pause(seconds * HZ);
+ /* FIXME: this is a very long busy wait right now */
+ initio_do_pause(seconds * HZ);
- TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
-
- return (SCSI_RESET_SUCCESS);
+ inb(host->addr + TUL_SInt);
+ return SCSI_RESET_SUCCESS;
}
-/***************************************************************************/
-static int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb,
- BYTE * pbBiosAdr, int seconds)
+/**
+ * initio_init - set up an InitIO host adapter
+ * @host: InitIO host adapter
+ * @num_scbs: Number of SCBS
+ * @bios_addr: BIOS address
+ *
+ * Set up the host adapter and devices according to the configuration
+ * retrieved from the E2PROM.
+ *
+ * Locking: Calls E2PROM layer code which is not re-enterable so must
+ * run single threaded for now.
+ */
+
+static void initio_init(struct initio_host * host, u8 *bios_addr)
{
int i;
- BYTE *pwFlags;
- BYTE *pbHeads;
- SCB *pTmpScb, *pPrevScb = NULL;
+ u8 *flags;
+ u8 *heads;
- pCurHcb->HCS_NumScbs = tul_num_scb;
- pCurHcb->HCS_Semaph = 1;
- spin_lock_init(&pCurHcb->HCS_SemaphLock);
- pCurHcb->HCS_JSStatus0 = 0;
- pCurHcb->HCS_Scb = scbp;
- pCurHcb->HCS_NxtPend = scbp;
- pCurHcb->HCS_NxtAvail = scbp;
- for (i = 0, pTmpScb = scbp; i < tul_num_scb; i++, pTmpScb++) {
- pTmpScb->SCB_TagId = i;
- if (i != 0)
- pPrevScb->SCB_NxtScb = pTmpScb;
- pPrevScb = pTmpScb;
- }
- pPrevScb->SCB_NxtScb = NULL;
- pCurHcb->HCS_ScbEnd = pTmpScb;
- pCurHcb->HCS_FirstAvail = scbp;
- pCurHcb->HCS_LastAvail = pPrevScb;
- spin_lock_init(&pCurHcb->HCS_AvailLock);
- pCurHcb->HCS_FirstPend = NULL;
- pCurHcb->HCS_LastPend = NULL;
- pCurHcb->HCS_FirstBusy = NULL;
- pCurHcb->HCS_LastBusy = NULL;
- pCurHcb->HCS_FirstDone = NULL;
- pCurHcb->HCS_LastDone = NULL;
- pCurHcb->HCS_ActScb = NULL;
- pCurHcb->HCS_ActTcs = NULL;
-
- tul_read_eeprom(pCurHcb->HCS_Base);
-/*---------- get H/A configuration -------------*/
+ /* Get E2Prom configuration */
+ initio_read_eeprom(host->addr);
if (i91unvramp->NVM_SCSIInfo[0].NVM_NumOfTarg == 8)
- pCurHcb->HCS_MaxTar = 8;
+ host->max_tar = 8;
else
- pCurHcb->HCS_MaxTar = 16;
+ host->max_tar = 16;
- pCurHcb->HCS_Config = i91unvramp->NVM_SCSIInfo[0].NVM_ChConfig1;
+ host->config = i91unvramp->NVM_SCSIInfo[0].NVM_ChConfig1;
- pCurHcb->HCS_SCSI_ID = i91unvramp->NVM_SCSIInfo[0].NVM_ChSCSIID;
- pCurHcb->HCS_IdMask = ~(1 << pCurHcb->HCS_SCSI_ID);
+ host->scsi_id = i91unvramp->NVM_SCSIInfo[0].NVM_ChSCSIID;
+ host->idmask = ~(1 << host->scsi_id);
#ifdef CHK_PARITY
/* Enable parity error response */
- TUL_WR(pCurHcb->HCS_Base + TUL_PCMD, TUL_RD(pCurHcb->HCS_Base, TUL_PCMD) | 0x40);
+ outb(inb(host->addr + TUL_PCMD) | 0x40, host->addr + TUL_PCMD);
#endif
/* Mask all the interrupt */
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+ outb(0x1F, host->addr + TUL_Mask);
- tul_stop_bm(pCurHcb);
+ initio_stop_bm(host);
/* --- Initialize the tulip --- */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_CHIP);
+ outb(TSC_RST_CHIP, host->addr + TUL_SCtrl0);
/* program HBA's SCSI ID */
- TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId, pCurHcb->HCS_SCSI_ID << 4);
+ outb(host->scsi_id << 4, host->addr + TUL_SScsiId);
/* Enable Initiator Mode ,phase latch,alternate sync period mode,
disable SCSI reset */
- if (pCurHcb->HCS_Config & HCC_EN_PAR)
- pCurHcb->HCS_SConf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR);
+ if (host->config & HCC_EN_PAR)
+ host->sconf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR);
else
- pCurHcb->HCS_SConf1 = (TSC_INITDEFAULT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_SConf1);
+ host->sconf1 = (TSC_INITDEFAULT);
+ outb(host->sconf1, host->addr + TUL_SConfig);
- /* Enable HW reselect */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);
+ /* Enable HW reselect */
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, 0);
+ outb(0, host->addr + TUL_SPeriod);
/* selection time out = 250 ms */
- TUL_WR(pCurHcb->HCS_Base + TUL_STimeOut, 153);
+ outb(153, host->addr + TUL_STimeOut);
-/*--------- Enable SCSI terminator -----*/
- TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, (pCurHcb->HCS_Config & (HCC_ACT_TERM1 | HCC_ACT_TERM2)));
- TUL_WR(pCurHcb->HCS_Base + TUL_GCTRL1,
- ((pCurHcb->HCS_Config & HCC_AUTO_TERM) >> 4) | (TUL_RD(pCurHcb->HCS_Base, TUL_GCTRL1) & 0xFE));
+ /* Enable SCSI terminator */
+ outb((host->config & (HCC_ACT_TERM1 | HCC_ACT_TERM2)),
+ host->addr + TUL_XCtrl);
+ outb(((host->config & HCC_AUTO_TERM) >> 4) |
+ (inb(host->addr + TUL_GCTRL1) & 0xFE),
+ host->addr + TUL_GCTRL1);
for (i = 0,
- pwFlags = & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config),
- pbHeads = pbBiosAdr + 0x180;
- i < pCurHcb->HCS_MaxTar;
- i++, pwFlags++) {
- pCurHcb->HCS_Tcs[i].TCS_Flags = *pwFlags & ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
- if (pCurHcb->HCS_Tcs[i].TCS_Flags & TCF_EN_255)
- pCurHcb->HCS_Tcs[i].TCS_DrvFlags = TCF_DRV_255_63;
+ flags = & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config),
+ heads = bios_addr + 0x180;
+ i < host->max_tar;
+ i++, flags++) {
+ host->targets[i].flags = *flags & ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+ if (host->targets[i].flags & TCF_EN_255)
+ host->targets[i].drv_flags = TCF_DRV_255_63;
else
- pCurHcb->HCS_Tcs[i].TCS_DrvFlags = 0;
- pCurHcb->HCS_Tcs[i].TCS_JS_Period = 0;
- pCurHcb->HCS_Tcs[i].TCS_SConfig0 = pCurHcb->HCS_SConf1;
- pCurHcb->HCS_Tcs[i].TCS_DrvHead = *pbHeads++;
- if (pCurHcb->HCS_Tcs[i].TCS_DrvHead == 255)
- pCurHcb->HCS_Tcs[i].TCS_DrvFlags = TCF_DRV_255_63;
+ host->targets[i].drv_flags = 0;
+ host->targets[i].js_period = 0;
+ host->targets[i].sconfig0 = host->sconf1;
+ host->targets[i].heads = *heads++;
+ if (host->targets[i].heads == 255)
+ host->targets[i].drv_flags = TCF_DRV_255_63;
else
- pCurHcb->HCS_Tcs[i].TCS_DrvFlags = 0;
- pCurHcb->HCS_Tcs[i].TCS_DrvSector = *pbHeads++;
- pCurHcb->HCS_Tcs[i].TCS_Flags &= ~TCF_BUSY;
- pCurHcb->HCS_ActTags[i] = 0;
- pCurHcb->HCS_MaxTags[i] = 0xFF;
+ host->targets[i].drv_flags = 0;
+ host->targets[i].sectors = *heads++;
+ host->targets[i].flags &= ~TCF_BUSY;
+ host->act_tags[i] = 0;
+ host->max_tags[i] = 0xFF;
} /* for */
printk("i91u: PCI Base=0x%04X, IRQ=%d, BIOS=0x%04X0, SCSI ID=%d\n",
- pCurHcb->HCS_Base, pCurHcb->HCS_Intr,
- pCurHcb->HCS_BIOS, pCurHcb->HCS_SCSI_ID);
-/*------------------- reset SCSI Bus ---------------------------*/
- if (pCurHcb->HCS_Config & HCC_SCSI_RESET) {
- printk("i91u: Reset SCSI Bus ... \n");
- tul_reset_scsi(pCurHcb, seconds);
+ host->addr, host->irq,
+ host->bios_addr, host->scsi_id);
+ /* Reset SCSI Bus */
+ if (host->config & HCC_SCSI_RESET) {
+ printk(KERN_INFO "i91u: Reset SCSI Bus ... \n");
+ initio_reset_scsi(host, 10);
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SCFG1, 0x17);
- TUL_WR(pCurHcb->HCS_Base + TUL_SIntEnable, 0xE9);
- return (0);
+ outb(0x17, host->addr + TUL_SCFG1);
+ outb(0xE9, host->addr + TUL_SIntEnable);
}
-/***************************************************************************/
-static SCB *tul_alloc_scb(HCS * hcsp)
+/**
+ * initio_alloc_scb - Allocate an SCB
+ * @host: InitIO host we are allocating for
+ *
+ * Walk the SCB list for the controller and allocate a free SCB if
+ * one exists.
+ */
+static struct scsi_ctrl_blk *initio_alloc_scb(struct initio_host *host)
{
- SCB *pTmpScb;
- ULONG flags;
- spin_lock_irqsave(&(hcsp->HCS_AvailLock), flags);
- if ((pTmpScb = hcsp->HCS_FirstAvail) != NULL) {
+ struct scsi_ctrl_blk *scb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->avail_lock, flags);
+ if ((scb = host->first_avail) != NULL) {
#if DEBUG_QUEUE
- printk("find scb at %08lx\n", (ULONG) pTmpScb);
+ printk("find scb at %p\n", scb);
#endif
- if ((hcsp->HCS_FirstAvail = pTmpScb->SCB_NxtScb) == NULL)
- hcsp->HCS_LastAvail = NULL;
- pTmpScb->SCB_NxtScb = NULL;
- pTmpScb->SCB_Status = SCB_RENT;
+ if ((host->first_avail = scb->next) == NULL)
+ host->last_avail = NULL;
+ scb->next = NULL;
+ scb->status = SCB_RENT;
}
- spin_unlock_irqrestore(&(hcsp->HCS_AvailLock), flags);
- return (pTmpScb);
+ spin_unlock_irqrestore(&host->avail_lock, flags);
+ return scb;
}
-/***************************************************************************/
-static void tul_release_scb(HCS * hcsp, SCB * scbp)
+/**
+ * initio_release_scb - Release an SCB
+ * @host: InitIO host that owns the SCB
+ * @cmnd: SCB command block being returned
+ *
+ * Return an allocated SCB to the host free list
+ */
+
+static void initio_release_scb(struct initio_host * host, struct scsi_ctrl_blk * cmnd)
{
- ULONG flags;
+ unsigned long flags;
#if DEBUG_QUEUE
- printk("Release SCB %lx; ", (ULONG) scbp);
+ printk("Release SCB %p; ", cmnd);
#endif
- spin_lock_irqsave(&(hcsp->HCS_AvailLock), flags);
- scbp->SCB_Srb = NULL;
- scbp->SCB_Status = 0;
- scbp->SCB_NxtScb = NULL;
- if (hcsp->HCS_LastAvail != NULL) {
- hcsp->HCS_LastAvail->SCB_NxtScb = scbp;
- hcsp->HCS_LastAvail = scbp;
+ spin_lock_irqsave(&(host->avail_lock), flags);
+ cmnd->srb = NULL;
+ cmnd->status = 0;
+ cmnd->next = NULL;
+ if (host->last_avail != NULL) {
+ host->last_avail->next = cmnd;
+ host->last_avail = cmnd;
} else {
- hcsp->HCS_FirstAvail = scbp;
- hcsp->HCS_LastAvail = scbp;
+ host->first_avail = cmnd;
+ host->last_avail = cmnd;
}
- spin_unlock_irqrestore(&(hcsp->HCS_AvailLock), flags);
+ spin_unlock_irqrestore(&(host->avail_lock), flags);
}
/***************************************************************************/
-static void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp)
+static void initio_append_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
{
#if DEBUG_QUEUE
- printk("Append pend SCB %lx; ", (ULONG) scbp);
+ printk("Append pend SCB %p; ", scbp);
#endif
- scbp->SCB_Status = SCB_PEND;
- scbp->SCB_NxtScb = NULL;
- if (pCurHcb->HCS_LastPend != NULL) {
- pCurHcb->HCS_LastPend->SCB_NxtScb = scbp;
- pCurHcb->HCS_LastPend = scbp;
+ scbp->status = SCB_PEND;
+ scbp->next = NULL;
+ if (host->last_pending != NULL) {
+ host->last_pending->next = scbp;
+ host->last_pending = scbp;
} else {
- pCurHcb->HCS_FirstPend = scbp;
- pCurHcb->HCS_LastPend = scbp;
+ host->first_pending = scbp;
+ host->last_pending = scbp;
}
}
/***************************************************************************/
-static void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp)
+static void initio_push_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
{
#if DEBUG_QUEUE
- printk("Push pend SCB %lx; ", (ULONG) scbp);
+ printk("Push pend SCB %p; ", scbp);
#endif
- scbp->SCB_Status = SCB_PEND;
- if ((scbp->SCB_NxtScb = pCurHcb->HCS_FirstPend) != NULL) {
- pCurHcb->HCS_FirstPend = scbp;
+ scbp->status = SCB_PEND;
+ if ((scbp->next = host->first_pending) != NULL) {
+ host->first_pending = scbp;
} else {
- pCurHcb->HCS_FirstPend = scbp;
- pCurHcb->HCS_LastPend = scbp;
+ host->first_pending = scbp;
+ host->last_pending = scbp;
}
}
-/***************************************************************************/
-static SCB *tul_find_first_pend_scb(HCS * pCurHcb)
+static struct scsi_ctrl_blk *initio_find_first_pend_scb(struct initio_host * host)
{
- SCB *pFirstPend;
+ struct scsi_ctrl_blk *first;
- pFirstPend = pCurHcb->HCS_FirstPend;
- while (pFirstPend != NULL) {
- if (pFirstPend->SCB_Opcode != ExecSCSI) {
- return (pFirstPend);
- }
- if (pFirstPend->SCB_TagMsg == 0) {
- if ((pCurHcb->HCS_ActTags[pFirstPend->SCB_Target] == 0) &&
- !(pCurHcb->HCS_Tcs[pFirstPend->SCB_Target].TCS_Flags & TCF_BUSY)) {
- return (pFirstPend);
- }
+ first = host->first_pending;
+ while (first != NULL) {
+ if (first->opcode != ExecSCSI)
+ return first;
+ if (first->tagmsg == 0) {
+ if ((host->act_tags[first->target] == 0) &&
+ !(host->targets[first->target].flags & TCF_BUSY))
+ return first;
} else {
- if ((pCurHcb->HCS_ActTags[pFirstPend->SCB_Target] >=
- pCurHcb->HCS_MaxTags[pFirstPend->SCB_Target]) |
- (pCurHcb->HCS_Tcs[pFirstPend->SCB_Target].TCS_Flags & TCF_BUSY)) {
- pFirstPend = pFirstPend->SCB_NxtScb;
+ if ((host->act_tags[first->target] >=
+ host->max_tags[first->target]) |
+ (host->targets[first->target].flags & TCF_BUSY)) {
+ first = first->next;
continue;
}
- return (pFirstPend);
+ return first;
}
- pFirstPend = pFirstPend->SCB_NxtScb;
+ first = first->next;
}
-
-
- return (pFirstPend);
+ return first;
}
-/***************************************************************************/
-static void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb)
+
+static void initio_unlink_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scb)
{
- SCB *pTmpScb, *pPrevScb;
+ struct scsi_ctrl_blk *tmp, *prev;
#if DEBUG_QUEUE
- printk("unlink pend SCB %lx; ", (ULONG) pCurScb);
+ printk("unlink pend SCB %p; ", scb);
#endif
- pPrevScb = pTmpScb = pCurHcb->HCS_FirstPend;
- while (pTmpScb != NULL) {
- if (pCurScb == pTmpScb) { /* Unlink this SCB */
- if (pTmpScb == pCurHcb->HCS_FirstPend) {
- if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastPend = NULL;
+ prev = tmp = host->first_pending;
+ while (tmp != NULL) {
+ if (scb == tmp) { /* Unlink this SCB */
+ if (tmp == host->first_pending) {
+ if ((host->first_pending = tmp->next) == NULL)
+ host->last_pending = NULL;
} else {
- pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
- if (pTmpScb == pCurHcb->HCS_LastPend)
- pCurHcb->HCS_LastPend = pPrevScb;
+ prev->next = tmp->next;
+ if (tmp == host->last_pending)
+ host->last_pending = prev;
}
- pTmpScb->SCB_NxtScb = NULL;
+ tmp->next = NULL;
break;
}
- pPrevScb = pTmpScb;
- pTmpScb = pTmpScb->SCB_NxtScb;
+ prev = tmp;
+ tmp = tmp->next;
}
- return;
}
-/***************************************************************************/
-static void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp)
+
+static void initio_append_busy_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
{
#if DEBUG_QUEUE
- printk("append busy SCB %lx; ", (ULONG) scbp);
+ printk("append busy SCB %o; ", scbp);
#endif
- if (scbp->SCB_TagMsg)
- pCurHcb->HCS_ActTags[scbp->SCB_Target]++;
+ if (scbp->tagmsg)
+ host->act_tags[scbp->target]++;
else
- pCurHcb->HCS_Tcs[scbp->SCB_Target].TCS_Flags |= TCF_BUSY;
- scbp->SCB_Status = SCB_BUSY;
- scbp->SCB_NxtScb = NULL;
- if (pCurHcb->HCS_LastBusy != NULL) {
- pCurHcb->HCS_LastBusy->SCB_NxtScb = scbp;
- pCurHcb->HCS_LastBusy = scbp;
+ host->targets[scbp->target].flags |= TCF_BUSY;
+ scbp->status = SCB_BUSY;
+ scbp->next = NULL;
+ if (host->last_busy != NULL) {
+ host->last_busy->next = scbp;
+ host->last_busy = scbp;
} else {
- pCurHcb->HCS_FirstBusy = scbp;
- pCurHcb->HCS_LastBusy = scbp;
+ host->first_busy = scbp;
+ host->last_busy = scbp;
}
}
/***************************************************************************/
-static SCB *tul_pop_busy_scb(HCS * pCurHcb)
+static struct scsi_ctrl_blk *initio_pop_busy_scb(struct initio_host * host)
{
- SCB *pTmpScb;
+ struct scsi_ctrl_blk *tmp;
- if ((pTmpScb = pCurHcb->HCS_FirstBusy) != NULL) {
- if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastBusy = NULL;
- pTmpScb->SCB_NxtScb = NULL;
- if (pTmpScb->SCB_TagMsg)
- pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+ if ((tmp = host->first_busy) != NULL) {
+ if ((host->first_busy = tmp->next) == NULL)
+ host->last_busy = NULL;
+ tmp->next = NULL;
+ if (tmp->tagmsg)
+ host->act_tags[tmp->target]--;
else
- pCurHcb->HCS_Tcs[pTmpScb->SCB_Target].TCS_Flags &= ~TCF_BUSY;
+ host->targets[tmp->target].flags &= ~TCF_BUSY;
}
#if DEBUG_QUEUE
- printk("Pop busy SCB %lx; ", (ULONG) pTmpScb);
+ printk("Pop busy SCB %p; ", tmp);
#endif
- return (pTmpScb);
+ return tmp;
}
/***************************************************************************/
-static void tul_unlink_busy_scb(HCS * pCurHcb, SCB * pCurScb)
+static void initio_unlink_busy_scb(struct initio_host * host, struct scsi_ctrl_blk * scb)
{
- SCB *pTmpScb, *pPrevScb;
+ struct scsi_ctrl_blk *tmp, *prev;
#if DEBUG_QUEUE
- printk("unlink busy SCB %lx; ", (ULONG) pCurScb);
+ printk("unlink busy SCB %p; ", scb);
#endif
- pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;
- while (pTmpScb != NULL) {
- if (pCurScb == pTmpScb) { /* Unlink this SCB */
- if (pTmpScb == pCurHcb->HCS_FirstBusy) {
- if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastBusy = NULL;
+ prev = tmp = host->first_busy;
+ while (tmp != NULL) {
+ if (scb == tmp) { /* Unlink this SCB */
+ if (tmp == host->first_busy) {
+ if ((host->first_busy = tmp->next) == NULL)
+ host->last_busy = NULL;
} else {
- pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
- if (pTmpScb == pCurHcb->HCS_LastBusy)
- pCurHcb->HCS_LastBusy = pPrevScb;
+ prev->next = tmp->next;
+ if (tmp == host->last_busy)
+ host->last_busy = prev;
}
- pTmpScb->SCB_NxtScb = NULL;
- if (pTmpScb->SCB_TagMsg)
- pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+ tmp->next = NULL;
+ if (tmp->tagmsg)
+ host->act_tags[tmp->target]--;
else
- pCurHcb->HCS_Tcs[pTmpScb->SCB_Target].TCS_Flags &= ~TCF_BUSY;
+ host->targets[tmp->target].flags &= ~TCF_BUSY;
break;
}
- pPrevScb = pTmpScb;
- pTmpScb = pTmpScb->SCB_NxtScb;
+ prev = tmp;
+ tmp = tmp->next;
}
return;
}
-/***************************************************************************/
-SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun)
+struct scsi_ctrl_blk *initio_find_busy_scb(struct initio_host * host, u16 tarlun)
{
- SCB *pTmpScb, *pPrevScb;
- WORD scbp_tarlun;
+ struct scsi_ctrl_blk *tmp, *prev;
+ u16 scbp_tarlun;
- pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;
- while (pTmpScb != NULL) {
- scbp_tarlun = (pTmpScb->SCB_Lun << 8) | (pTmpScb->SCB_Target);
+ prev = tmp = host->first_busy;
+ while (tmp != NULL) {
+ scbp_tarlun = (tmp->lun << 8) | (tmp->target);
if (scbp_tarlun == tarlun) { /* Unlink this SCB */
break;
}
- pPrevScb = pTmpScb;
- pTmpScb = pTmpScb->SCB_NxtScb;
+ prev = tmp;
+ tmp = tmp->next;
}
#if DEBUG_QUEUE
- printk("find busy SCB %lx; ", (ULONG) pTmpScb);
+ printk("find busy SCB %p; ", tmp);
#endif
- return (pTmpScb);
+ return tmp;
}
-/***************************************************************************/
-static void tul_append_done_scb(HCS * pCurHcb, SCB * scbp)
+static void initio_append_done_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
{
-
#if DEBUG_QUEUE
- printk("append done SCB %lx; ", (ULONG) scbp);
+ printk("append done SCB %p; ", scbp);
#endif
- scbp->SCB_Status = SCB_DONE;
- scbp->SCB_NxtScb = NULL;
- if (pCurHcb->HCS_LastDone != NULL) {
- pCurHcb->HCS_LastDone->SCB_NxtScb = scbp;
- pCurHcb->HCS_LastDone = scbp;
+ scbp->status = SCB_DONE;
+ scbp->next = NULL;
+ if (host->last_done != NULL) {
+ host->last_done->next = scbp;
+ host->last_done = scbp;
} else {
- pCurHcb->HCS_FirstDone = scbp;
- pCurHcb->HCS_LastDone = scbp;
+ host->first_done = scbp;
+ host->last_done = scbp;
}
}
-/***************************************************************************/
-SCB *tul_find_done_scb(HCS * pCurHcb)
+struct scsi_ctrl_blk *initio_find_done_scb(struct initio_host * host)
{
- SCB *pTmpScb;
+ struct scsi_ctrl_blk *tmp;
-
- if ((pTmpScb = pCurHcb->HCS_FirstDone) != NULL) {
- if ((pCurHcb->HCS_FirstDone = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastDone = NULL;
- pTmpScb->SCB_NxtScb = NULL;
+ if ((tmp = host->first_done) != NULL) {
+ if ((host->first_done = tmp->next) == NULL)
+ host->last_done = NULL;
+ tmp->next = NULL;
}
#if DEBUG_QUEUE
- printk("find done SCB %lx; ", (ULONG) pTmpScb);
+ printk("find done SCB %p; ",tmp);
#endif
- return (pTmpScb);
+ return tmp;
}
-/***************************************************************************/
-static int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp)
+static int initio_abort_srb(struct initio_host * host, struct scsi_cmnd *srbp)
{
- ULONG flags;
- SCB *pTmpScb, *pPrevScb;
+ unsigned long flags;
+ struct scsi_ctrl_blk *tmp, *prev;
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+ spin_lock_irqsave(&host->semaph_lock, flags);
- if ((pCurHcb->HCS_Semaph == 0) && (pCurHcb->HCS_ActScb == NULL)) {
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+ if ((host->semaph == 0) && (host->active == NULL)) {
/* disable Jasmin SCSI Int */
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
-
- tulip_main(pCurHcb);
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
-
- pCurHcb->HCS_Semaph = 1;
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
-
+ outb(0x1F, host->addr + TUL_Mask);
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
+ /* FIXME: synchronize_irq needed ? */
+ tulip_main(host);
+ spin_lock_irqsave(&host->semaph_lock, flags);
+ host->semaph = 1;
+ outb(0x0F, host->addr + TUL_Mask);
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return SCSI_ABORT_SNOOZE;
}
- pPrevScb = pTmpScb = pCurHcb->HCS_FirstPend; /* Check Pend queue */
- while (pTmpScb != NULL) {
+ prev = tmp = host->first_pending; /* Check Pend queue */
+ while (tmp != NULL) {
/* 07/27/98 */
- if (pTmpScb->SCB_Srb == srbp) {
- if (pTmpScb == pCurHcb->HCS_ActScb) {
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ if (tmp->srb == srbp) {
+ if (tmp == host->active) {
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return SCSI_ABORT_BUSY;
- } else if (pTmpScb == pCurHcb->HCS_FirstPend) {
- if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastPend = NULL;
+ } else if (tmp == host->first_pending) {
+ if ((host->first_pending = tmp->next) == NULL)
+ host->last_pending = NULL;
} else {
- pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
- if (pTmpScb == pCurHcb->HCS_LastPend)
- pCurHcb->HCS_LastPend = pPrevScb;
+ prev->next = tmp->next;
+ if (tmp == host->last_pending)
+ host->last_pending = prev;
}
- pTmpScb->SCB_HaStat = HOST_ABORTED;
- pTmpScb->SCB_Flags |= SCF_DONE;
- if (pTmpScb->SCB_Flags & SCF_POST)
- (*pTmpScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pTmpScb);
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ tmp->hastat = HOST_ABORTED;
+ tmp->flags |= SCF_DONE;
+ if (tmp->flags & SCF_POST)
+ (*tmp->post) ((u8 *) host, (u8 *) tmp);
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return SCSI_ABORT_SUCCESS;
}
- pPrevScb = pTmpScb;
- pTmpScb = pTmpScb->SCB_NxtScb;
+ prev = tmp;
+ tmp = tmp->next;
}
- pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy; /* Check Busy queue */
- while (pTmpScb != NULL) {
-
- if (pTmpScb->SCB_Srb == srbp) {
-
- if (pTmpScb == pCurHcb->HCS_ActScb) {
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ prev = tmp = host->first_busy; /* Check Busy queue */
+ while (tmp != NULL) {
+ if (tmp->srb == srbp) {
+ if (tmp == host->active) {
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return SCSI_ABORT_BUSY;
- } else if (pTmpScb->SCB_TagMsg == 0) {
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ } else if (tmp->tagmsg == 0) {
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return SCSI_ABORT_BUSY;
} else {
- pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
- if (pTmpScb == pCurHcb->HCS_FirstBusy) {
- if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastBusy = NULL;
+ host->act_tags[tmp->target]--;
+ if (tmp == host->first_busy) {
+ if ((host->first_busy = tmp->next) == NULL)
+ host->last_busy = NULL;
} else {
- pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
- if (pTmpScb == pCurHcb->HCS_LastBusy)
- pCurHcb->HCS_LastBusy = pPrevScb;
+ prev->next = tmp->next;
+ if (tmp == host->last_busy)
+ host->last_busy = prev;
}
- pTmpScb->SCB_NxtScb = NULL;
+ tmp->next = NULL;
- pTmpScb->SCB_HaStat = HOST_ABORTED;
- pTmpScb->SCB_Flags |= SCF_DONE;
- if (pTmpScb->SCB_Flags & SCF_POST)
- (*pTmpScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pTmpScb);
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ tmp->hastat = HOST_ABORTED;
+ tmp->flags |= SCF_DONE;
+ if (tmp->flags & SCF_POST)
+ (*tmp->post) ((u8 *) host, (u8 *) tmp);
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return SCSI_ABORT_SUCCESS;
}
}
- pPrevScb = pTmpScb;
- pTmpScb = pTmpScb->SCB_NxtScb;
+ prev = tmp;
+ tmp = tmp->next;
}
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
- return (SCSI_ABORT_NOT_RUNNING);
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
+ return SCSI_ABORT_NOT_RUNNING;
}
/***************************************************************************/
-static int tul_bad_seq(HCS * pCurHcb)
+static int initio_bad_seq(struct initio_host * host)
{
- SCB *pCurScb;
+ struct scsi_ctrl_blk *scb;
- printk("tul_bad_seg c=%d\n", pCurHcb->HCS_Index);
+ printk("initio_bad_seg c=%d\n", host->index);
- if ((pCurScb = pCurHcb->HCS_ActScb) != NULL) {
- tul_unlink_busy_scb(pCurHcb, pCurScb);
- pCurScb->SCB_HaStat = HOST_BAD_PHAS;
- pCurScb->SCB_TaStat = 0;
- tul_append_done_scb(pCurHcb, pCurScb);
+ if ((scb = host->active) != NULL) {
+ initio_unlink_busy_scb(host, scb);
+ scb->hastat = HOST_BAD_PHAS;
+ scb->tastat = 0;
+ initio_append_done_scb(host, scb);
}
- tul_stop_bm(pCurHcb);
-
- tul_reset_scsi(pCurHcb, 8); /* 7/29/98 */
-
- return (tul_post_scsi_rst(pCurHcb));
+ initio_stop_bm(host);
+ initio_reset_scsi(host, 8); /* 7/29/98 */
+ return initio_post_scsi_rst(host);
}
-#if 0
/************************************************************************/
-static int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
- unsigned int target, unsigned int ResetFlags)
+static void initio_exec_scb(struct initio_host * host, struct scsi_ctrl_blk * scb)
{
- ULONG flags;
- SCB *pScb;
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+ unsigned long flags;
- if (ResetFlags & SCSI_RESET_ASYNCHRONOUS) {
+ scb->mode = 0;
- if ((pCurHcb->HCS_Semaph == 0) && (pCurHcb->HCS_ActScb == NULL)) {
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
- /* disable Jasmin SCSI Int */
+ scb->sgidx = 0;
+ scb->sgmax = scb->sglen;
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ spin_lock_irqsave(&host->semaph_lock, flags);
- tulip_main(pCurHcb);
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
-
- pCurHcb->HCS_Semaph = 1;
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
-
- return SCSI_RESET_SNOOZE;
- }
- pScb = pCurHcb->HCS_FirstBusy; /* Check Busy queue */
- while (pScb != NULL) {
- if (pScb->SCB_Srb == pSrb)
- break;
- pScb = pScb->SCB_NxtScb;
- }
- if (pScb == NULL) {
- printk("Unable to Reset - No SCB Found\n");
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
- return SCSI_RESET_NOT_RUNNING;
- }
- }
- if ((pScb = tul_alloc_scb(pCurHcb)) == NULL) {
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
- return SCSI_RESET_NOT_RUNNING;
- }
- pScb->SCB_Opcode = BusDevRst;
- pScb->SCB_Flags = SCF_POST;
- pScb->SCB_Target = target;
- pScb->SCB_Mode = 0;
-
- pScb->SCB_Srb = NULL;
- if (ResetFlags & SCSI_RESET_SYNCHRONOUS) {
- pScb->SCB_Srb = pSrb;
- }
- tul_push_pend_scb(pCurHcb, pScb); /* push this SCB to Pending queue */
-
- if (pCurHcb->HCS_Semaph == 1) {
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
- /* disable Jasmin SCSI Int */
- pCurHcb->HCS_Semaph = 0;
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
-
- tulip_main(pCurHcb);
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
-
- pCurHcb->HCS_Semaph = 1;
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
- }
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
- return SCSI_RESET_PENDING;
-}
-
-static int tul_reset_scsi_bus(HCS * pCurHcb)
-{
- ULONG flags;
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
- pCurHcb->HCS_Semaph = 0;
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
-
- tul_stop_bm(pCurHcb);
-
- tul_reset_scsi(pCurHcb, 2); /* 7/29/98 */
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
- tul_post_scsi_rst(pCurHcb);
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
-
- tulip_main(pCurHcb);
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
-
- pCurHcb->HCS_Semaph = 1;
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
- return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET);
-}
-
-#endif /* 0 */
-
-/************************************************************************/
-static void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb)
-{
- ULONG flags;
-
- pCurScb->SCB_Mode = 0;
-
- pCurScb->SCB_SGIdx = 0;
- pCurScb->SCB_SGMax = pCurScb->SCB_SGLen;
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
-
- tul_append_pend_scb(pCurHcb, pCurScb); /* Append this SCB to Pending queue */
+ initio_append_pend_scb(host, scb); /* Append this SCB to Pending queue */
/* VVVVV 07/21/98 */
- if (pCurHcb->HCS_Semaph == 1) {
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
- /* disable Jasmin SCSI Int */
- pCurHcb->HCS_Semaph = 0;
+ if (host->semaph == 1) {
+ /* Disable Jasmin SCSI Int */
+ outb(0x1F, host->addr + TUL_Mask);
+ host->semaph = 0;
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ tulip_main(host);
- tulip_main(pCurHcb);
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
-
- pCurHcb->HCS_Semaph = 1;
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+ spin_lock_irqsave(&host->semaph_lock, flags);
+ host->semaph = 1;
+ outb(0x0F, host->addr + TUL_Mask);
}
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return;
}
/***************************************************************************/
-static int tul_isr(HCS * pCurHcb)
+static int initio_isr(struct initio_host * host)
{
- /* Enter critical section */
-
- if (TUL_RD(pCurHcb->HCS_Base, TUL_Int) & TSS_INT_PENDING) {
- if (pCurHcb->HCS_Semaph == 1) {
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+ if (inb(host->addr + TUL_Int) & TSS_INT_PENDING) {
+ if (host->semaph == 1) {
+ outb(0x1F, host->addr + TUL_Mask);
/* Disable Tulip SCSI Int */
- pCurHcb->HCS_Semaph = 0;
+ host->semaph = 0;
- tulip_main(pCurHcb);
+ tulip_main(host);
- pCurHcb->HCS_Semaph = 1;
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
- return (1);
+ host->semaph = 1;
+ outb(0x0F, host->addr + TUL_Mask);
+ return 1;
}
}
- return (0);
+ return 0;
}
-/***************************************************************************/
-int tulip_main(HCS * pCurHcb)
+static int tulip_main(struct initio_host * host)
{
- SCB *pCurScb;
+ struct scsi_ctrl_blk *scb;
for (;;) {
+ tulip_scsi(host); /* Call tulip_scsi */
- tulip_scsi(pCurHcb); /* Call tulip_scsi */
-
- while ((pCurScb = tul_find_done_scb(pCurHcb)) != NULL) { /* find done entry */
- if (pCurScb->SCB_TaStat == INI_QUEUE_FULL) {
- pCurHcb->HCS_MaxTags[pCurScb->SCB_Target] =
- pCurHcb->HCS_ActTags[pCurScb->SCB_Target] - 1;
- pCurScb->SCB_TaStat = 0;
- tul_append_pend_scb(pCurHcb, pCurScb);
+ /* Walk the list of completed SCBs */
+ while ((scb = initio_find_done_scb(host)) != NULL) { /* find done entry */
+ if (scb->tastat == INI_QUEUE_FULL) {
+ host->max_tags[scb->target] =
+ host->act_tags[scb->target] - 1;
+ scb->tastat = 0;
+ initio_append_pend_scb(host, scb);
continue;
}
- if (!(pCurScb->SCB_Mode & SCM_RSENS)) { /* not in auto req. sense mode */
- if (pCurScb->SCB_TaStat == 2) {
+ if (!(scb->mode & SCM_RSENS)) { /* not in auto req. sense mode */
+ if (scb->tastat == 2) {
/* clr sync. nego flag */
- if (pCurScb->SCB_Flags & SCF_SENSE) {
- BYTE len;
- len = pCurScb->SCB_SenseLen;
+ if (scb->flags & SCF_SENSE) {
+ u8 len;
+ len = scb->senselen;
if (len == 0)
len = 1;
- pCurScb->SCB_BufLen = pCurScb->SCB_SenseLen;
- pCurScb->SCB_BufPtr = pCurScb->SCB_SensePtr;
- pCurScb->SCB_Flags &= ~(SCF_SG | SCF_DIR); /* for xfer_data_in */
-/* pCurScb->SCB_Flags |= SCF_NO_DCHK; */
- /* so, we won't report worng direction in xfer_data_in,
+ scb->buflen = scb->senselen;
+ scb->bufptr = scb->senseptr;
+ scb->flags &= ~(SCF_SG | SCF_DIR); /* for xfer_data_in */
+ /* so, we won't report wrong direction in xfer_data_in,
and won't report HOST_DO_DU in state_6 */
- pCurScb->SCB_Mode = SCM_RSENS;
- pCurScb->SCB_Ident &= 0xBF; /* Disable Disconnect */
- pCurScb->SCB_TagMsg = 0;
- pCurScb->SCB_TaStat = 0;
- pCurScb->SCB_CDBLen = 6;
- pCurScb->SCB_CDB[0] = SCSICMD_RequestSense;
- pCurScb->SCB_CDB[1] = 0;
- pCurScb->SCB_CDB[2] = 0;
- pCurScb->SCB_CDB[3] = 0;
- pCurScb->SCB_CDB[4] = len;
- pCurScb->SCB_CDB[5] = 0;
- tul_push_pend_scb(pCurHcb, pCurScb);
+ scb->mode = SCM_RSENS;
+ scb->ident &= 0xBF; /* Disable Disconnect */
+ scb->tagmsg = 0;
+ scb->tastat = 0;
+ scb->cdblen = 6;
+ scb->cdb[0] = SCSICMD_RequestSense;
+ scb->cdb[1] = 0;
+ scb->cdb[2] = 0;
+ scb->cdb[3] = 0;
+ scb->cdb[4] = len;
+ scb->cdb[5] = 0;
+ initio_push_pend_scb(host, scb);
break;
}
}
} else { /* in request sense mode */
- if (pCurScb->SCB_TaStat == 2) { /* check contition status again after sending
+ if (scb->tastat == 2) { /* check contition status again after sending
requset sense cmd 0x3 */
- pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+ scb->hastat = HOST_BAD_PHAS;
}
- pCurScb->SCB_TaStat = 2;
+ scb->tastat = 2;
}
- pCurScb->SCB_Flags |= SCF_DONE;
- if (pCurScb->SCB_Flags & SCF_POST) {
- (*pCurScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pCurScb);
+ scb->flags |= SCF_DONE;
+ if (scb->flags & SCF_POST) {
+ /* FIXME: only one post method and lose casts */
+ (*scb->post) ((u8 *) host, (u8 *) scb);
}
} /* while */
-
/* find_active: */
- if (TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0) & TSS_INT_PENDING)
+ if (inb(host->addr + TUL_SStatus0) & TSS_INT_PENDING)
continue;
-
- if (pCurHcb->HCS_ActScb) { /* return to OS and wait for xfer_done_ISR/Selected_ISR */
+ if (host->active) /* return to OS and wait for xfer_done_ISR/Selected_ISR */
return 1; /* return to OS, enable interrupt */
- }
/* Check pending SCB */
- if (tul_find_first_pend_scb(pCurHcb) == NULL) {
+ if (initio_find_first_pend_scb(host) == NULL)
return 1; /* return to OS, enable interrupt */
- }
} /* End of for loop */
/* statement won't reach here */
}
-
-
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-/***************************************************************************/
-/***************************************************************************/
-/***************************************************************************/
-/***************************************************************************/
-
-/***************************************************************************/
-void tulip_scsi(HCS * pCurHcb)
+static void tulip_scsi(struct initio_host * host)
{
- SCB *pCurScb;
- TCS *pCurTcb;
+ struct scsi_ctrl_blk *scb;
+ struct target_control *active_tc;
/* make sure to service interrupt asap */
-
- if ((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0)) & TSS_INT_PENDING) {
-
- pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;
- pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);
- pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
- if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) { /* SCSI bus reset detected */
- int_tul_scsi_rst(pCurHcb);
+ if ((host->jsstatus0 = inb(host->addr + TUL_SStatus0)) & TSS_INT_PENDING) {
+ host->phase = host->jsstatus0 & TSS_PH_MASK;
+ host->jsstatus1 = inb(host->addr + TUL_SStatus1);
+ host->jsint = inb(host->addr + TUL_SInt);
+ if (host->jsint & TSS_SCSIRST_INT) { /* SCSI bus reset detected */
+ int_initio_scsi_rst(host);
return;
}
- if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) { /* if selected/reselected interrupt */
- if (int_tul_resel(pCurHcb) == 0)
- tul_next_state(pCurHcb);
+ if (host->jsint & TSS_RESEL_INT) { /* if selected/reselected interrupt */
+ if (int_initio_resel(host) == 0)
+ initio_next_state(host);
return;
}
- if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) {
- int_tul_busfree(pCurHcb);
+ if (host->jsint & TSS_SEL_TIMEOUT) {
+ int_initio_busfree(host);
return;
}
- if (pCurHcb->HCS_JSInt & TSS_DISC_INT) { /* BUS disconnection */
- int_tul_busfree(pCurHcb); /* unexpected bus free or sel timeout */
+ if (host->jsint & TSS_DISC_INT) { /* BUS disconnection */
+ int_initio_busfree(host); /* unexpected bus free or sel timeout */
return;
}
- if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) { /* func complete or Bus service */
- if ((pCurScb = pCurHcb->HCS_ActScb) != NULL)
- tul_next_state(pCurHcb);
+ if (host->jsint & (TSS_FUNC_COMP | TSS_BUS_SERV)) { /* func complete or Bus service */
+ if ((scb = host->active) != NULL)
+ initio_next_state(host);
return;
}
}
- if (pCurHcb->HCS_ActScb != NULL)
+ if (host->active != NULL)
return;
- if ((pCurScb = tul_find_first_pend_scb(pCurHcb)) == NULL)
+ if ((scb = initio_find_first_pend_scb(host)) == NULL)
return;
/* program HBA's SCSI ID & target SCSI ID */
- TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId,
- (pCurHcb->HCS_SCSI_ID << 4) | (pCurScb->SCB_Target & 0x0F));
- if (pCurScb->SCB_Opcode == ExecSCSI) {
- pCurTcb = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+ outb((host->scsi_id << 4) | (scb->target & 0x0F),
+ host->addr + TUL_SScsiId);
+ if (scb->opcode == ExecSCSI) {
+ active_tc = &host->targets[scb->target];
- if (pCurScb->SCB_TagMsg)
- pCurTcb->TCS_DrvFlags |= TCF_DRV_EN_TAG;
+ if (scb->tagmsg)
+ active_tc->drv_flags |= TCF_DRV_EN_TAG;
else
- pCurTcb->TCS_DrvFlags &= ~TCF_DRV_EN_TAG;
+ active_tc->drv_flags &= ~TCF_DRV_EN_TAG;
- TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);
- if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) { /* do wdtr negotiation */
- tul_select_atn_stop(pCurHcb, pCurScb);
+ outb(active_tc->js_period, host->addr + TUL_SPeriod);
+ if ((active_tc->flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) { /* do wdtr negotiation */
+ initio_select_atn_stop(host, scb);
} else {
- if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) { /* do sync negotiation */
- tul_select_atn_stop(pCurHcb, pCurScb);
+ if ((active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) { /* do sync negotiation */
+ initio_select_atn_stop(host, scb);
} else {
- if (pCurScb->SCB_TagMsg)
- tul_select_atn3(pCurHcb, pCurScb);
+ if (scb->tagmsg)
+ initio_select_atn3(host, scb);
else
- tul_select_atn(pCurHcb, pCurScb);
+ initio_select_atn(host, scb);
}
}
- if (pCurScb->SCB_Flags & SCF_POLL) {
- while (wait_tulip(pCurHcb) != -1) {
- if (tul_next_state(pCurHcb) == -1)
+ if (scb->flags & SCF_POLL) {
+ while (wait_tulip(host) != -1) {
+ if (initio_next_state(host) == -1)
break;
}
}
- } else if (pCurScb->SCB_Opcode == BusDevRst) {
- tul_select_atn_stop(pCurHcb, pCurScb);
- pCurScb->SCB_NxtStat = 8;
- if (pCurScb->SCB_Flags & SCF_POLL) {
- while (wait_tulip(pCurHcb) != -1) {
- if (tul_next_state(pCurHcb) == -1)
+ } else if (scb->opcode == BusDevRst) {
+ initio_select_atn_stop(host, scb);
+ scb->next_state = 8;
+ if (scb->flags & SCF_POLL) {
+ while (wait_tulip(host) != -1) {
+ if (initio_next_state(host) == -1)
break;
}
}
- } else if (pCurScb->SCB_Opcode == AbortCmd) {
- if (tul_abort_srb(pCurHcb, pCurScb->SCB_Srb) != 0) {
-
-
- tul_unlink_pend_scb(pCurHcb, pCurScb);
-
- tul_release_scb(pCurHcb, pCurScb);
+ } else if (scb->opcode == AbortCmd) {
+ if (initio_abort_srb(host, scb->srb) != 0) {
+ initio_unlink_pend_scb(host, scb);
+ initio_release_scb(host, scb);
} else {
- pCurScb->SCB_Opcode = BusDevRst;
- tul_select_atn_stop(pCurHcb, pCurScb);
- pCurScb->SCB_NxtStat = 8;
+ scb->opcode = BusDevRst;
+ initio_select_atn_stop(host, scb);
+ scb->next_state = 8;
}
-
-/* 08/03/98 */
} else {
- tul_unlink_pend_scb(pCurHcb, pCurScb);
- pCurScb->SCB_HaStat = 0x16; /* bad command */
- tul_append_done_scb(pCurHcb, pCurScb);
+ initio_unlink_pend_scb(host, scb);
+ scb->hastat = 0x16; /* bad command */
+ initio_append_done_scb(host, scb);
}
return;
}
+/**
+ * initio_next_state - Next SCSI state
+ * @host: InitIO host we are processing
+ *
+ * Progress the active command block along the state machine
+ * until we hit a state which we must wait for activity to occur.
+ *
+ * Returns zero or a negative code.
+ */
-/***************************************************************************/
-int tul_next_state(HCS * pCurHcb)
+static int initio_next_state(struct initio_host * host)
{
int next;
- next = pCurHcb->HCS_ActScb->SCB_NxtStat;
+ next = host->active->next_state;
for (;;) {
switch (next) {
case 1:
- next = tul_state_1(pCurHcb);
+ next = initio_state_1(host);
break;
case 2:
- next = tul_state_2(pCurHcb);
+ next = initio_state_2(host);
break;
case 3:
- next = tul_state_3(pCurHcb);
+ next = initio_state_3(host);
break;
case 4:
- next = tul_state_4(pCurHcb);
+ next = initio_state_4(host);
break;
case 5:
- next = tul_state_5(pCurHcb);
+ next = initio_state_5(host);
break;
case 6:
- next = tul_state_6(pCurHcb);
+ next = initio_state_6(host);
break;
case 7:
- next = tul_state_7(pCurHcb);
+ next = initio_state_7(host);
break;
case 8:
- return (tul_bus_device_reset(pCurHcb));
+ return initio_bus_device_reset(host);
default:
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
if (next <= 0)
return next;
@@ -1554,338 +1314,363 @@
}
-/***************************************************************************/
-/* sTate after selection with attention & stop */
-int tul_state_1(HCS * pCurHcb)
+/**
+ * initio_state_1 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ * Perform SCSI state processing for Select/Attention/Stop
+ */
+
+static int initio_state_1(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+ struct scsi_ctrl_blk *scb = host->active;
+ struct target_control *active_tc = host->active_tc;
#if DEBUG_STATE
printk("-s1-");
#endif
- tul_unlink_pend_scb(pCurHcb, pCurScb);
- tul_append_busy_scb(pCurHcb, pCurScb);
+ /* Move the SCB from pending to busy */
+ initio_unlink_pend_scb(host, scb);
+ initio_append_busy_scb(host, scb);
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+ outb(active_tc->sconfig0, host->addr + TUL_SConfig );
/* ATN on */
- if (pCurHcb->HCS_Phase == MSG_OUT) {
+ if (host->phase == MSG_OUT) {
+ outb(TSC_EN_BUS_IN | TSC_HW_RESELECT, host->addr + TUL_SCtrl1);
+ outb(scb->ident, host->addr + TUL_SFifo);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, (TSC_EN_BUS_IN | TSC_HW_RESELECT));
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
-
- if (pCurScb->SCB_TagMsg) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);
+ if (scb->tagmsg) {
+ outb(scb->tagmsg, host->addr + TUL_SFifo);
+ outb(scb->tagid, host->addr + TUL_SFifo);
}
- if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {
-
- pCurTcb->TCS_Flags |= TCF_WDTR_DONE;
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2); /* Extended msg length */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3); /* Sync request */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1); /* Start from 16 bits */
- } else if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {
-
- pCurTcb->TCS_Flags |= TCF_SYNC_DONE;
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3); /* extended msg length */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1); /* sync request */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET); /* REQ/ACK offset */
+ if ((active_tc->flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {
+ active_tc->flags |= TCF_WDTR_DONE;
+ outb(MSG_EXTEND, host->addr + TUL_SFifo);
+ outb(2, host->addr + TUL_SFifo); /* Extended msg length */
+ outb(3, host->addr + TUL_SFifo); /* Sync request */
+ outb(1, host->addr + TUL_SFifo); /* Start from 16 bits */
+ } else if ((active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {
+ active_tc->flags |= TCF_SYNC_DONE;
+ outb(MSG_EXTEND, host->addr + TUL_SFifo);
+ outb(3, host->addr + TUL_SFifo); /* extended msg length */
+ outb(1, host->addr + TUL_SFifo); /* sync request */
+ outb(initio_rate_tbl[active_tc->flags & TCF_SCSI_RATE], host->addr + TUL_SFifo);
+ outb(MAX_OFFSET, host->addr + TUL_SFifo); /* REQ/ACK offset */
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
- return (3);
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ outb((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)), host->addr + TUL_SSignal);
+ /* Into before CDB xfer */
+ return 3;
}
-/***************************************************************************/
-/* state after selection with attention */
-/* state after selection with attention3 */
-int tul_state_2(HCS * pCurHcb)
+/**
+ * initio_state_2 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ * state after selection with attention
+ * state after selection with attention3
+ */
+
+static int initio_state_2(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+ struct scsi_ctrl_blk *scb = host->active;
+ struct target_control *active_tc = host->active_tc;
#if DEBUG_STATE
printk("-s2-");
#endif
- tul_unlink_pend_scb(pCurHcb, pCurScb);
- tul_append_busy_scb(pCurHcb, pCurScb);
+ initio_unlink_pend_scb(host, scb);
+ initio_append_busy_scb(host, scb);
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+ outb(active_tc->sconfig0, host->addr + TUL_SConfig);
- if (pCurHcb->HCS_JSStatus1 & TSS_CMD_PH_CMP) {
- return (4);
- }
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
- return (3);
+ if (host->jsstatus1 & TSS_CMD_PH_CMP)
+ return 4;
+
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ outb((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)), host->addr + TUL_SSignal);
+ /* Into before CDB xfer */
+ return 3;
}
-/***************************************************************************/
-/* state before CDB xfer is done */
-int tul_state_3(HCS * pCurHcb)
+/**
+ * initio_state_3 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ * state before CDB xfer is done
+ */
+
+static int initio_state_3(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+ struct scsi_ctrl_blk *scb = host->active;
+ struct target_control *active_tc = host->active_tc;
int i;
#if DEBUG_STATE
printk("-s3-");
#endif
for (;;) {
- switch (pCurHcb->HCS_Phase) {
+ switch (host->phase) {
case CMD_OUT: /* Command out phase */
- for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
- if (pCurHcb->HCS_Phase == CMD_OUT) {
- return (tul_bad_seq(pCurHcb));
- }
- return (4);
+ for (i = 0; i < (int) scb->cdblen; i++)
+ outb(scb->cdb[i], host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ if (host->phase == CMD_OUT)
+ return initio_bad_seq(host);
+ return 4;
case MSG_IN: /* Message in phase */
- pCurScb->SCB_NxtStat = 3;
- if (tul_msgin(pCurHcb) == -1)
- return (-1);
+ scb->next_state = 3;
+ if (initio_msgin(host) == -1)
+ return -1;
break;
case STATUS_IN: /* Status phase */
- if (tul_status_msg(pCurHcb) == -1)
- return (-1);
+ if (initio_status_msg(host) == -1)
+ return -1;
break;
case MSG_OUT: /* Message out phase */
- if (pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) {
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP); /* msg nop */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
-
+ if (active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) {
+ outb(MSG_NOP, host->addr + TUL_SFifo); /* msg nop */
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
} else {
- pCurTcb->TCS_Flags |= TCF_SYNC_DONE;
+ active_tc->flags |= TCF_SYNC_DONE;
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3); /* ext. msg len */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1); /* sync request */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET); /* REQ/ACK offset */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7));
+ outb(MSG_EXTEND, host->addr + TUL_SFifo);
+ outb(3, host->addr + TUL_SFifo); /* ext. msg len */
+ outb(1, host->addr + TUL_SFifo); /* sync request */
+ outb(initio_rate_tbl[active_tc->flags & TCF_SCSI_RATE], host->addr + TUL_SFifo);
+ outb(MAX_OFFSET, host->addr + TUL_SFifo); /* REQ/ACK offset */
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ outb(inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7), host->addr + TUL_SSignal);
}
break;
-
default:
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
}
}
+/**
+ * initio_state_4 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ * SCSI state machine. State 4
+ */
-/***************************************************************************/
-int tul_state_4(HCS * pCurHcb)
+static int initio_state_4(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
+ struct scsi_ctrl_blk *scb = host->active;
#if DEBUG_STATE
printk("-s4-");
#endif
- if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_NO_XF) {
- return (6); /* Go to state 6 */
+ if ((scb->flags & SCF_DIR) == SCF_NO_XF) {
+ return 6; /* Go to state 6 (After data) */
}
for (;;) {
- if (pCurScb->SCB_BufLen == 0)
- return (6); /* Go to state 6 */
+ if (scb->buflen == 0)
+ return 6;
- switch (pCurHcb->HCS_Phase) {
+ switch (host->phase) {
case STATUS_IN: /* Status phase */
- if ((pCurScb->SCB_Flags & SCF_DIR) != 0) { /* if direction bit set then report data underrun */
- pCurScb->SCB_HaStat = HOST_DO_DU;
- }
- if ((tul_status_msg(pCurHcb)) == -1)
- return (-1);
+ if ((scb->flags & SCF_DIR) != 0) /* if direction bit set then report data underrun */
+ scb->hastat = HOST_DO_DU;
+ if ((initio_status_msg(host)) == -1)
+ return -1;
break;
case MSG_IN: /* Message in phase */
- pCurScb->SCB_NxtStat = 0x4;
- if (tul_msgin(pCurHcb) == -1)
- return (-1);
+ scb->next_state = 0x4;
+ if (initio_msgin(host) == -1)
+ return -1;
break;
case MSG_OUT: /* Message out phase */
- if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
- pCurScb->SCB_BufLen = 0;
- pCurScb->SCB_HaStat = HOST_DO_DU;
- if (tul_msgout_ide(pCurHcb) == -1)
- return (-1);
- return (6); /* Go to state 6 */
+ if (host->jsstatus0 & TSS_PAR_ERROR) {
+ scb->buflen = 0;
+ scb->hastat = HOST_DO_DU;
+ if (initio_msgout_ide(host) == -1)
+ return -1;
+ return 6;
} else {
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP); /* msg nop */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
+ outb(MSG_NOP, host->addr + TUL_SFifo); /* msg nop */
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
}
break;
case DATA_IN: /* Data in phase */
- return (tul_xfer_data_in(pCurHcb));
+ return initio_xfer_data_in(host);
case DATA_OUT: /* Data out phase */
- return (tul_xfer_data_out(pCurHcb));
+ return initio_xfer_data_out(host);
default:
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
}
}
-/***************************************************************************/
-/* state after dma xfer done or phase change before xfer done */
-int tul_state_5(HCS * pCurHcb)
+/**
+ * initio_state_5 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ * State after dma xfer done or phase change before xfer done
+ */
+
+static int initio_state_5(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
+ struct scsi_ctrl_blk *scb = host->active;
long cnt, xcnt; /* cannot use unsigned !! code: if (xcnt < 0) */
#if DEBUG_STATE
printk("-s5-");
#endif
-/*------ get remaining count -------*/
+ /*------ get remaining count -------*/
+ cnt = inl(host->addr + TUL_SCnt0) & 0x0FFFFFF;
- cnt = TUL_RDLONG(pCurHcb->HCS_Base, TUL_SCnt0) & 0x0FFFFFF;
-
- if (TUL_RD(pCurHcb->HCS_Base, TUL_XCmd) & 0x20) {
+ if (inb(host->addr + TUL_XCmd) & 0x20) {
/* ----------------------- DATA_IN ----------------------------- */
/* check scsi parity error */
- if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
- pCurScb->SCB_HaStat = HOST_DO_DU;
- }
- if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) { /* DMA xfer pending, Send STOP */
+ if (host->jsstatus0 & TSS_PAR_ERROR)
+ scb->hastat = HOST_DO_DU;
+ if (inb(host->addr + TUL_XStatus) & XPEND) { /* DMA xfer pending, Send STOP */
/* tell Hardware scsi xfer has been terminated */
- TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, TUL_RD(pCurHcb->HCS_Base, TUL_XCtrl) | 0x80);
+ outb(inb(host->addr + TUL_XCtrl) | 0x80, host->addr + TUL_XCtrl);
/* wait until DMA xfer not pending */
- while (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND);
+ while (inb(host->addr + TUL_XStatus) & XPEND)
+ cpu_relax();
}
} else {
-/*-------- DATA OUT -----------*/
- if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0) {
- if (pCurHcb->HCS_ActTcs->TCS_JS_Period & TSC_WIDE_SCSI)
- cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F) << 1;
+ /*-------- DATA OUT -----------*/
+ if ((inb(host->addr + TUL_SStatus1) & TSS_XFER_CMP) == 0) {
+ if (host->active_tc->js_period & TSC_WIDE_SCSI)
+ cnt += (inb(host->addr + TUL_SFifoCnt) & 0x1F) << 1;
else
- cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F);
+ cnt += (inb(host->addr + TUL_SFifoCnt) & 0x1F);
}
- if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT);
+ if (inb(host->addr + TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */
+ outb(TAX_X_ABT, host->addr + TUL_XCmd);
/* wait Abort DMA xfer done */
- while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);
+ while ((inb(host->addr + TUL_Int) & XABT) == 0)
+ cpu_relax();
}
- if ((cnt == 1) && (pCurHcb->HCS_Phase == DATA_OUT)) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1) {
- return (-1);
- }
+ if ((cnt == 1) && (host->phase == DATA_OUT)) {
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
cnt = 0;
} else {
- if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0)
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+ if ((inb(host->addr + TUL_SStatus1) & TSS_XFER_CMP) == 0)
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
}
}
-
if (cnt == 0) {
- pCurScb->SCB_BufLen = 0;
- return (6); /* Go to state 6 */
+ scb->buflen = 0;
+ return 6; /* After Data */
}
/* Update active data pointer */
- xcnt = (long) pCurScb->SCB_BufLen - cnt; /* xcnt== bytes already xferred */
- pCurScb->SCB_BufLen = (U32) cnt; /* cnt == bytes left to be xferred */
- if (pCurScb->SCB_Flags & SCF_SG) {
- register SG *sgp;
- ULONG i;
+ xcnt = (long) scb->buflen - cnt; /* xcnt== bytes already xferred */
+ scb->buflen = (u32) cnt; /* cnt == bytes left to be xferred */
+ if (scb->flags & SCF_SG) {
+ struct sg_entry *sgp;
+ unsigned long i;
- sgp = &pCurScb->SCB_SGList[pCurScb->SCB_SGIdx];
- for (i = pCurScb->SCB_SGIdx; i < pCurScb->SCB_SGMax; sgp++, i++) {
- xcnt -= (long) sgp->SG_Len;
+ sgp = &scb->sglist[scb->sgidx];
+ for (i = scb->sgidx; i < scb->sgmax; sgp++, i++) {
+ xcnt -= (long) sgp->len;
if (xcnt < 0) { /* this sgp xfer half done */
- xcnt += (long) sgp->SG_Len; /* xcnt == bytes xferred in this sgp */
- sgp->SG_Ptr += (U32) xcnt; /* new ptr to be xfer */
- sgp->SG_Len -= (U32) xcnt; /* new len to be xfer */
- pCurScb->SCB_BufPtr += ((U32) (i - pCurScb->SCB_SGIdx) << 3);
+ xcnt += (long) sgp->len; /* xcnt == bytes xferred in this sgp */
+ sgp->data += (u32) xcnt; /* new ptr to be xfer */
+ sgp->len -= (u32) xcnt; /* new len to be xfer */
+ scb->bufptr += ((u32) (i - scb->sgidx) << 3);
/* new SG table ptr */
- pCurScb->SCB_SGLen = (BYTE) (pCurScb->SCB_SGMax - i);
+ scb->sglen = (u8) (scb->sgmax - i);
/* new SG table len */
- pCurScb->SCB_SGIdx = (WORD) i;
+ scb->sgidx = (u16) i;
/* for next disc and come in this loop */
- return (4); /* Go to state 4 */
+ return 4; /* Go to state 4 */
}
/* else (xcnt >= 0 , i.e. this sgp already xferred */
} /* for */
- return (6); /* Go to state 6 */
+ return 6; /* Go to state 6 */
} else {
- pCurScb->SCB_BufPtr += (U32) xcnt;
+ scb->bufptr += (u32) xcnt;
}
- return (4); /* Go to state 4 */
+ return 4; /* Go to state 4 */
}
-/***************************************************************************/
-/* state after Data phase */
-int tul_state_6(HCS * pCurHcb)
+/**
+ * initio_state_6 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ * State after Data phase
+ */
+
+static int initio_state_6(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
+ struct scsi_ctrl_blk *scb = host->active;
#if DEBUG_STATE
printk("-s6-");
#endif
for (;;) {
- switch (pCurHcb->HCS_Phase) {
+ switch (host->phase) {
case STATUS_IN: /* Status phase */
- if ((tul_status_msg(pCurHcb)) == -1)
- return (-1);
+ if ((initio_status_msg(host)) == -1)
+ return -1;
break;
case MSG_IN: /* Message in phase */
- pCurScb->SCB_NxtStat = 6;
- if ((tul_msgin(pCurHcb)) == -1)
- return (-1);
+ scb->next_state = 6;
+ if ((initio_msgin(host)) == -1)
+ return -1;
break;
case MSG_OUT: /* Message out phase */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP); /* msg nop */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
+ outb(MSG_NOP, host->addr + TUL_SFifo); /* msg nop */
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
break;
case DATA_IN: /* Data in phase */
- return (tul_xpad_in(pCurHcb));
+ return initio_xpad_in(host);
case DATA_OUT: /* Data out phase */
- return (tul_xpad_out(pCurHcb));
+ return initio_xpad_out(host);
default:
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
}
}
-/***************************************************************************/
-int tul_state_7(HCS * pCurHcb)
+/**
+ * initio_state_7 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ */
+
+int initio_state_7(struct initio_host * host)
{
int cnt, i;
@@ -1893,1139 +1678,1029 @@
printk("-s7-");
#endif
/* flush SCSI FIFO */
- cnt = TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F;
+ cnt = inb(host->addr + TUL_SFifoCnt) & 0x1F;
if (cnt) {
for (i = 0; i < cnt; i++)
- TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+ inb(host->addr + TUL_SFifo);
}
- switch (pCurHcb->HCS_Phase) {
+ switch (host->phase) {
case DATA_IN: /* Data in phase */
case DATA_OUT: /* Data out phase */
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
default:
- return (6); /* Go to state 6 */
+ return 6; /* Go to state 6 */
}
}
-/***************************************************************************/
-int tul_xfer_data_in(HCS * pCurHcb)
+/**
+ * initio_xfer_data_in - Commence data input
+ * @host: InitIO host in use
+ *
+ * Commence a block of data transfer. The transfer itself will
+ * be managed by the controller and we will get a completion (or
+ * failure) interrupt.
+ */
+static int initio_xfer_data_in(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
+ struct scsi_ctrl_blk *scb = host->active;
- if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_DOUT) {
- return (6); /* wrong direction */
- }
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, pCurScb->SCB_BufLen);
+ if ((scb->flags & SCF_DIR) == SCF_DOUT)
+ return 6; /* wrong direction */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_DMA_IN); /* 7/25/95 */
+ outl(scb->buflen, host->addr + TUL_SCnt0);
+ outb(TSC_XF_DMA_IN, host->addr + TUL_SCmd); /* 7/25/95 */
- if (pCurScb->SCB_Flags & SCF_SG) { /* S/G xfer */
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, ((ULONG) pCurScb->SCB_SGLen) << 3);
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_SG_IN);
+ if (scb->flags & SCF_SG) { /* S/G xfer */
+ outl(((u32) scb->sglen) << 3, host->addr + TUL_XCntH);
+ outl(scb->bufptr, host->addr + TUL_XAddH);
+ outb(TAX_SG_IN, host->addr + TUL_XCmd);
} else {
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, pCurScb->SCB_BufLen);
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_IN);
+ outl(scb->buflen, host->addr + TUL_XCntH);
+ outl(scb->bufptr, host->addr + TUL_XAddH);
+ outb(TAX_X_IN, host->addr + TUL_XCmd);
}
- pCurScb->SCB_NxtStat = 0x5;
- return (0); /* return to OS, wait xfer done , let jas_isr come in */
+ scb->next_state = 0x5;
+ return 0; /* return to OS, wait xfer done , let jas_isr come in */
}
+/**
+ * initio_xfer_data_out - Commence data output
+ * @host: InitIO host in use
+ *
+ * Commence a block of data transfer. The transfer itself will
+ * be managed by the controller and we will get a completion (or
+ * failure) interrupt.
+ */
-/***************************************************************************/
-int tul_xfer_data_out(HCS * pCurHcb)
+static int initio_xfer_data_out(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
+ struct scsi_ctrl_blk *scb = host->active;
- if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_DIN) {
- return (6); /* wrong direction */
- }
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, pCurScb->SCB_BufLen);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_DMA_OUT);
+ if ((scb->flags & SCF_DIR) == SCF_DIN)
+ return 6; /* wrong direction */
- if (pCurScb->SCB_Flags & SCF_SG) { /* S/G xfer */
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, ((ULONG) pCurScb->SCB_SGLen) << 3);
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_SG_OUT);
+ outl(scb->buflen, host->addr + TUL_SCnt0);
+ outb(TSC_XF_DMA_OUT, host->addr + TUL_SCmd);
+
+ if (scb->flags & SCF_SG) { /* S/G xfer */
+ outl(((u32) scb->sglen) << 3, host->addr + TUL_XCntH);
+ outl(scb->bufptr, host->addr + TUL_XAddH);
+ outb(TAX_SG_OUT, host->addr + TUL_XCmd);
} else {
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, pCurScb->SCB_BufLen);
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_OUT);
+ outl(scb->buflen, host->addr + TUL_XCntH);
+ outl(scb->bufptr, host->addr + TUL_XAddH);
+ outb(TAX_X_OUT, host->addr + TUL_XCmd);
}
- pCurScb->SCB_NxtStat = 0x5;
- return (0); /* return to OS, wait xfer done , let jas_isr come in */
+ scb->next_state = 0x5;
+ return 0; /* return to OS, wait xfer done , let jas_isr come in */
}
-
-/***************************************************************************/
-int tul_xpad_in(HCS * pCurHcb)
+int initio_xpad_in(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+ struct scsi_ctrl_blk *scb = host->active;
+ struct target_control *active_tc = host->active_tc;
- if ((pCurScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) {
- pCurScb->SCB_HaStat = HOST_DO_DU; /* over run */
- }
+ if ((scb->flags & SCF_DIR) != SCF_NO_DCHK)
+ scb->hastat = HOST_DO_DU; /* over run */
for (;;) {
- if (pCurTcb->TCS_JS_Period & TSC_WIDE_SCSI)
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 2);
+ if (active_tc->js_period & TSC_WIDE_SCSI)
+ outl(2, host->addr + TUL_SCnt0);
else
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+ outl(1, host->addr + TUL_SCnt0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if ((wait_tulip(pCurHcb)) == -1) {
- return (-1);
+ outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ if (host->phase != DATA_IN) {
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ return 6;
}
- if (pCurHcb->HCS_Phase != DATA_IN) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- return (6);
- }
- TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+ inb(host->addr + TUL_SFifo);
}
}
-int tul_xpad_out(HCS * pCurHcb)
+int initio_xpad_out(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+ struct scsi_ctrl_blk *scb = host->active;
+ struct target_control *active_tc = host->active_tc;
- if ((pCurScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) {
- pCurScb->SCB_HaStat = HOST_DO_DU; /* over run */
- }
+ if ((scb->flags & SCF_DIR) != SCF_NO_DCHK)
+ scb->hastat = HOST_DO_DU; /* over run */
for (;;) {
- if (pCurTcb->TCS_JS_Period & TSC_WIDE_SCSI)
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 2);
+ if (active_tc->js_period & TSC_WIDE_SCSI)
+ outl(2, host->addr + TUL_SCnt0);
else
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+ outl(1, host->addr + TUL_SCnt0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if ((wait_tulip(pCurHcb)) == -1) {
- return (-1);
- }
- if (pCurHcb->HCS_Phase != DATA_OUT) { /* Disable wide CPU to allow read 16 bits */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- return (6);
+ outb(0, host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if ((wait_tulip(host)) == -1)
+ return -1;
+ if (host->phase != DATA_OUT) { /* Disable wide CPU to allow read 16 bits */
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1);
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ return 6;
}
}
}
-
-/***************************************************************************/
-int tul_status_msg(HCS * pCurHcb)
+int initio_status_msg(struct initio_host * host)
{ /* status & MSG_IN */
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- BYTE msg;
+ struct scsi_ctrl_blk *scb = host->active;
+ u8 msg;
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_CMD_COMP);
- if ((wait_tulip(pCurHcb)) == -1) {
- return (-1);
- }
+ outb(TSC_CMD_COMP, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+
/* get status */
- pCurScb->SCB_TaStat = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+ scb->tastat = inb(host->addr + TUL_SFifo);
- if (pCurHcb->HCS_Phase == MSG_OUT) {
- if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_PARITY);
- } else {
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);
- }
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- return (wait_tulip(pCurHcb));
+ if (host->phase == MSG_OUT) {
+ if (host->jsstatus0 & TSS_PAR_ERROR)
+ outb(MSG_PARITY, host->addr + TUL_SFifo);
+ else
+ outb(MSG_NOP, host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
- if (pCurHcb->HCS_Phase == MSG_IN) {
- msg = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
- if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) { /* Parity error */
- if ((tul_msgin_accept(pCurHcb)) == -1)
- return (-1);
- if (pCurHcb->HCS_Phase != MSG_OUT)
- return (tul_bad_seq(pCurHcb));
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_PARITY);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- return (wait_tulip(pCurHcb));
+ if (host->phase == MSG_IN) {
+ msg = inb(host->addr + TUL_SFifo);
+ if (host->jsstatus0 & TSS_PAR_ERROR) { /* Parity error */
+ if ((initio_msgin_accept(host)) == -1)
+ return -1;
+ if (host->phase != MSG_OUT)
+ return initio_bad_seq(host);
+ outb(MSG_PARITY, host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
if (msg == 0) { /* Command complete */
- if ((pCurScb->SCB_TaStat & 0x18) == 0x10) { /* No link support */
- return (tul_bad_seq(pCurHcb));
- }
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
- return tul_wait_done_disc(pCurHcb);
+ if ((scb->tastat & 0x18) == 0x10) /* No link support */
+ return initio_bad_seq(host);
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
+ return initio_wait_done_disc(host);
}
- if ((msg == MSG_LINK_COMP) || (msg == MSG_LINK_FLAG)) {
- if ((pCurScb->SCB_TaStat & 0x18) == 0x10)
- return (tul_msgin_accept(pCurHcb));
+ if (msg == MSG_LINK_COMP || msg == MSG_LINK_FLAG) {
+ if ((scb->tastat & 0x18) == 0x10)
+ return initio_msgin_accept(host);
}
}
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
-/***************************************************************************/
/* scsi bus free */
-int int_tul_busfree(HCS * pCurHcb)
+int int_initio_busfree(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
+ struct scsi_ctrl_blk *scb = host->active;
- if (pCurScb != NULL) {
- if (pCurScb->SCB_Status & SCB_SELECT) { /* selection timeout */
- tul_unlink_pend_scb(pCurHcb, pCurScb);
- pCurScb->SCB_HaStat = HOST_SEL_TOUT;
- tul_append_done_scb(pCurHcb, pCurScb);
+ if (scb != NULL) {
+ if (scb->status & SCB_SELECT) { /* selection timeout */
+ initio_unlink_pend_scb(host, scb);
+ scb->hastat = HOST_SEL_TOUT;
+ initio_append_done_scb(host, scb);
} else { /* Unexpected bus free */
- tul_unlink_busy_scb(pCurHcb, pCurScb);
- pCurScb->SCB_HaStat = HOST_BUS_FREE;
- tul_append_done_scb(pCurHcb, pCurScb);
+ initio_unlink_busy_scb(host, scb);
+ scb->hastat = HOST_BUS_FREE;
+ initio_append_done_scb(host, scb);
}
- pCurHcb->HCS_ActScb = NULL;
- pCurHcb->HCS_ActTcs = NULL;
+ host->active = NULL;
+ host->active_tc = NULL;
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT); /* Enable HW reselect */
- return (-1);
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
+ outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */
+ return -1;
}
-/***************************************************************************/
-/* scsi bus reset */
-static int int_tul_scsi_rst(HCS * pCurHcb)
+/**
+ * int_initio_scsi_rst - SCSI reset occurred
+ * @host: Host seeing the reset
+ *
+ * A SCSI bus reset has occurred. Clean up any pending transfer
+ * the hardware is doing by DMA and then abort all active and
+ * disconnected commands. The mid layer should sort the rest out
+ * for us
+ */
+
+static int int_initio_scsi_rst(struct initio_host * host)
{
- SCB *pCurScb;
+ struct scsi_ctrl_blk *scb;
int i;
/* if DMA xfer is pending, abort DMA xfer */
- if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & 0x01) {
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT | TAX_X_CLR_FIFO);
+ if (inb(host->addr + TUL_XStatus) & 0x01) {
+ outb(TAX_X_ABT | TAX_X_CLR_FIFO, host->addr + TUL_XCmd);
/* wait Abort DMA xfer done */
- while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & 0x04) == 0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+ while ((inb(host->addr + TUL_Int) & 0x04) == 0)
+ cpu_relax();
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
}
/* Abort all active & disconnected scb */
- while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
- pCurScb->SCB_HaStat = HOST_BAD_PHAS;
- tul_append_done_scb(pCurHcb, pCurScb);
+ while ((scb = initio_pop_busy_scb(host)) != NULL) {
+ scb->hastat = HOST_BAD_PHAS;
+ initio_append_done_scb(host, scb);
}
- pCurHcb->HCS_ActScb = NULL;
- pCurHcb->HCS_ActTcs = NULL;
+ host->active = NULL;
+ host->active_tc = NULL;
/* clr sync nego. done flag */
- for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
- pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
- }
- return (-1);
+ for (i = 0; i < host->max_tar; i++)
+ host->targets[i].flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+ return -1;
}
+/**
+ * int_initio_scsi_resel - Reselection occured
+ * @host: InitIO host adapter
+ *
+ * A SCSI reselection event has been signalled and the interrupt
+ * is now being processed. Work out which command block needs attention
+ * and continue processing that command.
+ */
-/***************************************************************************/
-/* scsi reselection */
-int int_tul_resel(HCS * pCurHcb)
+int int_initio_resel(struct initio_host * host)
{
- SCB *pCurScb;
- TCS *pCurTcb;
- BYTE tag, msg = 0;
- BYTE tar, lun;
+ struct scsi_ctrl_blk *scb;
+ struct target_control *active_tc;
+ u8 tag, msg = 0;
+ u8 tar, lun;
- if ((pCurScb = pCurHcb->HCS_ActScb) != NULL) {
- if (pCurScb->SCB_Status & SCB_SELECT) { /* if waiting for selection complete */
- pCurScb->SCB_Status &= ~SCB_SELECT;
- }
- pCurHcb->HCS_ActScb = NULL;
+ if ((scb = host->active) != NULL) {
+ /* FIXME: Why check and not just clear ? */
+ if (scb->status & SCB_SELECT) /* if waiting for selection complete */
+ scb->status &= ~SCB_SELECT;
+ host->active = NULL;
}
/* --------- get target id---------------------- */
- tar = TUL_RD(pCurHcb->HCS_Base, TUL_SBusId);
+ tar = inb(host->addr + TUL_SBusId);
/* ------ get LUN from Identify message----------- */
- lun = TUL_RD(pCurHcb->HCS_Base, TUL_SIdent) & 0x0F;
+ lun = inb(host->addr + TUL_SIdent) & 0x0F;
/* 07/22/98 from 0x1F -> 0x0F */
- pCurTcb = &pCurHcb->HCS_Tcs[tar];
- pCurHcb->HCS_ActTcs = pCurTcb;
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);
-
+ active_tc = &host->targets[tar];
+ host->active_tc = active_tc;
+ outb(active_tc->sconfig0, host->addr + TUL_SConfig);
+ outb(active_tc->js_period, host->addr + TUL_SPeriod);
/* ------------- tag queueing ? ------------------- */
- if (pCurTcb->TCS_DrvFlags & TCF_DRV_EN_TAG) {
- if ((tul_msgin_accept(pCurHcb)) == -1)
- return (-1);
- if (pCurHcb->HCS_Phase != MSG_IN)
+ if (active_tc->drv_flags & TCF_DRV_EN_TAG) {
+ if ((initio_msgin_accept(host)) == -1)
+ return -1;
+ if (host->phase != MSG_IN)
goto no_tag;
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if ((wait_tulip(pCurHcb)) == -1)
- return (-1);
- msg = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo); /* Read Tag Message */
+ outl(1, host->addr + TUL_SCnt0);
+ outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ msg = inb(host->addr + TUL_SFifo); /* Read Tag Message */
- if ((msg < MSG_STAG) || (msg > MSG_OTAG)) /* Is simple Tag */
+ if (msg < MSG_STAG || msg > MSG_OTAG) /* Is simple Tag */
goto no_tag;
- if ((tul_msgin_accept(pCurHcb)) == -1)
- return (-1);
+ if (initio_msgin_accept(host) == -1)
+ return -1;
- if (pCurHcb->HCS_Phase != MSG_IN)
+ if (host->phase != MSG_IN)
goto no_tag;
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if ((wait_tulip(pCurHcb)) == -1)
- return (-1);
- tag = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo); /* Read Tag ID */
- pCurScb = pCurHcb->HCS_Scb + tag;
- if ((pCurScb->SCB_Target != tar) || (pCurScb->SCB_Lun != lun)) {
- return tul_msgout_abort_tag(pCurHcb);
+ outl(1, host->addr + TUL_SCnt0);
+ outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ tag = inb(host->addr + TUL_SFifo); /* Read Tag ID */
+ scb = host->scb + tag;
+ if (scb->target != tar || scb->lun != lun) {
+ return initio_msgout_abort_tag(host);
}
- if (pCurScb->SCB_Status != SCB_BUSY) { /* 03/24/95 */
- return tul_msgout_abort_tag(pCurHcb);
+ if (scb->status != SCB_BUSY) { /* 03/24/95 */
+ return initio_msgout_abort_tag(host);
}
- pCurHcb->HCS_ActScb = pCurScb;
- if ((tul_msgin_accept(pCurHcb)) == -1)
- return (-1);
+ host->active = scb;
+ if ((initio_msgin_accept(host)) == -1)
+ return -1;
} else { /* No tag */
no_tag:
- if ((pCurScb = tul_find_busy_scb(pCurHcb, tar | (lun << 8))) == NULL) {
- return tul_msgout_abort_targ(pCurHcb);
+ if ((scb = initio_find_busy_scb(host, tar | (lun << 8))) == NULL) {
+ return initio_msgout_abort_targ(host);
}
- pCurHcb->HCS_ActScb = pCurScb;
- if (!(pCurTcb->TCS_DrvFlags & TCF_DRV_EN_TAG)) {
- if ((tul_msgin_accept(pCurHcb)) == -1)
- return (-1);
+ host->active = scb;
+ if (!(active_tc->drv_flags & TCF_DRV_EN_TAG)) {
+ if ((initio_msgin_accept(host)) == -1)
+ return -1;
}
}
return 0;
}
+/**
+ * int_initio_bad_seq - out of phase
+ * @host: InitIO host flagging event
+ *
+ * We have ended up out of phase somehow. Reset the host controller
+ * and throw all our toys out of the pram. Let the midlayer clean up
+ */
-/***************************************************************************/
-static int int_tul_bad_seq(HCS * pCurHcb)
+static int int_initio_bad_seq(struct initio_host * host)
{ /* target wrong phase */
- SCB *pCurScb;
+ struct scsi_ctrl_blk *scb;
int i;
- tul_reset_scsi(pCurHcb, 10);
+ initio_reset_scsi(host, 10);
- while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
- pCurScb->SCB_HaStat = HOST_BAD_PHAS;
- tul_append_done_scb(pCurHcb, pCurScb);
+ while ((scb = initio_pop_busy_scb(host)) != NULL) {
+ scb->hastat = HOST_BAD_PHAS;
+ initio_append_done_scb(host, scb);
}
- for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
- pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
- }
- return (-1);
+ for (i = 0; i < host->max_tar; i++)
+ host->targets[i].flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+ return -1;
}
-/***************************************************************************/
-int tul_msgout_abort_targ(HCS * pCurHcb)
+/**
+ * initio_msgout_abort_targ - abort a tag
+ * @host: InitIO host
+ *
+ * Abort when the target/lun does not match or when our SCB is not
+ * busy. Used by untagged commands.
+ */
+
+static int initio_msgout_abort_targ(struct initio_host * host)
{
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
- if (tul_msgin_accept(pCurHcb) == -1)
- return (-1);
- if (pCurHcb->HCS_Phase != MSG_OUT)
- return (tul_bad_seq(pCurHcb));
+ outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
+ if (initio_msgin_accept(host) == -1)
+ return -1;
+ if (host->phase != MSG_OUT)
+ return initio_bad_seq(host);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_ABORT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+ outb(MSG_ABORT, host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
- return tul_wait_disc(pCurHcb);
+ return initio_wait_disc(host);
}
-/***************************************************************************/
-int tul_msgout_abort_tag(HCS * pCurHcb)
+/**
+ * initio_msgout_abort_tag - abort a tag
+ * @host: InitIO host
+ *
+ * Abort when the target/lun does not match or when our SCB is not
+ * busy. Used for tagged commands.
+ */
+
+static int initio_msgout_abort_tag(struct initio_host * host)
{
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
- if (tul_msgin_accept(pCurHcb) == -1)
- return (-1);
- if (pCurHcb->HCS_Phase != MSG_OUT)
- return (tul_bad_seq(pCurHcb));
+ outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
+ if (initio_msgin_accept(host) == -1)
+ return -1;
+ if (host->phase != MSG_OUT)
+ return initio_bad_seq(host);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_ABORT_TAG);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+ outb(MSG_ABORT_TAG, host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
- return tul_wait_disc(pCurHcb);
+ return initio_wait_disc(host);
}
-/***************************************************************************/
-int tul_msgin(HCS * pCurHcb)
+/**
+ * initio_msgin - Message in
+ * @host: InitIO Host
+ *
+ * Process incoming message
+ */
+static int initio_msgin(struct initio_host * host)
{
- TCS *pCurTcb;
+ struct target_control *active_tc;
for (;;) {
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+ outl(1, host->addr + TUL_SCnt0);
+ outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if ((wait_tulip(pCurHcb)) == -1)
- return (-1);
-
- switch (TUL_RD(pCurHcb->HCS_Base, TUL_SFifo)) {
+ switch (inb(host->addr + TUL_SFifo)) {
case MSG_DISC: /* Disconnect msg */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
-
- return tul_wait_disc(pCurHcb);
-
+ outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
+ return initio_wait_disc(host);
case MSG_SDP:
case MSG_RESTORE:
case MSG_NOP:
- tul_msgin_accept(pCurHcb);
+ initio_msgin_accept(host);
break;
-
case MSG_REJ: /* Clear ATN first */
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal,
- (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
- pCurTcb = pCurHcb->HCS_ActTcs;
- if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) { /* do sync nego */
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
- }
- tul_msgin_accept(pCurHcb);
+ outb((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)),
+ host->addr + TUL_SSignal);
+ active_tc = host->active_tc;
+ if ((active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) /* do sync nego */
+ outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN),
+ host->addr + TUL_SSignal);
+ initio_msgin_accept(host);
break;
-
case MSG_EXTEND: /* extended msg */
- tul_msgin_extend(pCurHcb);
+ initio_msgin_extend(host);
break;
-
case MSG_IGNOREWIDE:
- tul_msgin_accept(pCurHcb);
+ initio_msgin_accept(host);
break;
-
- /* get */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if (wait_tulip(pCurHcb) == -1)
- return -1;
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 0); /* put pad */
- TUL_RD(pCurHcb->HCS_Base, TUL_SFifo); /* get IGNORE field */
- TUL_RD(pCurHcb->HCS_Base, TUL_SFifo); /* get pad */
-
- tul_msgin_accept(pCurHcb);
- break;
-
case MSG_COMP:
- {
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
- return tul_wait_done_disc(pCurHcb);
- }
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
+ return initio_wait_done_disc(host);
default:
- tul_msgout_reject(pCurHcb);
+ initio_msgout_reject(host);
break;
}
- if (pCurHcb->HCS_Phase != MSG_IN)
- return (pCurHcb->HCS_Phase);
+ if (host->phase != MSG_IN)
+ return host->phase;
}
/* statement won't reach here */
}
-
-
-
-/***************************************************************************/
-int tul_msgout_reject(HCS * pCurHcb)
+static int initio_msgout_reject(struct initio_host * host)
{
+ outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+ if (initio_msgin_accept(host) == -1)
+ return -1;
- if ((tul_msgin_accept(pCurHcb)) == -1)
- return (-1);
-
- if (pCurHcb->HCS_Phase == MSG_OUT) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_REJ); /* Msg reject */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- return (wait_tulip(pCurHcb));
+ if (host->phase == MSG_OUT) {
+ outb(MSG_REJ, host->addr + TUL_SFifo); /* Msg reject */
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
- return (pCurHcb->HCS_Phase);
+ return host->phase;
}
-
-
-/***************************************************************************/
-int tul_msgout_ide(HCS * pCurHcb)
+static int initio_msgout_ide(struct initio_host * host)
{
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_IDE); /* Initiator Detected Error */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- return (wait_tulip(pCurHcb));
+ outb(MSG_IDE, host->addr + TUL_SFifo); /* Initiator Detected Error */
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
-
-/***************************************************************************/
-int tul_msgin_extend(HCS * pCurHcb)
+static int initio_msgin_extend(struct initio_host * host)
{
- BYTE len, idx;
+ u8 len, idx;
- if (tul_msgin_accept(pCurHcb) != MSG_IN)
- return (pCurHcb->HCS_Phase);
+ if (initio_msgin_accept(host) != MSG_IN)
+ return host->phase;
/* Get extended msg length */
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
+ outl(1, host->addr + TUL_SCnt0);
+ outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
- len = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
- pCurHcb->HCS_Msg[0] = len;
+ len = inb(host->addr + TUL_SFifo);
+ host->msg[0] = len;
for (idx = 1; len != 0; len--) {
- if ((tul_msgin_accept(pCurHcb)) != MSG_IN)
- return (pCurHcb->HCS_Phase);
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
- pCurHcb->HCS_Msg[idx++] = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+ if ((initio_msgin_accept(host)) != MSG_IN)
+ return host->phase;
+ outl(1, host->addr + TUL_SCnt0);
+ outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ host->msg[idx++] = inb(host->addr + TUL_SFifo);
}
- if (pCurHcb->HCS_Msg[1] == 1) { /* if it's synchronous data transfer request */
- if (pCurHcb->HCS_Msg[0] != 3) /* if length is not right */
- return (tul_msgout_reject(pCurHcb));
- if (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_SYNC_NEGO) { /* Set OFFSET=0 to do async, nego back */
- pCurHcb->HCS_Msg[3] = 0;
+ if (host->msg[1] == 1) { /* if it's synchronous data transfer request */
+ u8 r;
+ if (host->msg[0] != 3) /* if length is not right */
+ return initio_msgout_reject(host);
+ if (host->active_tc->flags & TCF_NO_SYNC_NEGO) { /* Set OFFSET=0 to do async, nego back */
+ host->msg[3] = 0;
} else {
- if ((tul_msgin_sync(pCurHcb) == 0) &&
- (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_SYNC_DONE)) {
- tul_sync_done(pCurHcb);
- return (tul_msgin_accept(pCurHcb));
+ if (initio_msgin_sync(host) == 0 &&
+ (host->active_tc->flags & TCF_SYNC_DONE)) {
+ initio_sync_done(host);
+ return initio_msgin_accept(host);
}
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
- if ((tul_msgin_accept(pCurHcb)) != MSG_OUT)
- return (pCurHcb->HCS_Phase);
+ r = inb(host->addr + TUL_SSignal);
+ outb((r & (TSC_SET_ACK | 7)) | TSC_SET_ATN,
+ host->addr + TUL_SSignal);
+ if (initio_msgin_accept(host) != MSG_OUT)
+ return host->phase;
/* sync msg out */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
- tul_sync_done(pCurHcb);
+ initio_sync_done(host);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[2]);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[3]);
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- return (wait_tulip(pCurHcb));
+ outb(MSG_EXTEND, host->addr + TUL_SFifo);
+ outb(3, host->addr + TUL_SFifo);
+ outb(1, host->addr + TUL_SFifo);
+ outb(host->msg[2], host->addr + TUL_SFifo);
+ outb(host->msg[3], host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
- if ((pCurHcb->HCS_Msg[0] != 2) || (pCurHcb->HCS_Msg[1] != 3))
- return (tul_msgout_reject(pCurHcb));
+ if (host->msg[0] != 2 || host->msg[1] != 3)
+ return initio_msgout_reject(host);
/* if it's WIDE DATA XFER REQ */
- if (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) {
- pCurHcb->HCS_Msg[2] = 0;
+ if (host->active_tc->flags & TCF_NO_WDTR) {
+ host->msg[2] = 0;
} else {
- if (pCurHcb->HCS_Msg[2] > 2) /* > 32 bits */
- return (tul_msgout_reject(pCurHcb));
- if (pCurHcb->HCS_Msg[2] == 2) { /* == 32 */
- pCurHcb->HCS_Msg[2] = 1;
+ if (host->msg[2] > 2) /* > 32 bits */
+ return initio_msgout_reject(host);
+ if (host->msg[2] == 2) { /* == 32 */
+ host->msg[2] = 1;
} else {
- if ((pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) == 0) {
- wdtr_done(pCurHcb);
- if ((pCurHcb->HCS_ActTcs->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0)
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
- return (tul_msgin_accept(pCurHcb));
+ if ((host->active_tc->flags & TCF_NO_WDTR) == 0) {
+ wdtr_done(host);
+ if ((host->active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0)
+ outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
+ return initio_msgin_accept(host);
}
}
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+ outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
- if (tul_msgin_accept(pCurHcb) != MSG_OUT)
- return (pCurHcb->HCS_Phase);
+ if (initio_msgin_accept(host) != MSG_OUT)
+ return host->phase;
/* WDTR msg out */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[2]);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- return (wait_tulip(pCurHcb));
+ outb(MSG_EXTEND, host->addr + TUL_SFifo);
+ outb(2, host->addr + TUL_SFifo);
+ outb(3, host->addr + TUL_SFifo);
+ outb(host->msg[2], host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
-/***************************************************************************/
-int tul_msgin_sync(HCS * pCurHcb)
+static int initio_msgin_sync(struct initio_host * host)
{
char default_period;
- default_period = tul_rate_tbl[pCurHcb->HCS_ActTcs->TCS_Flags & TCF_SCSI_RATE];
- if (pCurHcb->HCS_Msg[3] > MAX_OFFSET) {
- pCurHcb->HCS_Msg[3] = MAX_OFFSET;
- if (pCurHcb->HCS_Msg[2] < default_period) {
- pCurHcb->HCS_Msg[2] = default_period;
+ default_period = initio_rate_tbl[host->active_tc->flags & TCF_SCSI_RATE];
+ if (host->msg[3] > MAX_OFFSET) {
+ host->msg[3] = MAX_OFFSET;
+ if (host->msg[2] < default_period) {
+ host->msg[2] = default_period;
return 1;
}
- if (pCurHcb->HCS_Msg[2] >= 59) { /* Change to async */
- pCurHcb->HCS_Msg[3] = 0;
- }
+ if (host->msg[2] >= 59) /* Change to async */
+ host->msg[3] = 0;
return 1;
}
/* offset requests asynchronous transfers ? */
- if (pCurHcb->HCS_Msg[3] == 0) {
+ if (host->msg[3] == 0) {
return 0;
}
- if (pCurHcb->HCS_Msg[2] < default_period) {
- pCurHcb->HCS_Msg[2] = default_period;
+ if (host->msg[2] < default_period) {
+ host->msg[2] = default_period;
return 1;
}
- if (pCurHcb->HCS_Msg[2] >= 59) {
- pCurHcb->HCS_Msg[3] = 0;
+ if (host->msg[2] >= 59) {
+ host->msg[3] = 0;
return 1;
}
return 0;
}
-
-/***************************************************************************/
-int wdtr_done(HCS * pCurHcb)
+static int wdtr_done(struct initio_host * host)
{
- pCurHcb->HCS_ActTcs->TCS_Flags &= ~TCF_SYNC_DONE;
- pCurHcb->HCS_ActTcs->TCS_Flags |= TCF_WDTR_DONE;
+ host->active_tc->flags &= ~TCF_SYNC_DONE;
+ host->active_tc->flags |= TCF_WDTR_DONE;
- pCurHcb->HCS_ActTcs->TCS_JS_Period = 0;
- if (pCurHcb->HCS_Msg[2]) { /* if 16 bit */
- pCurHcb->HCS_ActTcs->TCS_JS_Period |= TSC_WIDE_SCSI;
- }
- pCurHcb->HCS_ActTcs->TCS_SConfig0 &= ~TSC_ALT_PERIOD;
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_ActTcs->TCS_SConfig0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurHcb->HCS_ActTcs->TCS_JS_Period);
+ host->active_tc->js_period = 0;
+ if (host->msg[2]) /* if 16 bit */
+ host->active_tc->js_period |= TSC_WIDE_SCSI;
+ host->active_tc->sconfig0 &= ~TSC_ALT_PERIOD;
+ outb(host->active_tc->sconfig0, host->addr + TUL_SConfig);
+ outb(host->active_tc->js_period, host->addr + TUL_SPeriod);
return 1;
}
-/***************************************************************************/
-int tul_sync_done(HCS * pCurHcb)
+static int initio_sync_done(struct initio_host * host)
{
int i;
- pCurHcb->HCS_ActTcs->TCS_Flags |= TCF_SYNC_DONE;
+ host->active_tc->flags |= TCF_SYNC_DONE;
- if (pCurHcb->HCS_Msg[3]) {
- pCurHcb->HCS_ActTcs->TCS_JS_Period |= pCurHcb->HCS_Msg[3];
+ if (host->msg[3]) {
+ host->active_tc->js_period |= host->msg[3];
for (i = 0; i < 8; i++) {
- if (tul_rate_tbl[i] >= pCurHcb->HCS_Msg[2]) /* pick the big one */
+ if (initio_rate_tbl[i] >= host->msg[2]) /* pick the big one */
break;
}
- pCurHcb->HCS_ActTcs->TCS_JS_Period |= (i << 4);
- pCurHcb->HCS_ActTcs->TCS_SConfig0 |= TSC_ALT_PERIOD;
+ host->active_tc->js_period |= (i << 4);
+ host->active_tc->sconfig0 |= TSC_ALT_PERIOD;
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_ActTcs->TCS_SConfig0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurHcb->HCS_ActTcs->TCS_JS_Period);
+ outb(host->active_tc->sconfig0, host->addr + TUL_SConfig);
+ outb(host->active_tc->js_period, host->addr + TUL_SPeriod);
- return (-1);
+ return -1;
}
-int tul_post_scsi_rst(HCS * pCurHcb)
+static int initio_post_scsi_rst(struct initio_host * host)
{
- SCB *pCurScb;
- TCS *pCurTcb;
+ struct scsi_ctrl_blk *scb;
+ struct target_control *active_tc;
int i;
- pCurHcb->HCS_ActScb = NULL;
- pCurHcb->HCS_ActTcs = NULL;
- pCurHcb->HCS_Flags = 0;
+ host->active = NULL;
+ host->active_tc = NULL;
+ host->flags = 0;
- while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
- pCurScb->SCB_HaStat = HOST_BAD_PHAS;
- tul_append_done_scb(pCurHcb, pCurScb);
+ while ((scb = initio_pop_busy_scb(host)) != NULL) {
+ scb->hastat = HOST_BAD_PHAS;
+ initio_append_done_scb(host, scb);
}
/* clear sync done flag */
- pCurTcb = &pCurHcb->HCS_Tcs[0];
- for (i = 0; i < pCurHcb->HCS_MaxTar; pCurTcb++, i++) {
- pCurTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+ active_tc = &host->targets[0];
+ for (i = 0; i < host->max_tar; active_tc++, i++) {
+ active_tc->flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
/* Initialize the sync. xfer register values to an asyn xfer */
- pCurTcb->TCS_JS_Period = 0;
- pCurTcb->TCS_SConfig0 = pCurHcb->HCS_SConf1;
- pCurHcb->HCS_ActTags[0] = 0; /* 07/22/98 */
- pCurHcb->HCS_Tcs[i].TCS_Flags &= ~TCF_BUSY; /* 07/22/98 */
+ active_tc->js_period = 0;
+ active_tc->sconfig0 = host->sconf1;
+ host->act_tags[0] = 0; /* 07/22/98 */
+ host->targets[i].flags &= ~TCF_BUSY; /* 07/22/98 */
} /* for */
- return (-1);
+ return -1;
}
-/***************************************************************************/
-void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb)
+static void initio_select_atn_stop(struct initio_host * host, struct scsi_ctrl_blk * scb)
{
- pCurScb->SCB_Status |= SCB_SELECT;
- pCurScb->SCB_NxtStat = 0x1;
- pCurHcb->HCS_ActScb = pCurScb;
- pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SELATNSTOP);
- return;
+ scb->status |= SCB_SELECT;
+ scb->next_state = 0x1;
+ host->active = scb;
+ host->active_tc = &host->targets[scb->target];
+ outb(TSC_SELATNSTOP, host->addr + TUL_SCmd);
}
-/***************************************************************************/
-void tul_select_atn(HCS * pCurHcb, SCB * pCurScb)
+static void initio_select_atn(struct initio_host * host, struct scsi_ctrl_blk * scb)
{
int i;
- pCurScb->SCB_Status |= SCB_SELECT;
- pCurScb->SCB_NxtStat = 0x2;
+ scb->status |= SCB_SELECT;
+ scb->next_state = 0x2;
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
- for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
- pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
- pCurHcb->HCS_ActScb = pCurScb;
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SEL_ATN);
- return;
+ outb(scb->ident, host->addr + TUL_SFifo);
+ for (i = 0; i < (int) scb->cdblen; i++)
+ outb(scb->cdb[i], host->addr + TUL_SFifo);
+ host->active_tc = &host->targets[scb->target];
+ host->active = scb;
+ outb(TSC_SEL_ATN, host->addr + TUL_SCmd);
}
-/***************************************************************************/
-void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb)
+static void initio_select_atn3(struct initio_host * host, struct scsi_ctrl_blk * scb)
{
int i;
- pCurScb->SCB_Status |= SCB_SELECT;
- pCurScb->SCB_NxtStat = 0x2;
+ scb->status |= SCB_SELECT;
+ scb->next_state = 0x2;
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);
- for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
- pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
- pCurHcb->HCS_ActScb = pCurScb;
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SEL_ATN3);
- return;
+ outb(scb->ident, host->addr + TUL_SFifo);
+ outb(scb->tagmsg, host->addr + TUL_SFifo);
+ outb(scb->tagid, host->addr + TUL_SFifo);
+ for (i = 0; i < scb->cdblen; i++)
+ outb(scb->cdb[i], host->addr + TUL_SFifo);
+ host->active_tc = &host->targets[scb->target];
+ host->active = scb;
+ outb(TSC_SEL_ATN3, host->addr + TUL_SCmd);
}
-/***************************************************************************/
-/* SCSI Bus Device Reset */
-int tul_bus_device_reset(HCS * pCurHcb)
+/**
+ * initio_bus_device_reset - SCSI Bus Device Reset
+ * @host: InitIO host to reset
+ *
+ * Perform a device reset and abort all pending SCBs for the
+ * victim device
+ */
+int initio_bus_device_reset(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- TCS *pCurTcb = pCurHcb->HCS_ActTcs;
- SCB *pTmpScb, *pPrevScb;
- BYTE tar;
+ struct scsi_ctrl_blk *scb = host->active;
+ struct target_control *active_tc = host->active_tc;
+ struct scsi_ctrl_blk *tmp, *prev;
+ u8 tar;
- if (pCurHcb->HCS_Phase != MSG_OUT) {
- return (int_tul_bad_seq(pCurHcb)); /* Unexpected phase */
- }
- tul_unlink_pend_scb(pCurHcb, pCurScb);
- tul_release_scb(pCurHcb, pCurScb);
+ if (host->phase != MSG_OUT)
+ return int_initio_bad_seq(host); /* Unexpected phase */
+
+ initio_unlink_pend_scb(host, scb);
+ initio_release_scb(host, scb);
- tar = pCurScb->SCB_Target; /* target */
- pCurTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE | TCF_BUSY);
+ tar = scb->target; /* target */
+ active_tc->flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE | TCF_BUSY);
/* clr sync. nego & WDTR flags 07/22/98 */
/* abort all SCB with same target */
- pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy; /* Check Busy queue */
- while (pTmpScb != NULL) {
-
- if (pTmpScb->SCB_Target == tar) {
+ prev = tmp = host->first_busy; /* Check Busy queue */
+ while (tmp != NULL) {
+ if (tmp->target == tar) {
/* unlink it */
- if (pTmpScb == pCurHcb->HCS_FirstBusy) {
- if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastBusy = NULL;
+ if (tmp == host->first_busy) {
+ if ((host->first_busy = tmp->next) == NULL)
+ host->last_busy = NULL;
} else {
- pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
- if (pTmpScb == pCurHcb->HCS_LastBusy)
- pCurHcb->HCS_LastBusy = pPrevScb;
+ prev->next = tmp->next;
+ if (tmp == host->last_busy)
+ host->last_busy = prev;
}
- pTmpScb->SCB_HaStat = HOST_ABORTED;
- tul_append_done_scb(pCurHcb, pTmpScb);
+ tmp->hastat = HOST_ABORTED;
+ initio_append_done_scb(host, tmp);
}
/* Previous haven't change */
else {
- pPrevScb = pTmpScb;
+ prev = tmp;
}
- pTmpScb = pTmpScb->SCB_NxtScb;
+ tmp = tmp->next;
}
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_DEVRST);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
-
- return tul_wait_disc(pCurHcb);
+ outb(MSG_DEVRST, host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return initio_wait_disc(host);
}
-/***************************************************************************/
-int tul_msgin_accept(HCS * pCurHcb)
+static int initio_msgin_accept(struct initio_host * host)
{
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
- return (wait_tulip(pCurHcb));
+ outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
-/***************************************************************************/
-int wait_tulip(HCS * pCurHcb)
+static int wait_tulip(struct initio_host * host)
{
- while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
- & TSS_INT_PENDING));
+ while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0))
+ & TSS_INT_PENDING))
+ cpu_relax();
- pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
- pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;
- pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);
+ host->jsint = inb(host->addr + TUL_SInt);
+ host->phase = host->jsstatus0 & TSS_PH_MASK;
+ host->jsstatus1 = inb(host->addr + TUL_SStatus1);
- if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) { /* if SCSI bus reset detected */
- return (int_tul_resel(pCurHcb));
- }
- if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) { /* if selected/reselected timeout interrupt */
- return (int_tul_busfree(pCurHcb));
- }
- if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) { /* if SCSI bus reset detected */
- return (int_tul_scsi_rst(pCurHcb));
- }
- if (pCurHcb->HCS_JSInt & TSS_DISC_INT) { /* BUS disconnection */
- if (pCurHcb->HCS_Flags & HCF_EXPECT_DONE_DISC) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */
- tul_unlink_busy_scb(pCurHcb, pCurHcb->HCS_ActScb);
- pCurHcb->HCS_ActScb->SCB_HaStat = 0;
- tul_append_done_scb(pCurHcb, pCurHcb->HCS_ActScb);
- pCurHcb->HCS_ActScb = NULL;
- pCurHcb->HCS_ActTcs = NULL;
- pCurHcb->HCS_Flags &= ~HCF_EXPECT_DONE_DISC;
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT); /* Enable HW reselect */
- return (-1);
+ if (host->jsint & TSS_RESEL_INT) /* if SCSI bus reset detected */
+ return int_initio_resel(host);
+ if (host->jsint & TSS_SEL_TIMEOUT) /* if selected/reselected timeout interrupt */
+ return int_initio_busfree(host);
+ if (host->jsint & TSS_SCSIRST_INT) /* if SCSI bus reset detected */
+ return int_initio_scsi_rst(host);
+
+ if (host->jsint & TSS_DISC_INT) { /* BUS disconnection */
+ if (host->flags & HCF_EXPECT_DONE_DISC) {
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
+ initio_unlink_busy_scb(host, host->active);
+ host->active->hastat = 0;
+ initio_append_done_scb(host, host->active);
+ host->active = NULL;
+ host->active_tc = NULL;
+ host->flags &= ~HCF_EXPECT_DONE_DISC;
+ outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */
+ return -1;
}
- if (pCurHcb->HCS_Flags & HCF_EXPECT_DISC) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */
- pCurHcb->HCS_ActScb = NULL;
- pCurHcb->HCS_ActTcs = NULL;
- pCurHcb->HCS_Flags &= ~HCF_EXPECT_DISC;
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT); /* Enable HW reselect */
- return (-1);
+ if (host->flags & HCF_EXPECT_DISC) {
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
+ host->active = NULL;
+ host->active_tc = NULL;
+ host->flags &= ~HCF_EXPECT_DISC;
+ outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */
+ return -1;
}
- return (int_tul_busfree(pCurHcb));
+ return int_initio_busfree(host);
}
- if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) {
- return (pCurHcb->HCS_Phase);
- }
- return (pCurHcb->HCS_Phase);
+ /* The old code really does the below. Can probably be removed */
+ if (host->jsint & (TSS_FUNC_COMP | TSS_BUS_SERV))
+ return host->phase;
+ return host->phase;
}
-/***************************************************************************/
-int tul_wait_disc(HCS * pCurHcb)
+
+static int initio_wait_disc(struct initio_host * host)
{
+ while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0)) & TSS_INT_PENDING))
+ cpu_relax();
- while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
- & TSS_INT_PENDING));
+ host->jsint = inb(host->addr + TUL_SInt);
-
- pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
-
- if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) { /* if SCSI bus reset detected */
- return (int_tul_scsi_rst(pCurHcb));
+ if (host->jsint & TSS_SCSIRST_INT) /* if SCSI bus reset detected */
+ return int_initio_scsi_rst(host);
+ if (host->jsint & TSS_DISC_INT) { /* BUS disconnection */
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
+ outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */
+ host->active = NULL;
+ return -1;
}
- if (pCurHcb->HCS_JSInt & TSS_DISC_INT) { /* BUS disconnection */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT); /* Enable HW reselect */
- pCurHcb->HCS_ActScb = NULL;
- return (-1);
- }
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
-/***************************************************************************/
-int tul_wait_done_disc(HCS * pCurHcb)
+static int initio_wait_done_disc(struct initio_host * host)
{
+ while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0))
+ & TSS_INT_PENDING))
+ cpu_relax();
+ host->jsint = inb(host->addr + TUL_SInt);
- while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
- & TSS_INT_PENDING));
+ if (host->jsint & TSS_SCSIRST_INT) /* if SCSI bus reset detected */
+ return int_initio_scsi_rst(host);
+ if (host->jsint & TSS_DISC_INT) { /* BUS disconnection */
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
+ outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */
+ initio_unlink_busy_scb(host, host->active);
- pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
-
-
- if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) { /* if SCSI bus reset detected */
- return (int_tul_scsi_rst(pCurHcb));
+ initio_append_done_scb(host, host->active);
+ host->active = NULL;
+ return -1;
}
- if (pCurHcb->HCS_JSInt & TSS_DISC_INT) { /* BUS disconnection */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT); /* Enable HW reselect */
- tul_unlink_busy_scb(pCurHcb, pCurHcb->HCS_ActScb);
-
- tul_append_done_scb(pCurHcb, pCurHcb->HCS_ActScb);
- pCurHcb->HCS_ActScb = NULL;
- return (-1);
- }
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
+/**
+ * i91u_intr - IRQ handler
+ * @irqno: IRQ number
+ * @dev_id: IRQ identifier
+ *
+ * Take the relevant locks and then invoke the actual isr processing
+ * code under the lock.
+ */
+
static irqreturn_t i91u_intr(int irqno, void *dev_id)
{
struct Scsi_Host *dev = dev_id;
unsigned long flags;
+ int r;
spin_lock_irqsave(dev->host_lock, flags);
- tul_isr((HCS *)dev->base);
+ r = initio_isr((struct initio_host *)dev->hostdata);
spin_unlock_irqrestore(dev->host_lock, flags);
- return IRQ_HANDLED;
+ if (r)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
}
-static int tul_NewReturnNumberOfAdapters(void)
-{
- struct pci_dev *pDev = NULL; /* Start from none */
- int iAdapters = 0;
- long dRegValue;
- WORD wBIOS;
- int i = 0;
- init_i91uAdapter_table();
+/**
+ * initio_build_scb - Build the mappings and SCB
+ * @host: InitIO host taking the command
+ * @cblk: Firmware command block
+ * @cmnd: SCSI midlayer command block
+ *
+ * Translate the abstract SCSI command into a firmware command block
+ * suitable for feeding to the InitIO host controller. This also requires
+ * we build the scatter gather lists and ensure they are mapped properly.
+ */
- for (i = 0; i < ARRAY_SIZE(i91u_pci_devices); i++)
- {
- while ((pDev = pci_find_device(i91u_pci_devices[i].vendor, i91u_pci_devices[i].device, pDev)) != NULL) {
- if (pci_enable_device(pDev))
- continue;
- pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
- wBIOS = (UWORD) (dRegValue & 0xFF);
- if (((dRegValue & 0xFF00) >> 8) == 0xFF)
- dRegValue = 0;
- wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
- if (pci_set_dma_mask(pDev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING
- "i91u: Could not set 32 bit DMA mask\n");
- continue;
- }
-
- if (Addi91u_into_Adapter_table(wBIOS,
- (pDev->resource[0].start),
- pDev->irq,
- pDev->bus->number,
- (pDev->devfn >> 3)
- ) == 0)
- iAdapters++;
- }
- }
-
- return (iAdapters);
-}
-
-static int i91u_detect(struct scsi_host_template * tpnt)
-{
- HCS *pHCB;
- struct Scsi_Host *hreg;
- unsigned long i; /* 01/14/98 */
- int ok = 0, iAdapters;
- ULONG dBiosAdr;
- BYTE *pbBiosAdr;
-
- /* Get total number of adapters in the motherboard */
- iAdapters = tul_NewReturnNumberOfAdapters();
- if (iAdapters == 0) /* If no tulip founded, return */
- return (0);
-
- tul_num_ch = (iAdapters > tul_num_ch) ? tul_num_ch : iAdapters;
- /* Update actually channel number */
- if (tul_tag_enable) { /* 1.01i */
- tul_num_scb = MAX_TARGETS * i91u_MAXQUEUE;
- } else {
- tul_num_scb = MAX_TARGETS + 3; /* 1-tape, 1-CD_ROM, 1- extra */
- } /* Update actually SCBs per adapter */
-
- /* Get total memory needed for HCS */
- i = tul_num_ch * sizeof(HCS);
- memset((unsigned char *) &tul_hcs[0], 0, i); /* Initialize tul_hcs 0 */
- /* Get total memory needed for SCB */
-
- for (; tul_num_scb >= MAX_TARGETS + 3; tul_num_scb--) {
- i = tul_num_ch * tul_num_scb * sizeof(SCB);
- if ((tul_scb = kmalloc(i, GFP_ATOMIC | GFP_DMA)) != NULL)
- break;
- }
- if (tul_scb == NULL) {
- printk("i91u: SCB memory allocation error\n");
- return (0);
- }
- memset((unsigned char *) tul_scb, 0, i);
-
- for (i = 0, pHCB = &tul_hcs[0]; /* Get pointer for control block */
- i < tul_num_ch;
- i++, pHCB++) {
- get_tulipPCIConfig(pHCB, i);
-
- dBiosAdr = pHCB->HCS_BIOS;
- dBiosAdr = (dBiosAdr << 4);
-
- pbBiosAdr = phys_to_virt(dBiosAdr);
-
- init_tulip(pHCB, tul_scb + (i * tul_num_scb), tul_num_scb, pbBiosAdr, 10);
- request_region(pHCB->HCS_Base, 256, "i91u"); /* Register */
-
- pHCB->HCS_Index = i; /* 7/29/98 */
- hreg = scsi_register(tpnt, sizeof(HCS));
- if(hreg == NULL) {
- release_region(pHCB->HCS_Base, 256);
- return 0;
- }
- hreg->io_port = pHCB->HCS_Base;
- hreg->n_io_port = 0xff;
- hreg->can_queue = tul_num_scb; /* 03/05/98 */
- hreg->unique_id = pHCB->HCS_Base;
- hreg->max_id = pHCB->HCS_MaxTar;
- hreg->max_lun = 32; /* 10/21/97 */
- hreg->irq = pHCB->HCS_Intr;
- hreg->this_id = pHCB->HCS_SCSI_ID; /* Assign HCS index */
- hreg->base = (unsigned long)pHCB;
- hreg->sg_tablesize = TOTAL_SG_ENTRY; /* Maximun support is 32 */
-
- /* Initial tulip chip */
- ok = request_irq(pHCB->HCS_Intr, i91u_intr, IRQF_DISABLED | IRQF_SHARED, "i91u", hreg);
- if (ok < 0) {
- printk(KERN_WARNING "i91u: unable to request IRQ %d\n\n", pHCB->HCS_Intr);
- return 0;
- }
- }
-
- tpnt->this_id = -1;
- tpnt->can_queue = 1;
-
- return 1;
-}
-
-static void i91uBuildSCB(HCS * pHCB, SCB * pSCB, struct scsi_cmnd * SCpnt)
+static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * cblk, struct scsi_cmnd * cmnd)
{ /* Create corresponding SCB */
- struct scatterlist *pSrbSG;
- SG *pSG; /* Pointer to SG list */
- int i;
- long TotalLen;
+ struct scatterlist *sglist;
+ struct sg_entry *sg; /* Pointer to SG list */
+ int i, nseg;
+ long total_len;
dma_addr_t dma_addr;
- pSCB->SCB_Post = i91uSCBPost; /* i91u's callback routine */
- pSCB->SCB_Srb = SCpnt;
- pSCB->SCB_Opcode = ExecSCSI;
- pSCB->SCB_Flags = SCF_POST; /* After SCSI done, call post routine */
- pSCB->SCB_Target = SCpnt->device->id;
- pSCB->SCB_Lun = SCpnt->device->lun;
- pSCB->SCB_Ident = SCpnt->device->lun | DISC_ALLOW;
+ /* Fill in the command headers */
+ cblk->post = i91uSCBPost; /* i91u's callback routine */
+ cblk->srb = cmnd;
+ cblk->opcode = ExecSCSI;
+ cblk->flags = SCF_POST; /* After SCSI done, call post routine */
+ cblk->target = cmnd->device->id;
+ cblk->lun = cmnd->device->lun;
+ cblk->ident = cmnd->device->lun | DISC_ALLOW;
- pSCB->SCB_Flags |= SCF_SENSE; /* Turn on auto request sense */
- dma_addr = dma_map_single(&pHCB->pci_dev->dev, SCpnt->sense_buffer,
+ cblk->flags |= SCF_SENSE; /* Turn on auto request sense */
+
+ /* Map the sense buffer into bus memory */
+ dma_addr = dma_map_single(&host->pci_dev->dev, cmnd->sense_buffer,
SENSE_SIZE, DMA_FROM_DEVICE);
- pSCB->SCB_SensePtr = cpu_to_le32((u32)dma_addr);
- pSCB->SCB_SenseLen = cpu_to_le32(SENSE_SIZE);
- SCpnt->SCp.ptr = (char *)(unsigned long)dma_addr;
+ cblk->senseptr = cpu_to_le32((u32)dma_addr);
+ cblk->senselen = cpu_to_le32(SENSE_SIZE);
+ cmnd->SCp.ptr = (char *)(unsigned long)dma_addr;
+ cblk->cdblen = cmnd->cmd_len;
- pSCB->SCB_CDBLen = SCpnt->cmd_len;
- pSCB->SCB_HaStat = 0;
- pSCB->SCB_TaStat = 0;
- memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, SCpnt->cmd_len);
+ /* Clear the returned status */
+ cblk->hastat = 0;
+ cblk->tastat = 0;
+ /* Command the command */
+ memcpy(&cblk->cdb[0], &cmnd->cmnd, cmnd->cmd_len);
- if (SCpnt->device->tagged_supported) { /* Tag Support */
- pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */
+ /* Set up tags */
+ if (cmnd->device->tagged_supported) { /* Tag Support */
+ cblk->tagmsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */
} else {
- pSCB->SCB_TagMsg = 0; /* No tag support */
+ cblk->tagmsg = 0; /* No tag support */
}
+
/* todo handle map_sg error */
- if (SCpnt->use_sg) {
- dma_addr = dma_map_single(&pHCB->pci_dev->dev, &pSCB->SCB_SGList[0],
- sizeof(struct SG_Struc) * TOTAL_SG_ENTRY,
+ nseg = scsi_dma_map(cmnd);
+ BUG_ON(nseg < 0);
+ if (nseg) {
+ dma_addr = dma_map_single(&host->pci_dev->dev, &cblk->sglist[0],
+ sizeof(struct sg_entry) * TOTAL_SG_ENTRY,
DMA_BIDIRECTIONAL);
- pSCB->SCB_BufPtr = cpu_to_le32((u32)dma_addr);
- SCpnt->SCp.dma_handle = dma_addr;
+ cblk->bufptr = cpu_to_le32((u32)dma_addr);
+ cmnd->SCp.dma_handle = dma_addr;
- pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
- pSCB->SCB_SGLen = dma_map_sg(&pHCB->pci_dev->dev, pSrbSG,
- SCpnt->use_sg, SCpnt->sc_data_direction);
- pSCB->SCB_Flags |= SCF_SG; /* Turn on SG list flag */
- for (i = 0, TotalLen = 0, pSG = &pSCB->SCB_SGList[0]; /* 1.01g */
- i < pSCB->SCB_SGLen; i++, pSG++, pSrbSG++) {
- pSG->SG_Ptr = cpu_to_le32((u32)sg_dma_address(pSrbSG));
- TotalLen += pSG->SG_Len = cpu_to_le32((u32)sg_dma_len(pSrbSG));
+ cblk->flags |= SCF_SG; /* Turn on SG list flag */
+ total_len = 0;
+ sg = &cblk->sglist[0];
+ scsi_for_each_sg(cmnd, sglist, cblk->sglen, i) {
+ sg->data = cpu_to_le32((u32)sg_dma_address(sglist));
+ total_len += sg->len = cpu_to_le32((u32)sg_dma_len(sglist));
}
- pSCB->SCB_BufLen = (SCpnt->request_bufflen > TotalLen) ?
- TotalLen : SCpnt->request_bufflen;
- } else if (SCpnt->request_bufflen) { /* Non SG */
- dma_addr = dma_map_single(&pHCB->pci_dev->dev, SCpnt->request_buffer,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- SCpnt->SCp.dma_handle = dma_addr;
- pSCB->SCB_BufPtr = cpu_to_le32((u32)dma_addr);
- pSCB->SCB_BufLen = cpu_to_le32((u32)SCpnt->request_bufflen);
- pSCB->SCB_SGLen = 0;
- } else {
- pSCB->SCB_BufLen = 0;
- pSCB->SCB_SGLen = 0;
+ cblk->buflen = (scsi_bufflen(cmnd) > total_len) ?
+ total_len : scsi_bufflen(cmnd);
+ } else { /* No data transfer required */
+ cblk->buflen = 0;
+ cblk->sglen = 0;
}
}
+/**
+ * i91u_queuecommand - Queue a new command if possible
+ * @cmd: SCSI command block from the mid layer
+ * @done: Completion handler
+ *
+ * Attempts to queue a new command with the host adapter. Will return
+ * zero if successful or indicate a host busy condition if not (which
+ * will cause the mid layer to call us again later with the command)
+ */
+
static int i91u_queuecommand(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
- HCS *pHCB = (HCS *) cmd->device->host->base;
- register SCB *pSCB;
+ struct initio_host *host = (struct initio_host *) cmd->device->host->hostdata;
+ struct scsi_ctrl_blk *cmnd;
cmd->scsi_done = done;
- pSCB = tul_alloc_scb(pHCB);
- if (!pSCB)
+ cmnd = initio_alloc_scb(host);
+ if (!cmnd)
return SCSI_MLQUEUE_HOST_BUSY;
- i91uBuildSCB(pHCB, pSCB, cmd);
- tul_exec_scb(pHCB, pSCB);
+ initio_build_scb(host, cmnd, cmd);
+ initio_exec_scb(host, cmnd);
return 0;
}
-#if 0 /* no new EH yet */
-/*
- * Abort a queued command
- * (commands that are on the bus can't be aborted easily)
+/**
+ * i91u_bus_reset - reset the SCSI bus
+ * @cmnd: Command block we want to trigger the reset for
+ *
+ * Initiate a SCSI bus reset sequence
*/
-static int i91u_abort(struct scsi_cmnd * SCpnt)
+
+static int i91u_bus_reset(struct scsi_cmnd * cmnd)
{
- HCS *pHCB;
+ struct initio_host *host;
- pHCB = (HCS *) SCpnt->device->host->base;
- return tul_abort_srb(pHCB, SCpnt);
-}
+ host = (struct initio_host *) cmnd->device->host->hostdata;
-/*
- * Reset registers, reset a hanging bus and
- * kill active and disconnected commands for target w/o soft reset
- */
-static int i91u_reset(struct scsi_cmnd * SCpnt, unsigned int reset_flags)
-{ /* I need Host Control Block Information */
- HCS *pHCB;
-
- pHCB = (HCS *) SCpnt->device->host->base;
-
- if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
- return tul_reset_scsi_bus(pHCB);
- else
- return tul_device_reset(pHCB, SCpnt, SCpnt->device->id, reset_flags);
-}
-#endif
-
-static int i91u_bus_reset(struct scsi_cmnd * SCpnt)
-{
- HCS *pHCB;
-
- pHCB = (HCS *) SCpnt->device->host->base;
-
- spin_lock_irq(SCpnt->device->host->host_lock);
- tul_reset_scsi(pHCB, 0);
- spin_unlock_irq(SCpnt->device->host->host_lock);
+ spin_lock_irq(cmnd->device->host->host_lock);
+ initio_reset_scsi(host, 0);
+ spin_unlock_irq(cmnd->device->host->host_lock);
return SUCCESS;
}
-/*
- * Return the "logical geometry"
+/**
+ * i91u_biospararm - return the "logical geometry
+ * @sdev: SCSI device
+ * @dev; Matching block device
+ * @capacity: Sector size of drive
+ * @info_array: Return space for BIOS geometry
+ *
+ * Map the device geometry in a manner compatible with the host
+ * controller BIOS behaviour.
+ *
+ * FIXME: limited to 2^32 sector devices.
*/
+
static int i91u_biosparam(struct scsi_device *sdev, struct block_device *dev,
sector_t capacity, int *info_array)
{
- HCS *pHcb; /* Point to Host adapter control block */
- TCS *pTcb;
+ struct initio_host *host; /* Point to Host adapter control block */
+ struct target_control *tc;
- pHcb = (HCS *) sdev->host->base;
- pTcb = &pHcb->HCS_Tcs[sdev->id];
+ host = (struct initio_host *) sdev->host->hostdata;
+ tc = &host->targets[sdev->id];
- if (pTcb->TCS_DrvHead) {
- info_array[0] = pTcb->TCS_DrvHead;
- info_array[1] = pTcb->TCS_DrvSector;
- info_array[2] = (unsigned long)capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
+ if (tc->heads) {
+ info_array[0] = tc->heads;
+ info_array[1] = tc->sectors;
+ info_array[2] = (unsigned long)capacity / tc->heads / tc->sectors;
} else {
- if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) {
+ if (tc->drv_flags & TCF_DRV_255_63) {
info_array[0] = 255;
info_array[1] = 63;
info_array[2] = (unsigned long)capacity / 255 / 63;
@@ -3047,7 +2722,16 @@
return 0;
}
-static void i91u_unmap_cmnd(struct pci_dev *pci_dev, struct scsi_cmnd *cmnd)
+/**
+ * i91u_unmap_scb - Unmap a command
+ * @pci_dev: PCI device the command is for
+ * @cmnd: The command itself
+ *
+ * Unmap any PCI mapping/IOMMU resources allocated when the command
+ * was mapped originally as part of initio_build_scb
+ */
+
+static void i91u_unmap_scb(struct pci_dev *pci_dev, struct scsi_cmnd *cmnd)
{
/* auto sense buffer */
if (cmnd->SCp.ptr) {
@@ -3058,65 +2742,63 @@
}
/* request buffer */
- if (cmnd->use_sg) {
+ if (scsi_sg_count(cmnd)) {
dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,
- sizeof(struct SG_Struc) * TOTAL_SG_ENTRY,
+ sizeof(struct sg_entry) * TOTAL_SG_ENTRY,
DMA_BIDIRECTIONAL);
- dma_unmap_sg(&pci_dev->dev, cmnd->request_buffer,
- cmnd->use_sg,
- cmnd->sc_data_direction);
- } else if (cmnd->request_bufflen) {
- dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,
- cmnd->request_bufflen,
- cmnd->sc_data_direction);
+ scsi_dma_unmap(cmnd);
}
}
-/*****************************************************************************
- Function name : i91uSCBPost
- Description : This is callback routine be called when tulip finish one
- SCSI command.
- Input : pHCB - Pointer to host adapter control block.
- pSCB - Pointer to SCSI control block.
- Output : None.
- Return : None.
-*****************************************************************************/
-static void i91uSCBPost(BYTE * pHcb, BYTE * pScb)
+/**
+ * i91uSCBPost - SCSI callback
+ * @host: Pointer to host adapter control block.
+ * @cmnd: Pointer to SCSI control block.
+ *
+ * This is callback routine be called when tulip finish one
+ * SCSI command.
+ */
+
+static void i91uSCBPost(u8 * host_mem, u8 * cblk_mem)
{
- struct scsi_cmnd *pSRB; /* Pointer to SCSI request block */
- HCS *pHCB;
- SCB *pSCB;
+ struct scsi_cmnd *cmnd; /* Pointer to SCSI request block */
+ struct initio_host *host;
+ struct scsi_ctrl_blk *cblk;
- pHCB = (HCS *) pHcb;
- pSCB = (SCB *) pScb;
- if ((pSRB = pSCB->SCB_Srb) == 0) {
- printk("i91uSCBPost: SRB pointer is empty\n");
-
- tul_release_scb(pHCB, pSCB); /* Release SCB for current channel */
+ host = (struct initio_host *) host_mem;
+ cblk = (struct scsi_ctrl_blk *) cblk_mem;
+ if ((cmnd = cblk->srb) == NULL) {
+ printk(KERN_ERR "i91uSCBPost: SRB pointer is empty\n");
+ WARN_ON(1);
+ initio_release_scb(host, cblk); /* Release SCB for current channel */
return;
}
- switch (pSCB->SCB_HaStat) {
+
+ /*
+ * Remap the firmware error status into a mid layer one
+ */
+ switch (cblk->hastat) {
case 0x0:
case 0xa: /* Linked command complete without error and linked normally */
case 0xb: /* Linked command complete without error interrupt generated */
- pSCB->SCB_HaStat = 0;
+ cblk->hastat = 0;
break;
case 0x11: /* Selection time out-The initiator selection or target
reselection was not complete within the SCSI Time out period */
- pSCB->SCB_HaStat = DID_TIME_OUT;
+ cblk->hastat = DID_TIME_OUT;
break;
case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
phase sequence was requested by the target. The host adapter
will generate a SCSI Reset Condition, notifying the host with
a SCRD interrupt */
- pSCB->SCB_HaStat = DID_RESET;
+ cblk->hastat = DID_RESET;
break;
case 0x1a: /* SCB Aborted. 07/21/98 */
- pSCB->SCB_HaStat = DID_ABORT;
+ cblk->hastat = DID_ABORT;
break;
case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
@@ -3126,49 +2808,196 @@
case 0x16: /* Invalid SCB Operation Code. */
default:
- printk("ini9100u: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);
- pSCB->SCB_HaStat = DID_ERROR; /* Couldn't find any better */
+ printk("ini9100u: %x %x\n", cblk->hastat, cblk->tastat);
+ cblk->hastat = DID_ERROR; /* Couldn't find any better */
break;
}
- pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);
+ cmnd->result = cblk->tastat | (cblk->hastat << 16);
+ WARN_ON(cmnd == NULL);
+ i91u_unmap_scb(host->pci_dev, cmnd);
+ cmnd->scsi_done(cmnd); /* Notify system DONE */
+ initio_release_scb(host, cblk); /* Release SCB for current channel */
+}
- if (pSRB == NULL) {
- printk("pSRB is NULL\n");
+static struct scsi_host_template initio_template = {
+ .proc_name = "INI9100U",
+ .name = "Initio INI-9X00U/UW SCSI device driver",
+ .queuecommand = i91u_queuecommand,
+ .eh_bus_reset_handler = i91u_bus_reset,
+ .bios_param = i91u_biosparam,
+ .can_queue = MAX_TARGETS * i91u_MAXQUEUE,
+ .this_id = 1,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING,
+};
+
+static int initio_probe_one(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct Scsi_Host *shost;
+ struct initio_host *host;
+ u32 reg;
+ u16 bios_seg;
+ struct scsi_ctrl_blk *scb, *tmp, *prev = NULL /* silence gcc */;
+ int num_scb, i, error;
+
+ error = pci_enable_device(pdev);
+ if (error)
+ return error;
+
+ pci_read_config_dword(pdev, 0x44, (u32 *) & reg);
+ bios_seg = (u16) (reg & 0xFF);
+ if (((reg & 0xFF00) >> 8) == 0xFF)
+ reg = 0;
+ bios_seg = (bios_seg << 8) + ((u16) ((reg & 0xFF00) >> 8));
+
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+ printk(KERN_WARNING "i91u: Could not set 32 bit DMA mask\n");
+ error = -ENODEV;
+ goto out_disable_device;
+ }
+ shost = scsi_host_alloc(&initio_template, sizeof(struct initio_host));
+ if (!shost) {
+ printk(KERN_WARNING "initio: Could not allocate host structure.\n");
+ error = -ENOMEM;
+ goto out_disable_device;
+ }
+ host = (struct initio_host *)shost->hostdata;
+ memset(host, 0, sizeof(struct initio_host));
+
+ if (!request_region(host->addr, 256, "i91u")) {
+ printk(KERN_WARNING "initio: I/O port range 0x%x is busy.\n", host->addr);
+ error = -ENODEV;
+ goto out_host_put;
}
- i91u_unmap_cmnd(pHCB->pci_dev, pSRB);
- pSRB->scsi_done(pSRB); /* Notify system DONE */
+ if (initio_tag_enable) /* 1.01i */
+ num_scb = MAX_TARGETS * i91u_MAXQUEUE;
+ else
+ num_scb = MAX_TARGETS + 3; /* 1-tape, 1-CD_ROM, 1- extra */
- tul_release_scb(pHCB, pSCB); /* Release SCB for current channel */
-}
+ for (; num_scb >= MAX_TARGETS + 3; num_scb--) {
+ i = num_scb * sizeof(struct scsi_ctrl_blk);
+ if ((scb = kzalloc(i, GFP_DMA)) != NULL)
+ break;
+ }
-/*
- * Release ressources
- */
-static int i91u_release(struct Scsi_Host *hreg)
-{
- free_irq(hreg->irq, hreg);
- release_region(hreg->io_port, 256);
+ if (!scb) {
+ printk(KERN_WARNING "initio: Cannot allocate SCB array.\n");
+ error = -ENOMEM;
+ goto out_release_region;
+ }
+
+ host->num_scbs = num_scb;
+ host->scb = scb;
+ host->next_pending = scb;
+ host->next_avail = scb;
+ for (i = 0, tmp = scb; i < num_scb; i++, tmp++) {
+ tmp->tagid = i;
+ if (i != 0)
+ prev->next = tmp;
+ prev = tmp;
+ }
+ prev->next = NULL;
+ host->scb_end = tmp;
+ host->first_avail = scb;
+ host->last_avail = prev;
+
+ initio_init(host, phys_to_virt(bios_seg << 4));
+
+ host->jsstatus0 = 0;
+
+ shost->io_port = host->addr;
+ shost->n_io_port = 0xff;
+ shost->can_queue = num_scb; /* 03/05/98 */
+ shost->unique_id = host->addr;
+ shost->max_id = host->max_tar;
+ shost->max_lun = 32; /* 10/21/97 */
+ shost->irq = pdev->irq;
+ shost->this_id = host->scsi_id; /* Assign HCS index */
+ shost->base = host->addr;
+ shost->sg_tablesize = TOTAL_SG_ENTRY;
+
+ error = request_irq(pdev->irq, i91u_intr, IRQF_DISABLED|IRQF_SHARED, "i91u", shost);
+ if (error < 0) {
+ printk(KERN_WARNING "initio: Unable to request IRQ %d\n", pdev->irq);
+ goto out_free_scbs;
+ }
+
+ pci_set_drvdata(pdev, shost);
+ host->pci_dev = pdev;
+
+ error = scsi_add_host(shost, &pdev->dev);
+ if (error)
+ goto out_free_irq;
+ scsi_scan_host(shost);
return 0;
+out_free_irq:
+ free_irq(pdev->irq, shost);
+out_free_scbs:
+ kfree(host->scb);
+out_release_region:
+ release_region(host->addr, 256);
+out_host_put:
+ scsi_host_put(shost);
+out_disable_device:
+ pci_disable_device(pdev);
+ return error;
}
-MODULE_LICENSE("Dual BSD/GPL");
-static struct scsi_host_template driver_template = {
- .proc_name = "INI9100U",
- .name = i91u_REVID,
- .detect = i91u_detect,
- .release = i91u_release,
- .queuecommand = i91u_queuecommand,
-// .abort = i91u_abort,
-// .reset = i91u_reset,
- .eh_bus_reset_handler = i91u_bus_reset,
- .bios_param = i91u_biosparam,
- .can_queue = 1,
- .this_id = 1,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = 1,
- .use_clustering = ENABLE_CLUSTERING,
+/**
+ * initio_remove_one - control shutdown
+ * @pdev: PCI device being released
+ *
+ * Release the resources assigned to this adapter after it has
+ * finished being used.
+ */
+
+static void initio_remove_one(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct initio_host *s = (struct initio_host *)host->hostdata;
+ scsi_remove_host(host);
+ free_irq(pdev->irq, host);
+ release_region(s->addr, 256);
+ scsi_host_put(host);
+ pci_disable_device(pdev);
+}
+
+MODULE_LICENSE("GPL");
+
+static struct pci_device_id initio_pci_tbl[] = {
+ {PCI_VENDOR_ID_INIT, 0x9500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_INIT, 0x9400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_INIT, 0x9401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_INIT, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_DOMEX, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
};
-#include "scsi_module.c"
+MODULE_DEVICE_TABLE(pci, initio_pci_tbl);
+static struct pci_driver initio_pci_driver = {
+ .name = "initio",
+ .id_table = initio_pci_tbl,
+ .probe = initio_probe_one,
+ .remove = __devexit_p(initio_remove_one),
+};
+
+static int __init initio_init_driver(void)
+{
+ return pci_register_driver(&initio_pci_driver);
+}
+
+static void __exit initio_exit_driver(void)
+{
+ pci_unregister_driver(&initio_pci_driver);
+}
+
+MODULE_DESCRIPTION("Initio INI-9X00U/UW SCSI device driver");
+MODULE_AUTHOR("Initio Corporation");
+MODULE_LICENSE("GPL");
+
+module_init(initio_init_driver);
+module_exit(initio_exit_driver);
diff --git a/drivers/scsi/initio.h b/drivers/scsi/initio.h
index acb67a4..cb48efa 100644
--- a/drivers/scsi/initio.h
+++ b/drivers/scsi/initio.h
@@ -4,6 +4,8 @@
* Copyright (c) 1994-1998 Initio Corporation
* All rights reserved.
*
+ * Cleanups (c) Copyright 2007 Red Hat <alan@redhat.com>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -18,27 +20,6 @@
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * --------------------------------------------------------------------------
- *
- * 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, immediately at the beginning of the file.
- * 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.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * Where this Software is combined with software released under the terms of
- * the GNU General Public License ("GPL") and the terms of the GPL would require the
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
- *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -56,17 +37,6 @@
#include <linux/types.h>
-#define ULONG unsigned long
-#define USHORT unsigned short
-#define UCHAR unsigned char
-#define BYTE unsigned char
-#define WORD unsigned short
-#define DWORD unsigned long
-#define UBYTE unsigned char
-#define UWORD unsigned short
-#define UDWORD unsigned long
-#define U32 u32
-
#define TOTAL_SG_ENTRY 32
#define MAX_SUPPORTED_ADAPTERS 8
#define MAX_OFFSET 15
@@ -368,55 +338,55 @@
/************************************************************************/
/* Scatter-Gather Element Structure */
/************************************************************************/
-typedef struct SG_Struc {
- U32 SG_Ptr; /* Data Pointer */
- U32 SG_Len; /* Data Length */
-} SG;
+struct sg_entry {
+ u32 data; /* Data Pointer */
+ u32 len; /* Data Length */
+};
/***********************************************************************
SCSI Control Block
************************************************************************/
-typedef struct Scsi_Ctrl_Blk {
- struct Scsi_Ctrl_Blk *SCB_NxtScb;
- UBYTE SCB_Status; /*4 */
- UBYTE SCB_NxtStat; /*5 */
- UBYTE SCB_Mode; /*6 */
- UBYTE SCB_Msgin; /*7 SCB_Res0 */
- UWORD SCB_SGIdx; /*8 */
- UWORD SCB_SGMax; /*A */
+struct scsi_ctrl_blk {
+ struct scsi_ctrl_blk *next;
+ u8 status; /*4 */
+ u8 next_state; /*5 */
+ u8 mode; /*6 */
+ u8 msgin; /*7 SCB_Res0 */
+ u16 sgidx; /*8 */
+ u16 sgmax; /*A */
#ifdef ALPHA
- U32 SCB_Reserved[2]; /*C */
+ u32 reserved[2]; /*C */
#else
- U32 SCB_Reserved[3]; /*C */
+ u32 reserved[3]; /*C */
#endif
- U32 SCB_XferLen; /*18 Current xfer len */
- U32 SCB_TotXLen; /*1C Total xfer len */
- U32 SCB_PAddr; /*20 SCB phy. Addr. */
+ u32 xferlen; /*18 Current xfer len */
+ u32 totxlen; /*1C Total xfer len */
+ u32 paddr; /*20 SCB phy. Addr. */
- UBYTE SCB_Opcode; /*24 SCB command code */
- UBYTE SCB_Flags; /*25 SCB Flags */
- UBYTE SCB_Target; /*26 Target Id */
- UBYTE SCB_Lun; /*27 Lun */
- U32 SCB_BufPtr; /*28 Data Buffer Pointer */
- U32 SCB_BufLen; /*2C Data Allocation Length */
- UBYTE SCB_SGLen; /*30 SG list # */
- UBYTE SCB_SenseLen; /*31 Sense Allocation Length */
- UBYTE SCB_HaStat; /*32 */
- UBYTE SCB_TaStat; /*33 */
- UBYTE SCB_CDBLen; /*34 CDB Length */
- UBYTE SCB_Ident; /*35 Identify */
- UBYTE SCB_TagMsg; /*36 Tag Message */
- UBYTE SCB_TagId; /*37 Queue Tag */
- UBYTE SCB_CDB[12]; /*38 */
- U32 SCB_SGPAddr; /*44 SG List/Sense Buf phy. Addr. */
- U32 SCB_SensePtr; /*48 Sense data pointer */
- void (*SCB_Post) (BYTE *, BYTE *); /*4C POST routine */
- struct scsi_cmnd *SCB_Srb; /*50 SRB Pointer */
- SG SCB_SGList[TOTAL_SG_ENTRY]; /*54 Start of SG list */
-} SCB;
+ u8 opcode; /*24 SCB command code */
+ u8 flags; /*25 SCB Flags */
+ u8 target; /*26 Target Id */
+ u8 lun; /*27 Lun */
+ u32 bufptr; /*28 Data Buffer Pointer */
+ u32 buflen; /*2C Data Allocation Length */
+ u8 sglen; /*30 SG list # */
+ u8 senselen; /*31 Sense Allocation Length */
+ u8 hastat; /*32 */
+ u8 tastat; /*33 */
+ u8 cdblen; /*34 CDB Length */
+ u8 ident; /*35 Identify */
+ u8 tagmsg; /*36 Tag Message */
+ u8 tagid; /*37 Queue Tag */
+ u8 cdb[12]; /*38 */
+ u32 sgpaddr; /*44 SG List/Sense Buf phy. Addr. */
+ u32 senseptr; /*48 Sense data pointer */
+ void (*post) (u8 *, u8 *); /*4C POST routine */
+ struct scsi_cmnd *srb; /*50 SRB Pointer */
+ struct sg_entry sglist[TOTAL_SG_ENTRY]; /*54 Start of SG list */
+};
-/* Bit Definition for SCB_Status */
+/* Bit Definition for status */
#define SCB_RENT 0x01
#define SCB_PEND 0x02
#define SCB_CONTIG 0x04 /* Contigent Allegiance */
@@ -425,17 +395,17 @@
#define SCB_DONE 0x20
-/* Opcodes of SCB_Opcode */
+/* Opcodes for opcode */
#define ExecSCSI 0x1
#define BusDevRst 0x2
#define AbortCmd 0x3
-/* Bit Definition for SCB_Mode */
+/* Bit Definition for mode */
#define SCM_RSENS 0x01 /* request sense mode */
-/* Bit Definition for SCB_Flags */
+/* Bit Definition for flags */
#define SCF_DONE 0x01
#define SCF_POST 0x02
#define SCF_SENSE 0x04
@@ -492,15 +462,14 @@
Target Device Control Structure
**********************************************************************/
-typedef struct Tar_Ctrl_Struc {
- UWORD TCS_Flags; /* 0 */
- UBYTE TCS_JS_Period; /* 2 */
- UBYTE TCS_SConfig0; /* 3 */
-
- UWORD TCS_DrvFlags; /* 4 */
- UBYTE TCS_DrvHead; /* 6 */
- UBYTE TCS_DrvSector; /* 7 */
-} TCS;
+struct target_control {
+ u16 flags;
+ u8 js_period;
+ u8 sconfig0;
+ u16 drv_flags;
+ u8 heads;
+ u8 sectors;
+};
/***********************************************************************
Target Device Control Structure
@@ -523,62 +492,53 @@
#define TCF_DRV_EN_TAG 0x0800
#define TCF_DRV_255_63 0x0400
-typedef struct I91u_Adpt_Struc {
- UWORD ADPT_BIOS; /* 0 */
- UWORD ADPT_BASE; /* 1 */
- UBYTE ADPT_Bus; /* 2 */
- UBYTE ADPT_Device; /* 3 */
- UBYTE ADPT_INTR; /* 4 */
-} INI_ADPT_STRUCT;
-
-
/***********************************************************************
Host Adapter Control Structure
************************************************************************/
-typedef struct Ha_Ctrl_Struc {
- UWORD HCS_Base; /* 00 */
- UWORD HCS_BIOS; /* 02 */
- UBYTE HCS_Intr; /* 04 */
- UBYTE HCS_SCSI_ID; /* 05 */
- UBYTE HCS_MaxTar; /* 06 */
- UBYTE HCS_NumScbs; /* 07 */
+struct initio_host {
+ u16 addr; /* 00 */
+ u16 bios_addr; /* 02 */
+ u8 irq; /* 04 */
+ u8 scsi_id; /* 05 */
+ u8 max_tar; /* 06 */
+ u8 num_scbs; /* 07 */
- UBYTE HCS_Flags; /* 08 */
- UBYTE HCS_Index; /* 09 */
- UBYTE HCS_HaId; /* 0A */
- UBYTE HCS_Config; /* 0B */
- UWORD HCS_IdMask; /* 0C */
- UBYTE HCS_Semaph; /* 0E */
- UBYTE HCS_Phase; /* 0F */
- UBYTE HCS_JSStatus0; /* 10 */
- UBYTE HCS_JSInt; /* 11 */
- UBYTE HCS_JSStatus1; /* 12 */
- UBYTE HCS_SConf1; /* 13 */
+ u8 flags; /* 08 */
+ u8 index; /* 09 */
+ u8 ha_id; /* 0A */
+ u8 config; /* 0B */
+ u16 idmask; /* 0C */
+ u8 semaph; /* 0E */
+ u8 phase; /* 0F */
+ u8 jsstatus0; /* 10 */
+ u8 jsint; /* 11 */
+ u8 jsstatus1; /* 12 */
+ u8 sconf1; /* 13 */
- UBYTE HCS_Msg[8]; /* 14 */
- SCB *HCS_NxtAvail; /* 1C */
- SCB *HCS_Scb; /* 20 */
- SCB *HCS_ScbEnd; /* 24 */
- SCB *HCS_NxtPend; /* 28 */
- SCB *HCS_NxtContig; /* 2C */
- SCB *HCS_ActScb; /* 30 */
- TCS *HCS_ActTcs; /* 34 */
+ u8 msg[8]; /* 14 */
+ struct scsi_ctrl_blk *next_avail; /* 1C */
+ struct scsi_ctrl_blk *scb; /* 20 */
+ struct scsi_ctrl_blk *scb_end; /* 24 */ /*UNUSED*/
+ struct scsi_ctrl_blk *next_pending; /* 28 */
+ struct scsi_ctrl_blk *next_contig; /* 2C */ /*UNUSED*/
+ struct scsi_ctrl_blk *active; /* 30 */
+ struct target_control *active_tc; /* 34 */
- SCB *HCS_FirstAvail; /* 38 */
- SCB *HCS_LastAvail; /* 3C */
- SCB *HCS_FirstPend; /* 40 */
- SCB *HCS_LastPend; /* 44 */
- SCB *HCS_FirstBusy; /* 48 */
- SCB *HCS_LastBusy; /* 4C */
- SCB *HCS_FirstDone; /* 50 */
- SCB *HCS_LastDone; /* 54 */
- UBYTE HCS_MaxTags[16]; /* 58 */
- UBYTE HCS_ActTags[16]; /* 68 */
- TCS HCS_Tcs[MAX_TARGETS]; /* 78 */
- spinlock_t HCS_AvailLock;
- spinlock_t HCS_SemaphLock;
+ struct scsi_ctrl_blk *first_avail; /* 38 */
+ struct scsi_ctrl_blk *last_avail; /* 3C */
+ struct scsi_ctrl_blk *first_pending; /* 40 */
+ struct scsi_ctrl_blk *last_pending; /* 44 */
+ struct scsi_ctrl_blk *first_busy; /* 48 */
+ struct scsi_ctrl_blk *last_busy; /* 4C */
+ struct scsi_ctrl_blk *first_done; /* 50 */
+ struct scsi_ctrl_blk *last_done; /* 54 */
+ u8 max_tags[16]; /* 58 */
+ u8 act_tags[16]; /* 68 */
+ struct target_control targets[MAX_TARGETS]; /* 78 */
+ spinlock_t avail_lock;
+ spinlock_t semaph_lock;
struct pci_dev *pci_dev;
-} HCS;
+};
/* Bit Definition for HCB_Config */
#define HCC_SCSI_RESET 0x01
@@ -599,47 +559,47 @@
*******************************************************************/
typedef struct _NVRAM_SCSI { /* SCSI channel configuration */
- UCHAR NVM_ChSCSIID; /* 0Ch -> Channel SCSI ID */
- UCHAR NVM_ChConfig1; /* 0Dh -> Channel config 1 */
- UCHAR NVM_ChConfig2; /* 0Eh -> Channel config 2 */
- UCHAR NVM_NumOfTarg; /* 0Fh -> Number of SCSI target */
+ u8 NVM_ChSCSIID; /* 0Ch -> Channel SCSI ID */
+ u8 NVM_ChConfig1; /* 0Dh -> Channel config 1 */
+ u8 NVM_ChConfig2; /* 0Eh -> Channel config 2 */
+ u8 NVM_NumOfTarg; /* 0Fh -> Number of SCSI target */
/* SCSI target configuration */
- UCHAR NVM_Targ0Config; /* 10h -> Target 0 configuration */
- UCHAR NVM_Targ1Config; /* 11h -> Target 1 configuration */
- UCHAR NVM_Targ2Config; /* 12h -> Target 2 configuration */
- UCHAR NVM_Targ3Config; /* 13h -> Target 3 configuration */
- UCHAR NVM_Targ4Config; /* 14h -> Target 4 configuration */
- UCHAR NVM_Targ5Config; /* 15h -> Target 5 configuration */
- UCHAR NVM_Targ6Config; /* 16h -> Target 6 configuration */
- UCHAR NVM_Targ7Config; /* 17h -> Target 7 configuration */
- UCHAR NVM_Targ8Config; /* 18h -> Target 8 configuration */
- UCHAR NVM_Targ9Config; /* 19h -> Target 9 configuration */
- UCHAR NVM_TargAConfig; /* 1Ah -> Target A configuration */
- UCHAR NVM_TargBConfig; /* 1Bh -> Target B configuration */
- UCHAR NVM_TargCConfig; /* 1Ch -> Target C configuration */
- UCHAR NVM_TargDConfig; /* 1Dh -> Target D configuration */
- UCHAR NVM_TargEConfig; /* 1Eh -> Target E configuration */
- UCHAR NVM_TargFConfig; /* 1Fh -> Target F configuration */
+ u8 NVM_Targ0Config; /* 10h -> Target 0 configuration */
+ u8 NVM_Targ1Config; /* 11h -> Target 1 configuration */
+ u8 NVM_Targ2Config; /* 12h -> Target 2 configuration */
+ u8 NVM_Targ3Config; /* 13h -> Target 3 configuration */
+ u8 NVM_Targ4Config; /* 14h -> Target 4 configuration */
+ u8 NVM_Targ5Config; /* 15h -> Target 5 configuration */
+ u8 NVM_Targ6Config; /* 16h -> Target 6 configuration */
+ u8 NVM_Targ7Config; /* 17h -> Target 7 configuration */
+ u8 NVM_Targ8Config; /* 18h -> Target 8 configuration */
+ u8 NVM_Targ9Config; /* 19h -> Target 9 configuration */
+ u8 NVM_TargAConfig; /* 1Ah -> Target A configuration */
+ u8 NVM_TargBConfig; /* 1Bh -> Target B configuration */
+ u8 NVM_TargCConfig; /* 1Ch -> Target C configuration */
+ u8 NVM_TargDConfig; /* 1Dh -> Target D configuration */
+ u8 NVM_TargEConfig; /* 1Eh -> Target E configuration */
+ u8 NVM_TargFConfig; /* 1Fh -> Target F configuration */
} NVRAM_SCSI;
typedef struct _NVRAM {
/*----------header ---------------*/
- USHORT NVM_Signature; /* 0,1: Signature */
- UCHAR NVM_Size; /* 2: Size of data structure */
- UCHAR NVM_Revision; /* 3: Revision of data structure */
+ u16 NVM_Signature; /* 0,1: Signature */
+ u8 NVM_Size; /* 2: Size of data structure */
+ u8 NVM_Revision; /* 3: Revision of data structure */
/* ----Host Adapter Structure ---- */
- UCHAR NVM_ModelByte0; /* 4: Model number (byte 0) */
- UCHAR NVM_ModelByte1; /* 5: Model number (byte 1) */
- UCHAR NVM_ModelInfo; /* 6: Model information */
- UCHAR NVM_NumOfCh; /* 7: Number of SCSI channel */
- UCHAR NVM_BIOSConfig1; /* 8: BIOS configuration 1 */
- UCHAR NVM_BIOSConfig2; /* 9: BIOS configuration 2 */
- UCHAR NVM_HAConfig1; /* A: Hoat adapter configuration 1 */
- UCHAR NVM_HAConfig2; /* B: Hoat adapter configuration 2 */
+ u8 NVM_ModelByte0; /* 4: Model number (byte 0) */
+ u8 NVM_ModelByte1; /* 5: Model number (byte 1) */
+ u8 NVM_ModelInfo; /* 6: Model information */
+ u8 NVM_NumOfCh; /* 7: Number of SCSI channel */
+ u8 NVM_BIOSConfig1; /* 8: BIOS configuration 1 */
+ u8 NVM_BIOSConfig2; /* 9: BIOS configuration 2 */
+ u8 NVM_HAConfig1; /* A: Hoat adapter configuration 1 */
+ u8 NVM_HAConfig2; /* B: Hoat adapter configuration 2 */
NVRAM_SCSI NVM_SCSIInfo[2];
- UCHAR NVM_reserved[10];
+ u8 NVM_reserved[10];
/* ---------- CheckSum ---------- */
- USHORT NVM_CheckSum; /* 0x3E, 0x3F: Checksum of NVRam */
+ u16 NVM_CheckSum; /* 0x3E, 0x3F: Checksum of NVRam */
} NVRAM, *PNVRAM;
/* Bios Configuration for nvram->BIOSConfig1 */
@@ -681,19 +641,6 @@
#define DISC_ALLOW 0xC0 /* Disconnect is allowed */
#define SCSICMD_RequestSense 0x03
-typedef struct _HCSinfo {
- ULONG base;
- UCHAR vec;
- UCHAR bios; /* High byte of BIOS address */
- USHORT BaseAndBios; /* high byte: pHcsInfo->bios,low byte:pHcsInfo->base */
-} HCSINFO;
-
-#define TUL_RD(x,y) (UCHAR)(inb( (int)((ULONG)(x+y)) ))
-#define TUL_RDLONG(x,y) (ULONG)(inl((int)((ULONG)(x+y)) ))
-#define TUL_WR( adr,data) outb( (UCHAR)(data), (int)(adr))
-#define TUL_WRSHORT(adr,data) outw( (UWORD)(data), (int)(adr))
-#define TUL_WRLONG( adr,data) outl( (ULONG)(data), (int)(adr))
-
#define SCSI_ABORT_SNOOZE 0
#define SCSI_ABORT_SUCCESS 1
#define SCSI_ABORT_PENDING 2
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index b3bf77f..f142eaf 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -540,32 +540,6 @@
}
/**
- * ipr_unmap_sglist - Unmap scatterlist if mapped
- * @ioa_cfg: ioa config struct
- * @ipr_cmd: ipr command struct
- *
- * Return value:
- * nothing
- **/
-static void ipr_unmap_sglist(struct ipr_ioa_cfg *ioa_cfg,
- struct ipr_cmnd *ipr_cmd)
-{
- struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
-
- if (ipr_cmd->dma_use_sg) {
- if (scsi_cmd->use_sg > 0) {
- pci_unmap_sg(ioa_cfg->pdev, scsi_cmd->request_buffer,
- scsi_cmd->use_sg,
- scsi_cmd->sc_data_direction);
- } else {
- pci_unmap_single(ioa_cfg->pdev, ipr_cmd->dma_handle,
- scsi_cmd->request_bufflen,
- scsi_cmd->sc_data_direction);
- }
- }
-}
-
-/**
* ipr_mask_and_clear_interrupts - Mask all and clear specified interrupts
* @ioa_cfg: ioa config struct
* @clr_ints: interrupts to clear
@@ -677,7 +651,7 @@
scsi_cmd->result |= (DID_ERROR << 16);
- ipr_unmap_sglist(ioa_cfg, ipr_cmd);
+ scsi_dma_unmap(ipr_cmd->scsi_cmd);
scsi_cmd->scsi_done(scsi_cmd);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
}
@@ -4298,93 +4272,55 @@
static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
struct ipr_cmnd *ipr_cmd)
{
- int i;
- struct scatterlist *sglist;
+ int i, nseg;
+ struct scatterlist *sg;
u32 length;
u32 ioadl_flags = 0;
struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
- length = scsi_cmd->request_bufflen;
-
- if (length == 0)
+ length = scsi_bufflen(scsi_cmd);
+ if (!length)
return 0;
- if (scsi_cmd->use_sg) {
- ipr_cmd->dma_use_sg = pci_map_sg(ioa_cfg->pdev,
- scsi_cmd->request_buffer,
- scsi_cmd->use_sg,
- scsi_cmd->sc_data_direction);
-
- if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
- ioadl_flags = IPR_IOADL_FLAGS_WRITE;
- ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
- ioarcb->write_data_transfer_length = cpu_to_be32(length);
- ioarcb->write_ioadl_len =
- cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
- } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) {
- ioadl_flags = IPR_IOADL_FLAGS_READ;
- ioarcb->read_data_transfer_length = cpu_to_be32(length);
- ioarcb->read_ioadl_len =
- cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
- }
-
- sglist = scsi_cmd->request_buffer;
-
- if (ipr_cmd->dma_use_sg <= ARRAY_SIZE(ioarcb->add_data.u.ioadl)) {
- ioadl = ioarcb->add_data.u.ioadl;
- ioarcb->write_ioadl_addr =
- cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
- offsetof(struct ipr_ioarcb, add_data));
- ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
- }
-
- for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
- ioadl[i].flags_and_data_len =
- cpu_to_be32(ioadl_flags | sg_dma_len(&sglist[i]));
- ioadl[i].address =
- cpu_to_be32(sg_dma_address(&sglist[i]));
- }
-
- if (likely(ipr_cmd->dma_use_sg)) {
- ioadl[i-1].flags_and_data_len |=
- cpu_to_be32(IPR_IOADL_FLAGS_LAST);
- return 0;
- } else
- dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
- } else {
- if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
- ioadl_flags = IPR_IOADL_FLAGS_WRITE;
- ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
- ioarcb->write_data_transfer_length = cpu_to_be32(length);
- ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
- } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) {
- ioadl_flags = IPR_IOADL_FLAGS_READ;
- ioarcb->read_data_transfer_length = cpu_to_be32(length);
- ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
- }
-
- ipr_cmd->dma_handle = pci_map_single(ioa_cfg->pdev,
- scsi_cmd->request_buffer, length,
- scsi_cmd->sc_data_direction);
-
- if (likely(!pci_dma_mapping_error(ipr_cmd->dma_handle))) {
- ioadl = ioarcb->add_data.u.ioadl;
- ioarcb->write_ioadl_addr =
- cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
- offsetof(struct ipr_ioarcb, add_data));
- ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
- ipr_cmd->dma_use_sg = 1;
- ioadl[0].flags_and_data_len =
- cpu_to_be32(ioadl_flags | length | IPR_IOADL_FLAGS_LAST);
- ioadl[0].address = cpu_to_be32(ipr_cmd->dma_handle);
- return 0;
- } else
- dev_err(&ioa_cfg->pdev->dev, "pci_map_single failed!\n");
+ nseg = scsi_dma_map(scsi_cmd);
+ if (nseg < 0) {
+ dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
+ return -1;
}
- return -1;
+ ipr_cmd->dma_use_sg = nseg;
+
+ if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
+ ioadl_flags = IPR_IOADL_FLAGS_WRITE;
+ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+ ioarcb->write_data_transfer_length = cpu_to_be32(length);
+ ioarcb->write_ioadl_len =
+ cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+ } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) {
+ ioadl_flags = IPR_IOADL_FLAGS_READ;
+ ioarcb->read_data_transfer_length = cpu_to_be32(length);
+ ioarcb->read_ioadl_len =
+ cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+ }
+
+ if (ipr_cmd->dma_use_sg <= ARRAY_SIZE(ioarcb->add_data.u.ioadl)) {
+ ioadl = ioarcb->add_data.u.ioadl;
+ ioarcb->write_ioadl_addr =
+ cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
+ offsetof(struct ipr_ioarcb, add_data));
+ ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
+ }
+
+ scsi_for_each_sg(scsi_cmd, sg, ipr_cmd->dma_use_sg, i) {
+ ioadl[i].flags_and_data_len =
+ cpu_to_be32(ioadl_flags | sg_dma_len(sg));
+ ioadl[i].address = cpu_to_be32(sg_dma_address(sg));
+ }
+
+ ioadl[i-1].flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
+ return 0;
}
/**
@@ -4447,7 +4383,7 @@
res->needs_sync_complete = 1;
res->in_erp = 0;
}
- ipr_unmap_sglist(ioa_cfg, ipr_cmd);
+ scsi_dma_unmap(ipr_cmd->scsi_cmd);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
scsi_cmd->scsi_done(scsi_cmd);
}
@@ -4825,7 +4761,7 @@
break;
}
- ipr_unmap_sglist(ioa_cfg, ipr_cmd);
+ scsi_dma_unmap(ipr_cmd->scsi_cmd);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
scsi_cmd->scsi_done(scsi_cmd);
}
@@ -4846,10 +4782,10 @@
struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
- scsi_cmd->resid = be32_to_cpu(ipr_cmd->ioasa.residual_data_len);
+ scsi_set_resid(scsi_cmd, be32_to_cpu(ipr_cmd->ioasa.residual_data_len));
if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) {
- ipr_unmap_sglist(ioa_cfg, ipr_cmd);
+ scsi_dma_unmap(ipr_cmd->scsi_cmd);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
scsi_cmd->scsi_done(scsi_cmd);
} else
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 40f148e..9f8ed6b 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -211,19 +211,6 @@
#warning "This driver has only been tested on the x86/ia64/x86_64 platforms"
#endif
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-#include <linux/blk.h>
-#include "sd.h"
-#define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(&io_request_lock,flags)
-#define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(&io_request_lock,flags)
-#ifndef __devexit_p
-#define __devexit_p(x) x
-#endif
-#else
-#define IPS_LOCK_SAVE(lock,flags) do{spin_lock(lock);(void)flags;}while(0)
-#define IPS_UNLOCK_RESTORE(lock,flags) do{spin_unlock(lock);(void)flags;}while(0)
-#endif
-
#define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \
PCI_DMA_BIDIRECTIONAL : \
@@ -381,24 +368,13 @@
.eh_abort_handler = ips_eh_abort,
.eh_host_reset_handler = ips_eh_reset,
.proc_name = "ips",
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
.proc_info = ips_proc_info,
.slave_configure = ips_slave_configure,
-#else
- .proc_info = ips_proc24_info,
- .select_queue_depths = ips_select_queue_depth,
-#endif
.bios_param = ips_biosparam,
.this_id = -1,
.sg_tablesize = IPS_MAX_SG,
.cmd_per_lun = 3,
.use_clustering = ENABLE_CLUSTERING,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- .use_new_eh_code = 1,
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- .highmem_io = 1,
-#endif
};
@@ -731,7 +707,7 @@
/* free IRQ */
free_irq(ha->irq, ha);
- IPS_REMOVE_HOST(sh);
+ scsi_remove_host(sh);
scsi_host_put(sh);
ips_released_controllers++;
@@ -813,7 +789,6 @@
ips_ha_t *ha;
ips_copp_wait_item_t *item;
int ret;
- unsigned long cpu_flags;
struct Scsi_Host *host;
METHOD_TRACE("ips_eh_abort", 1);
@@ -830,7 +805,7 @@
if (!ha->active)
return (FAILED);
- IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+ spin_lock(host->host_lock);
/* See if the command is on the copp queue */
item = ha->copp_waitlist.head;
@@ -851,7 +826,7 @@
ret = (FAILED);
}
- IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+ spin_unlock(host->host_lock);
return ret;
}
@@ -1129,7 +1104,7 @@
/* A Reset IOCTL is only sent by the boot CD in extreme cases. */
/* There can never be any system activity ( network or disk ), but check */
/* anyway just as a good practice. */
- pt = (ips_passthru_t *) SC->request_buffer;
+ pt = (ips_passthru_t *) scsi_sglist(SC);
if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) &&
(pt->CoppCP.cmd.reset.adapter_flag == 1)) {
if (ha->scb_activelist.count != 0) {
@@ -1176,18 +1151,10 @@
/* Set bios geometry for the controller */
/* */
/****************************************************************************/
-static int
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-ips_biosparam(Disk * disk, kdev_t dev, int geom[])
-{
- ips_ha_t *ha = (ips_ha_t *) disk->device->host->hostdata;
- unsigned long capacity = disk->capacity;
-#else
-ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int geom[])
+static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+ sector_t capacity, int geom[])
{
ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata;
-#endif
int heads;
int sectors;
int cylinders;
@@ -1225,70 +1192,6 @@
return (0);
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-
-/* ips_proc24_info is a wrapper around ips_proc_info *
- * for compatibility with the 2.4 scsi parameters */
-static int
-ips_proc24_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int func)
-{
- int i;
-
- for (i = 0; i < ips_next_controller; i++) {
- if (ips_sh[i] && ips_sh[i]->host_no == hostno) {
- return ips_proc_info(ips_sh[i], buffer, start,
- offset, length, func);
- }
- }
- return -EINVAL;
-}
-
-/****************************************************************************/
-/* */
-/* Routine Name: ips_select_queue_depth */
-/* */
-/* Routine Description: */
-/* */
-/* Select queue depths for the devices on the contoller */
-/* */
-/****************************************************************************/
-static void
-ips_select_queue_depth(struct Scsi_Host *host, struct scsi_device * scsi_devs)
-{
- struct scsi_device *device;
- ips_ha_t *ha;
- int count = 0;
- int min;
-
- ha = IPS_HA(host);
- min = ha->max_cmds / 4;
-
- for (device = scsi_devs; device; device = device->next) {
- if (device->host == host) {
- if ((device->channel == 0) && (device->type == 0))
- count++;
- }
- }
-
- for (device = scsi_devs; device; device = device->next) {
- if (device->host == host) {
- if ((device->channel == 0) && (device->type == 0)) {
- device->queue_depth =
- (ha->max_cmds - 1) / count;
- if (device->queue_depth < min)
- device->queue_depth = min;
- } else {
- device->queue_depth = 2;
- }
-
- if (device->queue_depth < 2)
- device->queue_depth = 2;
- }
- }
-}
-
-#else
/****************************************************************************/
/* */
/* Routine Name: ips_slave_configure */
@@ -1316,7 +1219,6 @@
SDptr->skip_ms_page_3f = 1;
return 0;
}
-#endif
/****************************************************************************/
/* */
@@ -1331,7 +1233,6 @@
do_ipsintr(int irq, void *dev_id)
{
ips_ha_t *ha;
- unsigned long cpu_flags;
struct Scsi_Host *host;
int irqstatus;
@@ -1347,16 +1248,16 @@
return IRQ_HANDLED;
}
- IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+ spin_lock(host->host_lock);
if (!ha->active) {
- IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+ spin_unlock(host->host_lock);
return IRQ_HANDLED;
}
irqstatus = (*ha->func.intr) (ha);
- IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+ spin_unlock(host->host_lock);
/* start the next command */
ips_next(ha, IPS_INTR_ON);
@@ -1606,30 +1507,22 @@
if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) &&
(SC->device->channel == 0) &&
(SC->device->id == IPS_ADAPTER_ID) &&
- (SC->device->lun == 0) && SC->request_buffer) {
- if ((!SC->use_sg) && SC->request_bufflen &&
- (((char *) SC->request_buffer)[0] == 'C') &&
- (((char *) SC->request_buffer)[1] == 'O') &&
- (((char *) SC->request_buffer)[2] == 'P') &&
- (((char *) SC->request_buffer)[3] == 'P'))
- return 1;
- else if (SC->use_sg) {
- struct scatterlist *sg = SC->request_buffer;
- char *buffer;
+ (SC->device->lun == 0) && scsi_sglist(SC)) {
+ struct scatterlist *sg = scsi_sglist(SC);
+ char *buffer;
- /* kmap_atomic() ensures addressability of the user buffer.*/
- /* local_irq_save() protects the KM_IRQ0 address slot. */
- local_irq_save(flags);
- buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
- buffer[2] == 'P' && buffer[3] == 'P') {
- kunmap_atomic(buffer - sg->offset, KM_IRQ0);
- local_irq_restore(flags);
- return 1;
- }
- kunmap_atomic(buffer - sg->offset, KM_IRQ0);
- local_irq_restore(flags);
- }
+ /* kmap_atomic() ensures addressability of the user buffer.*/
+ /* local_irq_save() protects the KM_IRQ0 address slot. */
+ local_irq_save(flags);
+ buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
+ buffer[2] == 'P' && buffer[3] == 'P') {
+ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
+ local_irq_restore(flags);
+ return 1;
+ }
+ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
+ local_irq_restore(flags);
}
return 0;
}
@@ -1680,18 +1573,14 @@
{
ips_passthru_t *pt;
int length = 0;
- int ret;
+ int i, ret;
+ struct scatterlist *sg = scsi_sglist(SC);
METHOD_TRACE("ips_make_passthru", 1);
- if (!SC->use_sg) {
- length = SC->request_bufflen;
- } else {
- struct scatterlist *sg = SC->request_buffer;
- int i;
- for (i = 0; i < SC->use_sg; i++)
- length += sg[i].length;
- }
+ scsi_for_each_sg(SC, sg, scsi_sg_count(SC), i)
+ length += sg[i].length;
+
if (length < sizeof (ips_passthru_t)) {
/* wrong size */
DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
@@ -2115,7 +2004,7 @@
METHOD_TRACE("ips_cleanup_passthru", 1);
- if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) {
+ if ((!scb) || (!scb->scsi_cmd) || (!scsi_sglist(scb->scsi_cmd))) {
DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru",
ips_name, ha->host_num);
@@ -2730,7 +2619,6 @@
struct scsi_cmnd *q;
ips_copp_wait_item_t *item;
int ret;
- unsigned long cpu_flags = 0;
struct Scsi_Host *host;
METHOD_TRACE("ips_next", 1);
@@ -2742,7 +2630,7 @@
* this command won't time out
*/
if (intr == IPS_INTR_ON)
- IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+ spin_lock(host->host_lock);
if ((ha->subsys->param[3] & 0x300000)
&& (ha->scb_activelist.count == 0)) {
@@ -2769,14 +2657,14 @@
item = ips_removeq_copp_head(&ha->copp_waitlist);
ha->num_ioctl++;
if (intr == IPS_INTR_ON)
- IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+ spin_unlock(host->host_lock);
scb->scsi_cmd = item->scsi_cmd;
kfree(item);
ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
if (intr == IPS_INTR_ON)
- IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+ spin_lock(host->host_lock);
switch (ret) {
case IPS_FAILURE:
if (scb->scsi_cmd) {
@@ -2846,7 +2734,7 @@
SC = ips_removeq_wait(&ha->scb_waitlist, q);
if (intr == IPS_INTR_ON)
- IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); /* Unlock HA after command is taken off queue */
+ spin_unlock(host->host_lock); /* Unlock HA after command is taken off queue */
SC->result = DID_OK;
SC->host_scribble = NULL;
@@ -2866,41 +2754,26 @@
/* copy in the CDB */
memcpy(scb->cdb, SC->cmnd, SC->cmd_len);
- /* Now handle the data buffer */
- if (SC->use_sg) {
+ scb->sg_count = scsi_dma_map(SC);
+ BUG_ON(scb->sg_count < 0);
+ if (scb->sg_count) {
struct scatterlist *sg;
int i;
- sg = SC->request_buffer;
- scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg,
- SC->sc_data_direction);
scb->flags |= IPS_SCB_MAP_SG;
- for (i = 0; i < scb->sg_count; i++) {
+
+ scsi_for_each_sg(SC, sg, scb->sg_count, i) {
if (ips_fill_scb_sg_single
- (ha, sg_dma_address(&sg[i]), scb, i,
- sg_dma_len(&sg[i])) < 0)
+ (ha, sg_dma_address(sg), scb, i,
+ sg_dma_len(sg)) < 0)
break;
}
scb->dcdb.transfer_length = scb->data_len;
} else {
- if (SC->request_bufflen) {
- scb->data_busaddr =
- pci_map_single(ha->pcidev,
- SC->request_buffer,
- SC->request_bufflen,
- SC->sc_data_direction);
- scb->flags |= IPS_SCB_MAP_SINGLE;
- ips_fill_scb_sg_single(ha, scb->data_busaddr,
- scb, 0,
- SC->request_bufflen);
- scb->dcdb.transfer_length = scb->data_len;
- } else {
- scb->data_busaddr = 0L;
- scb->sg_len = 0;
- scb->data_len = 0;
- scb->dcdb.transfer_length = 0;
- }
-
+ scb->data_busaddr = 0L;
+ scb->sg_len = 0;
+ scb->data_len = 0;
+ scb->dcdb.transfer_length = 0;
}
scb->dcdb.cmd_attribute =
@@ -2919,7 +2792,7 @@
scb->dcdb.transfer_length = 0;
}
if (intr == IPS_INTR_ON)
- IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+ spin_lock(host->host_lock);
ret = ips_send_cmd(ha, scb);
@@ -2958,7 +2831,7 @@
} /* end while */
if (intr == IPS_INTR_ON)
- IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+ spin_unlock(host->host_lock);
}
/****************************************************************************/
@@ -3377,52 +3250,32 @@
* the rest of the data and continue.
*/
if ((scb->breakup) || (scb->sg_break)) {
+ struct scatterlist *sg;
+ int sg_dma_index, ips_sg_index = 0;
+
/* we had a data breakup */
scb->data_len = 0;
- if (scb->sg_count) {
- /* S/G request */
- struct scatterlist *sg;
- int ips_sg_index = 0;
- int sg_dma_index;
+ sg = scsi_sglist(scb->scsi_cmd);
- sg = scb->scsi_cmd->request_buffer;
+ /* Spin forward to last dma chunk */
+ sg_dma_index = scb->breakup;
- /* Spin forward to last dma chunk */
- sg_dma_index = scb->breakup;
+ /* Take care of possible partial on last chunk */
+ ips_fill_scb_sg_single(ha,
+ sg_dma_address(&sg[sg_dma_index]),
+ scb, ips_sg_index++,
+ sg_dma_len(&sg[sg_dma_index]));
- /* Take care of possible partial on last chunk */
- ips_fill_scb_sg_single(ha,
- sg_dma_address(&sg
- [sg_dma_index]),
- scb, ips_sg_index++,
- sg_dma_len(&sg
- [sg_dma_index]));
-
- for (; sg_dma_index < scb->sg_count;
- sg_dma_index++) {
- if (ips_fill_scb_sg_single
- (ha,
- sg_dma_address(&sg[sg_dma_index]),
- scb, ips_sg_index++,
- sg_dma_len(&sg[sg_dma_index])) < 0)
- break;
-
- }
-
- } else {
- /* Non S/G Request */
- (void) ips_fill_scb_sg_single(ha,
- scb->
- data_busaddr +
- (scb->sg_break *
- ha->max_xfer),
- scb, 0,
- scb->scsi_cmd->
- request_bufflen -
- (scb->sg_break *
- ha->max_xfer));
- }
+ for (; sg_dma_index < scsi_sg_count(scb->scsi_cmd);
+ sg_dma_index++) {
+ if (ips_fill_scb_sg_single
+ (ha,
+ sg_dma_address(&sg[sg_dma_index]),
+ scb, ips_sg_index++,
+ sg_dma_len(&sg[sg_dma_index])) < 0)
+ break;
+ }
scb->dcdb.transfer_length = scb->data_len;
scb->dcdb.cmd_attribute |=
@@ -3653,32 +3506,27 @@
static void
ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count)
{
- if (scmd->use_sg) {
- int i;
- unsigned int min_cnt, xfer_cnt;
- char *cdata = (char *) data;
- unsigned char *buffer;
- unsigned long flags;
- struct scatterlist *sg = scmd->request_buffer;
- for (i = 0, xfer_cnt = 0;
- (i < scmd->use_sg) && (xfer_cnt < count); i++) {
- min_cnt = min(count - xfer_cnt, sg[i].length);
+ int i;
+ unsigned int min_cnt, xfer_cnt;
+ char *cdata = (char *) data;
+ unsigned char *buffer;
+ unsigned long flags;
+ struct scatterlist *sg = scsi_sglist(scmd);
- /* kmap_atomic() ensures addressability of the data buffer.*/
- /* local_irq_save() protects the KM_IRQ0 address slot. */
- local_irq_save(flags);
- buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
- memcpy(buffer, &cdata[xfer_cnt], min_cnt);
- kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
- local_irq_restore(flags);
+ for (i = 0, xfer_cnt = 0;
+ (i < scsi_sg_count(scmd)) && (xfer_cnt < count); i++) {
+ min_cnt = min(count - xfer_cnt, sg[i].length);
- xfer_cnt += min_cnt;
- }
+ /* kmap_atomic() ensures addressability of the data buffer.*/
+ /* local_irq_save() protects the KM_IRQ0 address slot. */
+ local_irq_save(flags);
+ buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
+ memcpy(buffer, &cdata[xfer_cnt], min_cnt);
+ kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
+ local_irq_restore(flags);
- } else {
- unsigned int min_cnt = min(count, scmd->request_bufflen);
- memcpy(scmd->request_buffer, data, min_cnt);
- }
+ xfer_cnt += min_cnt;
+ }
}
/****************************************************************************/
@@ -3691,32 +3539,27 @@
static void
ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count)
{
- if (scmd->use_sg) {
- int i;
- unsigned int min_cnt, xfer_cnt;
- char *cdata = (char *) data;
- unsigned char *buffer;
- unsigned long flags;
- struct scatterlist *sg = scmd->request_buffer;
- for (i = 0, xfer_cnt = 0;
- (i < scmd->use_sg) && (xfer_cnt < count); i++) {
- min_cnt = min(count - xfer_cnt, sg[i].length);
+ int i;
+ unsigned int min_cnt, xfer_cnt;
+ char *cdata = (char *) data;
+ unsigned char *buffer;
+ unsigned long flags;
+ struct scatterlist *sg = scsi_sglist(scmd);
- /* kmap_atomic() ensures addressability of the data buffer.*/
- /* local_irq_save() protects the KM_IRQ0 address slot. */
- local_irq_save(flags);
- buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
- memcpy(&cdata[xfer_cnt], buffer, min_cnt);
- kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
- local_irq_restore(flags);
+ for (i = 0, xfer_cnt = 0;
+ (i < scsi_sg_count(scmd)) && (xfer_cnt < count); i++) {
+ min_cnt = min(count - xfer_cnt, sg[i].length);
- xfer_cnt += min_cnt;
- }
+ /* kmap_atomic() ensures addressability of the data buffer.*/
+ /* local_irq_save() protects the KM_IRQ0 address slot. */
+ local_irq_save(flags);
+ buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
+ memcpy(&cdata[xfer_cnt], buffer, min_cnt);
+ kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
+ local_irq_restore(flags);
- } else {
- unsigned int min_cnt = min(count, scmd->request_bufflen);
- memcpy(data, scmd->request_buffer, min_cnt);
- }
+ xfer_cnt += min_cnt;
+ }
}
/****************************************************************************/
@@ -4350,7 +4193,7 @@
METHOD_TRACE("ips_rdcap", 1);
- if (scb->scsi_cmd->request_bufflen < 8)
+ if (scsi_bufflen(scb->scsi_cmd) < 8)
return (0);
cap.lba =
@@ -4735,8 +4578,7 @@
METHOD_TRACE("ips_freescb", 1);
if (scb->flags & IPS_SCB_MAP_SG)
- pci_unmap_sg(ha->pcidev, scb->scsi_cmd->request_buffer,
- scb->scsi_cmd->use_sg, IPS_DMA_DIR(scb));
+ scsi_dma_unmap(scb->scsi_cmd);
else if (scb->flags & IPS_SCB_MAP_SINGLE)
pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len,
IPS_DMA_DIR(scb));
@@ -7004,7 +6846,6 @@
kfree(oldha);
ips_sh[index] = sh;
ips_ha[index] = ha;
- IPS_SCSI_SET_DEVICE(sh, ha);
/* Store away needed values for later use */
sh->io_port = ha->io_addr;
@@ -7016,17 +6857,16 @@
sh->cmd_per_lun = sh->hostt->cmd_per_lun;
sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
sh->use_clustering = sh->hostt->use_clustering;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
sh->max_sectors = 128;
-#endif
sh->max_id = ha->ntargets;
sh->max_lun = ha->nlun;
sh->max_channel = ha->nbus - 1;
sh->can_queue = ha->max_cmds - 1;
- IPS_ADD_HOST(sh, NULL);
+ scsi_add_host(sh, NULL);
+ scsi_scan_host(sh);
+
return 0;
}
@@ -7069,7 +6909,7 @@
return -ENODEV;
ips_driver_template.module = THIS_MODULE;
ips_order_controllers();
- if (IPS_REGISTER_HOSTS(&ips_driver_template)) {
+ if (!ips_detect(&ips_driver_template)) {
pci_unregister_driver(&ips_pci_driver);
return -ENODEV;
}
@@ -7087,7 +6927,6 @@
static void __exit
ips_module_exit(void)
{
- IPS_UNREGISTER_HOSTS(&ips_driver_template);
pci_unregister_driver(&ips_pci_driver);
unregister_reboot_notifier(&ips_notifier);
}
@@ -7436,15 +7275,9 @@
return SUCCESS;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
MODULE_LICENSE("GPL");
-#endif
-
MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING);
-
-#ifdef MODULE_VERSION
MODULE_VERSION(IPS_VER_STRING);
-#endif
/*
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index b726dcc..24123d5 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -58,10 +58,6 @@
/*
* Some handy macros
*/
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) || defined CONFIG_HIGHIO
- #define IPS_HIGHIO
- #endif
-
#define IPS_HA(x) ((ips_ha_t *) x->hostdata)
#define IPS_COMMAND_ID(ha, scb) (int) (scb - ha->scbs)
#define IPS_IS_TROMBONE(ha) (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
@@ -84,38 +80,8 @@
#define IPS_SGLIST_SIZE(ha) (IPS_USE_ENH_SGLIST(ha) ? \
sizeof(IPS_ENH_SG_LIST) : sizeof(IPS_STD_SG_LIST))
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
- #define pci_set_dma_mask(dev,mask) ( mask > 0xffffffff ? 1:0 )
- #define scsi_set_pci_device(sh,dev) (0)
- #endif
-
- #ifndef IRQ_NONE
- typedef void irqreturn_t;
- #define IRQ_NONE
- #define IRQ_HANDLED
- #define IRQ_RETVAL(x)
- #endif
-
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- #define IPS_REGISTER_HOSTS(SHT) scsi_register_module(MODULE_SCSI_HA,SHT)
- #define IPS_UNREGISTER_HOSTS(SHT) scsi_unregister_module(MODULE_SCSI_HA,SHT)
- #define IPS_ADD_HOST(shost,device)
- #define IPS_REMOVE_HOST(shost)
- #define IPS_SCSI_SET_DEVICE(sh,ha) scsi_set_pci_device(sh, (ha)->pcidev)
- #define IPS_PRINTK(level, pcidev, format, arg...) \
- printk(level "%s %s:" format , "ips" , \
- (pcidev)->slot_name , ## arg)
- #define scsi_host_alloc(sh,size) scsi_register(sh,size)
- #define scsi_host_put(sh) scsi_unregister(sh)
- #else
- #define IPS_REGISTER_HOSTS(SHT) (!ips_detect(SHT))
- #define IPS_UNREGISTER_HOSTS(SHT)
- #define IPS_ADD_HOST(shost,device) do { scsi_add_host(shost,device); scsi_scan_host(shost); } while (0)
- #define IPS_REMOVE_HOST(shost) scsi_remove_host(shost)
- #define IPS_SCSI_SET_DEVICE(sh,ha) do { } while (0)
- #define IPS_PRINTK(level, pcidev, format, arg...) \
+ #define IPS_PRINTK(level, pcidev, format, arg...) \
dev_printk(level , &((pcidev)->dev) , format , ## arg)
- #endif
#define MDELAY(n) \
do { \
@@ -134,7 +100,7 @@
#define pci_dma_hi32(a) ((a >> 16) >> 16)
#define pci_dma_lo32(a) (a & 0xffffffff)
- #if (BITS_PER_LONG > 32) || (defined CONFIG_HIGHMEM64G && defined IPS_HIGHIO)
+ #if (BITS_PER_LONG > 32) || defined(CONFIG_HIGHMEM64G)
#define IPS_ENABLE_DMA64 (1)
#else
#define IPS_ENABLE_DMA64 (0)
@@ -451,16 +417,10 @@
/*
* Scsi_Host Template
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- static int ips_proc24_info(char *, char **, off_t, int, int, int);
- static void ips_select_queue_depth(struct Scsi_Host *, struct scsi_device *);
- static int ips_biosparam(Disk *disk, kdev_t dev, int geom[]);
-#else
static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int geom[]);
static int ips_slave_configure(struct scsi_device *SDptr);
-#endif
/*
* Raid Command Formats
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index c9a3abf..aebcd5f 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -29,14 +29,15 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/inet.h>
+#include <linux/file.h>
#include <linux/blkdev.h>
#include <linux/crypto.h>
#include <linux/delay.h>
#include <linux/kfifo.h>
#include <linux/scatterlist.h>
-#include <linux/mutex.h>
#include <net/tcp.h>
#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi.h>
#include <scsi/scsi_transport_iscsi.h>
@@ -109,7 +110,7 @@
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
- buf->sg.length = tcp_conn->hdr_size;
+ buf->sg.length += sizeof(u32);
}
static inline int
@@ -211,16 +212,14 @@
static int
iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
- int rc;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
struct iscsi_session *session = conn->session;
+ struct scsi_cmnd *sc = ctask->sc;
int datasn = be32_to_cpu(rhdr->datasn);
- rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
- if (rc)
- return rc;
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
/*
* setup Data-In byte counter (gets decremented..)
*/
@@ -229,31 +228,36 @@
if (tcp_conn->in.datalen == 0)
return 0;
- if (ctask->datasn != datasn)
+ if (tcp_ctask->exp_datasn != datasn) {
+ debug_tcp("%s: ctask->exp_datasn(%d) != rhdr->datasn(%d)\n",
+ __FUNCTION__, tcp_ctask->exp_datasn, datasn);
return ISCSI_ERR_DATASN;
+ }
- ctask->datasn++;
+ tcp_ctask->exp_datasn++;
tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
- if (tcp_ctask->data_offset + tcp_conn->in.datalen > ctask->total_length)
+ if (tcp_ctask->data_offset + tcp_conn->in.datalen > scsi_bufflen(sc)) {
+ debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n",
+ __FUNCTION__, tcp_ctask->data_offset,
+ tcp_conn->in.datalen, scsi_bufflen(sc));
return ISCSI_ERR_DATA_OFFSET;
+ }
if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
- struct scsi_cmnd *sc = ctask->sc;
-
conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
int res_count = be32_to_cpu(rhdr->residual_count);
if (res_count > 0 &&
- res_count <= sc->request_bufflen) {
- sc->resid = res_count;
+ res_count <= scsi_bufflen(sc)) {
+ scsi_set_resid(sc, res_count);
sc->result = (DID_OK << 16) | rhdr->cmd_status;
} else
sc->result = (DID_BAD_TARGET << 16) |
rhdr->cmd_status;
} else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) {
- sc->resid = be32_to_cpu(rhdr->residual_count);
+ scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count));
sc->result = (DID_OK << 16) | rhdr->cmd_status;
} else
sc->result = (DID_OK << 16) | rhdr->cmd_status;
@@ -281,6 +285,8 @@
{
struct iscsi_data *hdr;
struct scsi_cmnd *sc = ctask->sc;
+ int i, sg_count = 0;
+ struct scatterlist *sg;
hdr = &r2t->dtask.hdr;
memset(hdr, 0, sizeof(struct iscsi_data));
@@ -308,39 +314,30 @@
iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
sizeof(struct iscsi_hdr));
- if (sc->use_sg) {
- int i, sg_count = 0;
- struct scatterlist *sg = sc->request_buffer;
+ sg = scsi_sglist(sc);
+ r2t->sg = NULL;
+ for (i = 0; i < scsi_sg_count(sc); i++, sg += 1) {
+ /* FIXME: prefetch ? */
+ if (sg_count + sg->length > r2t->data_offset) {
+ int page_offset;
- r2t->sg = NULL;
- for (i = 0; i < sc->use_sg; i++, sg += 1) {
- /* FIXME: prefetch ? */
- if (sg_count + sg->length > r2t->data_offset) {
- int page_offset;
+ /* sg page found! */
- /* sg page found! */
+ /* offset within this page */
+ page_offset = r2t->data_offset - sg_count;
- /* offset within this page */
- page_offset = r2t->data_offset - sg_count;
+ /* fill in this buffer */
+ iscsi_buf_init_sg(&r2t->sendbuf, sg);
+ r2t->sendbuf.sg.offset += page_offset;
+ r2t->sendbuf.sg.length -= page_offset;
- /* fill in this buffer */
- iscsi_buf_init_sg(&r2t->sendbuf, sg);
- r2t->sendbuf.sg.offset += page_offset;
- r2t->sendbuf.sg.length -= page_offset;
-
- /* xmit logic will continue with next one */
- r2t->sg = sg + 1;
- break;
- }
- sg_count += sg->length;
+ /* xmit logic will continue with next one */
+ r2t->sg = sg + 1;
+ break;
}
- BUG_ON(r2t->sg == NULL);
- } else {
- iscsi_buf_init_iov(&r2t->sendbuf,
- (char*)sc->request_buffer + r2t->data_offset,
- r2t->data_count);
- r2t->sg = NULL;
+ sg_count += sg->length;
}
+ BUG_ON(r2t->sg == NULL);
}
/**
@@ -365,17 +362,16 @@
return ISCSI_ERR_DATALEN;
}
- if (tcp_ctask->exp_r2tsn && tcp_ctask->exp_r2tsn != r2tsn)
+ if (tcp_ctask->exp_datasn != r2tsn){
+ debug_tcp("%s: ctask->exp_datasn(%d) != rhdr->r2tsn(%d)\n",
+ __FUNCTION__, tcp_ctask->exp_datasn, r2tsn);
return ISCSI_ERR_R2TSN;
-
- rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
- if (rc)
- return rc;
-
- /* FIXME: use R2TSN to detect missing R2T */
+ }
/* fill-in new R2T associated with the task */
spin_lock(&session->lock);
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
+
if (!ctask->sc || ctask->mtask ||
session->state != ISCSI_STATE_LOGGED_IN) {
printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in "
@@ -401,11 +397,11 @@
r2t->data_length, session->max_burst);
r2t->data_offset = be32_to_cpu(rhdr->data_offset);
- if (r2t->data_offset + r2t->data_length > ctask->total_length) {
+ if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
spin_unlock(&session->lock);
printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
"offset %u and total length %d\n", r2t->data_length,
- r2t->data_offset, ctask->total_length);
+ r2t->data_offset, scsi_bufflen(ctask->sc));
return ISCSI_ERR_DATALEN;
}
@@ -414,9 +410,9 @@
iscsi_solicit_data_init(conn, ctask, r2t);
- tcp_ctask->exp_r2tsn = r2tsn + 1;
+ tcp_ctask->exp_datasn = r2tsn + 1;
__kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
- tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
+ tcp_ctask->xmstate |= XMSTATE_SOL_HDR_INIT;
list_move_tail(&ctask->running, &conn->xmitqueue);
scsi_queue_work(session->host, &conn->xmitwork);
@@ -600,7 +596,7 @@
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
int buf_left = buf_size - (tcp_conn->data_copied + offset);
- int size = min(tcp_conn->in.copy, buf_left);
+ unsigned size = min(tcp_conn->in.copy, buf_left);
int rc;
size = min(size, ctask->data_count);
@@ -609,7 +605,7 @@
size, tcp_conn->in.offset, tcp_conn->in.copied);
BUG_ON(size <= 0);
- BUG_ON(tcp_ctask->sent + size > ctask->total_length);
+ BUG_ON(tcp_ctask->sent + size > scsi_bufflen(ctask->sc));
rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
(char*)buf + (offset + tcp_conn->data_copied), size);
@@ -707,25 +703,8 @@
BUG_ON((void*)ctask != sc->SCp.ptr);
- /*
- * copying Data-In into the Scsi_Cmnd
- */
- if (!sc->use_sg) {
- i = ctask->data_count;
- rc = iscsi_ctask_copy(tcp_conn, ctask, sc->request_buffer,
- sc->request_bufflen,
- tcp_ctask->data_offset);
- if (rc == -EAGAIN)
- return rc;
- if (conn->datadgst_en)
- iscsi_recv_digest_update(tcp_conn, sc->request_buffer,
- i);
- rc = 0;
- goto done;
- }
-
offset = tcp_ctask->data_offset;
- sg = sc->request_buffer;
+ sg = scsi_sglist(sc);
if (tcp_ctask->data_offset)
for (i = 0; i < tcp_ctask->sg_count; i++)
@@ -734,7 +713,7 @@
if (offset < 0)
offset = 0;
- for (i = tcp_ctask->sg_count; i < sc->use_sg; i++) {
+ for (i = tcp_ctask->sg_count; i < scsi_sg_count(sc); i++) {
char *dest;
dest = kmap_atomic(sg[i].page, KM_SOFTIRQ0);
@@ -779,7 +758,6 @@
}
BUG_ON(ctask->data_count);
-done:
/* check for non-exceptional status */
if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) {
debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n",
@@ -895,11 +873,27 @@
}
}
- if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV) {
+ if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV &&
+ tcp_conn->in.copy) {
uint32_t recv_digest;
debug_tcp("extra data_recv offset %d copy %d\n",
tcp_conn->in.offset, tcp_conn->in.copy);
+
+ if (!tcp_conn->data_copied) {
+ if (tcp_conn->in.padding) {
+ debug_tcp("padding -> %d\n",
+ tcp_conn->in.padding);
+ memset(pad, 0, tcp_conn->in.padding);
+ sg_init_one(&sg, pad, tcp_conn->in.padding);
+ crypto_hash_update(&tcp_conn->rx_hash,
+ &sg, sg.length);
+ }
+ crypto_hash_final(&tcp_conn->rx_hash,
+ (u8 *) &tcp_conn->in.datadgst);
+ debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
+ }
+
rc = iscsi_tcp_copy(conn, sizeof(uint32_t));
if (rc) {
if (rc == -EAGAIN)
@@ -924,8 +918,7 @@
}
if (tcp_conn->in_progress == IN_PROGRESS_DATA_RECV &&
- tcp_conn->in.copy) {
-
+ tcp_conn->in.copy) {
debug_tcp("data_recv offset %d copy %d\n",
tcp_conn->in.offset, tcp_conn->in.copy);
@@ -936,24 +929,32 @@
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return 0;
}
- tcp_conn->in.copy -= tcp_conn->in.padding;
- tcp_conn->in.offset += tcp_conn->in.padding;
- if (conn->datadgst_en) {
- if (tcp_conn->in.padding) {
- debug_tcp("padding -> %d\n",
- tcp_conn->in.padding);
- memset(pad, 0, tcp_conn->in.padding);
- sg_init_one(&sg, pad, tcp_conn->in.padding);
- crypto_hash_update(&tcp_conn->rx_hash,
- &sg, sg.length);
- }
- crypto_hash_final(&tcp_conn->rx_hash,
- (u8 *) &tcp_conn->in.datadgst);
- debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
+
+ if (tcp_conn->in.padding)
+ tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
+ else if (conn->datadgst_en)
tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
- tcp_conn->data_copied = 0;
- } else
+ else
tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+ tcp_conn->data_copied = 0;
+ }
+
+ if (tcp_conn->in_progress == IN_PROGRESS_PAD_RECV &&
+ tcp_conn->in.copy) {
+ int copylen = min(tcp_conn->in.padding - tcp_conn->data_copied,
+ tcp_conn->in.copy);
+
+ tcp_conn->in.copy -= copylen;
+ tcp_conn->in.offset += copylen;
+ tcp_conn->data_copied += copylen;
+
+ if (tcp_conn->data_copied != tcp_conn->in.padding)
+ tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
+ else if (conn->datadgst_en)
+ tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
+ else
+ tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+ tcp_conn->data_copied = 0;
}
debug_tcp("f, processed %d from out of %d padding %d\n",
@@ -1215,7 +1216,6 @@
struct iscsi_r2t_info *r2t, int left)
{
struct iscsi_data *hdr;
- struct scsi_cmnd *sc = ctask->sc;
int new_offset;
hdr = &r2t->dtask.hdr;
@@ -1245,15 +1245,8 @@
if (iscsi_buf_left(&r2t->sendbuf))
return;
- if (sc->use_sg) {
- iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
- r2t->sg += 1;
- } else {
- iscsi_buf_init_iov(&r2t->sendbuf,
- (char*)sc->request_buffer + new_offset,
- r2t->data_count);
- r2t->sg = NULL;
- }
+ iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
+ r2t->sg += 1;
}
static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask,
@@ -1277,41 +1270,10 @@
static void
iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
{
- struct scsi_cmnd *sc = ctask->sc;
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
BUG_ON(__kfifo_len(tcp_ctask->r2tqueue));
-
- tcp_ctask->sent = 0;
- tcp_ctask->sg_count = 0;
-
- if (sc->sc_data_direction == DMA_TO_DEVICE) {
- tcp_ctask->xmstate = XMSTATE_W_HDR;
- tcp_ctask->exp_r2tsn = 0;
- BUG_ON(ctask->total_length == 0);
-
- if (sc->use_sg) {
- struct scatterlist *sg = sc->request_buffer;
-
- iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
- tcp_ctask->sg = sg + 1;
- tcp_ctask->bad_sg = sg + sc->use_sg;
- } else {
- iscsi_buf_init_iov(&tcp_ctask->sendbuf,
- sc->request_buffer,
- sc->request_bufflen);
- tcp_ctask->sg = NULL;
- tcp_ctask->bad_sg = NULL;
- }
- debug_scsi("cmd [itt 0x%x total %d imm_data %d "
- "unsol count %d, unsol offset %d]\n",
- ctask->itt, ctask->total_length, ctask->imm_count,
- ctask->unsol_count, ctask->unsol_offset);
- } else
- tcp_ctask->xmstate = XMSTATE_R_HDR;
-
- iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
- sizeof(struct iscsi_hdr));
+ tcp_ctask->xmstate = XMSTATE_CMD_HDR_INIT;
}
/**
@@ -1324,9 +1286,11 @@
* call it again later, or recover. '0' return code means successful
* xmit.
*
- * Management xmit state machine consists of two states:
- * IN_PROGRESS_IMM_HEAD - PDU Header xmit in progress
- * IN_PROGRESS_IMM_DATA - PDU Data xmit in progress
+ * Management xmit state machine consists of these states:
+ * XMSTATE_IMM_HDR_INIT - calculate digest of PDU Header
+ * XMSTATE_IMM_HDR - PDU Header xmit in progress
+ * XMSTATE_IMM_DATA - PDU Data xmit in progress
+ * XMSTATE_IDLE - management PDU is done
**/
static int
iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
@@ -1337,23 +1301,34 @@
debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n",
conn->id, tcp_mtask->xmstate, mtask->itt);
- if (tcp_mtask->xmstate & XMSTATE_IMM_HDR) {
- tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR;
- if (mtask->data_count)
+ if (tcp_mtask->xmstate & XMSTATE_IMM_HDR_INIT) {
+ iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
+ sizeof(struct iscsi_hdr));
+
+ if (mtask->data_count) {
tcp_mtask->xmstate |= XMSTATE_IMM_DATA;
+ iscsi_buf_init_iov(&tcp_mtask->sendbuf,
+ (char*)mtask->data,
+ mtask->data_count);
+ }
+
if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE &&
conn->stop_stage != STOP_CONN_RECOVER &&
conn->hdrdgst_en)
iscsi_hdr_digest(conn, &tcp_mtask->headbuf,
(u8*)tcp_mtask->hdrext);
+
+ tcp_mtask->sent = 0;
+ tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR_INIT;
+ tcp_mtask->xmstate |= XMSTATE_IMM_HDR;
+ }
+
+ if (tcp_mtask->xmstate & XMSTATE_IMM_HDR) {
rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf,
mtask->data_count);
- if (rc) {
- tcp_mtask->xmstate |= XMSTATE_IMM_HDR;
- if (mtask->data_count)
- tcp_mtask->xmstate &= ~XMSTATE_IMM_DATA;
+ if (rc)
return rc;
- }
+ tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR;
}
if (tcp_mtask->xmstate & XMSTATE_IMM_DATA) {
@@ -1387,55 +1362,67 @@
return 0;
}
-static inline int
-iscsi_send_read_hdr(struct iscsi_conn *conn,
- struct iscsi_tcp_cmd_task *tcp_ctask)
+static int
+iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
- int rc;
-
- tcp_ctask->xmstate &= ~XMSTATE_R_HDR;
- if (conn->hdrdgst_en)
- iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
- (u8*)tcp_ctask->hdrext);
- rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, 0);
- if (!rc) {
- BUG_ON(tcp_ctask->xmstate != XMSTATE_IDLE);
- return 0; /* wait for Data-In */
- }
- tcp_ctask->xmstate |= XMSTATE_R_HDR;
- return rc;
-}
-
-static inline int
-iscsi_send_write_hdr(struct iscsi_conn *conn,
- struct iscsi_cmd_task *ctask)
-{
+ struct scsi_cmnd *sc = ctask->sc;
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- int rc;
+ int rc = 0;
- tcp_ctask->xmstate &= ~XMSTATE_W_HDR;
- if (conn->hdrdgst_en)
- iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
- (u8*)tcp_ctask->hdrext);
- rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
- if (rc) {
- tcp_ctask->xmstate |= XMSTATE_W_HDR;
- return rc;
- }
+ if (tcp_ctask->xmstate & XMSTATE_CMD_HDR_INIT) {
+ tcp_ctask->sent = 0;
+ tcp_ctask->sg_count = 0;
+ tcp_ctask->exp_datasn = 0;
- if (ctask->imm_count) {
- tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
- iscsi_set_padding(tcp_ctask, ctask->imm_count);
+ if (sc->sc_data_direction == DMA_TO_DEVICE) {
+ struct scatterlist *sg = scsi_sglist(sc);
- if (ctask->conn->datadgst_en) {
- iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);
- tcp_ctask->immdigest = 0;
+ iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
+ tcp_ctask->sg = sg + 1;
+ tcp_ctask->bad_sg = sg + scsi_sg_count(sc);
+
+ debug_scsi("cmd [itt 0x%x total %d imm_data %d "
+ "unsol count %d, unsol offset %d]\n",
+ ctask->itt, scsi_bufflen(sc),
+ ctask->imm_count, ctask->unsol_count,
+ ctask->unsol_offset);
}
+
+ iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
+ sizeof(struct iscsi_hdr));
+
+ if (conn->hdrdgst_en)
+ iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
+ (u8*)tcp_ctask->hdrext);
+ tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_INIT;
+ tcp_ctask->xmstate |= XMSTATE_CMD_HDR_XMIT;
}
- if (ctask->unsol_count)
- tcp_ctask->xmstate |= XMSTATE_UNS_HDR | XMSTATE_UNS_INIT;
- return 0;
+ if (tcp_ctask->xmstate & XMSTATE_CMD_HDR_XMIT) {
+ rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
+ if (rc)
+ return rc;
+ tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_XMIT;
+
+ if (sc->sc_data_direction != DMA_TO_DEVICE)
+ return 0;
+
+ if (ctask->imm_count) {
+ tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
+ iscsi_set_padding(tcp_ctask, ctask->imm_count);
+
+ if (ctask->conn->datadgst_en) {
+ iscsi_data_digest_init(ctask->conn->dd_data,
+ tcp_ctask);
+ tcp_ctask->immdigest = 0;
+ }
+ }
+
+ if (ctask->unsol_count)
+ tcp_ctask->xmstate |=
+ XMSTATE_UNS_HDR | XMSTATE_UNS_INIT;
+ }
+ return rc;
}
static int
@@ -1624,9 +1611,7 @@
struct iscsi_data_task *dtask;
int left, rc;
- if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
+ if (tcp_ctask->xmstate & XMSTATE_SOL_HDR_INIT) {
if (!tcp_ctask->r2t) {
spin_lock_bh(&session->lock);
__kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
@@ -1640,12 +1625,19 @@
if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &r2t->headbuf,
(u8*)dtask->hdrext);
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR_INIT;
+ tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
+ }
+
+ if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
+ r2t = tcp_ctask->r2t;
+ dtask = &r2t->dtask;
+
rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
- if (rc) {
- tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
- tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
+ if (rc)
return rc;
- }
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
+ tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
if (conn->datadgst_en) {
iscsi_data_digest_init(conn->dd_data, tcp_ctask);
@@ -1677,8 +1669,6 @@
left = r2t->data_length - r2t->sent;
if (left) {
iscsi_solicit_data_cont(conn, ctask, r2t, left);
- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
goto send_hdr;
}
@@ -1693,8 +1683,6 @@
if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t,
sizeof(void*))) {
tcp_ctask->r2t = r2t;
- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
spin_unlock_bh(&session->lock);
goto send_hdr;
}
@@ -1703,6 +1691,46 @@
return 0;
}
+/**
+ * iscsi_tcp_ctask_xmit - xmit normal PDU task
+ * @conn: iscsi connection
+ * @ctask: iscsi command task
+ *
+ * Notes:
+ * The function can return -EAGAIN in which case caller must
+ * call it again later, or recover. '0' return code means successful
+ * xmit.
+ * The function is devided to logical helpers (above) for the different
+ * xmit stages.
+ *
+ *iscsi_send_cmd_hdr()
+ * XMSTATE_CMD_HDR_INIT - prepare Header and Data buffers Calculate
+ * Header Digest
+ * XMSTATE_CMD_HDR_XMIT - Transmit header in progress
+ *
+ *iscsi_send_padding
+ * XMSTATE_W_PAD - Prepare and send pading
+ * XMSTATE_W_RESEND_PAD - retry send pading
+ *
+ *iscsi_send_digest
+ * XMSTATE_W_RESEND_DATA_DIGEST - Finalize and send Data Digest
+ * XMSTATE_W_RESEND_DATA_DIGEST - retry sending digest
+ *
+ *iscsi_send_unsol_hdr
+ * XMSTATE_UNS_INIT - prepare un-solicit data header and digest
+ * XMSTATE_UNS_HDR - send un-solicit header
+ *
+ *iscsi_send_unsol_pdu
+ * XMSTATE_UNS_DATA - send un-solicit data in progress
+ *
+ *iscsi_send_sol_pdu
+ * XMSTATE_SOL_HDR_INIT - solicit data header and digest initialize
+ * XMSTATE_SOL_HDR - send solicit header
+ * XMSTATE_SOL_DATA - send solicit data
+ *
+ *iscsi_tcp_ctask_xmit
+ * XMSTATE_IMM_DATA - xmit managment data (??)
+ **/
static int
iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
@@ -1712,20 +1740,11 @@
debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n",
conn->id, tcp_ctask->xmstate, ctask->itt);
- /*
- * serialize with TMF AbortTask
- */
- if (ctask->mtask)
+ rc = iscsi_send_cmd_hdr(conn, ctask);
+ if (rc)
return rc;
-
- if (tcp_ctask->xmstate & XMSTATE_R_HDR)
- return iscsi_send_read_hdr(conn, tcp_ctask);
-
- if (tcp_ctask->xmstate & XMSTATE_W_HDR) {
- rc = iscsi_send_write_hdr(conn, ctask);
- if (rc)
- return rc;
- }
+ if (ctask->sc->sc_data_direction != DMA_TO_DEVICE)
+ return 0;
if (tcp_ctask->xmstate & XMSTATE_IMM_DATA) {
rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
@@ -1810,18 +1829,22 @@
static void
iscsi_tcp_release_conn(struct iscsi_conn *conn)
{
+ struct iscsi_session *session = conn->session;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ struct socket *sock = tcp_conn->sock;
- if (!tcp_conn->sock)
+ if (!sock)
return;
- sock_hold(tcp_conn->sock->sk);
+ sock_hold(sock->sk);
iscsi_conn_restore_callbacks(tcp_conn);
- sock_put(tcp_conn->sock->sk);
+ sock_put(sock->sk);
- sock_release(tcp_conn->sock);
+ spin_lock_bh(&session->lock);
tcp_conn->sock = NULL;
conn->recv_lock = NULL;
+ spin_unlock_bh(&session->lock);
+ sockfd_put(sock);
}
static void
@@ -1852,6 +1875,46 @@
tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
}
+static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock,
+ char *buf, int *port,
+ int (*getname)(struct socket *, struct sockaddr *,
+ int *addrlen))
+{
+ struct sockaddr_storage *addr;
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in *sin;
+ int rc = 0, len;
+
+ addr = kmalloc(GFP_KERNEL, sizeof(*addr));
+ if (!addr)
+ return -ENOMEM;
+
+ if (getname(sock, (struct sockaddr *) addr, &len)) {
+ rc = -ENODEV;
+ goto free_addr;
+ }
+
+ switch (addr->ss_family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)addr;
+ spin_lock_bh(&conn->session->lock);
+ sprintf(buf, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
+ *port = be16_to_cpu(sin->sin_port);
+ spin_unlock_bh(&conn->session->lock);
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)addr;
+ spin_lock_bh(&conn->session->lock);
+ sprintf(buf, NIP6_FMT, NIP6(sin6->sin6_addr));
+ *port = be16_to_cpu(sin6->sin6_port);
+ spin_unlock_bh(&conn->session->lock);
+ break;
+ }
+free_addr:
+ kfree(addr);
+ return rc;
+}
+
static int
iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
@@ -1869,10 +1932,24 @@
printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err);
return -EEXIST;
}
+ /*
+ * copy these values now because if we drop the session
+ * userspace may still want to query the values since we will
+ * be using them for the reconnect
+ */
+ err = iscsi_tcp_get_addr(conn, sock, conn->portal_address,
+ &conn->portal_port, kernel_getpeername);
+ if (err)
+ goto free_socket;
+
+ err = iscsi_tcp_get_addr(conn, sock, conn->local_address,
+ &conn->local_port, kernel_getsockname);
+ if (err)
+ goto free_socket;
err = iscsi_conn_bind(cls_session, cls_conn, is_leading);
if (err)
- return err;
+ goto free_socket;
/* bind iSCSI connection and socket */
tcp_conn->sock = sock;
@@ -1896,25 +1973,19 @@
* set receive state machine into initial state
*/
tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
-
return 0;
+
+free_socket:
+ sockfd_put(sock);
+ return err;
}
/* called with host lock */
static void
-iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask,
- char *data, uint32_t data_size)
+iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
{
struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
-
- iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
- sizeof(struct iscsi_hdr));
- tcp_mtask->xmstate = XMSTATE_IMM_HDR;
- tcp_mtask->sent = 0;
-
- if (mtask->data_count)
- iscsi_buf_init_iov(&tcp_mtask->sendbuf, (char*)mtask->data,
- mtask->data_count);
+ tcp_mtask->xmstate = XMSTATE_IMM_HDR_INIT;
}
static int
@@ -2026,41 +2097,18 @@
enum iscsi_param param, char *buf)
{
struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct inet_sock *inet;
- struct ipv6_pinfo *np;
- struct sock *sk;
int len;
switch(param) {
case ISCSI_PARAM_CONN_PORT:
- mutex_lock(&conn->xmitmutex);
- if (!tcp_conn->sock) {
- mutex_unlock(&conn->xmitmutex);
- return -EINVAL;
- }
-
- inet = inet_sk(tcp_conn->sock->sk);
- len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport));
- mutex_unlock(&conn->xmitmutex);
+ spin_lock_bh(&conn->session->lock);
+ len = sprintf(buf, "%hu\n", conn->portal_port);
+ spin_unlock_bh(&conn->session->lock);
break;
case ISCSI_PARAM_CONN_ADDRESS:
- mutex_lock(&conn->xmitmutex);
- if (!tcp_conn->sock) {
- mutex_unlock(&conn->xmitmutex);
- return -EINVAL;
- }
-
- sk = tcp_conn->sock->sk;
- if (sk->sk_family == PF_INET) {
- inet = inet_sk(sk);
- len = sprintf(buf, NIPQUAD_FMT "\n",
- NIPQUAD(inet->daddr));
- } else {
- np = inet6_sk(sk);
- len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr));
- }
- mutex_unlock(&conn->xmitmutex);
+ spin_lock_bh(&conn->session->lock);
+ len = sprintf(buf, "%s\n", conn->portal_address);
+ spin_unlock_bh(&conn->session->lock);
break;
default:
return iscsi_conn_get_param(cls_conn, param, buf);
@@ -2069,6 +2117,29 @@
return len;
}
+static int
+iscsi_tcp_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
+ char *buf)
+{
+ struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+ int len;
+
+ switch (param) {
+ case ISCSI_HOST_PARAM_IPADDRESS:
+ spin_lock_bh(&session->lock);
+ if (!session->leadconn)
+ len = -ENODEV;
+ else
+ len = sprintf(buf, "%s\n",
+ session->leadconn->local_address);
+ spin_unlock_bh(&session->lock);
+ break;
+ default:
+ return iscsi_host_get_param(shost, param, buf);
+ }
+ return len;
+}
+
static void
iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats)
{
@@ -2096,6 +2167,7 @@
static struct iscsi_cls_session *
iscsi_tcp_session_create(struct iscsi_transport *iscsit,
struct scsi_transport_template *scsit,
+ uint16_t cmds_max, uint16_t qdepth,
uint32_t initial_cmdsn, uint32_t *hostno)
{
struct iscsi_cls_session *cls_session;
@@ -2103,7 +2175,7 @@
uint32_t hn;
int cmd_i;
- cls_session = iscsi_session_setup(iscsit, scsit,
+ cls_session = iscsi_session_setup(iscsit, scsit, cmds_max, qdepth,
sizeof(struct iscsi_tcp_cmd_task),
sizeof(struct iscsi_tcp_mgmt_task),
initial_cmdsn, &hn);
@@ -2142,17 +2214,24 @@
iscsi_session_teardown(cls_session);
}
+static int iscsi_tcp_slave_configure(struct scsi_device *sdev)
+{
+ blk_queue_dma_alignment(sdev->request_queue, 0);
+ return 0;
+}
+
static struct scsi_host_template iscsi_sht = {
.name = "iSCSI Initiator over TCP/IP",
.queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth,
- .can_queue = ISCSI_XMIT_CMDS_MAX - 1,
+ .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1,
.sg_tablesize = ISCSI_SG_TABLESIZE,
.max_sectors = 0xFFFF,
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
.eh_abort_handler = iscsi_eh_abort,
.eh_host_reset_handler = iscsi_eh_host_reset,
.use_clustering = DISABLE_CLUSTERING,
+ .slave_configure = iscsi_tcp_slave_configure,
.proc_name = "iscsi_tcp",
.this_id = -1,
};
@@ -2179,8 +2258,12 @@
ISCSI_EXP_STATSN |
ISCSI_PERSISTENT_PORT |
ISCSI_PERSISTENT_ADDRESS |
- ISCSI_TARGET_NAME |
- ISCSI_TPGT,
+ ISCSI_TARGET_NAME | ISCSI_TPGT |
+ ISCSI_USERNAME | ISCSI_PASSWORD |
+ ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
+ .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
+ ISCSI_HOST_INITIATOR_NAME |
+ ISCSI_HOST_NETDEV_NAME,
.host_template = &iscsi_sht,
.conndata_size = sizeof(struct iscsi_conn),
.max_conn = 1,
@@ -2197,6 +2280,9 @@
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_conn_start,
.stop_conn = iscsi_tcp_conn_stop,
+ /* iscsi host params */
+ .get_host_param = iscsi_tcp_host_get_param,
+ .set_host_param = iscsi_host_set_param,
/* IO */
.send_pdu = iscsi_conn_send_pdu,
.get_stats = iscsi_conn_get_stats,
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 3273683..7eba44d 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -29,11 +29,12 @@
#define IN_PROGRESS_HEADER_GATHER 0x1
#define IN_PROGRESS_DATA_RECV 0x2
#define IN_PROGRESS_DDIGEST_RECV 0x3
+#define IN_PROGRESS_PAD_RECV 0x4
/* xmit state machine */
#define XMSTATE_IDLE 0x0
-#define XMSTATE_R_HDR 0x1
-#define XMSTATE_W_HDR 0x2
+#define XMSTATE_CMD_HDR_INIT 0x1
+#define XMSTATE_CMD_HDR_XMIT 0x2
#define XMSTATE_IMM_HDR 0x4
#define XMSTATE_IMM_DATA 0x8
#define XMSTATE_UNS_INIT 0x10
@@ -44,6 +45,8 @@
#define XMSTATE_W_PAD 0x200
#define XMSTATE_W_RESEND_PAD 0x400
#define XMSTATE_W_RESEND_DATA_DIGEST 0x800
+#define XMSTATE_IMM_HDR_INIT 0x1000
+#define XMSTATE_SOL_HDR_INIT 0x2000
#define ISCSI_PAD_LEN 4
#define ISCSI_SG_TABLESIZE SG_ALL
@@ -152,7 +155,7 @@
struct scatterlist *sg; /* per-cmd SG list */
struct scatterlist *bad_sg; /* assert statement */
int sg_count; /* SG's to process */
- uint32_t exp_r2tsn;
+ uint32_t exp_datasn; /* expected target's R2TSN/DataSN */
int data_offset;
struct iscsi_r2t_info *r2t; /* in progress R2T */
struct iscsi_queue r2tpool;
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index 81e497d..5d23101 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -1,6 +1,6 @@
/* jazz_esp.c: ESP front-end for MIPS JAZZ systems.
*
- * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende)
+ * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende)
*/
#include <linux/kernel.h>
@@ -143,7 +143,7 @@
goto fail;
host->max_id = 8;
- esp = host_to_esp(host);
+ esp = shost_priv(host);
esp->host = host;
esp->dev = dev;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 3f5b9b4..4d85ce1 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -22,7 +22,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/types.h>
-#include <linux/mutex.h>
#include <linux/kfifo.h>
#include <linux/delay.h>
#include <asm/unaligned.h>
@@ -46,27 +45,53 @@
}
EXPORT_SYMBOL_GPL(class_to_transport_session);
-#define INVALID_SN_DELTA 0xffff
+/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
+#define SNA32_CHECK 2147483648UL
-int
-iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
+static int iscsi_sna_lt(u32 n1, u32 n2)
+{
+ return n1 != n2 && ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) ||
+ (n1 > n2 && (n2 - n1 < SNA32_CHECK)));
+}
+
+/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
+static int iscsi_sna_lte(u32 n1, u32 n2)
+{
+ return n1 == n2 || ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) ||
+ (n1 > n2 && (n2 - n1 < SNA32_CHECK)));
+}
+
+void
+iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
{
uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn);
uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn);
- if (max_cmdsn < exp_cmdsn -1 &&
- max_cmdsn > exp_cmdsn - INVALID_SN_DELTA)
- return ISCSI_ERR_MAX_CMDSN;
- if (max_cmdsn > session->max_cmdsn ||
- max_cmdsn < session->max_cmdsn - INVALID_SN_DELTA)
- session->max_cmdsn = max_cmdsn;
- if (exp_cmdsn > session->exp_cmdsn ||
- exp_cmdsn < session->exp_cmdsn - INVALID_SN_DELTA)
+ /*
+ * standard specifies this check for when to update expected and
+ * max sequence numbers
+ */
+ if (iscsi_sna_lt(max_cmdsn, exp_cmdsn - 1))
+ return;
+
+ if (exp_cmdsn != session->exp_cmdsn &&
+ !iscsi_sna_lt(exp_cmdsn, session->exp_cmdsn))
session->exp_cmdsn = exp_cmdsn;
- return 0;
+ if (max_cmdsn != session->max_cmdsn &&
+ !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) {
+ session->max_cmdsn = max_cmdsn;
+ /*
+ * if the window closed with IO queued, then kick the
+ * xmit thread
+ */
+ if (!list_empty(&session->leadconn->xmitqueue) ||
+ __kfifo_len(session->leadconn->mgmtqueue))
+ scsi_queue_work(session->host,
+ &session->leadconn->xmitwork);
+ }
}
-EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn);
+EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
struct iscsi_data *hdr)
@@ -115,14 +140,17 @@
hdr->flags = ISCSI_ATTR_SIMPLE;
int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
hdr->itt = build_itt(ctask->itt, conn->id, session->age);
- hdr->data_length = cpu_to_be32(sc->request_bufflen);
+ hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
hdr->cmdsn = cpu_to_be32(session->cmdsn);
session->cmdsn++;
hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
- memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len);
+ if (sc->cmd_len < MAX_COMMAND_SIZE)
+ memset(&hdr->cdb[sc->cmd_len], 0,
+ MAX_COMMAND_SIZE - sc->cmd_len);
ctask->data_count = 0;
+ ctask->imm_count = 0;
if (sc->sc_data_direction == DMA_TO_DEVICE) {
hdr->flags |= ISCSI_FLAG_CMD_WRITE;
/*
@@ -139,25 +167,24 @@
*
* pad_count bytes to be sent as zero-padding
*/
- ctask->imm_count = 0;
ctask->unsol_count = 0;
ctask->unsol_offset = 0;
ctask->unsol_datasn = 0;
if (session->imm_data_en) {
- if (ctask->total_length >= session->first_burst)
+ if (scsi_bufflen(sc) >= session->first_burst)
ctask->imm_count = min(session->first_burst,
conn->max_xmit_dlength);
else
- ctask->imm_count = min(ctask->total_length,
+ ctask->imm_count = min(scsi_bufflen(sc),
conn->max_xmit_dlength);
hton24(ctask->hdr->dlength, ctask->imm_count);
} else
zero_data(ctask->hdr->dlength);
if (!session->initial_r2t_en) {
- ctask->unsol_count = min(session->first_burst,
- ctask->total_length) - ctask->imm_count;
+ ctask->unsol_count = min((session->first_burst),
+ (scsi_bufflen(sc))) - ctask->imm_count;
ctask->unsol_offset = ctask->imm_count;
}
@@ -165,7 +192,6 @@
/* No unsolicit Data-Out's */
ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
} else {
- ctask->datasn = 0;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
zero_data(hdr->dlength);
@@ -174,8 +200,13 @@
}
conn->scsicmd_pdus_cnt++;
+
+ debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
+ "cmdsn %d win %d]\n",
+ sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+ conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
+ session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
}
-EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu);
/**
* iscsi_complete_command - return command back to scsi-ml
@@ -204,26 +235,12 @@
atomic_inc(&ctask->refcount);
}
-static void iscsi_get_ctask(struct iscsi_cmd_task *ctask)
-{
- spin_lock_bh(&ctask->conn->session->lock);
- __iscsi_get_ctask(ctask);
- spin_unlock_bh(&ctask->conn->session->lock);
-}
-
static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
{
if (atomic_dec_and_test(&ctask->refcount))
iscsi_complete_command(ctask);
}
-static void iscsi_put_ctask(struct iscsi_cmd_task *ctask)
-{
- spin_lock_bh(&ctask->conn->session->lock);
- __iscsi_put_ctask(ctask);
- spin_unlock_bh(&ctask->conn->session->lock);
-}
-
/**
* iscsi_cmd_rsp - SCSI Command Response processing
* @conn: iscsi connection
@@ -235,21 +252,15 @@
* iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and
* then completes the command and task.
**/
-static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- struct iscsi_cmd_task *ctask, char *data,
- int datalen)
+static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ struct iscsi_cmd_task *ctask, char *data,
+ int datalen)
{
- int rc;
struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr;
struct iscsi_session *session = conn->session;
struct scsi_cmnd *sc = ctask->sc;
- rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
- if (rc) {
- sc->result = DID_ERROR << 16;
- goto out;
- }
-
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
sc->result = (DID_OK << 16) | rhdr->cmd_status;
@@ -286,14 +297,14 @@
if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
int res_count = be32_to_cpu(rhdr->residual_count);
- if (res_count > 0 && res_count <= sc->request_bufflen)
- sc->resid = res_count;
+ if (res_count > 0 && res_count <= scsi_bufflen(sc))
+ scsi_set_resid(sc, res_count);
else
sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
} else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW)
sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW)
- sc->resid = be32_to_cpu(rhdr->residual_count);
+ scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count));
out:
debug_scsi("done [sc %lx res %d itt 0x%x]\n",
@@ -301,7 +312,6 @@
conn->scsirsp_pdus_cnt++;
__iscsi_put_ctask(ctask);
- return rc;
}
static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
@@ -381,8 +391,8 @@
switch(opcode) {
case ISCSI_OP_SCSI_CMD_RSP:
BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
- rc = iscsi_scsi_cmd_rsp(conn, hdr, ctask, data,
- datalen);
+ iscsi_scsi_cmd_rsp(conn, hdr, ctask, data,
+ datalen);
break;
case ISCSI_OP_SCSI_DATA_IN:
BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
@@ -405,11 +415,7 @@
debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n",
opcode, conn->id, mtask->itt, datalen);
- rc = iscsi_check_assign_cmdsn(session,
- (struct iscsi_nopin*)hdr);
- if (rc)
- goto done;
-
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
switch(opcode) {
case ISCSI_OP_LOGOUT_RSP:
if (datalen) {
@@ -458,10 +464,7 @@
break;
}
} else if (itt == ~0U) {
- rc = iscsi_check_assign_cmdsn(session,
- (struct iscsi_nopin*)hdr);
- if (rc)
- goto done;
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
switch(opcode) {
case ISCSI_OP_NOOP_IN:
@@ -491,7 +494,6 @@
} else
rc = ISCSI_ERR_BAD_ITT;
-done:
return rc;
}
EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
@@ -578,17 +580,47 @@
}
EXPORT_SYMBOL_GPL(iscsi_conn_failure);
+static void iscsi_prep_mtask(struct iscsi_conn *conn,
+ struct iscsi_mgmt_task *mtask)
+{
+ struct iscsi_session *session = conn->session;
+ struct iscsi_hdr *hdr = mtask->hdr;
+ struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
+
+ if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) &&
+ hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
+ nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
+ /*
+ * pre-format CmdSN for outgoing PDU.
+ */
+ nop->cmdsn = cpu_to_be32(session->cmdsn);
+ if (hdr->itt != RESERVED_ITT) {
+ hdr->itt = build_itt(mtask->itt, conn->id, session->age);
+ if (conn->c_stage == ISCSI_CONN_STARTED &&
+ !(hdr->opcode & ISCSI_OP_IMMEDIATE))
+ session->cmdsn++;
+ }
+
+ if (session->tt->init_mgmt_task)
+ session->tt->init_mgmt_task(conn, mtask);
+
+ debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
+ hdr->opcode, hdr->itt, mtask->data_count);
+}
+
static int iscsi_xmit_mtask(struct iscsi_conn *conn)
{
struct iscsi_hdr *hdr = conn->mtask->hdr;
int rc, was_logout = 0;
+ spin_unlock_bh(&conn->session->lock);
if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) {
conn->session->state = ISCSI_STATE_IN_RECOVERY;
iscsi_block_session(session_to_cls(conn->session));
was_logout = 1;
}
rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
+ spin_lock_bh(&conn->session->lock);
if (rc)
return rc;
@@ -602,6 +634,45 @@
return 0;
}
+static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
+{
+ struct iscsi_session *session = conn->session;
+
+ /*
+ * Check for iSCSI window and take care of CmdSN wrap-around
+ */
+ if (!iscsi_sna_lte(session->cmdsn, session->max_cmdsn)) {
+ debug_scsi("iSCSI CmdSN closed. MaxCmdSN %u CmdSN %u\n",
+ session->max_cmdsn, session->cmdsn);
+ return -ENOSPC;
+ }
+ return 0;
+}
+
+static int iscsi_xmit_ctask(struct iscsi_conn *conn)
+{
+ struct iscsi_cmd_task *ctask = conn->ctask;
+ int rc = 0;
+
+ /*
+ * serialize with TMF AbortTask
+ */
+ if (ctask->state == ISCSI_TASK_ABORTING)
+ goto done;
+
+ __iscsi_get_ctask(ctask);
+ spin_unlock_bh(&conn->session->lock);
+ rc = conn->session->tt->xmit_cmd_task(conn, ctask);
+ spin_lock_bh(&conn->session->lock);
+ __iscsi_put_ctask(ctask);
+
+done:
+ if (!rc)
+ /* done with this ctask */
+ conn->ctask = NULL;
+ return rc;
+}
+
/**
* iscsi_data_xmit - xmit any command into the scheduled connection
* @conn: iscsi connection
@@ -613,106 +684,79 @@
**/
static int iscsi_data_xmit(struct iscsi_conn *conn)
{
- struct iscsi_transport *tt;
int rc = 0;
+ spin_lock_bh(&conn->session->lock);
if (unlikely(conn->suspend_tx)) {
debug_scsi("conn %d Tx suspended!\n", conn->id);
+ spin_unlock_bh(&conn->session->lock);
return -ENODATA;
}
- tt = conn->session->tt;
-
- /*
- * Transmit in the following order:
- *
- * 1) un-finished xmit (ctask or mtask)
- * 2) immediate control PDUs
- * 3) write data
- * 4) SCSI commands
- * 5) non-immediate control PDUs
- *
- * No need to lock around __kfifo_get as long as
- * there's one producer and one consumer.
- */
-
- BUG_ON(conn->ctask && conn->mtask);
if (conn->ctask) {
- iscsi_get_ctask(conn->ctask);
- rc = tt->xmit_cmd_task(conn, conn->ctask);
- iscsi_put_ctask(conn->ctask);
+ rc = iscsi_xmit_ctask(conn);
if (rc)
goto again;
- /* done with this in-progress ctask */
- conn->ctask = NULL;
}
+
if (conn->mtask) {
rc = iscsi_xmit_mtask(conn);
if (rc)
goto again;
}
- /* process immediate first */
- if (unlikely(__kfifo_len(conn->immqueue))) {
- while (__kfifo_get(conn->immqueue, (void*)&conn->mtask,
- sizeof(void*))) {
- spin_lock_bh(&conn->session->lock);
- list_add_tail(&conn->mtask->running,
- &conn->mgmt_run_list);
- spin_unlock_bh(&conn->session->lock);
- rc = iscsi_xmit_mtask(conn);
- if (rc)
- goto again;
- }
+ /*
+ * process mgmt pdus like nops before commands since we should
+ * only have one nop-out as a ping from us and targets should not
+ * overflow us with nop-ins
+ */
+check_mgmt:
+ while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask,
+ sizeof(void*))) {
+ iscsi_prep_mtask(conn, conn->mtask);
+ list_add_tail(&conn->mtask->running, &conn->mgmt_run_list);
+ rc = iscsi_xmit_mtask(conn);
+ if (rc)
+ goto again;
}
/* process command queue */
- spin_lock_bh(&conn->session->lock);
while (!list_empty(&conn->xmitqueue)) {
+ rc = iscsi_check_cmdsn_window_closed(conn);
+ if (rc) {
+ spin_unlock_bh(&conn->session->lock);
+ return rc;
+ }
/*
* iscsi tcp may readd the task to the xmitqueue to send
* write data
*/
conn->ctask = list_entry(conn->xmitqueue.next,
struct iscsi_cmd_task, running);
+ if (conn->ctask->state == ISCSI_TASK_PENDING) {
+ iscsi_prep_scsi_cmd_pdu(conn->ctask);
+ conn->session->tt->init_cmd_task(conn->ctask);
+ }
conn->ctask->state = ISCSI_TASK_RUNNING;
list_move_tail(conn->xmitqueue.next, &conn->run_list);
- __iscsi_get_ctask(conn->ctask);
- spin_unlock_bh(&conn->session->lock);
-
- rc = tt->xmit_cmd_task(conn, conn->ctask);
-
- spin_lock_bh(&conn->session->lock);
- __iscsi_put_ctask(conn->ctask);
- if (rc) {
- spin_unlock_bh(&conn->session->lock);
+ rc = iscsi_xmit_ctask(conn);
+ if (rc)
goto again;
- }
+ /*
+ * we could continuously get new ctask requests so
+ * we need to check the mgmt queue for nops that need to
+ * be sent to aviod starvation
+ */
+ if (__kfifo_len(conn->mgmtqueue))
+ goto check_mgmt;
}
spin_unlock_bh(&conn->session->lock);
- /* done with this ctask */
- conn->ctask = NULL;
-
- /* process the rest control plane PDUs, if any */
- if (unlikely(__kfifo_len(conn->mgmtqueue))) {
- while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask,
- sizeof(void*))) {
- spin_lock_bh(&conn->session->lock);
- list_add_tail(&conn->mtask->running,
- &conn->mgmt_run_list);
- spin_unlock_bh(&conn->session->lock);
- rc = iscsi_xmit_mtask(conn);
- if (rc)
- goto again;
- }
- }
-
return -ENODATA;
again:
if (unlikely(conn->suspend_tx))
- return -ENODATA;
-
+ rc = -ENODATA;
+ spin_unlock_bh(&conn->session->lock);
return rc;
}
@@ -724,11 +768,9 @@
/*
* serialize Xmit worker on a per-connection basis.
*/
- mutex_lock(&conn->xmitmutex);
do {
rc = iscsi_data_xmit(conn);
} while (rc >= 0 || rc == -EAGAIN);
- mutex_unlock(&conn->xmitmutex);
}
enum {
@@ -786,20 +828,23 @@
goto fault;
}
- /*
- * Check for iSCSI window and take care of CmdSN wrap-around
- */
- if ((int)(session->max_cmdsn - session->cmdsn) < 0) {
- reason = FAILURE_WINDOW_CLOSED;
- goto reject;
- }
-
conn = session->leadconn;
if (!conn) {
reason = FAILURE_SESSION_FREED;
goto fault;
}
+ /*
+ * We check this here and in data xmit, because if we get to the point
+ * that this check is hitting the window then we have enough IO in
+ * flight and enough IO waiting to be transmitted it is better
+ * to let the scsi/block layer queue up.
+ */
+ if (iscsi_check_cmdsn_window_closed(conn)) {
+ reason = FAILURE_WINDOW_CLOSED;
+ goto reject;
+ }
+
if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask,
sizeof(void*))) {
reason = FAILURE_OOM;
@@ -814,18 +859,8 @@
ctask->conn = conn;
ctask->sc = sc;
INIT_LIST_HEAD(&ctask->running);
- ctask->total_length = sc->request_bufflen;
- iscsi_prep_scsi_cmd_pdu(ctask);
-
- session->tt->init_cmd_task(ctask);
list_add_tail(&ctask->running, &conn->xmitqueue);
- debug_scsi(
- "ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d "
- "win %d]\n",
- sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
- conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen,
- session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
spin_unlock(&session->lock);
scsi_queue_work(host, &conn->xmitwork);
@@ -841,7 +876,7 @@
printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n",
sc->cmnd[0], reason);
sc->result = (DID_NO_CONNECT << 16);
- sc->resid = sc->request_bufflen;
+ scsi_set_resid(sc, scsi_bufflen(sc));
sc->scsi_done(sc);
return 0;
}
@@ -856,19 +891,16 @@
}
EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
-static int
-iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- char *data, uint32_t data_size)
+static struct iscsi_mgmt_task *
+__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ char *data, uint32_t data_size)
{
struct iscsi_session *session = conn->session;
- struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
struct iscsi_mgmt_task *mtask;
- spin_lock_bh(&session->lock);
- if (session->state == ISCSI_STATE_TERMINATE) {
- spin_unlock_bh(&session->lock);
- return -EPERM;
- }
+ if (session->state == ISCSI_STATE_TERMINATE)
+ return NULL;
+
if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
/*
@@ -882,27 +914,11 @@
BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
- nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
if (!__kfifo_get(session->mgmtpool.queue,
- (void*)&mtask, sizeof(void*))) {
- spin_unlock_bh(&session->lock);
- return -ENOSPC;
- }
+ (void*)&mtask, sizeof(void*)))
+ return NULL;
}
- /*
- * pre-format CmdSN for outgoing PDU.
- */
- if (hdr->itt != RESERVED_ITT) {
- hdr->itt = build_itt(mtask->itt, conn->id, session->age);
- nop->cmdsn = cpu_to_be32(session->cmdsn);
- if (conn->c_stage == ISCSI_CONN_STARTED &&
- !(hdr->opcode & ISCSI_OP_IMMEDIATE))
- session->cmdsn++;
- } else
- /* do not advance CmdSN */
- nop->cmdsn = cpu_to_be32(session->cmdsn);
-
if (data_size) {
memcpy(mtask->data, data, data_size);
mtask->data_count = data_size;
@@ -911,38 +927,23 @@
INIT_LIST_HEAD(&mtask->running);
memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
- if (session->tt->init_mgmt_task)
- session->tt->init_mgmt_task(conn, mtask, data, data_size);
- spin_unlock_bh(&session->lock);
-
- debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
- hdr->opcode, hdr->itt, data_size);
-
- /*
- * since send_pdu() could be called at least from two contexts,
- * we need to serialize __kfifo_put, so we don't have to take
- * additional lock on fast data-path
- */
- if (hdr->opcode & ISCSI_OP_IMMEDIATE)
- __kfifo_put(conn->immqueue, (void*)&mtask, sizeof(void*));
- else
- __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
-
- scsi_queue_work(session->host, &conn->xmitwork);
- return 0;
+ __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
+ return mtask;
}
int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
char *data, uint32_t data_size)
{
struct iscsi_conn *conn = cls_conn->dd_data;
- int rc;
+ struct iscsi_session *session = conn->session;
+ int err = 0;
- mutex_lock(&conn->xmitmutex);
- rc = iscsi_conn_send_generic(conn, hdr, data, data_size);
- mutex_unlock(&conn->xmitmutex);
-
- return rc;
+ spin_lock_bh(&session->lock);
+ if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
+ err = -EPERM;
+ spin_unlock_bh(&session->lock);
+ scsi_queue_work(session->host, &conn->xmitwork);
+ return err;
}
EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
@@ -1027,14 +1028,12 @@
spin_unlock(&session->lock);
}
-/* must be called with the mutex lock */
static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
struct iscsi_cmd_task *ctask)
{
struct iscsi_conn *conn = ctask->conn;
struct iscsi_session *session = conn->session;
struct iscsi_tm *hdr = &conn->tmhdr;
- int rc;
/*
* ctask timed out but session is OK requests must be serialized.
@@ -1047,32 +1046,27 @@
hdr->rtt = ctask->hdr->itt;
hdr->refcmdsn = ctask->hdr->cmdsn;
- rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr,
- NULL, 0);
- if (rc) {
+ ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
+ NULL, 0);
+ if (!ctask->mtask) {
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- debug_scsi("abort sent failure [itt 0x%x] %d\n", ctask->itt,
- rc);
- return rc;
+ debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt);
+ return -EPERM;
}
+ ctask->state = ISCSI_TASK_ABORTING;
debug_scsi("abort sent [itt 0x%x]\n", ctask->itt);
- spin_lock_bh(&session->lock);
- ctask->mtask = (struct iscsi_mgmt_task *)
- session->mgmt_cmds[get_itt(hdr->itt) -
- ISCSI_MGMT_ITT_OFFSET];
-
if (conn->tmabort_state == TMABORT_INITIAL) {
conn->tmfcmd_pdus_cnt++;
- conn->tmabort_timer.expires = 10*HZ + jiffies;
+ conn->tmabort_timer.expires = 20*HZ + jiffies;
conn->tmabort_timer.function = iscsi_tmabort_timedout;
conn->tmabort_timer.data = (unsigned long)ctask;
add_timer(&conn->tmabort_timer);
debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt);
}
spin_unlock_bh(&session->lock);
- mutex_unlock(&conn->xmitmutex);
+ scsi_queue_work(session->host, &conn->xmitwork);
/*
* block eh thread until:
@@ -1089,13 +1083,12 @@
if (signal_pending(current))
flush_signals(current);
del_timer_sync(&conn->tmabort_timer);
-
- mutex_lock(&conn->xmitmutex);
+ spin_lock_bh(&session->lock);
return 0;
}
/*
- * xmit mutex and session lock must be held
+ * session lock must be held
*/
static struct iscsi_mgmt_task *
iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt)
@@ -1127,7 +1120,7 @@
if (!ctask->mtask)
return -EINVAL;
- if (!iscsi_remove_mgmt_task(conn->immqueue, ctask->mtask->itt))
+ if (!iscsi_remove_mgmt_task(conn->mgmtqueue, ctask->mtask->itt))
list_del(&ctask->mtask->running);
__kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask,
sizeof(void*));
@@ -1136,7 +1129,7 @@
}
/*
- * session lock and xmitmutex must be held
+ * session lock must be held
*/
static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
int err)
@@ -1147,11 +1140,14 @@
if (!sc)
return;
- conn->session->tt->cleanup_cmd_task(conn, ctask);
+ if (ctask->state != ISCSI_TASK_PENDING)
+ conn->session->tt->cleanup_cmd_task(conn, ctask);
iscsi_ctask_mtask_cleanup(ctask);
sc->result = err;
- sc->resid = sc->request_bufflen;
+ scsi_set_resid(sc, scsi_bufflen(sc));
+ if (conn->ctask == ctask)
+ conn->ctask = NULL;
/* release ref from queuecommand */
__iscsi_put_ctask(ctask);
}
@@ -1179,7 +1175,6 @@
conn->eh_abort_cnt++;
debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
- mutex_lock(&conn->xmitmutex);
spin_lock_bh(&session->lock);
/*
@@ -1192,9 +1187,8 @@
/* ctask completed before time out */
if (!ctask->sc) {
- spin_unlock_bh(&session->lock);
debug_scsi("sc completed while abort in progress\n");
- goto success_rel_mutex;
+ goto success;
}
/* what should we do here ? */
@@ -1204,15 +1198,13 @@
goto failed;
}
- if (ctask->state == ISCSI_TASK_PENDING)
- goto success_cleanup;
+ if (ctask->state == ISCSI_TASK_PENDING) {
+ fail_command(conn, ctask, DID_ABORT << 16);
+ goto success;
+ }
conn->tmabort_state = TMABORT_INITIAL;
-
- spin_unlock_bh(&session->lock);
rc = iscsi_exec_abort_task(sc, ctask);
- spin_lock_bh(&session->lock);
-
if (rc || sc->SCp.phase != session->age ||
session->state != ISCSI_STATE_LOGGED_IN)
goto failed;
@@ -1220,45 +1212,44 @@
switch (conn->tmabort_state) {
case TMABORT_SUCCESS:
- goto success_cleanup;
+ spin_unlock_bh(&session->lock);
+ /*
+ * clean up task if aborted. grab the recv lock as a writer
+ */
+ write_lock_bh(conn->recv_lock);
+ spin_lock(&session->lock);
+ fail_command(conn, ctask, DID_ABORT << 16);
+ spin_unlock(&session->lock);
+ write_unlock_bh(conn->recv_lock);
+ /*
+ * make sure xmit thread is not still touching the
+ * ctask/scsi_cmnd
+ */
+ scsi_flush_work(session->host);
+ goto success_unlocked;
case TMABORT_NOT_FOUND:
if (!ctask->sc) {
/* ctask completed before tmf abort response */
- spin_unlock_bh(&session->lock);
debug_scsi("sc completed while abort in progress\n");
- goto success_rel_mutex;
+ goto success;
}
/* fall through */
default:
/* timedout or failed */
spin_unlock_bh(&session->lock);
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- spin_lock_bh(&session->lock);
- goto failed;
+ goto failed_unlocked;
}
-success_cleanup:
- debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
+success:
spin_unlock_bh(&session->lock);
-
- /*
- * clean up task if aborted. we have the xmitmutex so grab
- * the recv lock as a writer
- */
- write_lock_bh(conn->recv_lock);
- spin_lock(&session->lock);
- fail_command(conn, ctask, DID_ABORT << 16);
- spin_unlock(&session->lock);
- write_unlock_bh(conn->recv_lock);
-
-success_rel_mutex:
- mutex_unlock(&conn->xmitmutex);
+success_unlocked:
+ debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
return SUCCESS;
failed:
spin_unlock_bh(&session->lock);
- mutex_unlock(&conn->xmitmutex);
-
+failed_unlocked:
debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
return FAILED;
}
@@ -1339,6 +1330,10 @@
* iscsi_session_setup - create iscsi cls session and host and session
* @scsit: scsi transport template
* @iscsit: iscsi transport template
+ * @cmds_max: scsi host can queue
+ * @qdepth: scsi host cmds per lun
+ * @cmd_task_size: LLD ctask private data size
+ * @mgmt_task_size: LLD mtask private data size
* @initial_cmdsn: initial CmdSN
* @hostno: host no allocated
*
@@ -1348,6 +1343,7 @@
struct iscsi_cls_session *
iscsi_session_setup(struct iscsi_transport *iscsit,
struct scsi_transport_template *scsit,
+ uint16_t cmds_max, uint16_t qdepth,
int cmd_task_size, int mgmt_task_size,
uint32_t initial_cmdsn, uint32_t *hostno)
{
@@ -1356,11 +1352,32 @@
struct iscsi_cls_session *cls_session;
int cmd_i;
+ if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) {
+ if (qdepth != 0)
+ printk(KERN_ERR "iscsi: invalid queue depth of %d. "
+ "Queue depth must be between 1 and %d.\n",
+ qdepth, ISCSI_MAX_CMD_PER_LUN);
+ qdepth = ISCSI_DEF_CMD_PER_LUN;
+ }
+
+ if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) ||
+ cmds_max >= ISCSI_MGMT_ITT_OFFSET) {
+ if (cmds_max != 0)
+ printk(KERN_ERR "iscsi: invalid can_queue of %d. "
+ "can_queue must be a power of 2 and between "
+ "2 and %d - setting to %d.\n", cmds_max,
+ ISCSI_MGMT_ITT_OFFSET, ISCSI_DEF_XMIT_CMDS_MAX);
+ cmds_max = ISCSI_DEF_XMIT_CMDS_MAX;
+ }
+
shost = scsi_host_alloc(iscsit->host_template,
hostdata_privsize(sizeof(*session)));
if (!shost)
return NULL;
+ /* the iscsi layer takes one task for reserve */
+ shost->can_queue = cmds_max - 1;
+ shost->cmd_per_lun = qdepth;
shost->max_id = 1;
shost->max_channel = 0;
shost->max_lun = iscsit->max_lun;
@@ -1374,7 +1391,7 @@
session->host = shost;
session->state = ISCSI_STATE_FREE;
session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
- session->cmds_max = ISCSI_XMIT_CMDS_MAX;
+ session->cmds_max = cmds_max;
session->cmdsn = initial_cmdsn;
session->exp_cmdsn = initial_cmdsn + 1;
session->max_cmdsn = initial_cmdsn + 1;
@@ -1461,7 +1478,14 @@
iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
+ kfree(session->password);
+ kfree(session->password_in);
+ kfree(session->username);
+ kfree(session->username_in);
kfree(session->targetname);
+ kfree(session->netdev);
+ kfree(session->hwaddress);
+ kfree(session->initiatorname);
iscsi_destroy_session(cls_session);
scsi_host_put(shost);
@@ -1499,11 +1523,6 @@
INIT_LIST_HEAD(&conn->xmitqueue);
/* initialize general immediate & non-immediate PDU commands queue */
- conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
- GFP_KERNEL, NULL);
- if (conn->immqueue == ERR_PTR(-ENOMEM))
- goto immqueue_alloc_fail;
-
conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
GFP_KERNEL, NULL);
if (conn->mgmtqueue == ERR_PTR(-ENOMEM))
@@ -1527,7 +1546,6 @@
conn->login_mtask->data = conn->data = data;
init_timer(&conn->tmabort_timer);
- mutex_init(&conn->xmitmutex);
init_waitqueue_head(&conn->ehwait);
return cls_conn;
@@ -1538,8 +1556,6 @@
login_mtask_alloc_fail:
kfifo_free(conn->mgmtqueue);
mgmtqueue_alloc_fail:
- kfifo_free(conn->immqueue);
-immqueue_alloc_fail:
iscsi_destroy_conn(cls_conn);
return NULL;
}
@@ -1558,10 +1574,8 @@
struct iscsi_session *session = conn->session;
unsigned long flags;
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- mutex_lock(&conn->xmitmutex);
-
spin_lock_bh(&session->lock);
+ set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
if (session->leadconn == conn) {
/*
@@ -1572,8 +1586,6 @@
}
spin_unlock_bh(&session->lock);
- mutex_unlock(&conn->xmitmutex);
-
/*
* Block until all in-progress commands for this connection
* time out or fail.
@@ -1610,7 +1622,6 @@
}
spin_unlock_bh(&session->lock);
- kfifo_free(conn->immqueue);
kfifo_free(conn->mgmtqueue);
iscsi_destroy_conn(cls_conn);
@@ -1671,8 +1682,7 @@
struct iscsi_mgmt_task *mtask, *tmp;
/* handle pending */
- while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*)) ||
- __kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) {
+ while (__kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) {
if (mtask == conn->login_mtask)
continue;
debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt);
@@ -1742,12 +1752,12 @@
conn->c_stage = ISCSI_CONN_STOPPED;
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
spin_unlock_bh(&session->lock);
+ scsi_flush_work(session->host);
write_lock_bh(conn->recv_lock);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
write_unlock_bh(conn->recv_lock);
- mutex_lock(&conn->xmitmutex);
/*
* for connection level recovery we should not calculate
* header digest. conn->hdr_size used for optimization
@@ -1771,8 +1781,6 @@
fail_all_commands(conn);
flush_control_queues(session, conn);
spin_unlock_bh(&session->lock);
-
- mutex_unlock(&conn->xmitmutex);
}
void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
@@ -1867,6 +1875,30 @@
case ISCSI_PARAM_EXP_STATSN:
sscanf(buf, "%u", &conn->exp_statsn);
break;
+ case ISCSI_PARAM_USERNAME:
+ kfree(session->username);
+ session->username = kstrdup(buf, GFP_KERNEL);
+ if (!session->username)
+ return -ENOMEM;
+ break;
+ case ISCSI_PARAM_USERNAME_IN:
+ kfree(session->username_in);
+ session->username_in = kstrdup(buf, GFP_KERNEL);
+ if (!session->username_in)
+ return -ENOMEM;
+ break;
+ case ISCSI_PARAM_PASSWORD:
+ kfree(session->password);
+ session->password = kstrdup(buf, GFP_KERNEL);
+ if (!session->password)
+ return -ENOMEM;
+ break;
+ case ISCSI_PARAM_PASSWORD_IN:
+ kfree(session->password_in);
+ session->password_in = kstrdup(buf, GFP_KERNEL);
+ if (!session->password_in)
+ return -ENOMEM;
+ break;
case ISCSI_PARAM_TARGET_NAME:
/* this should not change between logins */
if (session->targetname)
@@ -1940,6 +1972,18 @@
case ISCSI_PARAM_TPGT:
len = sprintf(buf, "%d\n", session->tpgt);
break;
+ case ISCSI_PARAM_USERNAME:
+ len = sprintf(buf, "%s\n", session->username);
+ break;
+ case ISCSI_PARAM_USERNAME_IN:
+ len = sprintf(buf, "%s\n", session->username_in);
+ break;
+ case ISCSI_PARAM_PASSWORD:
+ len = sprintf(buf, "%s\n", session->password);
+ break;
+ case ISCSI_PARAM_PASSWORD_IN:
+ len = sprintf(buf, "%s\n", session->password_in);
+ break;
default:
return -ENOSYS;
}
@@ -1990,6 +2034,66 @@
}
EXPORT_SYMBOL_GPL(iscsi_conn_get_param);
+int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
+ char *buf)
+{
+ struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+ int len;
+
+ switch (param) {
+ case ISCSI_HOST_PARAM_NETDEV_NAME:
+ if (!session->netdev)
+ len = sprintf(buf, "%s\n", "default");
+ else
+ len = sprintf(buf, "%s\n", session->netdev);
+ break;
+ case ISCSI_HOST_PARAM_HWADDRESS:
+ if (!session->hwaddress)
+ len = sprintf(buf, "%s\n", "default");
+ else
+ len = sprintf(buf, "%s\n", session->hwaddress);
+ break;
+ case ISCSI_HOST_PARAM_INITIATOR_NAME:
+ if (!session->initiatorname)
+ len = sprintf(buf, "%s\n", "unknown");
+ else
+ len = sprintf(buf, "%s\n", session->initiatorname);
+ break;
+
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(iscsi_host_get_param);
+
+int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param,
+ char *buf, int buflen)
+{
+ struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+
+ switch (param) {
+ case ISCSI_HOST_PARAM_NETDEV_NAME:
+ if (!session->netdev)
+ session->netdev = kstrdup(buf, GFP_KERNEL);
+ break;
+ case ISCSI_HOST_PARAM_HWADDRESS:
+ if (!session->hwaddress)
+ session->hwaddress = kstrdup(buf, GFP_KERNEL);
+ break;
+ case ISCSI_HOST_PARAM_INITIATOR_NAME:
+ if (!session->initiatorname)
+ session->initiatorname = kstrdup(buf, GFP_KERNEL);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iscsi_host_set_param);
+
MODULE_AUTHOR("Mike Christie");
MODULE_DESCRIPTION("iSCSI library functions");
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index b4b5269..d70ddfd 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -76,8 +76,8 @@
hs = DID_NO_CONNECT;
break;
case SAS_DATA_UNDERRUN:
- sc->resid = ts->residual;
- if (sc->request_bufflen - sc->resid < sc->underflow)
+ scsi_set_resid(sc, ts->residual);
+ if (scsi_bufflen(sc) - scsi_get_resid(sc) < sc->underflow)
hs = DID_ERROR;
break;
case SAS_DATA_OVERRUN:
@@ -161,9 +161,9 @@
task->ssp_task.task_attr = sas_scsi_get_task_attr(cmd);
memcpy(task->ssp_task.cdb, cmd->cmnd, 16);
- task->scatter = cmd->request_buffer;
- task->num_scatter = cmd->use_sg;
- task->total_xfer_len = cmd->request_bufflen;
+ task->scatter = scsi_sglist(cmd);
+ task->num_scatter = scsi_sg_count(cmd);
+ task->total_xfer_len = scsi_bufflen(cmd);
task->data_dir = cmd->sc_data_direction;
task->task_done = sas_scsi_task_done;
diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile
index d1be465..1c28670 100644
--- a/drivers/scsi/lpfc/Makefile
+++ b/drivers/scsi/lpfc/Makefile
@@ -1,7 +1,7 @@
#/*******************************************************************
# * This file is part of the Emulex Linux Device Driver for *
# * Fibre Channel Host Bus Adapters. *
-# * Copyright (C) 2004-2005 Emulex. All rights reserved. *
+# * Copyright (C) 2004-2006 Emulex. All rights reserved. *
# * EMULEX and SLI are trademarks of Emulex. *
# * www.emulex.com *
# * *
@@ -27,4 +27,5 @@
obj-$(CONFIG_SCSI_LPFC) := lpfc.o
lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o \
- lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o
+ lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \
+ lpfc_vport.o lpfc_debugfs.o
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 82e8f90..f8f64d6 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -19,8 +19,9 @@
* included with this package. *
*******************************************************************/
-struct lpfc_sli2_slim;
+#include <scsi/scsi_host.h>
+struct lpfc_sli2_slim;
#define LPFC_MAX_TARGET 256 /* max number of targets supported */
#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els
@@ -32,6 +33,20 @@
#define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */
#define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */
+/*
+ * Following time intervals are used of adjusting SCSI device
+ * queue depths when there are driver resource error or Firmware
+ * resource error.
+ */
+#define QUEUE_RAMP_DOWN_INTERVAL (1 * HZ) /* 1 Second */
+#define QUEUE_RAMP_UP_INTERVAL (300 * HZ) /* 5 minutes */
+
+/* Number of exchanges reserved for discovery to complete */
+#define LPFC_DISC_IOCB_BUFF_COUNT 20
+
+#define LPFC_HB_MBOX_INTERVAL 5 /* Heart beat interval in seconds. */
+#define LPFC_HB_MBOX_TIMEOUT 30 /* Heart beat timeout in seconds. */
+
/* Define macros for 64 bit support */
#define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr)))
#define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32)))
@@ -61,6 +76,11 @@
uint32_t current_count;
};
+struct hbq_dmabuf {
+ struct lpfc_dmabuf dbuf;
+ uint32_t tag;
+};
+
/* Priority bit. Set value to exceed low water mark in lpfc_mem. */
#define MEM_PRI 0x100
@@ -90,6 +110,29 @@
uint32_t sli2FwRev;
uint8_t sli2FwName[16];
} rev;
+ struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd2 :24; /* Reserved */
+ uint32_t cmv : 1; /* Configure Max VPIs */
+ uint32_t ccrp : 1; /* Config Command Ring Polling */
+ uint32_t csah : 1; /* Configure Synchronous Abort Handling */
+ uint32_t chbs : 1; /* Cofigure Host Backing store */
+ uint32_t cinb : 1; /* Enable Interrupt Notification Block */
+ uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */
+ uint32_t cmx : 1; /* Configure Max XRIs */
+ uint32_t cmr : 1; /* Configure Max RPIs */
+#else /* __LITTLE_ENDIAN */
+ uint32_t cmr : 1; /* Configure Max RPIs */
+ uint32_t cmx : 1; /* Configure Max XRIs */
+ uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */
+ uint32_t cinb : 1; /* Enable Interrupt Notification Block */
+ uint32_t chbs : 1; /* Cofigure Host Backing store */
+ uint32_t csah : 1; /* Configure Synchronous Abort Handling */
+ uint32_t ccrp : 1; /* Config Command Ring Polling */
+ uint32_t cmv : 1; /* Configure Max VPIs */
+ uint32_t rsvd2 :24; /* Reserved */
+#endif
+ } sli3Feat;
} lpfc_vpd_t;
struct lpfc_scsi_buf;
@@ -122,6 +165,7 @@
uint32_t elsRcvRPS;
uint32_t elsRcvRPL;
uint32_t elsXmitFLOGI;
+ uint32_t elsXmitFDISC;
uint32_t elsXmitPLOGI;
uint32_t elsXmitPRLI;
uint32_t elsXmitADISC;
@@ -165,96 +209,71 @@
struct lpfcMboxq * mbox;
};
-struct lpfc_hba {
- struct lpfc_sli sli;
- struct lpfc_sli2_slim *slim2p;
- dma_addr_t slim2p_mapping;
- uint16_t pci_cfg_value;
+struct lpfc_hba;
- int32_t hba_state;
-#define LPFC_STATE_UNKNOWN 0 /* HBA state is unknown */
-#define LPFC_WARM_START 1 /* HBA state after selective reset */
-#define LPFC_INIT_START 2 /* Initial state after board reset */
-#define LPFC_INIT_MBX_CMDS 3 /* Initialize HBA with mbox commands */
-#define LPFC_LINK_DOWN 4 /* HBA initialized, link is down */
-#define LPFC_LINK_UP 5 /* Link is up - issue READ_LA */
-#define LPFC_LOCAL_CFG_LINK 6 /* local NPORT Id configured */
-#define LPFC_FLOGI 7 /* FLOGI sent to Fabric */
-#define LPFC_FABRIC_CFG_LINK 8 /* Fabric assigned NPORT Id
- configured */
-#define LPFC_NS_REG 9 /* Register with NameServer */
-#define LPFC_NS_QRY 10 /* Query NameServer for NPort ID list */
-#define LPFC_BUILD_DISC_LIST 11 /* Build ADISC and PLOGI lists for
- * device authentication / discovery */
-#define LPFC_DISC_AUTH 12 /* Processing ADISC list */
-#define LPFC_CLEAR_LA 13 /* authentication cmplt - issue
- CLEAR_LA */
-#define LPFC_HBA_READY 32
-#define LPFC_HBA_ERROR -1
+enum discovery_state {
+ LPFC_VPORT_UNKNOWN = 0, /* vport state is unknown */
+ LPFC_VPORT_FAILED = 1, /* vport has failed */
+ LPFC_LOCAL_CFG_LINK = 6, /* local NPORT Id configured */
+ LPFC_FLOGI = 7, /* FLOGI sent to Fabric */
+ LPFC_FDISC = 8, /* FDISC sent for vport */
+ LPFC_FABRIC_CFG_LINK = 9, /* Fabric assigned NPORT Id
+ * configured */
+ LPFC_NS_REG = 10, /* Register with NameServer */
+ LPFC_NS_QRY = 11, /* Query NameServer for NPort ID list */
+ LPFC_BUILD_DISC_LIST = 12, /* Build ADISC and PLOGI lists for
+ * device authentication / discovery */
+ LPFC_DISC_AUTH = 13, /* Processing ADISC list */
+ LPFC_VPORT_READY = 32,
+};
- int32_t stopped; /* HBA has not been restarted since last ERATT */
- uint8_t fc_linkspeed; /* Link speed after last READ_LA */
+enum hba_state {
+ LPFC_LINK_UNKNOWN = 0, /* HBA state is unknown */
+ LPFC_WARM_START = 1, /* HBA state after selective reset */
+ LPFC_INIT_START = 2, /* Initial state after board reset */
+ LPFC_INIT_MBX_CMDS = 3, /* Initialize HBA with mbox commands */
+ LPFC_LINK_DOWN = 4, /* HBA initialized, link is down */
+ LPFC_LINK_UP = 5, /* Link is up - issue READ_LA */
+ LPFC_CLEAR_LA = 6, /* authentication cmplt - issue
+ * CLEAR_LA */
+ LPFC_HBA_READY = 32,
+ LPFC_HBA_ERROR = -1
+};
- uint32_t fc_eventTag; /* event tag for link attention */
- uint32_t fc_prli_sent; /* cntr for outstanding PRLIs */
+struct lpfc_vport {
+ struct list_head listentry;
+ struct lpfc_hba *phba;
+ uint8_t port_type;
+#define LPFC_PHYSICAL_PORT 1
+#define LPFC_NPIV_PORT 2
+#define LPFC_FABRIC_PORT 3
+ enum discovery_state port_state;
- uint32_t num_disc_nodes; /*in addition to hba_state */
+ uint16_t vpi;
- struct timer_list fc_estabtmo; /* link establishment timer */
- struct timer_list fc_disctmo; /* Discovery rescue timer */
- struct timer_list fc_fdmitmo; /* fdmi timer */
- /* These fields used to be binfo */
- struct lpfc_name fc_nodename; /* fc nodename */
- struct lpfc_name fc_portname; /* fc portname */
- uint32_t fc_pref_DID; /* preferred D_ID */
- uint8_t fc_pref_ALPA; /* preferred AL_PA */
- uint32_t fc_edtov; /* E_D_TOV timer value */
- uint32_t fc_arbtov; /* ARB_TOV timer value */
- uint32_t fc_ratov; /* R_A_TOV timer value */
- uint32_t fc_rttov; /* R_T_TOV timer value */
- uint32_t fc_altov; /* AL_TOV timer value */
- uint32_t fc_crtov; /* C_R_TOV timer value */
- uint32_t fc_citov; /* C_I_TOV timer value */
- uint32_t fc_myDID; /* fibre channel S_ID */
- uint32_t fc_prevDID; /* previous fibre channel S_ID */
-
- struct serv_parm fc_sparam; /* buffer for our service parameters */
- struct serv_parm fc_fabparam; /* fabric service parameters buffer */
- uint8_t alpa_map[128]; /* AL_PA map from READ_LA */
-
- uint8_t fc_ns_retry; /* retries for fabric nameserver */
- uint32_t fc_nlp_cnt; /* outstanding NODELIST requests */
- uint32_t fc_rscn_id_cnt; /* count of RSCNs payloads in list */
- struct lpfc_dmabuf *fc_rscn_id_list[FC_MAX_HOLD_RSCN];
- uint32_t lmt;
uint32_t fc_flag; /* FC flags */
-#define FC_PT2PT 0x1 /* pt2pt with no fabric */
-#define FC_PT2PT_PLOGI 0x2 /* pt2pt initiate PLOGI */
-#define FC_DISC_TMO 0x4 /* Discovery timer running */
-#define FC_PUBLIC_LOOP 0x8 /* Public loop */
-#define FC_LBIT 0x10 /* LOGIN bit in loopinit set */
-#define FC_RSCN_MODE 0x20 /* RSCN cmd rcv'ed */
-#define FC_NLP_MORE 0x40 /* More node to process in node tbl */
-#define FC_OFFLINE_MODE 0x80 /* Interface is offline for diag */
-#define FC_FABRIC 0x100 /* We are fabric attached */
-#define FC_ESTABLISH_LINK 0x200 /* Reestablish Link */
-#define FC_RSCN_DISCOVERY 0x400 /* Authenticate all devices after RSCN*/
-#define FC_BLOCK_MGMT_IO 0x800 /* Don't allow mgmt mbx or iocb cmds */
-#define FC_LOADING 0x1000 /* HBA in process of loading drvr */
-#define FC_UNLOADING 0x2000 /* HBA in process of unloading drvr */
-#define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */
-#define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */
-#define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */
-#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */
-#define FC_LOOPBACK_MODE 0x40000 /* NPort is in Loopback mode */
- /* This flag is set while issuing */
- /* INIT_LINK mailbox command */
-#define FC_IGNORE_ERATT 0x80000 /* intr handler should ignore ERATT */
-
- uint32_t fc_topology; /* link topology, from LINK INIT */
-
- struct lpfc_stats fc_stat;
+/* Several of these flags are HBA centric and should be moved to
+ * phba->link_flag (e.g. FC_PTP, FC_PUBLIC_LOOP)
+ */
+#define FC_PT2PT 0x1 /* pt2pt with no fabric */
+#define FC_PT2PT_PLOGI 0x2 /* pt2pt initiate PLOGI */
+#define FC_DISC_TMO 0x4 /* Discovery timer running */
+#define FC_PUBLIC_LOOP 0x8 /* Public loop */
+#define FC_LBIT 0x10 /* LOGIN bit in loopinit set */
+#define FC_RSCN_MODE 0x20 /* RSCN cmd rcv'ed */
+#define FC_NLP_MORE 0x40 /* More node to process in node tbl */
+#define FC_OFFLINE_MODE 0x80 /* Interface is offline for diag */
+#define FC_FABRIC 0x100 /* We are fabric attached */
+#define FC_ESTABLISH_LINK 0x200 /* Reestablish Link */
+#define FC_RSCN_DISCOVERY 0x400 /* Auth all devices after RSCN */
+#define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */
+#define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */
+#define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */
+#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */
+#define FC_RFF_NOT_SUPPORTED 0x40000 /* RFF_ID was rejected by switch */
+#define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */
+#define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */
struct list_head fc_nodes;
@@ -267,10 +286,131 @@
uint16_t fc_map_cnt;
uint16_t fc_npr_cnt;
uint16_t fc_unused_cnt;
+ struct serv_parm fc_sparam; /* buffer for our service parameters */
+
+ uint32_t fc_myDID; /* fibre channel S_ID */
+ uint32_t fc_prevDID; /* previous fibre channel S_ID */
+
+ int32_t stopped; /* HBA has not been restarted since last ERATT */
+ uint8_t fc_linkspeed; /* Link speed after last READ_LA */
+
+ uint32_t num_disc_nodes; /*in addition to hba_state */
+
+ uint32_t fc_nlp_cnt; /* outstanding NODELIST requests */
+ uint32_t fc_rscn_id_cnt; /* count of RSCNs payloads in list */
+ struct lpfc_dmabuf *fc_rscn_id_list[FC_MAX_HOLD_RSCN];
+ struct lpfc_name fc_nodename; /* fc nodename */
+ struct lpfc_name fc_portname; /* fc portname */
+
+ struct lpfc_work_evt disc_timeout_evt;
+
+ struct timer_list fc_disctmo; /* Discovery rescue timer */
+ uint8_t fc_ns_retry; /* retries for fabric nameserver */
+ uint32_t fc_prli_sent; /* cntr for outstanding PRLIs */
+
+ spinlock_t work_port_lock;
+ uint32_t work_port_events; /* Timeout to be handled */
+#define WORKER_DISC_TMO 0x1 /* vport: Discovery timeout */
+#define WORKER_ELS_TMO 0x2 /* vport: ELS timeout */
+#define WORKER_FDMI_TMO 0x4 /* vport: FDMI timeout */
+
+#define WORKER_MBOX_TMO 0x100 /* hba: MBOX timeout */
+#define WORKER_HB_TMO 0x200 /* hba: Heart beat timeout */
+#define WORKER_FABRIC_BLOCK_TMO 0x400 /* hba: fabric block timout */
+#define WORKER_RAMP_DOWN_QUEUE 0x800 /* hba: Decrease Q depth */
+#define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */
+
+ struct timer_list fc_fdmitmo;
+ struct timer_list els_tmofunc;
+
+ int unreg_vpi_cmpl;
+
+ uint8_t load_flag;
+#define FC_LOADING 0x1 /* HBA in process of loading drvr */
+#define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */
+ char *vname; /* Application assigned name */
+ struct fc_vport *fc_vport;
+
+#ifdef CONFIG_LPFC_DEBUG_FS
+ struct dentry *debug_disc_trc;
+ struct dentry *debug_nodelist;
+ struct dentry *vport_debugfs_root;
+ struct lpfc_disc_trc *disc_trc;
+ atomic_t disc_trc_cnt;
+#endif
+};
+
+struct hbq_s {
+ uint16_t entry_count; /* Current number of HBQ slots */
+ uint32_t next_hbqPutIdx; /* Index to next HBQ slot to use */
+ uint32_t hbqPutIdx; /* HBQ slot to use */
+ uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */
+};
+
+#define LPFC_MAX_HBQS 16
+/* this matches the possition in the lpfc_hbq_defs array */
+#define LPFC_ELS_HBQ 0
+
+struct lpfc_hba {
+ struct lpfc_sli sli;
+ uint32_t sli_rev; /* SLI2 or SLI3 */
+ uint32_t sli3_options; /* Mask of enabled SLI3 options */
+#define LPFC_SLI3_ENABLED 0x01
+#define LPFC_SLI3_HBQ_ENABLED 0x02
+#define LPFC_SLI3_NPIV_ENABLED 0x04
+#define LPFC_SLI3_VPORT_TEARDOWN 0x08
+ uint32_t iocb_cmd_size;
+ uint32_t iocb_rsp_size;
+
+ enum hba_state link_state;
+ uint32_t link_flag; /* link state flags */
+#define LS_LOOPBACK_MODE 0x1 /* NPort is in Loopback mode */
+ /* This flag is set while issuing */
+ /* INIT_LINK mailbox command */
+#define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */
+#define LS_IGNORE_ERATT 0x3 /* intr handler should ignore ERATT */
+
+ struct lpfc_sli2_slim *slim2p;
+ struct lpfc_dmabuf hbqslimp;
+
+ dma_addr_t slim2p_mapping;
+
+ uint16_t pci_cfg_value;
+
+ uint8_t work_found;
+#define LPFC_MAX_WORKER_ITERATION 4
+
+ uint8_t fc_linkspeed; /* Link speed after last READ_LA */
+
+ uint32_t fc_eventTag; /* event tag for link attention */
+
+
+ struct timer_list fc_estabtmo; /* link establishment timer */
+ /* These fields used to be binfo */
+ uint32_t fc_pref_DID; /* preferred D_ID */
+ uint8_t fc_pref_ALPA; /* preferred AL_PA */
+ uint32_t fc_edtov; /* E_D_TOV timer value */
+ uint32_t fc_arbtov; /* ARB_TOV timer value */
+ uint32_t fc_ratov; /* R_A_TOV timer value */
+ uint32_t fc_rttov; /* R_T_TOV timer value */
+ uint32_t fc_altov; /* AL_TOV timer value */
+ uint32_t fc_crtov; /* C_R_TOV timer value */
+ uint32_t fc_citov; /* C_I_TOV timer value */
+
+ struct serv_parm fc_fabparam; /* fabric service parameters buffer */
+ uint8_t alpa_map[128]; /* AL_PA map from READ_LA */
+
+ uint32_t lmt;
+
+ uint32_t fc_topology; /* link topology, from LINK INIT */
+
+ struct lpfc_stats fc_stat;
+
struct lpfc_nodelist fc_fcpnodev; /* nodelist entry for no device */
uint32_t nport_event_cnt; /* timestamp for nlplist entry */
- uint32_t wwnn[2];
+ uint8_t wwnn[8];
+ uint8_t wwpn[8];
uint32_t RandomData[7];
uint32_t cfg_log_verbose;
@@ -278,6 +418,9 @@
uint32_t cfg_nodev_tmo;
uint32_t cfg_devloss_tmo;
uint32_t cfg_hba_queue_depth;
+ uint32_t cfg_peer_port_login;
+ uint32_t cfg_vport_restrict_login;
+ uint32_t cfg_npiv_enable;
uint32_t cfg_fcp_class;
uint32_t cfg_use_adisc;
uint32_t cfg_ack0;
@@ -304,22 +447,20 @@
lpfc_vpd_t vpd; /* vital product data */
- struct Scsi_Host *host;
struct pci_dev *pcidev;
struct list_head work_list;
uint32_t work_ha; /* Host Attention Bits for WT */
uint32_t work_ha_mask; /* HA Bits owned by WT */
uint32_t work_hs; /* HS stored in case of ERRAT */
uint32_t work_status[2]; /* Extra status from SLIM */
- uint32_t work_hba_events; /* Timeout to be handled */
-#define WORKER_DISC_TMO 0x1 /* Discovery timeout */
-#define WORKER_ELS_TMO 0x2 /* ELS timeout */
-#define WORKER_MBOX_TMO 0x4 /* MBOX timeout */
-#define WORKER_FDMI_TMO 0x8 /* FDMI timeout */
wait_queue_head_t *work_wait;
struct task_struct *worker_thread;
+ struct list_head hbq_buffer_list;
+ uint32_t hbq_count; /* Count of configured HBQs */
+ struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */
+
unsigned long pci_bar0_map; /* Physical address for PCI BAR0 */
unsigned long pci_bar2_map; /* Physical address for PCI BAR2 */
void __iomem *slim_memmap_p; /* Kernel memory mapped address for
@@ -334,6 +475,10 @@
reg */
void __iomem *HCregaddr; /* virtual address for host ctl reg */
+ struct lpfc_hgp __iomem *host_gp; /* Host side get/put pointers */
+ uint32_t __iomem *hbq_put; /* Address in SLIM to HBQ put ptrs */
+ uint32_t *hbq_get; /* Host mem address of HBQ get ptrs */
+
int brd_no; /* FC board number */
char SerialNumber[32]; /* adapter Serial Number */
@@ -353,7 +498,6 @@
uint8_t soft_wwn_enable;
struct timer_list fcp_poll_timer;
- struct timer_list els_tmofunc;
/*
* stat counters
@@ -370,31 +514,69 @@
uint32_t total_scsi_bufs;
struct list_head lpfc_iocb_list;
uint32_t total_iocbq_bufs;
+ spinlock_t hbalock;
/* pci_mem_pools */
struct pci_pool *lpfc_scsi_dma_buf_pool;
struct pci_pool *lpfc_mbuf_pool;
+ struct pci_pool *lpfc_hbq_pool;
struct lpfc_dma_pool lpfc_mbuf_safety_pool;
mempool_t *mbox_mem_pool;
mempool_t *nlp_mem_pool;
struct fc_host_statistics link_stats;
+
+ struct list_head port_list;
+ struct lpfc_vport *pport; /* physical lpfc_vport pointer */
+ uint16_t max_vpi; /* Maximum virtual nports */
+#define LPFC_MAX_VPI 100 /* Max number of VPorts supported */
+ unsigned long *vpi_bmask; /* vpi allocation table */
+
+ /* Data structure used by fabric iocb scheduler */
+ struct list_head fabric_iocb_list;
+ atomic_t fabric_iocb_count;
+ struct timer_list fabric_block_timer;
+ unsigned long bit_flags;
+#define FABRIC_COMANDS_BLOCKED 0
+ atomic_t num_rsrc_err;
+ atomic_t num_cmd_success;
+ unsigned long last_rsrc_error_time;
+ unsigned long last_ramp_down_time;
+ unsigned long last_ramp_up_time;
+#ifdef CONFIG_LPFC_DEBUG_FS
+ struct dentry *hba_debugfs_root;
+ atomic_t debugfs_vport_count;
+#endif
+
+ /* Fields used for heart beat. */
+ unsigned long last_completion_time;
+ struct timer_list hb_tmofunc;
+ uint8_t hb_outstanding;
};
-static inline void
-lpfc_set_loopback_flag(struct lpfc_hba *phba) {
- if (phba->cfg_topology == FLAGS_LOCAL_LB)
- phba->fc_flag |= FC_LOOPBACK_MODE;
- else
- phba->fc_flag &= ~FC_LOOPBACK_MODE;
+static inline struct Scsi_Host *
+lpfc_shost_from_vport(struct lpfc_vport *vport)
+{
+ return container_of((void *) vport, struct Scsi_Host, hostdata[0]);
}
-struct rnidrsp {
- void *buf;
- uint32_t uniqueid;
- struct list_head list;
- uint32_t data;
-};
+static inline void
+lpfc_set_loopback_flag(struct lpfc_hba *phba)
+{
+ if (phba->cfg_topology == FLAGS_LOCAL_LB)
+ phba->link_flag |= LS_LOOPBACK_MODE;
+ else
+ phba->link_flag &= ~LS_LOOPBACK_MODE;
+}
+
+static inline int
+lpfc_is_link_up(struct lpfc_hba *phba)
+{
+ return phba->link_state == LPFC_LINK_UP ||
+ phba->link_state == LPFC_CLEAR_LA ||
+ phba->link_state == LPFC_HBA_READY;
+}
#define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */
+
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 5dfda97..860a52c 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -39,6 +39,7 @@
#include "lpfc_version.h"
#include "lpfc_compat.h"
#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
#define LPFC_DEF_DEVLOSS_TMO 30
#define LPFC_MIN_DEVLOSS_TMO 1
@@ -76,116 +77,156 @@
lpfc_info_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
+
return snprintf(buf, PAGE_SIZE, "%s\n",lpfc_info(host));
}
static ssize_t
lpfc_serialnum_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber);
}
static ssize_t
lpfc_modeldesc_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc);
}
static ssize_t
lpfc_modelname_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName);
}
static ssize_t
lpfc_programtype_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType);
}
static ssize_t
-lpfc_portnum_show(struct class_device *cdev, char *buf)
+lpfc_vportnum_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port);
}
static ssize_t
lpfc_fwrev_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
char fwrev[32];
+
lpfc_decode_firmware_rev(phba, fwrev, 1);
- return snprintf(buf, PAGE_SIZE, "%s\n",fwrev);
+ return snprintf(buf, PAGE_SIZE, "%s, sli-%d\n", fwrev, phba->sli_rev);
}
static ssize_t
lpfc_hdw_show(struct class_device *cdev, char *buf)
{
char hdw[9];
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
lpfc_vpd_t *vp = &phba->vpd;
+
lpfc_jedec_to_ascii(vp->rev.biuRev, hdw);
return snprintf(buf, PAGE_SIZE, "%s\n", hdw);
}
static ssize_t
lpfc_option_rom_version_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion);
}
static ssize_t
lpfc_state_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- int len = 0;
- switch (phba->hba_state) {
- case LPFC_STATE_UNKNOWN:
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ int len = 0;
+
+ switch (phba->link_state) {
+ case LPFC_LINK_UNKNOWN:
case LPFC_WARM_START:
case LPFC_INIT_START:
case LPFC_INIT_MBX_CMDS:
case LPFC_LINK_DOWN:
+ case LPFC_HBA_ERROR:
len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n");
break;
case LPFC_LINK_UP:
- case LPFC_LOCAL_CFG_LINK:
- len += snprintf(buf + len, PAGE_SIZE-len, "Link Up\n");
- break;
- case LPFC_FLOGI:
- case LPFC_FABRIC_CFG_LINK:
- case LPFC_NS_REG:
- case LPFC_NS_QRY:
- case LPFC_BUILD_DISC_LIST:
- case LPFC_DISC_AUTH:
case LPFC_CLEAR_LA:
- len += snprintf(buf + len, PAGE_SIZE-len,
- "Link Up - Discovery\n");
- break;
case LPFC_HBA_READY:
- len += snprintf(buf + len, PAGE_SIZE-len,
- "Link Up - Ready:\n");
+ len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - \n");
+
+ switch (vport->port_state) {
+ len += snprintf(buf + len, PAGE_SIZE-len,
+ "initializing\n");
+ break;
+ case LPFC_LOCAL_CFG_LINK:
+ len += snprintf(buf + len, PAGE_SIZE-len,
+ "Configuring Link\n");
+ break;
+ case LPFC_FDISC:
+ case LPFC_FLOGI:
+ case LPFC_FABRIC_CFG_LINK:
+ case LPFC_NS_REG:
+ case LPFC_NS_QRY:
+ case LPFC_BUILD_DISC_LIST:
+ case LPFC_DISC_AUTH:
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "Discovery\n");
+ break;
+ case LPFC_VPORT_READY:
+ len += snprintf(buf + len, PAGE_SIZE - len, "Ready\n");
+ break;
+
+ case LPFC_VPORT_FAILED:
+ len += snprintf(buf + len, PAGE_SIZE - len, "Failed\n");
+ break;
+
+ case LPFC_VPORT_UNKNOWN:
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "Unknown\n");
+ break;
+ }
+
if (phba->fc_topology == TOPOLOGY_LOOP) {
- if (phba->fc_flag & FC_PUBLIC_LOOP)
+ if (vport->fc_flag & FC_PUBLIC_LOOP)
len += snprintf(buf + len, PAGE_SIZE-len,
" Public Loop\n");
else
len += snprintf(buf + len, PAGE_SIZE-len,
" Private Loop\n");
} else {
- if (phba->fc_flag & FC_FABRIC)
+ if (vport->fc_flag & FC_FABRIC)
len += snprintf(buf + len, PAGE_SIZE-len,
" Fabric\n");
else
@@ -193,29 +234,32 @@
" Point-2-Point\n");
}
}
+
return len;
}
static ssize_t
lpfc_num_discovered_ports_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->fc_map_cnt +
- phba->fc_unmap_cnt);
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ vport->fc_map_cnt + vport->fc_unmap_cnt);
}
static int
-lpfc_issue_lip(struct Scsi_Host *host)
+lpfc_issue_lip(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *pmboxq;
int mbxstatus = MBXERR_ERROR;
- if ((phba->fc_flag & FC_OFFLINE_MODE) ||
- (phba->fc_flag & FC_BLOCK_MGMT_IO) ||
- (phba->hba_state != LPFC_HBA_READY))
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
+ (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) ||
+ (vport->port_state != LPFC_VPORT_READY))
return -EPERM;
pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
@@ -238,9 +282,7 @@
}
lpfc_set_loopback_flag(phba);
- if (mbxstatus == MBX_TIMEOUT)
- pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- else
+ if (mbxstatus != MBX_TIMEOUT)
mempool_free(pmboxq, phba->mbox_mem_pool);
if (mbxstatus == MBXERR_ERROR)
@@ -320,8 +362,10 @@
static ssize_t
lpfc_issue_reset(struct class_device *cdev, const char *buf, size_t count)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
int status = -EINVAL;
if (strncmp(buf, "selective", sizeof("selective") - 1) == 0)
@@ -336,23 +380,26 @@
static ssize_t
lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
}
static ssize_t
lpfc_board_mode_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
char * state;
- if (phba->hba_state == LPFC_HBA_ERROR)
+ if (phba->link_state == LPFC_HBA_ERROR)
state = "error";
- else if (phba->hba_state == LPFC_WARM_START)
+ else if (phba->link_state == LPFC_WARM_START)
state = "warm start";
- else if (phba->hba_state == LPFC_INIT_START)
+ else if (phba->link_state == LPFC_INIT_START)
state = "offline";
else
state = "online";
@@ -363,8 +410,9 @@
static ssize_t
lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
struct completion online_compl;
int status=0;
@@ -389,11 +437,166 @@
return -EIO;
}
+int
+lpfc_get_hba_info(struct lpfc_hba *phba,
+ uint32_t *mxri, uint32_t *axri,
+ uint32_t *mrpi, uint32_t *arpi,
+ uint32_t *mvpi, uint32_t *avpi)
+{
+ struct lpfc_sli *psli = &phba->sli;
+ LPFC_MBOXQ_t *pmboxq;
+ MAILBOX_t *pmb;
+ int rc = 0;
+
+ /*
+ * prevent udev from issuing mailbox commands until the port is
+ * configured.
+ */
+ if (phba->link_state < LPFC_LINK_DOWN ||
+ !phba->mbox_mem_pool ||
+ (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0)
+ return 0;
+
+ if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)
+ return 0;
+
+ pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmboxq)
+ return 0;
+ memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t));
+
+ pmb = &pmboxq->mb;
+ pmb->mbxCommand = MBX_READ_CONFIG;
+ pmb->mbxOwner = OWN_HOST;
+ pmboxq->context1 = NULL;
+
+ if ((phba->pport->fc_flag & FC_OFFLINE_MODE) ||
+ (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+ rc = MBX_NOT_FINISHED;
+ else
+ rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+
+ if (rc != MBX_SUCCESS) {
+ if (rc != MBX_TIMEOUT)
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ return 0;
+ }
+
+ if (mrpi)
+ *mrpi = pmb->un.varRdConfig.max_rpi;
+ if (arpi)
+ *arpi = pmb->un.varRdConfig.avail_rpi;
+ if (mxri)
+ *mxri = pmb->un.varRdConfig.max_xri;
+ if (axri)
+ *axri = pmb->un.varRdConfig.avail_xri;
+ if (mvpi)
+ *mvpi = pmb->un.varRdConfig.max_vpi;
+ if (avpi)
+ *avpi = pmb->un.varRdConfig.avail_vpi;
+
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ return 1;
+}
+
+static ssize_t
+lpfc_max_rpi_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t cnt;
+
+ if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL, NULL, NULL))
+ return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
+ return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_used_rpi_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t cnt, acnt;
+
+ if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt, NULL, NULL))
+ return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
+ return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_max_xri_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t cnt;
+
+ if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL, NULL, NULL))
+ return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
+ return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_used_xri_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t cnt, acnt;
+
+ if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL, NULL, NULL))
+ return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
+ return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_max_vpi_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t cnt;
+
+ if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, NULL))
+ return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
+ return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_used_vpi_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t cnt, acnt;
+
+ if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, &acnt))
+ return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
+ return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_npiv_info_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
+ if (!(phba->max_vpi))
+ return snprintf(buf, PAGE_SIZE, "NPIV Not Supported\n");
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ return snprintf(buf, PAGE_SIZE, "NPIV Physical\n");
+ return snprintf(buf, PAGE_SIZE, "NPIV Virtual (VPI %d)\n", vport->vpi);
+}
+
static ssize_t
lpfc_poll_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
return snprintf(buf, PAGE_SIZE, "%#x\n", phba->cfg_poll);
}
@@ -402,8 +605,9 @@
lpfc_poll_store(struct class_device *cdev, const char *buf,
size_t count)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
uint32_t creg_val;
uint32_t old_val;
int val=0;
@@ -417,7 +621,7 @@
if ((val & 0x3) != val)
return -EINVAL;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
old_val = phba->cfg_poll;
@@ -432,16 +636,16 @@
lpfc_poll_start_timer(phba);
}
} else if (val != 0x0) {
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EINVAL;
}
if (!(val & DISABLE_FCP_RING_INT) &&
(old_val & DISABLE_FCP_RING_INT))
{
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
del_timer(&phba->fcp_poll_timer);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
creg_val = readl(phba->HCregaddr);
creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING);
writel(creg_val, phba->HCregaddr);
@@ -450,7 +654,7 @@
phba->cfg_poll = val;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return strlen(buf);
}
@@ -459,8 +663,9 @@
static ssize_t \
lpfc_##attr##_show(struct class_device *cdev, char *buf) \
{ \
- struct Scsi_Host *host = class_to_shost(cdev);\
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;\
+ struct Scsi_Host *shost = class_to_shost(cdev);\
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
+ struct lpfc_hba *phba = vport->phba;\
int val = 0;\
val = phba->cfg_##attr;\
return snprintf(buf, PAGE_SIZE, "%d\n",\
@@ -471,8 +676,9 @@
static ssize_t \
lpfc_##attr##_show(struct class_device *cdev, char *buf) \
{ \
- struct Scsi_Host *host = class_to_shost(cdev);\
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;\
+ struct Scsi_Host *shost = class_to_shost(cdev);\
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
+ struct lpfc_hba *phba = vport->phba;\
int val = 0;\
val = phba->cfg_##attr;\
return snprintf(buf, PAGE_SIZE, "%#x\n",\
@@ -514,8 +720,9 @@
static ssize_t \
lpfc_##attr##_store(struct class_device *cdev, const char *buf, size_t count) \
{ \
- struct Scsi_Host *host = class_to_shost(cdev);\
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;\
+ struct Scsi_Host *shost = class_to_shost(cdev);\
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
+ struct lpfc_hba *phba = vport->phba;\
int val=0;\
if (!isdigit(buf[0]))\
return -EINVAL;\
@@ -576,7 +783,7 @@
static CLASS_DEVICE_ATTR(modeldesc, S_IRUGO, lpfc_modeldesc_show, NULL);
static CLASS_DEVICE_ATTR(modelname, S_IRUGO, lpfc_modelname_show, NULL);
static CLASS_DEVICE_ATTR(programtype, S_IRUGO, lpfc_programtype_show, NULL);
-static CLASS_DEVICE_ATTR(portnum, S_IRUGO, lpfc_portnum_show, NULL);
+static CLASS_DEVICE_ATTR(portnum, S_IRUGO, lpfc_vportnum_show, NULL);
static CLASS_DEVICE_ATTR(fwrev, S_IRUGO, lpfc_fwrev_show, NULL);
static CLASS_DEVICE_ATTR(hdw, S_IRUGO, lpfc_hdw_show, NULL);
static CLASS_DEVICE_ATTR(state, S_IRUGO, lpfc_state_show, NULL);
@@ -592,6 +799,13 @@
static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
lpfc_board_mode_show, lpfc_board_mode_store);
static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
+static CLASS_DEVICE_ATTR(max_vpi, S_IRUGO, lpfc_max_vpi_show, NULL);
+static CLASS_DEVICE_ATTR(used_vpi, S_IRUGO, lpfc_used_vpi_show, NULL);
+static CLASS_DEVICE_ATTR(max_rpi, S_IRUGO, lpfc_max_rpi_show, NULL);
+static CLASS_DEVICE_ATTR(used_rpi, S_IRUGO, lpfc_used_rpi_show, NULL);
+static CLASS_DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL);
+static CLASS_DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL);
+static CLASS_DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL);
static char *lpfc_soft_wwn_key = "C99G71SL8032A";
@@ -600,8 +814,9 @@
lpfc_soft_wwn_enable_store(struct class_device *cdev, const char *buf,
size_t count)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
unsigned int cnt = count;
/*
@@ -634,8 +849,10 @@
static ssize_t
lpfc_soft_wwpn_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "0x%llx\n",
(unsigned long long)phba->cfg_soft_wwpn);
}
@@ -644,8 +861,9 @@
static ssize_t
lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
struct completion online_compl;
int stat1=0, stat2=0;
unsigned int i, j, cnt=count;
@@ -680,9 +898,9 @@
}
}
phba->cfg_soft_wwpn = wwn_to_u64(wwpn);
- fc_host_port_name(host) = phba->cfg_soft_wwpn;
+ fc_host_port_name(shost) = phba->cfg_soft_wwpn;
if (phba->cfg_soft_wwnn)
- fc_host_node_name(host) = phba->cfg_soft_wwnn;
+ fc_host_node_name(shost) = phba->cfg_soft_wwnn;
dev_printk(KERN_NOTICE, &phba->pcidev->dev,
"lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);
@@ -777,6 +995,15 @@
static CLASS_DEVICE_ATTR(lpfc_poll, S_IRUGO | S_IWUSR,
lpfc_poll_show, lpfc_poll_store);
+int lpfc_sli_mode = 0;
+module_param(lpfc_sli_mode, int, 0);
+MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
+ " 0 - auto (SLI-3 if supported),"
+ " 2 - select SLI-2 even on SLI-3 capable HBAs,"
+ " 3 - select SLI-3");
+
+LPFC_ATTR_R(npiv_enable, 0, 0, 1, "Enable NPIV functionality");
+
/*
# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
# until the timer expires. Value range is [0,255]. Default value is 30.
@@ -790,8 +1017,9 @@
static ssize_t
lpfc_nodev_tmo_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
int val = 0;
val = phba->cfg_devloss_tmo;
return snprintf(buf, PAGE_SIZE, "%d\n",
@@ -832,13 +1060,19 @@
static void
lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
{
+ struct lpfc_vport *vport;
+ struct Scsi_Host *shost;
struct lpfc_nodelist *ndlp;
- spin_lock_irq(phba->host->host_lock);
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp)
- if (ndlp->rport)
- ndlp->rport->dev_loss_tmo = phba->cfg_devloss_tmo;
- spin_unlock_irq(phba->host->host_lock);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ shost = lpfc_shost_from_vport(vport);
+ spin_lock_irq(shost->host_lock);
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
+ if (ndlp->rport)
+ ndlp->rport->dev_loss_tmo =
+ phba->cfg_devloss_tmo;
+ spin_unlock_irq(shost->host_lock);
+ }
}
static int
@@ -946,6 +1180,33 @@
"Max number of FCP commands we can queue to a lpfc HBA");
/*
+# peer_port_login: This parameter allows/prevents logins
+# between peer ports hosted on the same physical port.
+# When this parameter is set 0 peer ports of same physical port
+# are not allowed to login to each other.
+# When this parameter is set 1 peer ports of same physical port
+# are allowed to login to each other.
+# Default value of this parameter is 0.
+*/
+LPFC_ATTR_R(peer_port_login, 0, 0, 1,
+ "Allow peer ports on the same physical port to login to each "
+ "other.");
+
+/*
+# vport_restrict_login: This parameter allows/prevents logins
+# between Virtual Ports and remote initiators.
+# When this parameter is not set (0) Virtual Ports will accept PLOGIs from
+# other initiators and will attempt to PLOGI all remote ports.
+# When this parameter is set (1) Virtual Ports will reject PLOGIs from
+# remote ports and will not attempt to PLOGI to other initiators.
+# This parameter does not restrict to the physical port.
+# This parameter does not restrict logins to Fabric resident remote ports.
+# Default value of this parameter is 1.
+*/
+LPFC_ATTR_RW(vport_restrict_login, 1, 0, 1,
+ "Restrict virtual ports login to remote initiators.");
+
+/*
# Some disk devices have a "select ID" or "select Target" capability.
# From a protocol standpoint "select ID" usually means select the
# Fibre channel "ALPA". In the FC-AL Profile there is an "informative
@@ -1088,7 +1349,8 @@
LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible");
-struct class_device_attribute *lpfc_host_attrs[] = {
+
+struct class_device_attribute *lpfc_hba_attrs[] = {
&class_device_attr_info,
&class_device_attr_serialnum,
&class_device_attr_modeldesc,
@@ -1104,6 +1366,8 @@
&class_device_attr_lpfc_log_verbose,
&class_device_attr_lpfc_lun_queue_depth,
&class_device_attr_lpfc_hba_queue_depth,
+ &class_device_attr_lpfc_peer_port_login,
+ &class_device_attr_lpfc_vport_restrict_login,
&class_device_attr_lpfc_nodev_tmo,
&class_device_attr_lpfc_devloss_tmo,
&class_device_attr_lpfc_fcp_class,
@@ -1119,9 +1383,17 @@
&class_device_attr_lpfc_multi_ring_type,
&class_device_attr_lpfc_fdmi_on,
&class_device_attr_lpfc_max_luns,
+ &class_device_attr_lpfc_npiv_enable,
&class_device_attr_nport_evt_cnt,
&class_device_attr_management_version,
&class_device_attr_board_mode,
+ &class_device_attr_max_vpi,
+ &class_device_attr_used_vpi,
+ &class_device_attr_max_rpi,
+ &class_device_attr_used_rpi,
+ &class_device_attr_max_xri,
+ &class_device_attr_used_xri,
+ &class_device_attr_npiv_info,
&class_device_attr_issue_reset,
&class_device_attr_lpfc_poll,
&class_device_attr_lpfc_poll_tmo,
@@ -1137,9 +1409,11 @@
char *buf, loff_t off, size_t count)
{
size_t buf_off;
- struct Scsi_Host *host = class_to_shost(container_of(kobj,
- struct class_device, kobj));
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct class_device *cdev = container_of(kobj, struct class_device,
+ kobj);
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
if ((off + count) > FF_REG_AREA_SIZE)
return -ERANGE;
@@ -1149,18 +1423,16 @@
if (off % 4 || count % 4 || (unsigned long)buf % 4)
return -EINVAL;
- spin_lock_irq(phba->host->host_lock);
-
- if (!(phba->fc_flag & FC_OFFLINE_MODE)) {
- spin_unlock_irq(phba->host->host_lock);
+ if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
return -EPERM;
}
+ spin_lock_irq(&phba->hbalock);
for (buf_off = 0; buf_off < count; buf_off += sizeof(uint32_t))
writel(*((uint32_t *)(buf + buf_off)),
phba->ctrl_regs_memmap_p + off + buf_off);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return count;
}
@@ -1171,9 +1443,11 @@
{
size_t buf_off;
uint32_t * tmp_ptr;
- struct Scsi_Host *host = class_to_shost(container_of(kobj,
- struct class_device, kobj));
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct class_device *cdev = container_of(kobj, struct class_device,
+ kobj);
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
if (off > FF_REG_AREA_SIZE)
return -ERANGE;
@@ -1186,14 +1460,14 @@
if (off % 4 || count % 4 || (unsigned long)buf % 4)
return -EINVAL;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
for (buf_off = 0; buf_off < count; buf_off += sizeof(uint32_t)) {
tmp_ptr = (uint32_t *)(buf + buf_off);
*tmp_ptr = readl(phba->ctrl_regs_memmap_p + off + buf_off);
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return count;
}
@@ -1210,7 +1484,7 @@
static void
-sysfs_mbox_idle (struct lpfc_hba * phba)
+sysfs_mbox_idle(struct lpfc_hba *phba)
{
phba->sysfs_mbox.state = SMBOX_IDLE;
phba->sysfs_mbox.offset = 0;
@@ -1226,10 +1500,12 @@
sysfs_mbox_write(struct kobject *kobj, struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct Scsi_Host * host =
- class_to_shost(container_of(kobj, struct class_device, kobj));
- struct lpfc_hba * phba = (struct lpfc_hba*)host->hostdata;
- struct lpfcMboxq * mbox = NULL;
+ struct class_device *cdev = container_of(kobj, struct class_device,
+ kobj);
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfcMboxq *mbox = NULL;
if ((count + off) > MAILBOX_CMD_SIZE)
return -ERANGE;
@@ -1247,7 +1523,7 @@
memset(mbox, 0, sizeof (LPFC_MBOXQ_t));
}
- spin_lock_irq(host->host_lock);
+ spin_lock_irq(&phba->hbalock);
if (off == 0) {
if (phba->sysfs_mbox.mbox)
@@ -1258,9 +1534,9 @@
} else {
if (phba->sysfs_mbox.state != SMBOX_WRITING ||
phba->sysfs_mbox.offset != off ||
- phba->sysfs_mbox.mbox == NULL ) {
+ phba->sysfs_mbox.mbox == NULL) {
sysfs_mbox_idle(phba);
- spin_unlock_irq(host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EAGAIN;
}
}
@@ -1270,7 +1546,7 @@
phba->sysfs_mbox.offset = off + count;
- spin_unlock_irq(host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return count;
}
@@ -1279,10 +1555,11 @@
sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct Scsi_Host *host =
- class_to_shost(container_of(kobj, struct class_device,
- kobj));
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct class_device *cdev = container_of(kobj, struct class_device,
+ kobj);
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
int rc;
if (off > MAILBOX_CMD_SIZE)
@@ -1297,7 +1574,7 @@
if (off && count == 0)
return 0;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
if (off == 0 &&
phba->sysfs_mbox.state == SMBOX_WRITING &&
@@ -1320,12 +1597,12 @@
case MBX_SET_MASK:
case MBX_SET_SLIM:
case MBX_SET_DEBUG:
- if (!(phba->fc_flag & FC_OFFLINE_MODE)) {
+ if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
printk(KERN_WARNING "mbox_read:Command 0x%x "
"is illegal in on-line state\n",
phba->sysfs_mbox.mbox->mb.mbxCommand);
sysfs_mbox_idle(phba);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EPERM;
}
case MBX_LOAD_SM:
@@ -1355,48 +1632,48 @@
printk(KERN_WARNING "mbox_read: Illegal Command 0x%x\n",
phba->sysfs_mbox.mbox->mb.mbxCommand);
sysfs_mbox_idle(phba);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EPERM;
default:
printk(KERN_WARNING "mbox_read: Unknown Command 0x%x\n",
phba->sysfs_mbox.mbox->mb.mbxCommand);
sysfs_mbox_idle(phba);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EPERM;
}
- if (phba->fc_flag & FC_BLOCK_MGMT_IO) {
+ phba->sysfs_mbox.mbox->vport = vport;
+
+ if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
sysfs_mbox_idle(phba);
- spin_unlock_irq(host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EAGAIN;
}
- if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
(!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
rc = lpfc_sli_issue_mbox (phba,
phba->sysfs_mbox.mbox,
MBX_POLL);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
} else {
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
rc = lpfc_sli_issue_mbox_wait (phba,
phba->sysfs_mbox.mbox,
lpfc_mbox_tmo_val(phba,
phba->sysfs_mbox.mbox->mb.mbxCommand) * HZ);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
}
if (rc != MBX_SUCCESS) {
if (rc == MBX_TIMEOUT) {
- phba->sysfs_mbox.mbox->mbox_cmpl =
- lpfc_sli_def_mbox_cmpl;
phba->sysfs_mbox.mbox = NULL;
}
sysfs_mbox_idle(phba);
- spin_unlock_irq(host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
}
phba->sysfs_mbox.state = SMBOX_READING;
@@ -1405,7 +1682,7 @@
phba->sysfs_mbox.state != SMBOX_READING) {
printk(KERN_WARNING "mbox_read: Bad State\n");
sysfs_mbox_idle(phba);
- spin_unlock_irq(host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EAGAIN;
}
@@ -1416,7 +1693,7 @@
if (phba->sysfs_mbox.offset == MAILBOX_CMD_SIZE)
sysfs_mbox_idle(phba);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return count;
}
@@ -1432,35 +1709,35 @@
};
int
-lpfc_alloc_sysfs_attr(struct lpfc_hba *phba)
+lpfc_alloc_sysfs_attr(struct lpfc_vport *vport)
{
- struct Scsi_Host *host = phba->host;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
int error;
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &sysfs_ctlreg_attr);
+ error = sysfs_create_bin_file(&shost->shost_classdev.kobj,
+ &sysfs_ctlreg_attr);
if (error)
goto out;
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &sysfs_mbox_attr);
+ error = sysfs_create_bin_file(&shost->shost_classdev.kobj,
+ &sysfs_mbox_attr);
if (error)
goto out_remove_ctlreg_attr;
return 0;
out_remove_ctlreg_attr:
- sysfs_remove_bin_file(&host->shost_classdev.kobj, &sysfs_ctlreg_attr);
+ sysfs_remove_bin_file(&shost->shost_classdev.kobj, &sysfs_ctlreg_attr);
out:
return error;
}
void
-lpfc_free_sysfs_attr(struct lpfc_hba *phba)
+lpfc_free_sysfs_attr(struct lpfc_vport *vport)
{
- struct Scsi_Host *host = phba->host;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- sysfs_remove_bin_file(&host->shost_classdev.kobj, &sysfs_mbox_attr);
- sysfs_remove_bin_file(&host->shost_classdev.kobj, &sysfs_ctlreg_attr);
+ sysfs_remove_bin_file(&shost->shost_classdev.kobj, &sysfs_mbox_attr);
+ sysfs_remove_bin_file(&shost->shost_classdev.kobj, &sysfs_ctlreg_attr);
}
@@ -1471,26 +1748,30 @@
static void
lpfc_get_host_port_id(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+
/* note: fc_myDID already in cpu endianness */
- fc_host_port_id(shost) = phba->fc_myDID;
+ fc_host_port_id(shost) = vport->fc_myDID;
}
static void
lpfc_get_host_port_type(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
spin_lock_irq(shost->host_lock);
- if (phba->hba_state == LPFC_HBA_READY) {
+ if (vport->port_type == LPFC_NPIV_PORT) {
+ fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
+ } else if (lpfc_is_link_up(phba)) {
if (phba->fc_topology == TOPOLOGY_LOOP) {
- if (phba->fc_flag & FC_PUBLIC_LOOP)
+ if (vport->fc_flag & FC_PUBLIC_LOOP)
fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
else
fc_host_port_type(shost) = FC_PORTTYPE_LPORT;
} else {
- if (phba->fc_flag & FC_FABRIC)
+ if (vport->fc_flag & FC_FABRIC)
fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
else
fc_host_port_type(shost) = FC_PORTTYPE_PTP;
@@ -1504,29 +1785,20 @@
static void
lpfc_get_host_port_state(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
spin_lock_irq(shost->host_lock);
- if (phba->fc_flag & FC_OFFLINE_MODE)
+ if (vport->fc_flag & FC_OFFLINE_MODE)
fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
else {
- switch (phba->hba_state) {
- case LPFC_STATE_UNKNOWN:
- case LPFC_WARM_START:
- case LPFC_INIT_START:
- case LPFC_INIT_MBX_CMDS:
+ switch (phba->link_state) {
+ case LPFC_LINK_UNKNOWN:
case LPFC_LINK_DOWN:
fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;
break;
case LPFC_LINK_UP:
- case LPFC_LOCAL_CFG_LINK:
- case LPFC_FLOGI:
- case LPFC_FABRIC_CFG_LINK:
- case LPFC_NS_REG:
- case LPFC_NS_QRY:
- case LPFC_BUILD_DISC_LIST:
- case LPFC_DISC_AUTH:
case LPFC_CLEAR_LA:
case LPFC_HBA_READY:
/* Links up, beyond this port_type reports state */
@@ -1547,11 +1819,12 @@
static void
lpfc_get_host_speed(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
spin_lock_irq(shost->host_lock);
- if (phba->hba_state == LPFC_HBA_READY) {
+ if (lpfc_is_link_up(phba)) {
switch(phba->fc_linkspeed) {
case LA_1GHZ_LINK:
fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
@@ -1577,39 +1850,31 @@
static void
lpfc_get_host_fabric_name (struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
u64 node_name;
spin_lock_irq(shost->host_lock);
- if ((phba->fc_flag & FC_FABRIC) ||
+ if ((vport->fc_flag & FC_FABRIC) ||
((phba->fc_topology == TOPOLOGY_LOOP) &&
- (phba->fc_flag & FC_PUBLIC_LOOP)))
+ (vport->fc_flag & FC_PUBLIC_LOOP)))
node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn);
else
/* fabric is local port if there is no F/FL_Port */
- node_name = wwn_to_u64(phba->fc_nodename.u.wwn);
+ node_name = wwn_to_u64(vport->fc_nodename.u.wwn);
spin_unlock_irq(shost->host_lock);
fc_host_fabric_name(shost) = node_name;
}
-static void
-lpfc_get_host_symbolic_name (struct Scsi_Host *shost)
-{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
-
- spin_lock_irq(shost->host_lock);
- lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
- spin_unlock_irq(shost->host_lock);
-}
-
static struct fc_host_statistics *
lpfc_get_stats(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
- struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
struct fc_host_statistics *hs = &phba->link_stats;
struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets;
LPFC_MBOXQ_t *pmboxq;
@@ -1617,7 +1882,16 @@
unsigned long seconds;
int rc = 0;
- if (phba->fc_flag & FC_BLOCK_MGMT_IO)
+ /*
+ * prevent udev from issuing mailbox commands until the port is
+ * configured.
+ */
+ if (phba->link_state < LPFC_LINK_DOWN ||
+ !phba->mbox_mem_pool ||
+ (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0)
+ return NULL;
+
+ if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)
return NULL;
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -1629,17 +1903,16 @@
pmb->mbxCommand = MBX_READ_STATUS;
pmb->mbxOwner = OWN_HOST;
pmboxq->context1 = NULL;
+ pmboxq->vport = vport;
- if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
(!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
- if (rc == MBX_TIMEOUT)
- pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- else
+ if (rc != MBX_TIMEOUT)
mempool_free(pmboxq, phba->mbox_mem_pool);
return NULL;
}
@@ -1655,18 +1928,17 @@
pmb->mbxCommand = MBX_READ_LNK_STAT;
pmb->mbxOwner = OWN_HOST;
pmboxq->context1 = NULL;
+ pmboxq->vport = vport;
- if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
(!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
- if (rc == MBX_TIMEOUT)
- pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- else
- mempool_free( pmboxq, phba->mbox_mem_pool);
+ if (rc != MBX_TIMEOUT)
+ mempool_free(pmboxq, phba->mbox_mem_pool);
return NULL;
}
@@ -1713,14 +1985,15 @@
static void
lpfc_reset_stats(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
- struct lpfc_sli *psli = &phba->sli;
- struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_lnk_stat *lso = &psli->lnk_stat_offsets;
LPFC_MBOXQ_t *pmboxq;
MAILBOX_t *pmb;
int rc = 0;
- if (phba->fc_flag & FC_BLOCK_MGMT_IO)
+ if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)
return;
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -1733,17 +2006,16 @@
pmb->mbxOwner = OWN_HOST;
pmb->un.varWords[0] = 0x1; /* reset request */
pmboxq->context1 = NULL;
+ pmboxq->vport = vport;
- if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
(!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
- if (rc == MBX_TIMEOUT)
- pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- else
+ if (rc != MBX_TIMEOUT)
mempool_free(pmboxq, phba->mbox_mem_pool);
return;
}
@@ -1752,17 +2024,16 @@
pmb->mbxCommand = MBX_READ_LNK_STAT;
pmb->mbxOwner = OWN_HOST;
pmboxq->context1 = NULL;
+ pmboxq->vport = vport;
- if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
(!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
- if (rc == MBX_TIMEOUT)
- pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- else
+ if (rc != MBX_TIMEOUT)
mempool_free( pmboxq, phba->mbox_mem_pool);
return;
}
@@ -1791,13 +2062,13 @@
static struct lpfc_nodelist *
lpfc_get_node_by_target(struct scsi_target *starget)
{
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
- struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_nodelist *ndlp;
spin_lock_irq(shost->host_lock);
/* Search for this, mapped, target ID */
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
starget->id == ndlp->nlp_sid) {
spin_unlock_irq(shost->host_lock);
@@ -1887,8 +2158,66 @@
.get_host_fabric_name = lpfc_get_host_fabric_name,
.show_host_fabric_name = 1,
- .get_host_symbolic_name = lpfc_get_host_symbolic_name,
- .show_host_symbolic_name = 1,
+ /*
+ * The LPFC driver treats linkdown handling as target loss events
+ * so there are no sysfs handlers for link_down_tmo.
+ */
+
+ .get_fc_host_stats = lpfc_get_stats,
+ .reset_fc_host_stats = lpfc_reset_stats,
+
+ .dd_fcrport_size = sizeof(struct lpfc_rport_data),
+ .show_rport_maxframe_size = 1,
+ .show_rport_supported_classes = 1,
+
+ .set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo,
+ .show_rport_dev_loss_tmo = 1,
+
+ .get_starget_port_id = lpfc_get_starget_port_id,
+ .show_starget_port_id = 1,
+
+ .get_starget_node_name = lpfc_get_starget_node_name,
+ .show_starget_node_name = 1,
+
+ .get_starget_port_name = lpfc_get_starget_port_name,
+ .show_starget_port_name = 1,
+
+ .issue_fc_host_lip = lpfc_issue_lip,
+ .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
+ .terminate_rport_io = lpfc_terminate_rport_io,
+
+ .vport_create = lpfc_vport_create,
+ .vport_delete = lpfc_vport_delete,
+ .dd_fcvport_size = sizeof(struct lpfc_vport *),
+};
+
+struct fc_function_template lpfc_vport_transport_functions = {
+ /* fixed attributes the driver supports */
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+ .show_host_supported_fc4s = 1,
+ .show_host_supported_speeds = 1,
+ .show_host_maxframe_size = 1,
+
+ /* dynamic attributes the driver supports */
+ .get_host_port_id = lpfc_get_host_port_id,
+ .show_host_port_id = 1,
+
+ .get_host_port_type = lpfc_get_host_port_type,
+ .show_host_port_type = 1,
+
+ .get_host_port_state = lpfc_get_host_port_state,
+ .show_host_port_state = 1,
+
+ /* active_fc4s is shown but doesn't change (thus no get function) */
+ .show_host_active_fc4s = 1,
+
+ .get_host_speed = lpfc_get_host_speed,
+ .show_host_speed = 1,
+
+ .get_host_fabric_name = lpfc_get_host_fabric_name,
+ .show_host_fabric_name = 1,
/*
* The LPFC driver treats linkdown handling as target loss events
@@ -1917,6 +2246,8 @@
.issue_fc_host_lip = lpfc_issue_lip,
.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
.terminate_rport_io = lpfc_terminate_rport_io,
+
+ .vport_disable = lpfc_vport_disable,
};
void
@@ -1939,6 +2270,9 @@
lpfc_discovery_threads_init(phba, lpfc_discovery_threads);
lpfc_max_luns_init(phba, lpfc_max_luns);
lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
+ lpfc_peer_port_login_init(phba, lpfc_peer_port_login);
+ lpfc_npiv_enable_init(phba, lpfc_npiv_enable);
+ lpfc_vport_restrict_login_init(phba, lpfc_vport_restrict_login);
lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);
lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index b8c2a88..e19d1a7 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -23,92 +23,114 @@
struct fc_rport;
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
struct lpfc_dmabuf *mp);
void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport);
void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *, int);
void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_reg_login(struct lpfc_hba *, uint32_t, uint8_t *, LPFC_MBOXQ_t *,
- uint32_t);
-void lpfc_unreg_login(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *);
-void lpfc_unreg_did(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *);
+int lpfc_reg_login(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
+ LPFC_MBOXQ_t *, uint32_t);
+void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
+void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
+void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
+void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *);
void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
-
+void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove);
int lpfc_linkdown(struct lpfc_hba *);
void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
-void lpfc_dequeue_node(struct lpfc_hba *, struct lpfc_nodelist *);
-void lpfc_nlp_set_state(struct lpfc_hba *, struct lpfc_nodelist *, int);
-void lpfc_drop_node(struct lpfc_hba *, struct lpfc_nodelist *);
-void lpfc_set_disctmo(struct lpfc_hba *);
-int lpfc_can_disctmo(struct lpfc_hba *);
-int lpfc_unreg_rpi(struct lpfc_hba *, struct lpfc_nodelist *);
+void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *);
+void lpfc_nlp_set_state(struct lpfc_vport *, struct lpfc_nodelist *, int);
+void lpfc_drop_node(struct lpfc_vport *, struct lpfc_nodelist *);
+void lpfc_set_disctmo(struct lpfc_vport *);
+int lpfc_can_disctmo(struct lpfc_vport *);
+int lpfc_unreg_rpi(struct lpfc_vport *, struct lpfc_nodelist *);
+void lpfc_unreg_all_rpis(struct lpfc_vport *);
+void lpfc_unreg_default_rpis(struct lpfc_vport *);
+void lpfc_issue_reg_vpi(struct lpfc_hba *, struct lpfc_vport *);
+
int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
- struct lpfc_iocbq *, struct lpfc_nodelist *);
-void lpfc_nlp_init(struct lpfc_hba *, struct lpfc_nodelist *, uint32_t);
+ struct lpfc_iocbq *, struct lpfc_nodelist *);
+void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t);
struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
int lpfc_nlp_put(struct lpfc_nodelist *);
-struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_hba *, uint32_t);
-void lpfc_disc_list_loopmap(struct lpfc_hba *);
-void lpfc_disc_start(struct lpfc_hba *);
-void lpfc_disc_flush_list(struct lpfc_hba *);
+struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t);
+void lpfc_disc_list_loopmap(struct lpfc_vport *);
+void lpfc_disc_start(struct lpfc_vport *);
+void lpfc_disc_flush_list(struct lpfc_vport *);
+void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
void lpfc_disc_timeout(unsigned long);
-struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
-struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
+struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
+struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
+void lpfc_worker_wake_up(struct lpfc_hba *);
int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
int lpfc_do_work(void *);
-int lpfc_disc_state_machine(struct lpfc_hba *, struct lpfc_nodelist *, void *,
+int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *,
uint32_t);
-int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *,
- struct serv_parm *, uint32_t);
-int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp);
-int lpfc_els_abort_flogi(struct lpfc_hba *);
-int lpfc_initial_flogi(struct lpfc_hba *);
-int lpfc_issue_els_plogi(struct lpfc_hba *, uint32_t, uint8_t);
-int lpfc_issue_els_prli(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
-int lpfc_issue_els_adisc(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
-int lpfc_issue_els_logo(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
-int lpfc_issue_els_scr(struct lpfc_hba *, uint32_t, uint8_t);
-int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
-int lpfc_els_rsp_acc(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *,
- struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t);
-int lpfc_els_rsp_reject(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *,
+void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *,
struct lpfc_nodelist *);
-int lpfc_els_rsp_adisc_acc(struct lpfc_hba *, struct lpfc_iocbq *,
+void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
+int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
+ struct serv_parm *, uint32_t);
+int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
+int lpfc_els_chk_latt(struct lpfc_vport *);
+int lpfc_els_abort_flogi(struct lpfc_hba *);
+int lpfc_initial_flogi(struct lpfc_vport *);
+int lpfc_initial_fdisc(struct lpfc_vport *);
+int lpfc_issue_els_fdisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_plogi(struct lpfc_vport *, uint32_t, uint8_t);
+int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *);
+int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t);
+int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
+int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
+int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
+ struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t);
+int lpfc_els_rsp_reject(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
+ struct lpfc_nodelist *, LPFC_MBOXQ_t *);
+int lpfc_els_rsp_adisc_acc(struct lpfc_vport *, struct lpfc_iocbq *,
struct lpfc_nodelist *);
-int lpfc_els_rsp_prli_acc(struct lpfc_hba *, struct lpfc_iocbq *,
+int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
struct lpfc_nodelist *);
-void lpfc_cancel_retry_delay_tmo(struct lpfc_hba *, struct lpfc_nodelist *);
+void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *);
void lpfc_els_retry_delay(unsigned long);
void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
+void lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *);
void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
-int lpfc_els_handle_rscn(struct lpfc_hba *);
-int lpfc_els_flush_rscn(struct lpfc_hba *);
-int lpfc_rscn_payload_check(struct lpfc_hba *, uint32_t);
-void lpfc_els_flush_cmd(struct lpfc_hba *);
-int lpfc_els_disc_adisc(struct lpfc_hba *);
-int lpfc_els_disc_plogi(struct lpfc_hba *);
+int lpfc_els_handle_rscn(struct lpfc_vport *);
+void lpfc_els_flush_rscn(struct lpfc_vport *);
+int lpfc_rscn_payload_check(struct lpfc_vport *, uint32_t);
+void lpfc_els_flush_cmd(struct lpfc_vport *);
+int lpfc_els_disc_adisc(struct lpfc_vport *);
+int lpfc_els_disc_plogi(struct lpfc_vport *);
void lpfc_els_timeout(unsigned long);
-void lpfc_els_timeout_handler(struct lpfc_hba *);
+void lpfc_els_timeout_handler(struct lpfc_vport *);
+void lpfc_hb_timeout(unsigned long);
+void lpfc_hb_timeout_handler(struct lpfc_hba *);
void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
-int lpfc_ns_cmd(struct lpfc_hba *, struct lpfc_nodelist *, int);
-int lpfc_fdmi_cmd(struct lpfc_hba *, struct lpfc_nodelist *, int);
+int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
+int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
void lpfc_fdmi_tmo(unsigned long);
-void lpfc_fdmi_tmo_handler(struct lpfc_hba *);
+void lpfc_fdmi_timeout_handler(struct lpfc_vport *vport);
int lpfc_config_port_prep(struct lpfc_hba *);
int lpfc_config_port_post(struct lpfc_hba *);
@@ -136,16 +158,23 @@
void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
+void lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
+void lpfc_config_hbq(struct lpfc_hba *, struct lpfc_hbq_init *, uint32_t ,
+ LPFC_MBOXQ_t *);
+struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t);
+
int lpfc_mem_alloc(struct lpfc_hba *);
void lpfc_mem_free(struct lpfc_hba *);
+void lpfc_stop_vport_timers(struct lpfc_vport *);
void lpfc_poll_timeout(unsigned long ptr);
void lpfc_poll_start_timer(struct lpfc_hba * phba);
void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba);
struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
+void __lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
void lpfc_reset_barrier(struct lpfc_hba * phba);
@@ -154,6 +183,7 @@
int lpfc_sli_brdreset(struct lpfc_hba *);
int lpfc_sli_brdrestart(struct lpfc_hba *);
int lpfc_sli_hba_setup(struct lpfc_hba *);
+int lpfc_sli_host_down(struct lpfc_vport *);
int lpfc_sli_hba_down(struct lpfc_hba *);
int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
int lpfc_sli_handle_mb_event(struct lpfc_hba *);
@@ -164,27 +194,36 @@
int lpfc_sli_issue_iocb(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *, uint32_t);
void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t);
-int lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
+void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_dmabuf *);
struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
struct lpfc_sli_ring *,
dma_addr_t);
+int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t);
+int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t);
+void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *);
+struct hbq_dmabuf *lpfc_sli_hbqbuf_find(struct lpfc_hba *, uint32_t);
+int lpfc_sli_hbq_size(void);
int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
- uint64_t, lpfc_ctx_cmd);
+ uint64_t, lpfc_ctx_cmd);
int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
- uint64_t, uint32_t, lpfc_ctx_cmd);
+ uint64_t, uint32_t, lpfc_ctx_cmd);
void lpfc_mbox_timeout(unsigned long);
void lpfc_mbox_timeout_handler(struct lpfc_hba *);
-struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t);
-struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, struct lpfc_name *);
+struct lpfc_nodelist *__lpfc_find_node(struct lpfc_vport *, node_filter,
+ void *);
+struct lpfc_nodelist *lpfc_find_node(struct lpfc_vport *, node_filter, void *);
+struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t);
+struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *,
+ struct lpfc_name *);
int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
- uint32_t timeout);
+ uint32_t timeout);
int lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
struct lpfc_sli_ring * pring,
@@ -195,25 +234,56 @@
struct lpfc_iocbq * cmdiocb,
struct lpfc_iocbq * rspiocb);
+void *lpfc_hbq_alloc(struct lpfc_hba *, int, dma_addr_t *);
+void lpfc_hbq_free(struct lpfc_hba *, void *, dma_addr_t);
+void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *);
+
void *lpfc_mbuf_alloc(struct lpfc_hba *, int, dma_addr_t *);
+void __lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
+void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *);
/* Function prototypes. */
const char* lpfc_info(struct Scsi_Host *);
-void lpfc_scan_start(struct Scsi_Host *);
int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
void lpfc_get_cfgparam(struct lpfc_hba *);
-int lpfc_alloc_sysfs_attr(struct lpfc_hba *);
-void lpfc_free_sysfs_attr(struct lpfc_hba *);
-extern struct class_device_attribute *lpfc_host_attrs[];
+int lpfc_alloc_sysfs_attr(struct lpfc_vport *);
+void lpfc_free_sysfs_attr(struct lpfc_vport *);
+extern struct class_device_attribute *lpfc_hba_attrs[];
extern struct scsi_host_template lpfc_template;
extern struct fc_function_template lpfc_transport_functions;
+extern struct fc_function_template lpfc_vport_transport_functions;
+extern int lpfc_sli_mode;
-void lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp);
+int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
void lpfc_terminate_rport_io(struct fc_rport *);
void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport);
+struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct fc_vport *);
+int lpfc_vport_disable(struct fc_vport *fc_vport, bool disable);
+void lpfc_mbx_unreg_vpi(struct lpfc_vport *);
+void destroy_port(struct lpfc_vport *);
+int lpfc_get_instance(void);
+void lpfc_host_attrib_init(struct Scsi_Host *);
+
+extern void lpfc_debugfs_initialize(struct lpfc_vport *);
+extern void lpfc_debugfs_terminate(struct lpfc_vport *);
+extern void lpfc_debugfs_disc_trc(struct lpfc_vport *, int, char *, uint32_t,
+ uint32_t, uint32_t);
+
+/* Interface exported by fabric iocb scheduler */
+int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
+void lpfc_fabric_abort_vport(struct lpfc_vport *);
+void lpfc_fabric_abort_nport(struct lpfc_nodelist *);
+void lpfc_fabric_abort_hba(struct lpfc_hba *);
+void lpfc_fabric_abort_flogi(struct lpfc_hba *);
+void lpfc_fabric_block_timeout(unsigned long);
+void lpfc_unblock_fabric_iocbs(struct lpfc_hba *);
+void lpfc_adjust_queue_depth(struct lpfc_hba *);
+void lpfc_ramp_down_queue_handler(struct lpfc_hba *);
+void lpfc_ramp_up_queue_handler(struct lpfc_hba *);
+
#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
#define HBA_EVENT_RSCN 5
#define HBA_EVENT_LINK_UP 2
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 34a9e3b..ae9d6f38 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -40,6 +40,8 @@
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
#include "lpfc_version.h"
+#include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
#define HBA_PORTSPEED_UNKNOWN 0 /* Unknown - transceiver
* incapable of reporting */
@@ -58,25 +60,69 @@
/*
* lpfc_ct_unsol_event
*/
+static void
+lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+ struct lpfc_dmabuf *mp, uint32_t size)
+{
+ if (!mp) {
+ printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, "
+ "piocbq = %p, status = x%x, mp = %p, size = %d\n",
+ __FUNCTION__, __LINE__,
+ piocbq, piocbq->iocb.ulpStatus, mp, size);
+ }
+
+ printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, "
+ "buffer = %p, size = %d, status = x%x\n",
+ __FUNCTION__, __LINE__,
+ piocbq, mp, size,
+ piocbq->iocb.ulpStatus);
+
+}
+
+static void
+lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+ struct lpfc_dmabuf *mp, uint32_t size)
+{
+ if (!mp) {
+ printk(KERN_ERR "%s (%d): Unsolited CT, no "
+ "HBQ buffer, piocbq = %p, status = x%x\n",
+ __FUNCTION__, __LINE__,
+ piocbq, piocbq->iocb.ulpStatus);
+ } else {
+ lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
+ printk(KERN_ERR "%s (%d): Ignoring unsolicted CT "
+ "piocbq = %p, buffer = %p, size = %d, "
+ "status = x%x\n",
+ __FUNCTION__, __LINE__,
+ piocbq, mp, size, piocbq->iocb.ulpStatus);
+ }
+}
+
void
-lpfc_ct_unsol_event(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring, struct lpfc_iocbq * piocbq)
+lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocbq)
{
- struct lpfc_iocbq *next_piocbq;
- struct lpfc_dmabuf *pmbuf = NULL;
- struct lpfc_dmabuf *matp, *next_matp;
- uint32_t ctx = 0, size = 0, cnt = 0;
+ struct lpfc_dmabuf *mp = NULL;
IOCB_t *icmd = &piocbq->iocb;
- IOCB_t *save_icmd = icmd;
- int i, go_exit = 0;
- struct list_head head;
+ int i;
+ struct lpfc_iocbq *iocbq;
+ dma_addr_t paddr;
+ uint32_t size;
+ struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
+ struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
- if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+ piocbq->context2 = NULL;
+ piocbq->context3 = NULL;
+
+ if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
+ lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
+ } else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
/* Not enough posted buffers; Try posting more buffers */
phba->fc_stat.NoRcvBuf++;
- lpfc_post_buffer(phba, pring, 0, 1);
+ if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
+ lpfc_post_buffer(phba, pring, 0, 1);
return;
}
@@ -86,66 +132,56 @@
if (icmd->ulpBdeCount == 0)
return;
- INIT_LIST_HEAD(&head);
- list_add_tail(&head, &piocbq->list);
-
- list_for_each_entry_safe(piocbq, next_piocbq, &head, list) {
- icmd = &piocbq->iocb;
- if (ctx == 0)
- ctx = (uint32_t) (icmd->ulpContext);
- if (icmd->ulpBdeCount == 0)
- continue;
-
- for (i = 0; i < icmd->ulpBdeCount; i++) {
- matp = lpfc_sli_ringpostbuf_get(phba, pring,
- getPaddr(icmd->un.
- cont64[i].
- addrHigh,
- icmd->un.
- cont64[i].
- addrLow));
- if (!matp) {
- /* Insert lpfc log message here */
- lpfc_post_buffer(phba, pring, cnt, 1);
- go_exit = 1;
- goto ct_unsol_event_exit_piocbq;
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ list_for_each_entry(iocbq, &piocbq->list, list) {
+ icmd = &iocbq->iocb;
+ if (icmd->ulpBdeCount == 0) {
+ printk(KERN_ERR "%s (%d): Unsolited CT, no "
+ "BDE, iocbq = %p, status = x%x\n",
+ __FUNCTION__, __LINE__,
+ iocbq, iocbq->iocb.ulpStatus);
+ continue;
}
- /* Typically for Unsolicited CT requests */
- if (!pmbuf) {
- pmbuf = matp;
- INIT_LIST_HEAD(&pmbuf->list);
- } else
- list_add_tail(&matp->list, &pmbuf->list);
-
- size += icmd->un.cont64[i].tus.f.bdeSize;
- cnt++;
+ size = icmd->un.cont64[0].tus.f.bdeSize;
+ lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf1, size);
+ lpfc_in_buf_free(phba, bdeBuf1);
+ if (icmd->ulpBdeCount == 2) {
+ lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf2,
+ size);
+ lpfc_in_buf_free(phba, bdeBuf2);
+ }
}
+ } else {
+ struct lpfc_iocbq *next;
- icmd->ulpBdeCount = 0;
- }
+ list_for_each_entry_safe(iocbq, next, &piocbq->list, list) {
+ icmd = &iocbq->iocb;
+ if (icmd->ulpBdeCount == 0) {
+ printk(KERN_ERR "%s (%d): Unsolited CT, no "
+ "BDE, iocbq = %p, status = x%x\n",
+ __FUNCTION__, __LINE__,
+ iocbq, iocbq->iocb.ulpStatus);
+ continue;
+ }
- lpfc_post_buffer(phba, pring, cnt, 1);
- if (save_icmd->ulpStatus) {
- go_exit = 1;
- }
-
-ct_unsol_event_exit_piocbq:
- list_del(&head);
- if (pmbuf) {
- list_for_each_entry_safe(matp, next_matp, &pmbuf->list, list) {
- lpfc_mbuf_free(phba, matp->virt, matp->phys);
- list_del(&matp->list);
- kfree(matp);
+ for (i = 0; i < icmd->ulpBdeCount; i++) {
+ paddr = getPaddr(icmd->un.cont64[i].addrHigh,
+ icmd->un.cont64[i].addrLow);
+ mp = lpfc_sli_ringpostbuf_get(phba, pring,
+ paddr);
+ size = icmd->un.cont64[i].tus.f.bdeSize;
+ lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
+ lpfc_in_buf_free(phba, mp);
+ }
+ list_del(&iocbq->list);
+ lpfc_sli_release_iocbq(phba, iocbq);
}
- lpfc_mbuf_free(phba, pmbuf->virt, pmbuf->phys);
- kfree(pmbuf);
}
- return;
}
static void
-lpfc_free_ct_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mlist)
+lpfc_free_ct_rsp(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist)
{
struct lpfc_dmabuf *mlast, *next_mlast;
@@ -160,7 +196,7 @@
}
static struct lpfc_dmabuf *
-lpfc_alloc_ct_rsp(struct lpfc_hba * phba, int cmdcode, struct ulp_bde64 * bpl,
+lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
uint32_t size, int *entries)
{
struct lpfc_dmabuf *mlist = NULL;
@@ -181,7 +217,8 @@
INIT_LIST_HEAD(&mp->list);
- if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT))
+ if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT) ||
+ cmdcode == be16_to_cpu(SLI_CTNS_GFF_ID))
mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
else
mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys));
@@ -201,8 +238,8 @@
bpl->tus.f.bdeFlags = BUFF_USE_RCV;
/* build buffer ptr list for IOCB */
- bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) );
- bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) );
+ bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
+ bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
bpl->tus.f.bdeSize = (uint16_t) cnt;
bpl->tus.w = le32_to_cpu(bpl->tus.w);
bpl++;
@@ -215,24 +252,49 @@
return mlist;
}
+int
+lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
+{
+ struct lpfc_dmabuf *buf_ptr;
+
+ if (ctiocb->context1) {
+ buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1;
+ lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+ kfree(buf_ptr);
+ ctiocb->context1 = NULL;
+ }
+ if (ctiocb->context2) {
+ lpfc_free_ct_rsp(phba, (struct lpfc_dmabuf *) ctiocb->context2);
+ ctiocb->context2 = NULL;
+ }
+
+ if (ctiocb->context3) {
+ buf_ptr = (struct lpfc_dmabuf *) ctiocb->context3;
+ lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+ kfree(buf_ptr);
+ ctiocb->context1 = NULL;
+ }
+ lpfc_sli_release_iocbq(phba, ctiocb);
+ return 0;
+}
+
static int
-lpfc_gen_req(struct lpfc_hba *phba, struct lpfc_dmabuf *bmp,
+lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *),
struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry,
- uint32_t tmo)
+ uint32_t tmo, uint8_t retry)
{
-
- struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
IOCB_t *icmd;
struct lpfc_iocbq *geniocb;
+ int rc;
/* Allocate buffer for command iocb */
- spin_lock_irq(phba->host->host_lock);
geniocb = lpfc_sli_get_iocbq(phba);
- spin_unlock_irq(phba->host->host_lock);
if (geniocb == NULL)
return 1;
@@ -272,31 +334,40 @@
icmd->ulpClass = CLASS3;
icmd->ulpContext = ndlp->nlp_rpi;
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ /* For GEN_REQUEST64_CR, use the RPI */
+ icmd->ulpCt_h = 0;
+ icmd->ulpCt_l = 0;
+ }
+
/* Issue GEN REQ IOCB for NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0119 Issue GEN REQ IOCB for NPORT x%x "
- "Data: x%x x%x\n", phba->brd_no, icmd->un.ulpWord[5],
- icmd->ulpIoTag, phba->hba_state);
+ "%d (%d):0119 Issue GEN REQ IOCB to NPORT x%x "
+ "Data: x%x x%x\n", phba->brd_no, vport->vpi,
+ ndlp->nlp_DID, icmd->ulpIoTag,
+ vport->port_state);
geniocb->iocb_cmpl = cmpl;
geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT;
- spin_lock_irq(phba->host->host_lock);
- if (lpfc_sli_issue_iocb(phba, pring, geniocb, 0) == IOCB_ERROR) {
+ geniocb->vport = vport;
+ geniocb->retry = retry;
+ rc = lpfc_sli_issue_iocb(phba, pring, geniocb, 0);
+
+ if (rc == IOCB_ERROR) {
lpfc_sli_release_iocbq(phba, geniocb);
- spin_unlock_irq(phba->host->host_lock);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
return 0;
}
static int
-lpfc_ct_cmd(struct lpfc_hba *phba, struct lpfc_dmabuf *inmp,
+lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp,
void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *),
- uint32_t rsp_size)
+ uint32_t rsp_size, uint8_t retry)
{
+ struct lpfc_hba *phba = vport->phba;
struct ulp_bde64 *bpl = (struct ulp_bde64 *) bmp->virt;
struct lpfc_dmabuf *outmp;
int cnt = 0, status;
@@ -310,8 +381,8 @@
if (!outmp)
return -ENOMEM;
- status = lpfc_gen_req(phba, bmp, inmp, outmp, cmpl, ndlp, 0,
- cnt+1, 0);
+ status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0,
+ cnt+1, 0, retry);
if (status) {
lpfc_free_ct_rsp(phba, outmp);
return -ENOMEM;
@@ -319,20 +390,35 @@
return 0;
}
+static struct lpfc_vport *
+lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) {
+
+ struct lpfc_vport *vport_curr;
+
+ list_for_each_entry(vport_curr, &phba->port_list, listentry) {
+ if ((vport_curr->fc_myDID) &&
+ (vport_curr->fc_myDID == did))
+ return vport_curr;
+ }
+
+ return NULL;
+}
+
static int
-lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size)
+lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_sli_ct_request *Response =
(struct lpfc_sli_ct_request *) mp->virt;
struct lpfc_nodelist *ndlp = NULL;
struct lpfc_dmabuf *mlast, *next_mp;
uint32_t *ctptr = (uint32_t *) & Response->un.gid.PortType;
- uint32_t Did;
- uint32_t CTentry;
+ uint32_t Did, CTentry;
int Cnt;
struct list_head head;
- lpfc_set_disctmo(phba);
+ lpfc_set_disctmo(vport);
+ vport->num_disc_nodes = 0;
list_add_tail(&head, &mp->list);
@@ -350,39 +436,96 @@
/* Loop through entire NameServer list of DIDs */
while (Cnt >= sizeof (uint32_t)) {
-
/* Get next DID from NameServer List */
CTentry = *ctptr++;
Did = ((be32_to_cpu(CTentry)) & Mask_DID);
ndlp = NULL;
- if (Did != phba->fc_myDID) {
- /* Check for rscn processing or not */
- ndlp = lpfc_setup_disc_node(phba, Did);
- }
- /* Mark all node table entries that are in the
- Nameserver */
- if (ndlp) {
- /* NameServer Rsp */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0238 Process x%x NameServer"
- " Rsp Data: x%x x%x x%x\n",
- phba->brd_no,
- Did, ndlp->nlp_flag,
- phba->fc_flag,
- phba->fc_rscn_id_cnt);
- } else {
- /* NameServer Rsp */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0239 Skip x%x NameServer "
- "Rsp Data: x%x x%x x%x\n",
- phba->brd_no,
- Did, Size, phba->fc_flag,
- phba->fc_rscn_id_cnt);
- }
+ /*
+ * Check for rscn processing or not
+ * To conserve rpi's, filter out addresses for other
+ * vports on the same physical HBAs.
+ */
+ if ((Did != vport->fc_myDID) &&
+ ((lpfc_find_vport_by_did(phba, Did) == NULL) ||
+ phba->cfg_peer_port_login)) {
+ if ((vport->port_type != LPFC_NPIV_PORT) ||
+ (vport->fc_flag & FC_RFF_NOT_SUPPORTED) ||
+ (!phba->cfg_vport_restrict_login)) {
+ ndlp = lpfc_setup_disc_node(vport, Did);
+ if (ndlp) {
+ lpfc_debugfs_disc_trc(vport,
+ LPFC_DISC_TRC_CT,
+ "Parse GID_FTrsp: "
+ "did:x%x flg:x%x x%x",
+ Did, ndlp->nlp_flag,
+ vport->fc_flag);
+
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_DISCOVERY,
+ "%d (%d):0238 Process "
+ "x%x NameServer Rsp"
+ "Data: x%x x%x x%x\n",
+ phba->brd_no,
+ vport->vpi, Did,
+ ndlp->nlp_flag,
+ vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+ } else {
+ lpfc_debugfs_disc_trc(vport,
+ LPFC_DISC_TRC_CT,
+ "Skip1 GID_FTrsp: "
+ "did:x%x flg:x%x cnt:%d",
+ Did, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_DISCOVERY,
+ "%d (%d):0239 Skip x%x "
+ "NameServer Rsp Data: "
+ "x%x x%x\n",
+ phba->brd_no,
+ vport->vpi, Did,
+ vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+ }
+
+ } else {
+ if (!(vport->fc_flag & FC_RSCN_MODE) ||
+ (lpfc_rscn_payload_check(vport, Did))) {
+ lpfc_debugfs_disc_trc(vport,
+ LPFC_DISC_TRC_CT,
+ "Query GID_FTrsp: "
+ "did:x%x flg:x%x cnt:%d",
+ Did, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+
+ if (lpfc_ns_cmd(vport,
+ SLI_CTNS_GFF_ID,
+ 0, Did) == 0)
+ vport->num_disc_nodes++;
+ }
+ else {
+ lpfc_debugfs_disc_trc(vport,
+ LPFC_DISC_TRC_CT,
+ "Skip2 GID_FTrsp: "
+ "did:x%x flg:x%x cnt:%d",
+ Did, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_DISCOVERY,
+ "%d (%d):0245 Skip x%x "
+ "NameServer Rsp Data: "
+ "x%x x%x\n",
+ phba->brd_no,
+ vport->vpi, Did,
+ vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+ }
+ }
+ }
if (CTentry & (be32_to_cpu(SLI_CT_LAST_ENTRY)))
goto nsout1;
Cnt -= sizeof (uint32_t);
@@ -393,188 +536,367 @@
nsout1:
list_del(&head);
-
- /*
- * The driver has cycled through all Nports in the RSCN payload.
- * Complete the handling by cleaning up and marking the
- * current driver state.
- */
- if (phba->hba_state == LPFC_HBA_READY) {
- lpfc_els_flush_rscn(phba);
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_RSCN_MODE; /* we are still in RSCN mode */
- spin_unlock_irq(phba->host->host_lock);
- }
return 0;
}
-
-
-
static void
-lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp;
- struct lpfc_sli *psli;
struct lpfc_dmabuf *bmp;
- struct lpfc_dmabuf *inp;
struct lpfc_dmabuf *outp;
- struct lpfc_nodelist *ndlp;
struct lpfc_sli_ct_request *CTrsp;
+ int rc;
- psli = &phba->sli;
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
- inp = (struct lpfc_dmabuf *) cmdiocb->context1;
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
-
irsp = &rspiocb->iocb;
- if (irsp->ulpStatus) {
- if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
- (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) {
- goto out;
- }
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "GID_FT cmpl: status:x%x/x%x rtry:%d",
+ irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry);
+
+ /* Don't bother processing response if vport is being torn down. */
+ if (vport->load_flag & FC_UNLOADING)
+ goto out;
+
+
+ if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0216 Link event during NS query\n",
+ phba->brd_no, vport->vpi);
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ goto out;
+ }
+
+ if (irsp->ulpStatus) {
/* Check for retry */
- if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
- phba->fc_ns_retry++;
+ if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
+ if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
+ (irsp->un.ulpWord[4] != IOERR_NO_RESOURCES))
+ vport->fc_ns_retry++;
/* CT command is being retried */
- ndlp = lpfc_findnode_did(phba, NameServer_DID);
- if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
- if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) ==
- 0) {
- goto out;
- }
- }
+ rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
+ vport->fc_ns_retry, 0);
+ if (rc == 0)
+ goto out;
}
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0257 GID_FT Query error: 0x%x 0x%x\n",
+ phba->brd_no, vport->vpi, irsp->ulpStatus,
+ vport->fc_ns_retry);
} else {
/* Good status, continue checking */
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0208 NameServer Rsp "
+ "%d (%d):0208 NameServer Rsp "
"Data: x%x\n",
- phba->brd_no,
- phba->fc_flag);
- lpfc_ns_rsp(phba, outp,
+ phba->brd_no, vport->vpi,
+ vport->fc_flag);
+ lpfc_ns_rsp(vport, outp,
(uint32_t) (irsp->un.genreq64.bdl.bdeSize));
} else if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
/* NameServer Rsp Error */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0240 NameServer Rsp Error "
+ "%d (%d):0240 NameServer Rsp Error "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
CTrsp->CommandResponse.bits.CmdRsp,
(uint32_t) CTrsp->ReasonCode,
(uint32_t) CTrsp->Explanation,
- phba->fc_flag);
+ vport->fc_flag);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "GID_FT rsp err1 cmd:x%x rsn:x%x exp:x%x",
+ (uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
+ (uint32_t) CTrsp->ReasonCode,
+ (uint32_t) CTrsp->Explanation);
+
} else {
/* NameServer Rsp Error */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0241 NameServer Rsp Error "
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0241 NameServer Rsp Error "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
CTrsp->CommandResponse.bits.CmdRsp,
(uint32_t) CTrsp->ReasonCode,
(uint32_t) CTrsp->Explanation,
- phba->fc_flag);
+ vport->fc_flag);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "GID_FT rsp err2 cmd:x%x rsn:x%x exp:x%x",
+ (uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
+ (uint32_t) CTrsp->ReasonCode,
+ (uint32_t) CTrsp->Explanation);
}
}
/* Link up / RSCN discovery */
- lpfc_disc_start(phba);
+ if (vport->num_disc_nodes == 0) {
+ /*
+ * The driver has cycled through all Nports in the RSCN payload.
+ * Complete the handling by cleaning up and marking the
+ * current driver state.
+ */
+ if (vport->port_state >= LPFC_DISC_AUTH) {
+ if (vport->fc_flag & FC_RSCN_MODE) {
+ lpfc_els_flush_rscn(vport);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */
+ spin_unlock_irq(shost->host_lock);
+ }
+ else
+ lpfc_els_flush_rscn(vport);
+ }
+
+ lpfc_disc_start(vport);
+ }
out:
- lpfc_free_ct_rsp(phba, outp);
- lpfc_mbuf_free(phba, inp->virt, inp->phys);
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
- kfree(inp);
- kfree(bmp);
- spin_lock_irq(phba->host->host_lock);
- lpfc_sli_release_iocbq(phba, cmdiocb);
- spin_unlock_irq(phba->host->host_lock);
+ lpfc_ct_free_iocb(phba, cmdiocb);
return;
}
-static void
-lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+void
+lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
- struct lpfc_sli *psli;
- struct lpfc_dmabuf *bmp;
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1;
+ struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+ struct lpfc_sli_ct_request *CTrsp;
+ int did;
+ uint8_t fbits;
+ struct lpfc_nodelist *ndlp;
+
+ did = ((struct lpfc_sli_ct_request *) inp->virt)->un.gff.PortId;
+ did = be32_to_cpu(did);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "GFF_ID cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4], did);
+
+ if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+ /* Good status, continue checking */
+ CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+ fbits = CTrsp->un.gff_acc.fbits[FCP_TYPE_FEATURE_OFFSET];
+
+ if (CTrsp->CommandResponse.bits.CmdRsp ==
+ be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
+ if ((fbits & FC4_FEATURE_INIT) &&
+ !(fbits & FC4_FEATURE_TARGET)) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0245 Skip x%x GFF "
+ "NameServer Rsp Data: (init) "
+ "x%x x%x\n", phba->brd_no,
+ vport->vpi, did, fbits,
+ vport->fc_rscn_id_cnt);
+ goto out;
+ }
+ }
+ }
+ else {
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0267 NameServer GFF Rsp"
+ " x%x Error (%d %d) Data: x%x x%x\n",
+ phba->brd_no, vport->vpi, did,
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ vport->fc_flag, vport->fc_rscn_id_cnt)
+ }
+
+ /* This is a target port, unregistered port, or the GFF_ID failed */
+ ndlp = lpfc_setup_disc_node(vport, did);
+ if (ndlp) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0242 Process x%x GFF "
+ "NameServer Rsp Data: x%x x%x x%x\n",
+ phba->brd_no, vport->vpi,
+ did, ndlp->nlp_flag, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+ } else {
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0243 Skip x%x GFF "
+ "NameServer Rsp Data: x%x x%x\n",
+ phba->brd_no, vport->vpi, did,
+ vport->fc_flag, vport->fc_rscn_id_cnt);
+ }
+out:
+ /* Link up / RSCN discovery */
+ if (vport->num_disc_nodes)
+ vport->num_disc_nodes--;
+ if (vport->num_disc_nodes == 0) {
+ /*
+ * The driver has cycled through all Nports in the RSCN payload.
+ * Complete the handling by cleaning up and marking the
+ * current driver state.
+ */
+ if (vport->port_state >= LPFC_DISC_AUTH) {
+ if (vport->fc_flag & FC_RSCN_MODE) {
+ lpfc_els_flush_rscn(vport);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */
+ spin_unlock_irq(shost->host_lock);
+ }
+ else
+ lpfc_els_flush_rscn(vport);
+ }
+ lpfc_disc_start(vport);
+ }
+ lpfc_ct_free_iocb(phba, cmdiocb);
+ return;
+}
+
+
+static void
+lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
struct lpfc_dmabuf *inp;
struct lpfc_dmabuf *outp;
IOCB_t *irsp;
struct lpfc_sli_ct_request *CTrsp;
+ int cmdcode, rc;
+ uint8_t retry;
+ uint32_t latt;
- psli = &phba->sli;
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
inp = (struct lpfc_dmabuf *) cmdiocb->context1;
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
- bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
irsp = &rspiocb->iocb;
+ cmdcode = be16_to_cpu(((struct lpfc_sli_ct_request *) inp->virt)->
+ CommandResponse.bits.CmdRsp);
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+ latt = lpfc_els_chk_latt(vport);
+
/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0209 RFT request completes ulpStatus x%x "
- "CmdRsp x%x\n", phba->brd_no, irsp->ulpStatus,
- CTrsp->CommandResponse.bits.CmdRsp);
+ "%d (%d):0209 RFT request completes, latt %d, "
+ "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
+ phba->brd_no, vport->vpi, latt, irsp->ulpStatus,
+ CTrsp->CommandResponse.bits.CmdRsp,
+ cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag);
- lpfc_free_ct_rsp(phba, outp);
- lpfc_mbuf_free(phba, inp->virt, inp->phys);
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
- kfree(inp);
- kfree(bmp);
- spin_lock_irq(phba->host->host_lock);
- lpfc_sli_release_iocbq(phba, cmdiocb);
- spin_unlock_irq(phba->host->host_lock);
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "CT cmd cmpl: status:x%x/x%x cmd:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4], cmdcode);
+
+ if (irsp->ulpStatus) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0268 NS cmd %x Error (%d %d)\n",
+ phba->brd_no, vport->vpi, cmdcode,
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
+
+ if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+ ((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
+ (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)))
+ goto out;
+
+ retry = cmdiocb->retry;
+ if (retry >= LPFC_MAX_NS_RETRY)
+ goto out;
+
+ retry++;
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0216 Retrying NS cmd %x\n",
+ phba->brd_no, vport->vpi, cmdcode);
+ rc = lpfc_ns_cmd(vport, cmdcode, retry, 0);
+ if (rc == 0)
+ goto out;
+ }
+
+out:
+ lpfc_ct_free_iocb(phba, cmdiocb);
return;
}
static void
-lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
return;
}
static void
-lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
return;
}
static void
-lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
return;
}
-void
-lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp)
+static void
+lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_vport *vport = cmdiocb->vport;
+
+ if (irsp->ulpStatus != IOSTAT_SUCCESS)
+ vport->fc_flag |= FC_RFF_NOT_SUPPORTED;
+
+ lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+ return;
+}
+
+int
+lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol,
+ size_t size)
+{
+ int n;
+ uint8_t *wwn = vport->phba->wwpn;
+
+ n = snprintf(symbol, size,
+ "Emulex PPN-%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ wwn[0], wwn[1], wwn[2], wwn[3],
+ wwn[4], wwn[5], wwn[6], wwn[7]);
+
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ return n;
+
+ if (n < size)
+ n += snprintf(symbol + n, size - n, " VPort-%d", vport->vpi);
+
+ if (n < size && vport->vname)
+ n += snprintf(symbol + n, size - n, " VName-%s", vport->vname);
+ return n;
+}
+
+int
+lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
+ size_t size)
{
char fwrev[16];
+ int n;
- lpfc_decode_firmware_rev(phba, fwrev, 0);
+ lpfc_decode_firmware_rev(vport->phba, fwrev, 0);
- sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName,
- fwrev, lpfc_release_version);
- return;
+ n = snprintf(symbol, size, "Emulex %s FV%s DV%s",
+ vport->phba->ModelName, fwrev, lpfc_release_version);
+ return n;
}
/*
@@ -585,55 +907,76 @@
* LI_CTNS_RFT_ID
*/
int
-lpfc_ns_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
+lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
+ uint8_t retry, uint32_t context)
{
+ struct lpfc_nodelist * ndlp;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *mp, *bmp;
struct lpfc_sli_ct_request *CtReq;
struct ulp_bde64 *bpl;
void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *) = NULL;
uint32_t rsp_size = 1024;
+ size_t size;
+ int rc = 0;
+
+ ndlp = lpfc_findnode_did(vport, NameServer_DID);
+ if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) {
+ rc=1;
+ goto ns_cmd_exit;
+ }
/* fill in BDEs for command */
/* Allocate buffer for command payload */
mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
- if (!mp)
+ if (!mp) {
+ rc=2;
goto ns_cmd_exit;
+ }
INIT_LIST_HEAD(&mp->list);
mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
- if (!mp->virt)
+ if (!mp->virt) {
+ rc=3;
goto ns_cmd_free_mp;
+ }
/* Allocate buffer for Buffer ptr list */
bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
- if (!bmp)
+ if (!bmp) {
+ rc=4;
goto ns_cmd_free_mpvirt;
+ }
INIT_LIST_HEAD(&bmp->list);
bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(bmp->phys));
- if (!bmp->virt)
+ if (!bmp->virt) {
+ rc=5;
goto ns_cmd_free_bmp;
+ }
/* NameServer Req */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0236 NameServer Req Data: x%x x%x x%x\n",
- phba->brd_no, cmdcode, phba->fc_flag,
- phba->fc_rscn_id_cnt);
+ lpfc_printf_log(phba, KERN_INFO ,LOG_DISCOVERY,
+ "%d (%d):0236 NameServer Req Data: x%x x%x x%x\n",
+ phba->brd_no, vport->vpi, cmdcode, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
bpl = (struct ulp_bde64 *) bmp->virt;
memset(bpl, 0, sizeof(struct ulp_bde64));
- bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) );
- bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) );
+ bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
+ bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
bpl->tus.f.bdeFlags = 0;
if (cmdcode == SLI_CTNS_GID_FT)
bpl->tus.f.bdeSize = GID_REQUEST_SZ;
+ else if (cmdcode == SLI_CTNS_GFF_ID)
+ bpl->tus.f.bdeSize = GFF_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RFT_ID)
bpl->tus.f.bdeSize = RFT_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RNN_ID)
bpl->tus.f.bdeSize = RNN_REQUEST_SZ;
+ else if (cmdcode == SLI_CTNS_RSPN_ID)
+ bpl->tus.f.bdeSize = RSPN_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RSNN_NN)
bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RFF_ID)
@@ -654,56 +997,78 @@
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_GID_FT);
CtReq->un.gid.Fc4Type = SLI_CTPT_FCP;
- if (phba->hba_state < LPFC_HBA_READY)
- phba->hba_state = LPFC_NS_QRY;
- lpfc_set_disctmo(phba);
+ if (vport->port_state < LPFC_NS_QRY)
+ vport->port_state = LPFC_NS_QRY;
+ lpfc_set_disctmo(vport);
cmpl = lpfc_cmpl_ct_cmd_gid_ft;
rsp_size = FC_MAX_NS_RSP;
break;
+ case SLI_CTNS_GFF_ID:
+ CtReq->CommandResponse.bits.CmdRsp =
+ be16_to_cpu(SLI_CTNS_GFF_ID);
+ CtReq->un.gff.PortId = be32_to_cpu(context);
+ cmpl = lpfc_cmpl_ct_cmd_gff_id;
+ break;
+
case SLI_CTNS_RFT_ID:
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_RFT_ID);
- CtReq->un.rft.PortId = be32_to_cpu(phba->fc_myDID);
+ CtReq->un.rft.PortId = be32_to_cpu(vport->fc_myDID);
CtReq->un.rft.fcpReg = 1;
cmpl = lpfc_cmpl_ct_cmd_rft_id;
break;
- case SLI_CTNS_RFF_ID:
- CtReq->CommandResponse.bits.CmdRsp =
- be16_to_cpu(SLI_CTNS_RFF_ID);
- CtReq->un.rff.PortId = be32_to_cpu(phba->fc_myDID);
- CtReq->un.rff.feature_res = 0;
- CtReq->un.rff.feature_tgt = 0;
- CtReq->un.rff.type_code = FC_FCP_DATA;
- CtReq->un.rff.feature_init = 1;
- cmpl = lpfc_cmpl_ct_cmd_rff_id;
- break;
-
case SLI_CTNS_RNN_ID:
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_RNN_ID);
- CtReq->un.rnn.PortId = be32_to_cpu(phba->fc_myDID);
- memcpy(CtReq->un.rnn.wwnn, &phba->fc_nodename,
+ CtReq->un.rnn.PortId = be32_to_cpu(vport->fc_myDID);
+ memcpy(CtReq->un.rnn.wwnn, &vport->fc_nodename,
sizeof (struct lpfc_name));
cmpl = lpfc_cmpl_ct_cmd_rnn_id;
break;
+ case SLI_CTNS_RSPN_ID:
+ CtReq->CommandResponse.bits.CmdRsp =
+ be16_to_cpu(SLI_CTNS_RSPN_ID);
+ CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID);
+ size = sizeof(CtReq->un.rspn.symbname);
+ CtReq->un.rspn.len =
+ lpfc_vport_symbolic_port_name(vport,
+ CtReq->un.rspn.symbname, size);
+ cmpl = lpfc_cmpl_ct_cmd_rspn_id;
+ break;
case SLI_CTNS_RSNN_NN:
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_RSNN_NN);
- memcpy(CtReq->un.rsnn.wwnn, &phba->fc_nodename,
+ memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
sizeof (struct lpfc_name));
- lpfc_get_hba_sym_node_name(phba, CtReq->un.rsnn.symbname);
- CtReq->un.rsnn.len = strlen(CtReq->un.rsnn.symbname);
+ size = sizeof(CtReq->un.rsnn.symbname);
+ CtReq->un.rsnn.len =
+ lpfc_vport_symbolic_node_name(vport,
+ CtReq->un.rsnn.symbname, size);
cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
break;
+ case SLI_CTNS_RFF_ID:
+ vport->fc_flag &= ~FC_RFF_NOT_SUPPORTED;
+ CtReq->CommandResponse.bits.CmdRsp =
+ be16_to_cpu(SLI_CTNS_RFF_ID);
+ CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);;
+ CtReq->un.rff.fbits = FC4_FEATURE_INIT;
+ CtReq->un.rff.type_code = FC_FCP_DATA;
+ cmpl = lpfc_cmpl_ct_cmd_rff_id;
+ break;
}
- if (!lpfc_ct_cmd(phba, mp, bmp, ndlp, cmpl, rsp_size))
+ if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) {
/* On success, The cmpl function will free the buffers */
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "Issue CT cmd: cmd:x%x did:x%x",
+ cmdcode, ndlp->nlp_DID, 0);
return 0;
+ }
+ rc=6;
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
ns_cmd_free_bmp:
kfree(bmp);
@@ -712,14 +1077,17 @@
ns_cmd_free_mp:
kfree(mp);
ns_cmd_exit:
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0266 Issue NameServer Req x%x err %d Data: x%x x%x\n",
+ phba->brd_no, vport->vpi, cmdcode, rc, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
return 1;
}
static void
-lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq * rspiocb)
{
- struct lpfc_dmabuf *bmp = cmdiocb->context3;
struct lpfc_dmabuf *inp = cmdiocb->context1;
struct lpfc_dmabuf *outp = cmdiocb->context2;
struct lpfc_sli_ct_request *CTrsp = outp->virt;
@@ -727,48 +1095,60 @@
struct lpfc_nodelist *ndlp;
uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
+ struct lpfc_vport *vport = cmdiocb->vport;
+ IOCB_t *irsp = &rspiocb->iocb;
+ uint32_t latt;
- ndlp = lpfc_findnode_did(phba, FDMI_DID);
+ latt = lpfc_els_chk_latt(vport);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "FDMI cmpl: status:x%x/x%x latt:%d",
+ irsp->ulpStatus, irsp->un.ulpWord[4], latt);
+
+ if (latt || irsp->ulpStatus) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0229 FDMI cmd %04x failed, latt = %d "
+ "ulpStatus: x%x, rid x%x\n",
+ phba->brd_no, vport->vpi,
+ be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
+ lpfc_ct_free_iocb(phba, cmdiocb);
+ return;
+ }
+
+ ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
/* FDMI rsp failed */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0220 FDMI rsp failed Data: x%x\n",
- phba->brd_no,
- be16_to_cpu(fdmi_cmd));
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0220 FDMI rsp failed Data: x%x\n",
+ phba->brd_no, vport->vpi,
+ be16_to_cpu(fdmi_cmd));
}
switch (be16_to_cpu(fdmi_cmd)) {
case SLI_MGMT_RHBA:
- lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_RPA);
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA);
break;
case SLI_MGMT_RPA:
break;
case SLI_MGMT_DHBA:
- lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DPRT);
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT);
break;
case SLI_MGMT_DPRT:
- lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_RHBA);
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
break;
}
-
- lpfc_free_ct_rsp(phba, outp);
- lpfc_mbuf_free(phba, inp->virt, inp->phys);
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
- kfree(inp);
- kfree(bmp);
- spin_lock_irq(phba->host->host_lock);
- lpfc_sli_release_iocbq(phba, cmdiocb);
- spin_unlock_irq(phba->host->host_lock);
+ lpfc_ct_free_iocb(phba, cmdiocb);
return;
}
+
int
-lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
+lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *mp, *bmp;
struct lpfc_sli_ct_request *CtReq;
struct ulp_bde64 *bpl;
@@ -805,12 +1185,10 @@
INIT_LIST_HEAD(&bmp->list);
/* FDMI request */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0218 FDMI Request Data: x%x x%x x%x\n",
- phba->brd_no,
- phba->fc_flag, phba->hba_state, cmdcode);
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0218 FDMI Request Data: x%x x%x x%x\n",
+ phba->brd_no, vport->vpi, vport->fc_flag,
+ vport->port_state, cmdcode);
CtReq = (struct lpfc_sli_ct_request *) mp->virt;
@@ -833,11 +1211,11 @@
be16_to_cpu(SLI_MGMT_RHBA);
CtReq->CommandResponse.bits.Size = 0;
rh = (REG_HBA *) & CtReq->un.PortID;
- memcpy(&rh->hi.PortName, &phba->fc_sparam.portName,
+ memcpy(&rh->hi.PortName, &vport->fc_sparam.portName,
sizeof (struct lpfc_name));
/* One entry (port) per adapter */
rh->rpl.EntryCnt = be32_to_cpu(1);
- memcpy(&rh->rpl.pe, &phba->fc_sparam.portName,
+ memcpy(&rh->rpl.pe, &vport->fc_sparam.portName,
sizeof (struct lpfc_name));
/* point to the HBA attribute block */
@@ -853,7 +1231,7 @@
ae->ad.bits.AttrType = be16_to_cpu(NODE_NAME);
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES
+ sizeof (struct lpfc_name));
- memcpy(&ae->un.NodeName, &phba->fc_sparam.nodeName,
+ memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
sizeof (struct lpfc_name));
ab->EntryCnt++;
size += FOURBYTES + sizeof (struct lpfc_name);
@@ -991,7 +1369,7 @@
pab = (REG_PORT_ATTRIBUTE *) & CtReq->un.PortID;
size = sizeof (struct lpfc_name) + FOURBYTES;
memcpy((uint8_t *) & pab->PortName,
- (uint8_t *) & phba->fc_sparam.portName,
+ (uint8_t *) & vport->fc_sparam.portName,
sizeof (struct lpfc_name));
pab->ab.EntryCnt = 0;
@@ -1053,7 +1431,7 @@
ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
ae->ad.bits.AttrType = be16_to_cpu(MAX_FRAME_SIZE);
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
- hsp = (struct serv_parm *) & phba->fc_sparam;
+ hsp = (struct serv_parm *) & vport->fc_sparam;
ae->un.MaxFrameSize =
(((uint32_t) hsp->cmn.
bbRcvSizeMsb) << 8) | (uint32_t) hsp->cmn.
@@ -1097,7 +1475,7 @@
CtReq->CommandResponse.bits.Size = 0;
pe = (PORT_ENTRY *) & CtReq->un.PortID;
memcpy((uint8_t *) & pe->PortName,
- (uint8_t *) & phba->fc_sparam.portName,
+ (uint8_t *) & vport->fc_sparam.portName,
sizeof (struct lpfc_name));
size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name);
break;
@@ -1107,22 +1485,22 @@
CtReq->CommandResponse.bits.Size = 0;
pe = (PORT_ENTRY *) & CtReq->un.PortID;
memcpy((uint8_t *) & pe->PortName,
- (uint8_t *) & phba->fc_sparam.portName,
+ (uint8_t *) & vport->fc_sparam.portName,
sizeof (struct lpfc_name));
size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name);
break;
}
bpl = (struct ulp_bde64 *) bmp->virt;
- bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) );
- bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) );
+ bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
+ bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
bpl->tus.f.bdeFlags = 0;
bpl->tus.f.bdeSize = size;
bpl->tus.w = le32_to_cpu(bpl->tus.w);
cmpl = lpfc_cmpl_ct_cmd_fdmi;
- if (!lpfc_ct_cmd(phba, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP))
+ if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0))
return 0;
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
@@ -1134,49 +1512,50 @@
kfree(mp);
fdmi_cmd_exit:
/* Issue FDMI request failed */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0244 Issue FDMI request failed Data: x%x\n",
- phba->brd_no,
- cmdcode);
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0244 Issue FDMI request failed Data: x%x\n",
+ phba->brd_no, vport->vpi, cmdcode);
return 1;
}
void
lpfc_fdmi_tmo(unsigned long ptr)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
+ struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
+ struct lpfc_hba *phba = vport->phba;
unsigned long iflag;
- spin_lock_irqsave(phba->host->host_lock, iflag);
- if (!(phba->work_hba_events & WORKER_FDMI_TMO)) {
- phba->work_hba_events |= WORKER_FDMI_TMO;
+ spin_lock_irqsave(&vport->work_port_lock, iflag);
+ if (!(vport->work_port_events & WORKER_FDMI_TMO)) {
+ vport->work_port_events |= WORKER_FDMI_TMO;
+ spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+
+ spin_lock_irqsave(&phba->hbalock, iflag);
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
}
- spin_unlock_irqrestore(phba->host->host_lock,iflag);
+ else
+ spin_unlock_irqrestore(&vport->work_port_lock, iflag);
}
void
-lpfc_fdmi_tmo_handler(struct lpfc_hba *phba)
+lpfc_fdmi_timeout_handler(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp;
- ndlp = lpfc_findnode_did(phba, FDMI_DID);
+ ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (ndlp) {
- if (init_utsname()->nodename[0] != '\0') {
- lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
- } else {
- mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
- }
+ if (init_utsname()->nodename[0] != '\0')
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
+ else
+ mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60);
}
return;
}
-
void
-lpfc_decode_firmware_rev(struct lpfc_hba * phba, char *fwrevision, int flag)
+lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
{
struct lpfc_sli *psli = &phba->sli;
lpfc_vpd_t *vp = &phba->vpd;
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
new file mode 100644
index 0000000..673cfe1
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -0,0 +1,508 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for *
+ * Fibre Channel Host Bus Adapters. *
+ * Copyright (C) 2007 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *******************************************************************/
+
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+#include <linux/version.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
+#include "lpfc_version.h"
+#include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
+
+#ifdef CONFIG_LPFC_DEBUG_FS
+/* debugfs interface
+ *
+ * To access this interface the user should:
+ * # mkdir /debug
+ * # mount -t debugfs none /debug
+ *
+ * The lpfc debugfs directory hierachy is:
+ * lpfc/lpfcX/vportY
+ * where X is the lpfc hba unique_id
+ * where Y is the vport VPI on that hba
+ *
+ * Debugging services available per vport:
+ * discovery_trace
+ * This is an ACSII readable file that contains a trace of the last
+ * lpfc_debugfs_max_disc_trc events that happened on a specific vport.
+ * See lpfc_debugfs.h for different categories of
+ * discovery events. To enable the discovery trace, the following
+ * module parameters must be set:
+ * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support
+ * lpfc_debugfs_max_disc_trc=X Where X is the event trace depth for
+ * EACH vport. X MUST also be a power of 2.
+ * lpfc_debugfs_mask_disc_trc=Y Where Y is an event mask as defined in
+ * lpfc_debugfs.h .
+ */
+static int lpfc_debugfs_enable = 0;
+module_param(lpfc_debugfs_enable, int, 0);
+MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
+
+static int lpfc_debugfs_max_disc_trc = 0; /* This MUST be a power of 2 */
+module_param(lpfc_debugfs_max_disc_trc, int, 0);
+MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
+ "Set debugfs discovery trace depth");
+
+static int lpfc_debugfs_mask_disc_trc = 0;
+module_param(lpfc_debugfs_mask_disc_trc, int, 0);
+MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
+ "Set debugfs discovery trace mask");
+
+#include <linux/debugfs.h>
+
+/* size of discovery_trace output line */
+#define LPFC_DISC_TRC_ENTRY_SIZE 80
+
+/* nodelist output buffer size */
+#define LPFC_NODELIST_SIZE 8192
+#define LPFC_NODELIST_ENTRY_SIZE 120
+
+struct lpfc_debug {
+ char *buffer;
+ int len;
+};
+
+atomic_t lpfc_debugfs_disc_trc_cnt = ATOMIC_INIT(0);
+unsigned long lpfc_debugfs_start_time = 0L;
+
+static int
+lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
+{
+ int i, index, len, enable;
+ uint32_t ms;
+ struct lpfc_disc_trc *dtp;
+ char buffer[80];
+
+
+ enable = lpfc_debugfs_enable;
+ lpfc_debugfs_enable = 0;
+
+ len = 0;
+ index = (atomic_read(&vport->disc_trc_cnt) + 1) &
+ (lpfc_debugfs_max_disc_trc - 1);
+ for (i = index; i < lpfc_debugfs_max_disc_trc; i++) {
+ dtp = vport->disc_trc + i;
+ if (!dtp->fmt)
+ continue;
+ ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
+ snprintf(buffer, 80, "%010d:%010d ms:%s\n",
+ dtp->seq_cnt, ms, dtp->fmt);
+ len += snprintf(buf+len, size-len, buffer,
+ dtp->data1, dtp->data2, dtp->data3);
+ }
+ for (i = 0; i < index; i++) {
+ dtp = vport->disc_trc + i;
+ if (!dtp->fmt)
+ continue;
+ ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
+ snprintf(buffer, 80, "%010d:%010d ms:%s\n",
+ dtp->seq_cnt, ms, dtp->fmt);
+ len += snprintf(buf+len, size-len, buffer,
+ dtp->data1, dtp->data2, dtp->data3);
+ }
+
+ lpfc_debugfs_enable = enable;
+ return len;
+}
+
+static int
+lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
+{
+ int len = 0;
+ int cnt;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_nodelist *ndlp;
+ unsigned char *statep, *name;
+
+ cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE);
+
+ spin_lock_irq(shost->host_lock);
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+ if (!cnt) {
+ len += snprintf(buf+len, size-len,
+ "Missing Nodelist Entries\n");
+ break;
+ }
+ cnt--;
+ switch (ndlp->nlp_state) {
+ case NLP_STE_UNUSED_NODE:
+ statep = "UNUSED";
+ break;
+ case NLP_STE_PLOGI_ISSUE:
+ statep = "PLOGI ";
+ break;
+ case NLP_STE_ADISC_ISSUE:
+ statep = "ADISC ";
+ break;
+ case NLP_STE_REG_LOGIN_ISSUE:
+ statep = "REGLOG";
+ break;
+ case NLP_STE_PRLI_ISSUE:
+ statep = "PRLI ";
+ break;
+ case NLP_STE_UNMAPPED_NODE:
+ statep = "UNMAP ";
+ break;
+ case NLP_STE_MAPPED_NODE:
+ statep = "MAPPED";
+ break;
+ case NLP_STE_NPR_NODE:
+ statep = "NPR ";
+ break;
+ default:
+ statep = "UNKNOWN";
+ }
+ len += snprintf(buf+len, size-len, "%s DID:x%06x ",
+ statep, ndlp->nlp_DID);
+ name = (unsigned char *)&ndlp->nlp_portname;
+ len += snprintf(buf+len, size-len,
+ "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ",
+ *name, *(name+1), *(name+2), *(name+3),
+ *(name+4), *(name+5), *(name+6), *(name+7));
+ name = (unsigned char *)&ndlp->nlp_nodename;
+ len += snprintf(buf+len, size-len,
+ "WWNN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ",
+ *name, *(name+1), *(name+2), *(name+3),
+ *(name+4), *(name+5), *(name+6), *(name+7));
+ len += snprintf(buf+len, size-len, "RPI:%03d flag:x%08x ",
+ ndlp->nlp_rpi, ndlp->nlp_flag);
+ if (!ndlp->nlp_type)
+ len += snprintf(buf+len, size-len, "UNKNOWN_TYPE");
+ if (ndlp->nlp_type & NLP_FC_NODE)
+ len += snprintf(buf+len, size-len, "FC_NODE ");
+ if (ndlp->nlp_type & NLP_FABRIC)
+ len += snprintf(buf+len, size-len, "FABRIC ");
+ if (ndlp->nlp_type & NLP_FCP_TARGET)
+ len += snprintf(buf+len, size-len, "FCP_TGT sid:%d ",
+ ndlp->nlp_sid);
+ if (ndlp->nlp_type & NLP_FCP_INITIATOR)
+ len += snprintf(buf+len, size-len, "FCP_INITIATOR");
+ len += snprintf(buf+len, size-len, "\n");
+ }
+ spin_unlock_irq(shost->host_lock);
+ return len;
+}
+#endif
+
+
+inline void
+lpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt,
+ uint32_t data1, uint32_t data2, uint32_t data3)
+{
+#ifdef CONFIG_LPFC_DEBUG_FS
+ struct lpfc_disc_trc *dtp;
+ int index;
+
+ if (!(lpfc_debugfs_mask_disc_trc & mask))
+ return;
+
+ if (!lpfc_debugfs_enable || !lpfc_debugfs_max_disc_trc ||
+ !vport || !vport->disc_trc)
+ return;
+
+ index = atomic_inc_return(&vport->disc_trc_cnt) &
+ (lpfc_debugfs_max_disc_trc - 1);
+ dtp = vport->disc_trc + index;
+ dtp->fmt = fmt;
+ dtp->data1 = data1;
+ dtp->data2 = data2;
+ dtp->data3 = data3;
+ dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_disc_trc_cnt);
+ dtp->jif = jiffies;
+#endif
+ return;
+}
+
+#ifdef CONFIG_LPFC_DEBUG_FS
+static int
+lpfc_debugfs_disc_trc_open(struct inode *inode, struct file *file)
+{
+ struct lpfc_vport *vport = inode->i_private;
+ struct lpfc_debug *debug;
+ int size;
+ int rc = -ENOMEM;
+
+ if (!lpfc_debugfs_max_disc_trc) {
+ rc = -ENOSPC;
+ goto out;
+ }
+
+ debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+ if (!debug)
+ goto out;
+
+ /* Round to page boundry */
+ size = (lpfc_debugfs_max_disc_trc * LPFC_DISC_TRC_ENTRY_SIZE);
+ size = PAGE_ALIGN(size);
+
+ debug->buffer = kmalloc(size, GFP_KERNEL);
+ if (!debug->buffer) {
+ kfree(debug);
+ goto out;
+ }
+
+ debug->len = lpfc_debugfs_disc_trc_data(vport, debug->buffer, size);
+ file->private_data = debug;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static int
+lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file)
+{
+ struct lpfc_vport *vport = inode->i_private;
+ struct lpfc_debug *debug;
+ int rc = -ENOMEM;
+
+ debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+ if (!debug)
+ goto out;
+
+ /* Round to page boundry */
+ debug->buffer = kmalloc(LPFC_NODELIST_SIZE, GFP_KERNEL);
+ if (!debug->buffer) {
+ kfree(debug);
+ goto out;
+ }
+
+ debug->len = lpfc_debugfs_nodelist_data(vport, debug->buffer,
+ LPFC_NODELIST_SIZE);
+ file->private_data = debug;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static loff_t
+lpfc_debugfs_lseek(struct file *file, loff_t off, int whence)
+{
+ struct lpfc_debug *debug;
+ loff_t pos = -1;
+
+ debug = file->private_data;
+
+ switch (whence) {
+ case 0:
+ pos = off;
+ break;
+ case 1:
+ pos = file->f_pos + off;
+ break;
+ case 2:
+ pos = debug->len - off;
+ }
+ return (pos < 0 || pos > debug->len) ? -EINVAL : (file->f_pos = pos);
+}
+
+static ssize_t
+lpfc_debugfs_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct lpfc_debug *debug = file->private_data;
+ return simple_read_from_buffer(buf, nbytes, ppos, debug->buffer,
+ debug->len);
+}
+
+static int
+lpfc_debugfs_release(struct inode *inode, struct file *file)
+{
+ struct lpfc_debug *debug = file->private_data;
+
+ kfree(debug->buffer);
+ kfree(debug);
+
+ return 0;
+}
+
+#undef lpfc_debugfs_op_disc_trc
+static struct file_operations lpfc_debugfs_op_disc_trc = {
+ .owner = THIS_MODULE,
+ .open = lpfc_debugfs_disc_trc_open,
+ .llseek = lpfc_debugfs_lseek,
+ .read = lpfc_debugfs_read,
+ .release = lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_nodelist
+static struct file_operations lpfc_debugfs_op_nodelist = {
+ .owner = THIS_MODULE,
+ .open = lpfc_debugfs_nodelist_open,
+ .llseek = lpfc_debugfs_lseek,
+ .read = lpfc_debugfs_read,
+ .release = lpfc_debugfs_release,
+};
+
+static struct dentry *lpfc_debugfs_root = NULL;
+static atomic_t lpfc_debugfs_hba_count;
+#endif
+
+inline void
+lpfc_debugfs_initialize(struct lpfc_vport *vport)
+{
+#ifdef CONFIG_LPFC_DEBUG_FS
+ struct lpfc_hba *phba = vport->phba;
+ char name[64];
+ uint32_t num, i;
+
+ if (!lpfc_debugfs_enable)
+ return;
+
+ if (lpfc_debugfs_max_disc_trc) {
+ num = lpfc_debugfs_max_disc_trc - 1;
+ if (num & lpfc_debugfs_max_disc_trc) {
+ /* Change to be a power of 2 */
+ num = lpfc_debugfs_max_disc_trc;
+ i = 0;
+ while (num > 1) {
+ num = num >> 1;
+ i++;
+ }
+ lpfc_debugfs_max_disc_trc = (1 << i);
+ printk(KERN_ERR
+ "lpfc_debugfs_max_disc_trc changed to %d\n",
+ lpfc_debugfs_max_disc_trc);
+ }
+ }
+
+ if (!lpfc_debugfs_root) {
+ lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL);
+ atomic_set(&lpfc_debugfs_hba_count, 0);
+ if (!lpfc_debugfs_root)
+ goto debug_failed;
+ }
+
+ snprintf(name, sizeof(name), "lpfc%d", phba->brd_no);
+ if (!phba->hba_debugfs_root) {
+ phba->hba_debugfs_root =
+ debugfs_create_dir(name, lpfc_debugfs_root);
+ if (!phba->hba_debugfs_root)
+ goto debug_failed;
+ atomic_inc(&lpfc_debugfs_hba_count);
+ atomic_set(&phba->debugfs_vport_count, 0);
+ }
+
+ snprintf(name, sizeof(name), "vport%d", vport->vpi);
+ if (!vport->vport_debugfs_root) {
+ vport->vport_debugfs_root =
+ debugfs_create_dir(name, phba->hba_debugfs_root);
+ if (!vport->vport_debugfs_root)
+ goto debug_failed;
+ atomic_inc(&phba->debugfs_vport_count);
+ }
+
+ if (!lpfc_debugfs_start_time)
+ lpfc_debugfs_start_time = jiffies;
+
+ vport->disc_trc = kmalloc(
+ (sizeof(struct lpfc_disc_trc) * lpfc_debugfs_max_disc_trc),
+ GFP_KERNEL);
+
+ if (!vport->disc_trc)
+ goto debug_failed;
+ memset(vport->disc_trc, 0,
+ (sizeof(struct lpfc_disc_trc) * lpfc_debugfs_max_disc_trc));
+
+ snprintf(name, sizeof(name), "discovery_trace");
+ vport->debug_disc_trc =
+ debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+ vport->vport_debugfs_root,
+ vport, &lpfc_debugfs_op_disc_trc);
+ if (!vport->debug_disc_trc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0409 Cannot create debugfs",
+ phba->brd_no);
+ goto debug_failed;
+ }
+ snprintf(name, sizeof(name), "nodelist");
+ vport->debug_nodelist =
+ debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+ vport->vport_debugfs_root,
+ vport, &lpfc_debugfs_op_nodelist);
+ if (!vport->debug_nodelist) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0409 Cannot create debugfs",
+ phba->brd_no);
+ goto debug_failed;
+ }
+debug_failed:
+ return;
+#endif
+}
+
+
+inline void
+lpfc_debugfs_terminate(struct lpfc_vport *vport)
+{
+#ifdef CONFIG_LPFC_DEBUG_FS
+ struct lpfc_hba *phba = vport->phba;
+
+ if (vport->disc_trc) {
+ kfree(vport->disc_trc);
+ vport->disc_trc = NULL;
+ }
+ if (vport->debug_disc_trc) {
+ debugfs_remove(vport->debug_disc_trc); /* discovery_trace */
+ vport->debug_disc_trc = NULL;
+ }
+ if (vport->debug_nodelist) {
+ debugfs_remove(vport->debug_nodelist); /* nodelist */
+ vport->debug_nodelist = NULL;
+ }
+ if (vport->vport_debugfs_root) {
+ debugfs_remove(vport->vport_debugfs_root); /* vportX */
+ vport->vport_debugfs_root = NULL;
+ atomic_dec(&phba->debugfs_vport_count);
+ }
+ if (atomic_read(&phba->debugfs_vport_count) == 0) {
+ debugfs_remove(vport->phba->hba_debugfs_root); /* lpfcX */
+ vport->phba->hba_debugfs_root = NULL;
+ atomic_dec(&lpfc_debugfs_hba_count);
+ if (atomic_read(&lpfc_debugfs_hba_count) == 0) {
+ debugfs_remove(lpfc_debugfs_root); /* lpfc */
+ lpfc_debugfs_root = NULL;
+ }
+ }
+#endif
+}
+
+
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h
new file mode 100644
index 0000000..fffb678
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_debugfs.h
@@ -0,0 +1,50 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for *
+ * Fibre Channel Host Bus Adapters. *
+ * Copyright (C) 2007 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *******************************************************************/
+
+#ifndef _H_LPFC_DEBUG_FS
+#define _H_LPFC_DEBUG_FS
+
+#ifdef CONFIG_LPFC_DEBUG_FS
+struct lpfc_disc_trc {
+ char *fmt;
+ uint32_t data1;
+ uint32_t data2;
+ uint32_t data3;
+ uint32_t seq_cnt;
+ unsigned long jif;
+};
+#endif
+
+/* Mask for discovery_trace */
+#define LPFC_DISC_TRC_ELS_CMD 0x1 /* Trace ELS commands */
+#define LPFC_DISC_TRC_ELS_RSP 0x2 /* Trace ELS response */
+#define LPFC_DISC_TRC_ELS_UNSOL 0x4 /* Trace ELS rcv'ed */
+#define LPFC_DISC_TRC_ELS_ALL 0x7 /* Trace ELS */
+#define LPFC_DISC_TRC_MBOX_VPORT 0x8 /* Trace vport MBOXs */
+#define LPFC_DISC_TRC_MBOX 0x10 /* Trace other MBOXs */
+#define LPFC_DISC_TRC_MBOX_ALL 0x18 /* Trace all MBOXs */
+#define LPFC_DISC_TRC_CT 0x20 /* Trace disc CT requests */
+#define LPFC_DISC_TRC_DSM 0x40 /* Trace DSM events */
+#define LPFC_DISC_TRC_RPORT 0x80 /* Trace rport events */
+#define LPFC_DISC_TRC_NODE 0x100 /* Trace ndlp state changes */
+
+#define LPFC_DISC_TRC_DISCOVERY 0xef /* common mask for general
+ * discovery */
+#endif /* H_LPFC_DEBUG_FS */
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 498059f..aacac9a 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -36,21 +36,23 @@
LPFC_EVT_WARM_START,
LPFC_EVT_KILL,
LPFC_EVT_ELS_RETRY,
+ LPFC_EVT_DEV_LOSS_DELAY,
+ LPFC_EVT_DEV_LOSS,
};
/* structure used to queue event to the discovery tasklet */
struct lpfc_work_evt {
struct list_head evt_listp;
- void * evt_arg1;
- void * evt_arg2;
+ void *evt_arg1;
+ void *evt_arg2;
enum lpfc_work_type evt;
};
struct lpfc_nodelist {
struct list_head nlp_listp;
- struct lpfc_name nlp_portname; /* port name */
- struct lpfc_name nlp_nodename; /* node name */
+ struct lpfc_name nlp_portname;
+ struct lpfc_name nlp_nodename;
uint32_t nlp_flag; /* entry flags */
uint32_t nlp_DID; /* FC D_ID of entry */
uint32_t nlp_last_elscmd; /* Last ELS cmd sent */
@@ -75,8 +77,9 @@
struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */
struct fc_rport *rport; /* Corresponding FC transport
port structure */
- struct lpfc_hba *nlp_phba;
+ struct lpfc_vport *vport;
struct lpfc_work_evt els_retry_evt;
+ struct lpfc_work_evt dev_loss_evt;
unsigned long last_ramp_up_time; /* jiffy of last ramp up */
unsigned long last_q_full_time; /* jiffy of last queue full */
struct kref kref;
@@ -98,7 +101,9 @@
ACC */
#define NLP_NPR_ADISC 0x2000000 /* Issue ADISC when dq'ed from
NPR list */
+#define NLP_RM_DFLT_RPI 0x4000000 /* need to remove leftover dflt RPI */
#define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */
+#define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */
/* There are 4 different double linked lists nodelist entries can reside on.
* The Port Login (PLOGI) list and Address Discovery (ADISC) list are used
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 638b3cd..33fbc16 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -35,38 +35,38 @@
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *);
+static void lpfc_cmpl_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *,
+ struct lpfc_iocbq *);
+
static int lpfc_max_els_tries = 3;
-static int
-lpfc_els_chk_latt(struct lpfc_hba * phba)
+int
+lpfc_els_chk_latt(struct lpfc_vport *vport)
{
- struct lpfc_sli *psli;
- LPFC_MBOXQ_t *mbox;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
uint32_t ha_copy;
- int rc;
- psli = &phba->sli;
-
- if ((phba->hba_state >= LPFC_HBA_READY) ||
- (phba->hba_state == LPFC_LINK_DOWN))
+ if (vport->port_state >= LPFC_VPORT_READY ||
+ phba->link_state == LPFC_LINK_DOWN)
return 0;
/* Read the HBA Host Attention Register */
- spin_lock_irq(phba->host->host_lock);
ha_copy = readl(phba->HAregaddr);
- spin_unlock_irq(phba->host->host_lock);
if (!(ha_copy & HA_LATT))
return 0;
/* Pending Link Event during Discovery */
- lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY,
- "%d:0237 Pending Link Event during "
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0237 Pending Link Event during "
"Discovery: State x%x\n",
- phba->brd_no, phba->hba_state);
+ phba->brd_no, vport->vpi, phba->pport->port_state);
/* CLEAR_LA should re-enable link attention events and
* we should then imediately take a LATT event. The
@@ -74,48 +74,34 @@
* will cleanup any left over in-progress discovery
* events.
*/
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_ABORT_DISCOVERY;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_ABORT_DISCOVERY;
+ spin_unlock_irq(shost->host_lock);
- if (phba->hba_state != LPFC_CLEAR_LA) {
- if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
- phba->hba_state = LPFC_CLEAR_LA;
- lpfc_clear_la(phba, mbox);
- mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- rc = lpfc_sli_issue_mbox (phba, mbox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox, phba->mbox_mem_pool);
- phba->hba_state = LPFC_HBA_ERROR;
- }
- }
- }
+ if (phba->link_state != LPFC_CLEAR_LA)
+ lpfc_issue_clear_la(phba, vport);
return 1;
-
}
static struct lpfc_iocbq *
-lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
- uint16_t cmdSize, uint8_t retry, struct lpfc_nodelist * ndlp,
- uint32_t did, uint32_t elscmd)
+lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
+ uint16_t cmdSize, uint8_t retry,
+ struct lpfc_nodelist *ndlp, uint32_t did,
+ uint32_t elscmd)
{
- struct lpfc_sli_ring *pring;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *elsiocb;
struct lpfc_dmabuf *pcmd, *prsp, *pbuflist;
struct ulp_bde64 *bpl;
IOCB_t *icmd;
- pring = &phba->sli.ring[LPFC_ELS_RING];
- if (phba->hba_state < LPFC_LINK_UP)
- return NULL;
+ if (!lpfc_is_link_up(phba))
+ return NULL;
/* Allocate buffer for command iocb */
- spin_lock_irq(phba->host->host_lock);
elsiocb = lpfc_sli_get_iocbq(phba);
- spin_unlock_irq(phba->host->host_lock);
if (elsiocb == NULL)
return NULL;
@@ -123,14 +109,12 @@
/* fill in BDEs for command */
/* Allocate buffer for command payload */
- if (((pcmd = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
+ if (((pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
((pcmd->virt = lpfc_mbuf_alloc(phba,
MEM_PRI, &(pcmd->phys))) == 0)) {
kfree(pcmd);
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_release_iocbq(phba, elsiocb);
- spin_unlock_irq(phba->host->host_lock);
return NULL;
}
@@ -138,7 +122,7 @@
/* Allocate buffer for response payload */
if (expectRsp) {
- prsp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+ prsp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
if (prsp)
prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
&prsp->phys);
@@ -146,9 +130,7 @@
kfree(prsp);
lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
kfree(pcmd);
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_release_iocbq(phba, elsiocb);
- spin_unlock_irq(phba->host->host_lock);
return NULL;
}
INIT_LIST_HEAD(&prsp->list);
@@ -157,14 +139,12 @@
}
/* Allocate buffer for Buffer ptr list */
- pbuflist = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+ pbuflist = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
if (pbuflist)
- pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
- &pbuflist->phys);
+ pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
+ &pbuflist->phys);
if (pbuflist == 0 || pbuflist->virt == 0) {
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_release_iocbq(phba, elsiocb);
- spin_unlock_irq(phba->host->host_lock);
lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
kfree(pcmd);
@@ -178,20 +158,28 @@
icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL;
+ icmd->un.elsreq64.remoteID = did; /* DID */
if (expectRsp) {
- icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
- icmd->un.elsreq64.remoteID = did; /* DID */
+ icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64));
icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
icmd->ulpTimeout = phba->fc_ratov * 2;
} else {
- icmd->un.elsreq64.bdl.bdeSize = sizeof (struct ulp_bde64);
+ icmd->un.elsreq64.bdl.bdeSize = sizeof(struct ulp_bde64);
icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
}
-
icmd->ulpBdeCount = 1;
icmd->ulpLe = 1;
icmd->ulpClass = CLASS3;
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ icmd->un.elsreq64.myID = vport->fc_myDID;
+
+ /* For ELS_REQUEST64_CR, use the VPI by default */
+ icmd->ulpContext = vport->vpi;
+ icmd->ulpCt_h = 0;
+ icmd->ulpCt_l = 1;
+ }
+
bpl = (struct ulp_bde64 *) pbuflist->virt;
bpl->addrLow = le32_to_cpu(putPaddrLow(pcmd->phys));
bpl->addrHigh = le32_to_cpu(putPaddrHigh(pcmd->phys));
@@ -209,10 +197,12 @@
}
/* Save for completion so we can release these resources */
- elsiocb->context1 = lpfc_nlp_get(ndlp);
+ if (elscmd != ELS_CMD_LS_RJT)
+ elsiocb->context1 = lpfc_nlp_get(ndlp);
elsiocb->context2 = pcmd;
elsiocb->context3 = pbuflist;
elsiocb->retry = retry;
+ elsiocb->vport = vport;
elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;
if (prsp) {
@@ -222,16 +212,16 @@
if (expectRsp) {
/* Xmit ELS command <elsCmd> to remote NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0116 Xmit ELS command x%x to remote "
- "NPORT x%x I/O tag: x%x, HBA state: x%x\n",
- phba->brd_no, elscmd,
- did, elsiocb->iotag, phba->hba_state);
+ "%d (%d):0116 Xmit ELS command x%x to remote "
+ "NPORT x%x I/O tag: x%x, port state: x%x\n",
+ phba->brd_no, vport->vpi, elscmd, did,
+ elsiocb->iotag, vport->port_state);
} else {
/* Xmit ELS response <elsCmd> to remote NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0117 Xmit ELS response x%x to remote "
+ "%d (%d):0117 Xmit ELS response x%x to remote "
"NPORT x%x I/O tag: x%x, size: x%x\n",
- phba->brd_no, elscmd,
+ phba->brd_no, vport->vpi, elscmd,
ndlp->nlp_DID, elsiocb->iotag, cmdSize);
}
@@ -240,16 +230,79 @@
static int
-lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
- struct serv_parm *sp, IOCB_t *irsp)
+lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
{
+ struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *mbox;
struct lpfc_dmabuf *mp;
+ struct lpfc_nodelist *ndlp;
+ struct serv_parm *sp;
int rc;
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_FABRIC;
- spin_unlock_irq(phba->host->host_lock);
+ sp = &phba->fc_fabparam;
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ if (!ndlp)
+ goto fail;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ goto fail;
+
+ vport->port_state = LPFC_FABRIC_CFG_LINK;
+ lpfc_config_link(phba, mbox);
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
+ if (rc == MBX_NOT_FINISHED)
+ goto fail_free_mbox;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ goto fail;
+ rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
+ 0);
+ if (rc)
+ goto fail_free_mbox;
+
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
+ mbox->vport = vport;
+ mbox->context2 = lpfc_nlp_get(ndlp);
+
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
+ if (rc == MBX_NOT_FINISHED)
+ goto fail_issue_reg_login;
+
+ return 0;
+
+fail_issue_reg_login:
+ lpfc_nlp_put(ndlp);
+ mp = (struct lpfc_dmabuf *) mbox->context1;
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+fail_free_mbox:
+ mempool_free(mbox, phba->mbox_mem_pool);
+
+fail:
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0249 Cannot issue Register Fabric login\n",
+ phba->brd_no, vport->vpi);
+ return -ENXIO;
+}
+
+static int
+lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct serv_parm *sp, IOCB_t *irsp)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *np;
+ struct lpfc_nodelist *next_np;
+
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_FABRIC;
+ spin_unlock_irq(shost->host_lock);
phba->fc_edtov = be32_to_cpu(sp->cmn.e_d_tov);
if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */
@@ -258,20 +311,20 @@
phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;
if (phba->fc_topology == TOPOLOGY_LOOP) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_PUBLIC_LOOP;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_PUBLIC_LOOP;
+ spin_unlock_irq(shost->host_lock);
} else {
/*
* If we are a N-port connected to a Fabric, fixup sparam's so
* logins to devices on remote loops work.
*/
- phba->fc_sparam.cmn.altBbCredit = 1;
+ vport->fc_sparam.cmn.altBbCredit = 1;
}
- phba->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
+ vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name));
- memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
+ memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof(struct lpfc_name));
ndlp->nlp_class_sup = 0;
if (sp->cls1.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS1;
@@ -285,68 +338,85 @@
sp->cmn.bbRcvSizeLsb;
memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox)
- goto fail;
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ if (sp->cmn.response_multiple_NPort) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_VPORT,
+ "%d:1816 FLOGI NPIV supported, "
+ "response data 0x%x\n",
+ phba->brd_no,
+ sp->cmn.response_multiple_NPort);
+ phba->link_flag |= LS_NPIV_FAB_SUPPORTED;
- phba->hba_state = LPFC_FABRIC_CFG_LINK;
- lpfc_config_link(phba, mbox);
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ } else {
+ /* Because we asked f/w for NPIV it still expects us
+ to call reg_vnpid atleast for the physcial host */
+ lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_VPORT,
+ "%d:1817 Fabric does not support NPIV "
+ "- configuring single port mode.\n",
+ phba->brd_no);
+ phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
+ }
+ }
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
- if (rc == MBX_NOT_FINISHED)
- goto fail_free_mbox;
+ if ((vport->fc_prevDID != vport->fc_myDID) &&
+ !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox)
- goto fail;
+ /* If our NportID changed, we need to ensure all
+ * remaining NPORTs get unreg_login'ed.
+ */
+ list_for_each_entry_safe(np, next_np,
+ &vport->fc_nodes, nlp_listp) {
+ if ((np->nlp_state != NLP_STE_NPR_NODE) ||
+ !(np->nlp_flag & NLP_NPR_ADISC))
+ continue;
+ spin_lock_irq(shost->host_lock);
+ np->nlp_flag &= ~NLP_NPR_ADISC;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_unreg_rpi(vport, np);
+ }
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ lpfc_mbx_unreg_vpi(vport);
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ }
+ }
- if (lpfc_reg_login(phba, Fabric_DID, (uint8_t *) sp, mbox, 0))
- goto fail_free_mbox;
+ ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID;
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
- mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
- mbox->context2 = lpfc_nlp_get(ndlp);
-
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
- if (rc == MBX_NOT_FINISHED)
- goto fail_issue_reg_login;
-
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
+ vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) {
+ lpfc_register_new_vport(phba, vport, ndlp);
+ return 0;
+ }
+ lpfc_issue_fabric_reglogin(vport);
return 0;
-
- fail_issue_reg_login:
- lpfc_nlp_put(ndlp);
- mp = (struct lpfc_dmabuf *) mbox->context1;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- fail_free_mbox:
- mempool_free(mbox, phba->mbox_mem_pool);
- fail:
- return -ENXIO;
}
/*
* We FLOGIed into an NPort, initiate pt2pt protocol
*/
static int
-lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
- struct serv_parm *sp)
+lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct serv_parm *sp)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *mbox;
int rc;
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
phba->fc_edtov = FF_DEF_EDTOV;
phba->fc_ratov = FF_DEF_RATOV;
- rc = memcmp(&phba->fc_portname, &sp->portName,
- sizeof(struct lpfc_name));
+ rc = memcmp(&vport->fc_portname, &sp->portName,
+ sizeof(vport->fc_portname));
if (rc >= 0) {
/* This side will initiate the PLOGI */
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_PT2PT_PLOGI;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_PT2PT_PLOGI;
+ spin_unlock_irq(shost->host_lock);
/*
* N_Port ID cannot be 0, set our to LocalID the other
@@ -355,7 +425,7 @@
/* not equal */
if (rc)
- phba->fc_myDID = PT2PT_LocalID;
+ vport->fc_myDID = PT2PT_LocalID;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
@@ -364,15 +434,16 @@
lpfc_config_link(phba, mbox);
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
rc = lpfc_sli_issue_mbox(phba, mbox,
- MBX_NOWAIT | MBX_STOP_IOCB);
+ MBX_NOWAIT | MBX_STOP_IOCB);
if (rc == MBX_NOT_FINISHED) {
mempool_free(mbox, phba->mbox_mem_pool);
goto fail;
}
lpfc_nlp_put(ndlp);
- ndlp = lpfc_findnode_did(phba, PT2PT_RemoteID);
+ ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID);
if (!ndlp) {
/*
* Cannot find existing Fabric ndlp, so allocate a
@@ -382,28 +453,30 @@
if (!ndlp)
goto fail;
- lpfc_nlp_init(phba, ndlp, PT2PT_RemoteID);
+ lpfc_nlp_init(vport, ndlp, PT2PT_RemoteID);
}
memcpy(&ndlp->nlp_portname, &sp->portName,
- sizeof(struct lpfc_name));
+ sizeof(struct lpfc_name));
memcpy(&ndlp->nlp_nodename, &sp->nodeName,
- sizeof(struct lpfc_name));
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ sizeof(struct lpfc_name));
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+ spin_unlock_irq(shost->host_lock);
} else {
/* This side will wait for the PLOGI */
lpfc_nlp_put(ndlp);
}
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_PT2PT;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_PT2PT;
+ spin_unlock_irq(shost->host_lock);
/* Start discovery - this should just do CLEAR_LA */
- lpfc_disc_start(phba);
+ lpfc_disc_start(vport);
return 0;
- fail:
+fail:
return -ENXIO;
}
@@ -411,6 +484,8 @@
lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp = &rspiocb->iocb;
struct lpfc_nodelist *ndlp = cmdiocb->context1;
struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
@@ -418,21 +493,25 @@
int rc;
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba)) {
+ if (lpfc_els_chk_latt(vport)) {
lpfc_nlp_put(ndlp);
goto out;
}
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "FLOGI cmpl: status:x%x/x%x state:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ vport->port_state);
+
if (irsp->ulpStatus) {
/* Check for retry */
- if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
- /* ELS command is being retried */
+ if (lpfc_els_retry(phba, cmdiocb, rspiocb))
goto out;
- }
+
/* FLOGI failed, so there is no fabric */
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
/* If private loop, then allow max outstanding els to be
* LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
@@ -443,11 +522,10 @@
}
/* FLOGI failure */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_ELS,
- "%d:0100 FLOGI failure Data: x%x x%x x%x\n",
- phba->brd_no,
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0100 FLOGI failure Data: x%x x%x "
+ "x%x\n",
+ phba->brd_no, vport->vpi,
irsp->ulpStatus, irsp->un.ulpWord[4],
irsp->ulpTimeout);
goto flogifail;
@@ -463,21 +541,21 @@
/* FLOGI completes successfully */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0101 FLOGI completes sucessfully "
+ "%d (%d):0101 FLOGI completes sucessfully "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
irsp->un.ulpWord[4], sp->cmn.e_d_tov,
sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
- if (phba->hba_state == LPFC_FLOGI) {
+ if (vport->port_state == LPFC_FLOGI) {
/*
* If Common Service Parameters indicate Nport
* we are point to point, if Fport we are Fabric.
*/
if (sp->cmn.fPort)
- rc = lpfc_cmpl_els_flogi_fabric(phba, ndlp, sp, irsp);
+ rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
else
- rc = lpfc_cmpl_els_flogi_nport(phba, ndlp, sp);
+ rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
if (!rc)
goto out;
@@ -486,14 +564,12 @@
flogifail:
lpfc_nlp_put(ndlp);
- if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
- (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED &&
- irsp->un.ulpWord[4] != IOERR_SLI_DOWN)) {
+ if (!lpfc_error_lost_link(irsp)) {
/* FLOGI failed, so just use loop map to make discovery list */
- lpfc_disc_list_loopmap(phba);
+ lpfc_disc_list_loopmap(vport);
/* Start discovery */
- lpfc_disc_start(phba);
+ lpfc_disc_start(vport);
}
out:
@@ -501,9 +577,10 @@
}
static int
-lpfc_issue_els_flogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint8_t retry)
{
+ struct lpfc_hba *phba = vport->phba;
struct serv_parm *sp;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
@@ -515,9 +592,10 @@
pring = &phba->sli.ring[LPFC_ELS_RING];
- cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
- ndlp->nlp_DID, ELS_CMD_FLOGI);
+ cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_FLOGI);
+
if (!elsiocb)
return 1;
@@ -526,8 +604,8 @@
/* For FLOGI request, remainder of payload is service parameters */
*((uint32_t *) (pcmd)) = ELS_CMD_FLOGI;
- pcmd += sizeof (uint32_t);
- memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm));
+ pcmd += sizeof(uint32_t);
+ memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
sp = (struct serv_parm *) pcmd;
/* Setup CSPs accordingly for Fabric */
@@ -541,16 +619,32 @@
if (sp->cmn.fcphHigh < FC_PH3)
sp->cmn.fcphHigh = FC_PH3;
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ sp->cmn.request_multiple_Nport = 1;
+
+ /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
+ icmd->ulpCt_h = 1;
+ icmd->ulpCt_l = 0;
+ }
+
+ if (phba->fc_topology != TOPOLOGY_LOOP) {
+ icmd->un.elsreq64.myID = 0;
+ icmd->un.elsreq64.fl = 1;
+ }
+
tmo = phba->fc_ratov;
phba->fc_ratov = LPFC_DISC_FLOGI_TMO;
- lpfc_set_disctmo(phba);
+ lpfc_set_disctmo(vport);
phba->fc_ratov = tmo;
phba->fc_stat.elsXmitFLOGI++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi;
- spin_lock_irq(phba->host->host_lock);
- rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
- spin_unlock_irq(phba->host->host_lock);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue FLOGI: opt:x%x",
+ phba->sli3_options, 0, 0);
+
+ rc = lpfc_issue_fabric_iocb(phba, elsiocb);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -559,7 +653,7 @@
}
int
-lpfc_els_abort_flogi(struct lpfc_hba * phba)
+lpfc_els_abort_flogi(struct lpfc_hba *phba)
{
struct lpfc_sli_ring *pring;
struct lpfc_iocbq *iocb, *next_iocb;
@@ -577,73 +671,99 @@
* Check the txcmplq for an iocb that matches the nport the driver is
* searching for.
*/
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
icmd = &iocb->iocb;
- if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) {
+ if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
+ icmd->un.elsreq64.bdl.ulpIoTag32) {
ndlp = (struct lpfc_nodelist *)(iocb->context1);
- if (ndlp && (ndlp->nlp_DID == Fabric_DID))
+ if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+ }
}
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return 0;
}
int
-lpfc_initial_flogi(struct lpfc_hba *phba)
+lpfc_initial_flogi(struct lpfc_vport *vport)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp;
/* First look for the Fabric ndlp */
- ndlp = lpfc_findnode_did(phba, Fabric_DID);
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
if (!ndlp) {
/* Cannot find existing Fabric ndlp, so allocate a new one */
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp)
return 0;
- lpfc_nlp_init(phba, ndlp, Fabric_DID);
+ lpfc_nlp_init(vport, ndlp, Fabric_DID);
} else {
- lpfc_dequeue_node(phba, ndlp);
+ lpfc_dequeue_node(vport, ndlp);
}
- if (lpfc_issue_els_flogi(phba, ndlp, 0)) {
+ if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
lpfc_nlp_put(ndlp);
}
return 1;
}
+int
+lpfc_initial_fdisc(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp;
+
+ /* First look for the Fabric ndlp */
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ if (!ndlp) {
+ /* Cannot find existing Fabric ndlp, so allocate a new one */
+ ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+ if (!ndlp)
+ return 0;
+ lpfc_nlp_init(vport, ndlp, Fabric_DID);
+ } else {
+ lpfc_dequeue_node(vport, ndlp);
+ }
+ if (lpfc_issue_els_fdisc(vport, ndlp, 0)) {
+ lpfc_nlp_put(ndlp);
+ }
+ return 1;
+}
static void
-lpfc_more_plogi(struct lpfc_hba * phba)
+lpfc_more_plogi(struct lpfc_vport *vport)
{
int sentplogi;
+ struct lpfc_hba *phba = vport->phba;
- if (phba->num_disc_nodes)
- phba->num_disc_nodes--;
+ if (vport->num_disc_nodes)
+ vport->num_disc_nodes--;
/* Continue discovery with <num_disc_nodes> PLOGIs to go */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0232 Continue discovery with %d PLOGIs to go "
+ "%d (%d):0232 Continue discovery with %d PLOGIs to go "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->num_disc_nodes, phba->fc_plogi_cnt,
- phba->fc_flag, phba->hba_state);
+ phba->brd_no, vport->vpi, vport->num_disc_nodes,
+ vport->fc_plogi_cnt, vport->fc_flag, vport->port_state);
/* Check to see if there are more PLOGIs to be sent */
- if (phba->fc_flag & FC_NLP_MORE) {
- /* go thru NPR list and issue any remaining ELS PLOGIs */
- sentplogi = lpfc_els_disc_plogi(phba);
- }
+ if (vport->fc_flag & FC_NLP_MORE)
+ /* go thru NPR nodes and issue any remaining ELS PLOGIs */
+ sentplogi = lpfc_els_disc_plogi(vport);
+
return;
}
static struct lpfc_nodelist *
-lpfc_plogi_confirm_nport(struct lpfc_hba *phba, struct lpfc_dmabuf *prsp,
+lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
struct lpfc_nodelist *ndlp)
{
+ struct lpfc_vport *vport = ndlp->vport;
struct lpfc_nodelist *new_ndlp;
- uint32_t *lp;
struct serv_parm *sp;
- uint8_t name[sizeof (struct lpfc_name)];
+ uint8_t name[sizeof(struct lpfc_name)];
uint32_t rc;
/* Fabric nodes can have the same WWPN so we don't bother searching
@@ -652,50 +772,51 @@
if (ndlp->nlp_type & NLP_FABRIC)
return ndlp;
- lp = (uint32_t *) prsp->virt;
- sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+ sp = (struct serv_parm *) ((uint8_t *) prsp + sizeof(uint32_t));
memset(name, 0, sizeof(struct lpfc_name));
/* Now we find out if the NPort we are logging into, matches the WWPN
* we have for that ndlp. If not, we have some work to do.
*/
- new_ndlp = lpfc_findnode_wwpn(phba, &sp->portName);
+ new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName);
if (new_ndlp == ndlp)
return ndlp;
if (!new_ndlp) {
- rc =
- memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name));
+ rc = memcmp(&ndlp->nlp_portname, name,
+ sizeof(struct lpfc_name));
if (!rc)
return ndlp;
new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
if (!new_ndlp)
return ndlp;
- lpfc_nlp_init(phba, new_ndlp, ndlp->nlp_DID);
+ lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
}
- lpfc_unreg_rpi(phba, new_ndlp);
+ lpfc_unreg_rpi(vport, new_ndlp);
new_ndlp->nlp_DID = ndlp->nlp_DID;
new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
- lpfc_nlp_set_state(phba, new_ndlp, ndlp->nlp_state);
+ lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
- /* Move this back to NPR list */
+ /* Move this back to NPR state */
if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
else {
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
}
return new_ndlp;
}
static void
-lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp;
struct lpfc_nodelist *ndlp;
struct lpfc_dmabuf *prsp;
@@ -705,32 +826,43 @@
cmdiocb->context_un.rsp_iocb = rspiocb;
irsp = &rspiocb->iocb;
- ndlp = lpfc_findnode_did(phba, irsp->un.elsreq64.remoteID);
- if (!ndlp)
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "PLOGI cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->un.elsreq64.remoteID);
+
+ ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
+ if (!ndlp) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0136 PLOGI completes to NPort x%x "
+ "with no ndlp. Data: x%x x%x x%x\n",
+ phba->brd_no, vport->vpi, irsp->un.elsreq64.remoteID,
+ irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpIoTag);
goto out;
+ }
/* Since ndlp can be freed in the disc state machine, note if this node
* is being used during discovery.
*/
+ spin_lock_irq(shost->host_lock);
disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
- spin_lock_irq(phba->host->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
rc = 0;
/* PLOGI completes to NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0102 PLOGI completes to NPort x%x "
+ "%d (%d):0102 PLOGI completes to NPort x%x "
"Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
- irsp->un.ulpWord[4], irsp->ulpTimeout, disc,
- phba->num_disc_nodes);
+ phba->brd_no, vport->vpi, ndlp->nlp_DID,
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout, disc, vport->num_disc_nodes);
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba)) {
- spin_lock_irq(phba->host->host_lock);
+ if (lpfc_els_chk_latt(vport)) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
goto out;
}
@@ -743,56 +875,62 @@
if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
/* ELS command is being retried */
if (disc) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
}
goto out;
}
/* PLOGI failed */
+ if (ndlp->nlp_DID == NameServer_DID) {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0250 Nameserver login error: "
+ "0x%x / 0x%x\n",
+ phba->brd_no, vport->vpi,
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
+ }
+
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
- if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
- (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
- (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+ if (lpfc_error_lost_link(irsp)) {
rc = NLP_STE_FREED_NODE;
} else {
- rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb,
- NLP_EVT_CMPL_PLOGI);
+ rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_PLOGI);
}
} else {
/* Good status, call state machine */
prsp = list_entry(((struct lpfc_dmabuf *)
- cmdiocb->context2)->list.next,
- struct lpfc_dmabuf, list);
- ndlp = lpfc_plogi_confirm_nport(phba, prsp, ndlp);
- rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb,
- NLP_EVT_CMPL_PLOGI);
+ cmdiocb->context2)->list.next,
+ struct lpfc_dmabuf, list);
+ ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp);
+ rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_PLOGI);
}
- if (disc && phba->num_disc_nodes) {
+ if (disc && vport->num_disc_nodes) {
/* Check to see if there are more PLOGIs to be sent */
- lpfc_more_plogi(phba);
+ lpfc_more_plogi(vport);
- if (phba->num_disc_nodes == 0) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_NDISC_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ if (vport->num_disc_nodes == 0) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(shost->host_lock);
- lpfc_can_disctmo(phba);
- if (phba->fc_flag & FC_RSCN_MODE) {
+ lpfc_can_disctmo(vport);
+ if (vport->fc_flag & FC_RSCN_MODE) {
/*
* Check to see if more RSCNs came in while
* we were processing this one.
*/
- if ((phba->fc_rscn_id_cnt == 0) &&
- (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_RSCN_MODE;
- spin_unlock_irq(phba->host->host_lock);
+ if ((vport->fc_rscn_id_cnt == 0) &&
+ (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_RSCN_MODE;
+ spin_unlock_irq(shost->host_lock);
} else {
- lpfc_els_handle_rscn(phba);
+ lpfc_els_handle_rscn(vport);
}
}
}
@@ -804,8 +942,9 @@
}
int
-lpfc_issue_els_plogi(struct lpfc_hba * phba, uint32_t did, uint8_t retry)
+lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
{
+ struct lpfc_hba *phba = vport->phba;
struct serv_parm *sp;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
@@ -813,13 +952,14 @@
struct lpfc_sli *psli;
uint8_t *pcmd;
uint16_t cmdsize;
+ int ret;
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
- cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, NULL, did,
- ELS_CMD_PLOGI);
+ cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did,
+ ELS_CMD_PLOGI);
if (!elsiocb)
return 1;
@@ -828,8 +968,8 @@
/* For PLOGI request, remainder of payload is service parameters */
*((uint32_t *) (pcmd)) = ELS_CMD_PLOGI;
- pcmd += sizeof (uint32_t);
- memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm));
+ pcmd += sizeof(uint32_t);
+ memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
sp = (struct serv_parm *) pcmd;
if (sp->cmn.fcphLow < FC_PH_4_3)
@@ -838,22 +978,27 @@
if (sp->cmn.fcphHigh < FC_PH3)
sp->cmn.fcphHigh = FC_PH3;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue PLOGI: did:x%x",
+ did, 0, 0);
+
phba->fc_stat.elsXmitPLOGI++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
- spin_lock_irq(phba->host->host_lock);
- if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
- spin_unlock_irq(phba->host->host_lock);
+ ret = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+
+ if (ret == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
return 0;
}
static void
-lpfc_cmpl_els_prli(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp;
struct lpfc_sli *psli;
struct lpfc_nodelist *ndlp;
@@ -864,21 +1009,26 @@
irsp = &(rspiocb->iocb);
ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_PRLI_SND;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "PRLI cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ ndlp->nlp_DID);
/* PRLI completes to NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0103 PRLI completes to NPort x%x "
+ "%d (%d):0103 PRLI completes to NPort x%x "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
- irsp->un.ulpWord[4], irsp->ulpTimeout,
- phba->num_disc_nodes);
+ phba->brd_no, vport->vpi, ndlp->nlp_DID,
+ irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
+ vport->num_disc_nodes);
- phba->fc_prli_sent--;
+ vport->fc_prli_sent--;
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba))
+ if (lpfc_els_chk_latt(vport))
goto out;
if (irsp->ulpStatus) {
@@ -889,18 +1039,16 @@
}
/* PRLI failed */
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
- if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
- (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
- (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+ if (lpfc_error_lost_link(irsp)) {
goto out;
} else {
- lpfc_disc_state_machine(phba, ndlp, cmdiocb,
- NLP_EVT_CMPL_PRLI);
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_PRLI);
}
} else {
/* Good status, call state machine */
- lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_PRLI);
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_PRLI);
}
out:
@@ -909,9 +1057,11 @@
}
int
-lpfc_issue_els_prli(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint8_t retry)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
PRLI *npr;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
@@ -923,9 +1073,9 @@
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
- cmdsize = (sizeof (uint32_t) + sizeof (PRLI));
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
- ndlp->nlp_DID, ELS_CMD_PRLI);
+ cmdsize = (sizeof(uint32_t) + sizeof(PRLI));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_PRLI);
if (!elsiocb)
return 1;
@@ -933,9 +1083,9 @@
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
/* For PRLI request, remainder of payload is service parameters */
- memset(pcmd, 0, (sizeof (PRLI) + sizeof (uint32_t)));
+ memset(pcmd, 0, (sizeof(PRLI) + sizeof(uint32_t)));
*((uint32_t *) (pcmd)) = ELS_CMD_PRLI;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
/* For PRLI, remainder of payload is PRLI parameter page */
npr = (PRLI *) pcmd;
@@ -955,81 +1105,88 @@
npr->prliType = PRLI_FCP_TYPE;
npr->initiatorFunc = 1;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue PRLI: did:x%x",
+ ndlp->nlp_DID, 0, 0);
+
phba->fc_stat.elsXmitPRLI++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_prli;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_PRLI_SND;
+ spin_unlock_irq(shost->host_lock);
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_PRLI_SND;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
- phba->fc_prli_sent++;
+ vport->fc_prli_sent++;
return 0;
}
static void
-lpfc_more_adisc(struct lpfc_hba * phba)
+lpfc_more_adisc(struct lpfc_vport *vport)
{
int sentadisc;
+ struct lpfc_hba *phba = vport->phba;
- if (phba->num_disc_nodes)
- phba->num_disc_nodes--;
+ if (vport->num_disc_nodes)
+ vport->num_disc_nodes--;
/* Continue discovery with <num_disc_nodes> ADISCs to go */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0210 Continue discovery with %d ADISCs to go "
+ "%d (%d):0210 Continue discovery with %d ADISCs to go "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->num_disc_nodes, phba->fc_adisc_cnt,
- phba->fc_flag, phba->hba_state);
+ phba->brd_no, vport->vpi, vport->num_disc_nodes,
+ vport->fc_adisc_cnt, vport->fc_flag, vport->port_state);
/* Check to see if there are more ADISCs to be sent */
- if (phba->fc_flag & FC_NLP_MORE) {
- lpfc_set_disctmo(phba);
-
- /* go thru NPR list and issue any remaining ELS ADISCs */
- sentadisc = lpfc_els_disc_adisc(phba);
+ if (vport->fc_flag & FC_NLP_MORE) {
+ lpfc_set_disctmo(vport);
+ /* go thru NPR nodes and issue any remaining ELS ADISCs */
+ sentadisc = lpfc_els_disc_adisc(vport);
}
return;
}
static void
-lpfc_rscn_disc(struct lpfc_hba * phba)
+lpfc_rscn_disc(struct lpfc_vport *vport)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ lpfc_can_disctmo(vport);
+
/* RSCN discovery */
- /* go thru NPR list and issue ELS PLOGIs */
- if (phba->fc_npr_cnt) {
- if (lpfc_els_disc_plogi(phba))
+ /* go thru NPR nodes and issue ELS PLOGIs */
+ if (vport->fc_npr_cnt)
+ if (lpfc_els_disc_plogi(vport))
return;
- }
- if (phba->fc_flag & FC_RSCN_MODE) {
+
+ if (vport->fc_flag & FC_RSCN_MODE) {
/* Check to see if more RSCNs came in while we were
* processing this one.
*/
- if ((phba->fc_rscn_id_cnt == 0) &&
- (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_RSCN_MODE;
- spin_unlock_irq(phba->host->host_lock);
+ if ((vport->fc_rscn_id_cnt == 0) &&
+ (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_RSCN_MODE;
+ spin_unlock_irq(shost->host_lock);
} else {
- lpfc_els_handle_rscn(phba);
+ lpfc_els_handle_rscn(vport);
}
}
}
static void
-lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp;
- struct lpfc_sli *psli;
struct lpfc_nodelist *ndlp;
- LPFC_MBOXQ_t *mbox;
- int disc, rc;
-
- psli = &phba->sli;
+ int disc;
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
@@ -1037,27 +1194,32 @@
irsp = &(rspiocb->iocb);
ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "ADISC cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ ndlp->nlp_DID);
+
/* Since ndlp can be freed in the disc state machine, note if this node
* is being used during discovery.
*/
+ spin_lock_irq(shost->host_lock);
disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
- spin_lock_irq(phba->host->host_lock);
ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
/* ADISC completes to NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0104 ADISC completes to NPort x%x "
+ "%d (%d):0104 ADISC completes to NPort x%x "
"Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
- irsp->un.ulpWord[4], irsp->ulpTimeout, disc,
- phba->num_disc_nodes);
+ phba->brd_no, vport->vpi, ndlp->nlp_DID,
+ irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
+ disc, vport->num_disc_nodes);
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba)) {
- spin_lock_irq(phba->host->host_lock);
+ if (lpfc_els_chk_latt(vport)) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
goto out;
}
@@ -1066,67 +1228,68 @@
if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
/* ELS command is being retried */
if (disc) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
- spin_unlock_irq(phba->host->host_lock);
- lpfc_set_disctmo(phba);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_set_disctmo(vport);
}
goto out;
}
/* ADISC failed */
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
- if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
- ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
- (irsp->un.ulpWord[4] != IOERR_LINK_DOWN) &&
- (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) {
- lpfc_disc_state_machine(phba, ndlp, cmdiocb,
- NLP_EVT_CMPL_ADISC);
+ if (!lpfc_error_lost_link(irsp)) {
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_ADISC);
}
} else {
/* Good status, call state machine */
- lpfc_disc_state_machine(phba, ndlp, cmdiocb,
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_CMPL_ADISC);
}
- if (disc && phba->num_disc_nodes) {
+ if (disc && vport->num_disc_nodes) {
/* Check to see if there are more ADISCs to be sent */
- lpfc_more_adisc(phba);
+ lpfc_more_adisc(vport);
/* Check to see if we are done with ADISC authentication */
- if (phba->num_disc_nodes == 0) {
- lpfc_can_disctmo(phba);
- /* If we get here, there is nothing left to wait for */
- if ((phba->hba_state < LPFC_HBA_READY) &&
- (phba->hba_state != LPFC_CLEAR_LA)) {
- /* Link up discovery */
- if ((mbox = mempool_alloc(phba->mbox_mem_pool,
- GFP_KERNEL))) {
- phba->hba_state = LPFC_CLEAR_LA;
- lpfc_clear_la(phba, mbox);
- mbox->mbox_cmpl =
- lpfc_mbx_cmpl_clear_la;
- rc = lpfc_sli_issue_mbox
- (phba, mbox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox,
- phba->mbox_mem_pool);
- lpfc_disc_flush_list(phba);
- psli->ring[(psli->extra_ring)].
- flag &=
- ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->fcp_ring)].
- flag &=
- ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->next_ring)].
- flag &=
- ~LPFC_STOP_IOCB_EVENT;
- phba->hba_state =
- LPFC_HBA_READY;
+ if (vport->num_disc_nodes == 0) {
+ /* If we get here, there is nothing left to ADISC */
+ /*
+ * For NPIV, cmpl_reg_vpi will set port_state to READY,
+ * and continue discovery.
+ */
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ !(vport->fc_flag & FC_RSCN_MODE)) {
+ lpfc_issue_reg_vpi(phba, vport);
+ goto out;
+ }
+ /*
+ * For SLI2, we need to set port_state to READY
+ * and continue discovery.
+ */
+ if (vport->port_state < LPFC_VPORT_READY) {
+ /* If we get here, there is nothing to ADISC */
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ lpfc_issue_clear_la(phba, vport);
+
+ if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
+ vport->num_disc_nodes = 0;
+ /* go thru NPR list, issue ELS PLOGIs */
+ if (vport->fc_npr_cnt)
+ lpfc_els_disc_plogi(vport);
+
+ if (!vport->num_disc_nodes) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &=
+ ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(
+ shost->host_lock);
+ lpfc_can_disctmo(vport);
}
}
+ vport->port_state = LPFC_VPORT_READY;
} else {
- lpfc_rscn_disc(phba);
+ lpfc_rscn_disc(vport);
}
}
}
@@ -1136,23 +1299,22 @@
}
int
-lpfc_issue_els_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint8_t retry)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
ADISC *ap;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
- struct lpfc_sli_ring *pring;
- struct lpfc_sli *psli;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
uint8_t *pcmd;
uint16_t cmdsize;
- psli = &phba->sli;
- pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
-
- cmdsize = (sizeof (uint32_t) + sizeof (ADISC));
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
- ndlp->nlp_DID, ELS_CMD_ADISC);
+ cmdsize = (sizeof(uint32_t) + sizeof(ADISC));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ADISC);
if (!elsiocb)
return 1;
@@ -1161,81 +1323,97 @@
/* For ADISC request, remainder of payload is service parameters */
*((uint32_t *) (pcmd)) = ELS_CMD_ADISC;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
/* Fill in ADISC payload */
ap = (ADISC *) pcmd;
ap->hardAL_PA = phba->fc_pref_ALPA;
- memcpy(&ap->portName, &phba->fc_portname, sizeof (struct lpfc_name));
- memcpy(&ap->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
- ap->DID = be32_to_cpu(phba->fc_myDID);
+ memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name));
+ memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
+ ap->DID = be32_to_cpu(vport->fc_myDID);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue ADISC: did:x%x",
+ ndlp->nlp_DID, 0, 0);
phba->fc_stat.elsXmitADISC++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_ADISC_SND;
+ spin_unlock_irq(shost->host_lock);
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_ADISC_SND;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
return 0;
}
static void
-lpfc_cmpl_els_logo(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_vport *vport = ndlp->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp;
struct lpfc_sli *psli;
- struct lpfc_nodelist *ndlp;
psli = &phba->sli;
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
irsp = &(rspiocb->iocb);
- ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_LOGO_SND;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "LOGO cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ ndlp->nlp_DID);
/* LOGO completes to NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0105 LOGO completes to NPort x%x "
+ "%d (%d):0105 LOGO completes to NPort x%x "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
- irsp->un.ulpWord[4], irsp->ulpTimeout,
- phba->num_disc_nodes);
+ phba->brd_no, vport->vpi, ndlp->nlp_DID,
+ irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
+ vport->num_disc_nodes);
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba))
+ if (lpfc_els_chk_latt(vport))
goto out;
+ if (ndlp->nlp_flag & NLP_TARGET_REMOVE) {
+ /* NLP_EVT_DEVICE_RM should unregister the RPI
+ * which should abort all outstanding IOs.
+ */
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_DEVICE_RM);
+ goto out;
+ }
+
if (irsp->ulpStatus) {
/* Check for retry */
- if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
+ if (lpfc_els_retry(phba, cmdiocb, rspiocb))
/* ELS command is being retried */
goto out;
- }
/* LOGO failed */
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
- if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
- (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
- (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+ if (lpfc_error_lost_link(irsp))
goto out;
- } else {
- lpfc_disc_state_machine(phba, ndlp, cmdiocb,
- NLP_EVT_CMPL_LOGO);
- }
+ else
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_LOGO);
} else {
/* Good status, call state machine.
* This will unregister the rpi if needed.
*/
- lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_LOGO);
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_LOGO);
}
out:
@@ -1244,75 +1422,91 @@
}
int
-lpfc_issue_els_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint8_t retry)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
struct lpfc_sli_ring *pring;
struct lpfc_sli *psli;
uint8_t *pcmd;
uint16_t cmdsize;
+ int rc;
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING];
- cmdsize = (2 * sizeof (uint32_t)) + sizeof (struct lpfc_name);
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
- ndlp->nlp_DID, ELS_CMD_LOGO);
+ cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name);
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_LOGO);
if (!elsiocb)
return 1;
icmd = &elsiocb->iocb;
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
/* Fill in LOGO payload */
- *((uint32_t *) (pcmd)) = be32_to_cpu(phba->fc_myDID);
- pcmd += sizeof (uint32_t);
- memcpy(pcmd, &phba->fc_portname, sizeof (struct lpfc_name));
+ *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
+ pcmd += sizeof(uint32_t);
+ memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue LOGO: did:x%x",
+ ndlp->nlp_DID, 0, 0);
phba->fc_stat.elsXmitLOGO++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_logo;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_LOGO_SND;
- if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+ spin_unlock_irq(shost->host_lock);
+ rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+
+ if (rc == IOCB_ERROR) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_LOGO_SND;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
return 0;
}
static void
-lpfc_cmpl_els_cmd(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
IOCB_t *irsp;
irsp = &rspiocb->iocb;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "ELS cmd cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->un.elsreq64.remoteID);
+
/* ELS cmd tag <ulpIoTag> completes */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_ELS,
- "%d:0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n",
- phba->brd_no,
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0106 ELS cmd tag x%x completes Data: x%x x%x "
+ "x%x\n",
+ phba->brd_no, vport->vpi,
irsp->ulpIoTag, irsp->ulpStatus,
irsp->un.ulpWord[4], irsp->ulpTimeout);
/* Check to see if link went down during discovery */
- lpfc_els_chk_latt(phba);
+ lpfc_els_chk_latt(vport);
lpfc_els_free_iocb(phba, cmdiocb);
return;
}
int
-lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
+lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
{
+ struct lpfc_hba *phba = vport->phba;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
struct lpfc_sli_ring *pring;
@@ -1323,15 +1517,16 @@
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
- cmdsize = (sizeof (uint32_t) + sizeof (SCR));
+ cmdsize = (sizeof(uint32_t) + sizeof(SCR));
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp)
return 1;
- lpfc_nlp_init(phba, ndlp, nportid);
+ lpfc_nlp_init(vport, ndlp, nportid);
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
- ndlp->nlp_DID, ELS_CMD_SCR);
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_SCR);
+
if (!elsiocb) {
lpfc_nlp_put(ndlp);
return 1;
@@ -1341,29 +1536,31 @@
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_SCR;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
/* For SCR, remainder of payload is SCR parameter page */
- memset(pcmd, 0, sizeof (SCR));
+ memset(pcmd, 0, sizeof(SCR));
((SCR *) pcmd)->Function = SCR_FUNC_FULL;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue SCR: did:x%x",
+ ndlp->nlp_DID, 0, 0);
+
phba->fc_stat.elsXmitSCR++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
- spin_lock_irq(phba->host->host_lock);
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
- spin_unlock_irq(phba->host->host_lock);
lpfc_nlp_put(ndlp);
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
lpfc_nlp_put(ndlp);
return 0;
}
static int
-lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
+lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
{
+ struct lpfc_hba *phba = vport->phba;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
struct lpfc_sli_ring *pring;
@@ -1377,14 +1574,15 @@
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
- cmdsize = (sizeof (uint32_t) + sizeof (FARP));
+ cmdsize = (sizeof(uint32_t) + sizeof(FARP));
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp)
return 1;
- lpfc_nlp_init(phba, ndlp, nportid);
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
- ndlp->nlp_DID, ELS_CMD_RNID);
+ lpfc_nlp_init(vport, ndlp, nportid);
+
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_RNID);
if (!elsiocb) {
lpfc_nlp_put(ndlp);
return 1;
@@ -1394,44 +1592,71 @@
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_FARPR;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
/* Fill in FARPR payload */
fp = (FARP *) (pcmd);
- memset(fp, 0, sizeof (FARP));
+ memset(fp, 0, sizeof(FARP));
lp = (uint32_t *) pcmd;
*lp++ = be32_to_cpu(nportid);
- *lp++ = be32_to_cpu(phba->fc_myDID);
+ *lp++ = be32_to_cpu(vport->fc_myDID);
fp->Rflags = 0;
fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE);
- memcpy(&fp->RportName, &phba->fc_portname, sizeof (struct lpfc_name));
- memcpy(&fp->RnodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
- if ((ondlp = lpfc_findnode_did(phba, nportid))) {
+ memcpy(&fp->RportName, &vport->fc_portname, sizeof(struct lpfc_name));
+ memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
+ ondlp = lpfc_findnode_did(vport, nportid);
+ if (ondlp) {
memcpy(&fp->OportName, &ondlp->nlp_portname,
- sizeof (struct lpfc_name));
+ sizeof(struct lpfc_name));
memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
- sizeof (struct lpfc_name));
+ sizeof(struct lpfc_name));
}
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue FARPR: did:x%x",
+ ndlp->nlp_DID, 0, 0);
+
phba->fc_stat.elsXmitFARPR++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
- spin_lock_irq(phba->host->host_lock);
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
- spin_unlock_irq(phba->host->host_lock);
lpfc_nlp_put(ndlp);
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
lpfc_nlp_put(ndlp);
return 0;
}
-void
-lpfc_cancel_retry_delay_tmo(struct lpfc_hba *phba, struct lpfc_nodelist * nlp)
+static void
+lpfc_end_rscn(struct lpfc_vport *vport)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ if (vport->fc_flag & FC_RSCN_MODE) {
+ /*
+ * Check to see if more RSCNs came in while we were
+ * processing this one.
+ */
+ if (vport->fc_rscn_id_cnt ||
+ (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
+ lpfc_els_handle_rscn(vport);
+ else {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_RSCN_MODE;
+ spin_unlock_irq(shost->host_lock);
+ }
+ }
+}
+
+void
+lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ spin_lock_irq(shost->host_lock);
nlp->nlp_flag &= ~NLP_DELAY_TMO;
+ spin_unlock_irq(shost->host_lock);
del_timer_sync(&nlp->nlp_delayfunc);
nlp->nlp_last_elscmd = 0;
@@ -1439,30 +1664,21 @@
list_del_init(&nlp->els_retry_evt.evt_listp);
if (nlp->nlp_flag & NLP_NPR_2B_DISC) {
+ spin_lock_irq(shost->host_lock);
nlp->nlp_flag &= ~NLP_NPR_2B_DISC;
- if (phba->num_disc_nodes) {
+ spin_unlock_irq(shost->host_lock);
+ if (vport->num_disc_nodes) {
/* Check to see if there are more
* PLOGIs to be sent
*/
- lpfc_more_plogi(phba);
+ lpfc_more_plogi(vport);
- if (phba->num_disc_nodes == 0) {
- phba->fc_flag &= ~FC_NDISC_ACTIVE;
- lpfc_can_disctmo(phba);
- if (phba->fc_flag & FC_RSCN_MODE) {
- /*
- * Check to see if more RSCNs
- * came in while we were
- * processing this one.
- */
- if((phba->fc_rscn_id_cnt==0) &&
- !(phba->fc_flag & FC_RSCN_DISCOVERY)) {
- phba->fc_flag &= ~FC_RSCN_MODE;
- }
- else {
- lpfc_els_handle_rscn(phba);
- }
- }
+ if (vport->num_disc_nodes == 0) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
+ lpfc_end_rscn(vport);
}
}
}
@@ -1472,18 +1688,19 @@
void
lpfc_els_retry_delay(unsigned long ptr)
{
- struct lpfc_nodelist *ndlp;
- struct lpfc_hba *phba;
- unsigned long iflag;
- struct lpfc_work_evt *evtp;
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
+ struct lpfc_vport *vport = ndlp->vport;
+ struct lpfc_hba *phba = vport->phba;
+ unsigned long flags;
+ struct lpfc_work_evt *evtp = &ndlp->els_retry_evt;
- ndlp = (struct lpfc_nodelist *)ptr;
- phba = ndlp->nlp_phba;
+ ndlp = (struct lpfc_nodelist *) ptr;
+ phba = ndlp->vport->phba;
evtp = &ndlp->els_retry_evt;
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, flags);
if (!list_empty(&evtp->evt_listp)) {
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return;
}
@@ -1491,33 +1708,31 @@
evtp->evt = LPFC_EVT_ELS_RETRY;
list_add_tail(&evtp->evt_listp, &phba->work_list);
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return;
}
void
lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
{
- struct lpfc_hba *phba;
- uint32_t cmd;
- uint32_t did;
- uint8_t retry;
+ struct lpfc_vport *vport = ndlp->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ uint32_t cmd, did, retry;
- phba = ndlp->nlp_phba;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
did = ndlp->nlp_DID;
cmd = ndlp->nlp_last_elscmd;
ndlp->nlp_last_elscmd = 0;
if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
return;
}
ndlp->nlp_flag &= ~NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
/*
* If a discovery event readded nlp_delayfunc after timer
* firing and before processing the timer, cancel the
@@ -1528,57 +1743,54 @@
switch (cmd) {
case ELS_CMD_FLOGI:
- lpfc_issue_els_flogi(phba, ndlp, retry);
+ lpfc_issue_els_flogi(vport, ndlp, retry);
break;
case ELS_CMD_PLOGI:
- if(!lpfc_issue_els_plogi(phba, ndlp->nlp_DID, retry)) {
+ if (!lpfc_issue_els_plogi(vport, ndlp->nlp_DID, retry)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
}
break;
case ELS_CMD_ADISC:
- if (!lpfc_issue_els_adisc(phba, ndlp, retry)) {
+ if (!lpfc_issue_els_adisc(vport, ndlp, retry)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
}
break;
case ELS_CMD_PRLI:
- if (!lpfc_issue_els_prli(phba, ndlp, retry)) {
+ if (!lpfc_issue_els_prli(vport, ndlp, retry)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
}
break;
case ELS_CMD_LOGO:
- if (!lpfc_issue_els_logo(phba, ndlp, retry)) {
+ if (!lpfc_issue_els_logo(vport, ndlp, retry)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
}
break;
+ case ELS_CMD_FDISC:
+ lpfc_issue_els_fdisc(vport, ndlp, retry);
+ break;
}
return;
}
static int
-lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
- IOCB_t *irsp;
- struct lpfc_dmabuf *pcmd;
- struct lpfc_nodelist *ndlp;
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
uint32_t *elscmd;
struct ls_rjt stat;
- int retry, maxretry;
- int delay;
- uint32_t cmd;
+ int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
+ uint32_t cmd = 0;
uint32_t did;
- retry = 0;
- delay = 0;
- maxretry = lpfc_max_els_tries;
- irsp = &rspiocb->iocb;
- ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
- cmd = 0;
/* Note: context2 may be 0 for internal driver abort
* of delays ELS command.
@@ -1594,11 +1806,15 @@
else {
/* We should only hit this case for retrying PLOGI */
did = irsp->un.elsreq64.remoteID;
- ndlp = lpfc_findnode_did(phba, did);
+ ndlp = lpfc_findnode_did(vport, did);
if (!ndlp && (cmd != ELS_CMD_PLOGI))
return 1;
}
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Retry ELS: wd7:x%x wd4:x%x did:x%x",
+ *(((uint32_t *) irsp) + 7), irsp->un.ulpWord[4], ndlp->nlp_DID);
+
switch (irsp->ulpStatus) {
case IOSTAT_FCP_RSP_ERROR:
case IOSTAT_REMOTE_STOP:
@@ -1607,25 +1823,37 @@
case IOSTAT_LOCAL_REJECT:
switch ((irsp->un.ulpWord[4] & 0xff)) {
case IOERR_LOOP_OPEN_FAILURE:
- if (cmd == ELS_CMD_PLOGI) {
- if (cmdiocb->retry == 0) {
- delay = 1;
- }
+ if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0)
+ delay = 1000;
+ retry = 1;
+ break;
+
+ case IOERR_ILLEGAL_COMMAND:
+ if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) &&
+ (cmd == ELS_CMD_FDISC)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0124 FDISC failed (3/6) retrying...\n",
+ phba->brd_no, vport->vpi);
+ lpfc_mbx_unreg_vpi(vport);
+ retry = 1;
+ /* Always retry for this case */
+ cmdiocb->retry = 0;
}
+ break;
+
+ case IOERR_NO_RESOURCES:
+ retry = 1;
+ if (cmdiocb->retry > 100)
+ delay = 100;
+ maxretry = 250;
+ break;
+
+ case IOERR_ILLEGAL_FRAME:
+ delay = 100;
retry = 1;
break;
case IOERR_SEQUENCE_TIMEOUT:
- retry = 1;
- break;
-
- case IOERR_NO_RESOURCES:
- if (cmd == ELS_CMD_PLOGI) {
- delay = 1;
- }
- retry = 1;
- break;
-
case IOERR_INVALID_RPI:
retry = 1;
break;
@@ -1655,27 +1883,57 @@
if (stat.un.b.lsRjtRsnCodeExp ==
LSEXP_CMD_IN_PROGRESS) {
if (cmd == ELS_CMD_PLOGI) {
- delay = 1;
+ delay = 1000;
maxretry = 48;
}
retry = 1;
break;
}
if (cmd == ELS_CMD_PLOGI) {
- delay = 1;
+ delay = 1000;
maxretry = lpfc_max_els_tries + 1;
retry = 1;
break;
}
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ (cmd == ELS_CMD_FDISC) &&
+ (stat.un.b.lsRjtRsnCodeExp == LSEXP_OUT_OF_RESOURCE)){
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0125 FDISC Failed (x%x)."
+ " Fabric out of resources\n",
+ phba->brd_no, vport->vpi, stat.un.lsRjtError);
+ lpfc_vport_set_state(vport,
+ FC_VPORT_NO_FABRIC_RSCS);
+ }
break;
case LSRJT_LOGICAL_BSY:
- if (cmd == ELS_CMD_PLOGI) {
- delay = 1;
+ if ((cmd == ELS_CMD_PLOGI) ||
+ (cmd == ELS_CMD_PRLI)) {
+ delay = 1000;
maxretry = 48;
+ } else if (cmd == ELS_CMD_FDISC) {
+ /* Always retry for this case */
+ cmdiocb->retry = 0;
}
retry = 1;
break;
+
+ case LSRJT_LOGICAL_ERR:
+ case LSRJT_PROTOCOL_ERR:
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ (cmd == ELS_CMD_FDISC) &&
+ ((stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_PNAME) ||
+ (stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_NPORT_ID))
+ ) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0123 FDISC Failed (x%x)."
+ " Fabric Detected Bad WWN\n",
+ phba->brd_no, vport->vpi, stat.un.lsRjtError);
+ lpfc_vport_set_state(vport,
+ FC_VPORT_FABRIC_REJ_WWN);
+ }
+ break;
}
break;
@@ -1695,21 +1953,27 @@
retry = 0;
}
+ if ((vport->load_flag & FC_UNLOADING) != 0)
+ retry = 0;
+
if (retry) {
/* Retry ELS command <elsCmd> to remote NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0107 Retry ELS command x%x to remote "
+ "%d (%d):0107 Retry ELS command x%x to remote "
"NPORT x%x Data: x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
cmd, did, cmdiocb->retry, delay);
- if ((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) {
+ if (((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) &&
+ ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
+ ((irsp->un.ulpWord[4] & 0xff) != IOERR_NO_RESOURCES))) {
+ /* Don't reset timer for no resources */
+
/* If discovery / RSCN timer is running, reset it */
- if (timer_pending(&phba->fc_disctmo) ||
- (phba->fc_flag & FC_RSCN_MODE)) {
- lpfc_set_disctmo(phba);
- }
+ if (timer_pending(&vport->fc_disctmo) ||
+ (vport->fc_flag & FC_RSCN_MODE))
+ lpfc_set_disctmo(vport);
}
phba->fc_stat.elsXmitRetry++;
@@ -1717,50 +1981,62 @@
phba->fc_stat.elsDelayRetry++;
ndlp->nlp_retry = cmdiocb->retry;
- mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+ /* delay is specified in milliseconds */
+ mod_timer(&ndlp->nlp_delayfunc,
+ jiffies + msecs_to_jiffies(delay));
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ if (cmd == ELS_CMD_PRLI)
+ lpfc_nlp_set_state(vport, ndlp,
+ NLP_STE_REG_LOGIN_ISSUE);
+ else
+ lpfc_nlp_set_state(vport, ndlp,
+ NLP_STE_NPR_NODE);
ndlp->nlp_last_elscmd = cmd;
return 1;
}
switch (cmd) {
case ELS_CMD_FLOGI:
- lpfc_issue_els_flogi(phba, ndlp, cmdiocb->retry);
+ lpfc_issue_els_flogi(vport, ndlp, cmdiocb->retry);
+ return 1;
+ case ELS_CMD_FDISC:
+ lpfc_issue_els_fdisc(vport, ndlp, cmdiocb->retry);
return 1;
case ELS_CMD_PLOGI:
if (ndlp) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp,
+ lpfc_nlp_set_state(vport, ndlp,
NLP_STE_PLOGI_ISSUE);
}
- lpfc_issue_els_plogi(phba, did, cmdiocb->retry);
+ lpfc_issue_els_plogi(vport, did, cmdiocb->retry);
return 1;
case ELS_CMD_ADISC:
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
- lpfc_issue_els_adisc(phba, ndlp, cmdiocb->retry);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
+ lpfc_issue_els_adisc(vport, ndlp, cmdiocb->retry);
return 1;
case ELS_CMD_PRLI:
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
- lpfc_issue_els_prli(phba, ndlp, cmdiocb->retry);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
+ lpfc_issue_els_prli(vport, ndlp, cmdiocb->retry);
return 1;
case ELS_CMD_LOGO:
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- lpfc_issue_els_logo(phba, ndlp, cmdiocb->retry);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ lpfc_issue_els_logo(vport, ndlp, cmdiocb->retry);
return 1;
}
}
/* No retry ELS command <elsCmd> to remote NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0108 No retry ELS command x%x to remote NPORT x%x "
- "Data: x%x\n",
- phba->brd_no,
+ "%d (%d):0108 No retry ELS command x%x to remote "
+ "NPORT x%x Data: x%x\n",
+ phba->brd_no, vport->vpi,
cmd, did, cmdiocb->retry);
return 0;
@@ -1795,33 +2071,36 @@
lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
kfree(buf_ptr);
}
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_release_iocbq(phba, elsiocb);
- spin_unlock_irq(phba->host->host_lock);
return 0;
}
static void
-lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
- struct lpfc_nodelist *ndlp;
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_vport *vport = cmdiocb->vport;
+ IOCB_t *irsp;
- ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ irsp = &rspiocb->iocb;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "ACC LOGO cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID);
/* ACC to LOGO completes to NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0109 ACC to LOGO completes to NPort x%x "
+ "%d (%d):0109 ACC to LOGO completes to NPort x%x "
"Data: x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
- ndlp->nlp_state, ndlp->nlp_rpi);
+ phba->brd_no, vport->vpi, ndlp->nlp_DID,
+ ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
switch (ndlp->nlp_state) {
case NLP_STE_UNUSED_NODE: /* node is just allocated */
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
case NLP_STE_NPR_NODE: /* NPort Recovery mode */
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
break;
default:
break;
@@ -1830,24 +2109,38 @@
return;
}
+void
+lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+
+ pmb->context1 = NULL;
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_nlp_put(ndlp);
+ return;
+}
+
static void
-lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
+ struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
IOCB_t *irsp;
- struct lpfc_nodelist *ndlp;
LPFC_MBOXQ_t *mbox = NULL;
- struct lpfc_dmabuf *mp;
+ struct lpfc_dmabuf *mp = NULL;
irsp = &rspiocb->iocb;
- ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
if (cmdiocb->context_un.mbox)
mbox = cmdiocb->context_un.mbox;
-
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba) || !ndlp) {
+ if (!ndlp || lpfc_els_chk_latt(vport)) {
if (mbox) {
mp = (struct lpfc_dmabuf *) mbox->context1;
if (mp) {
@@ -1859,24 +2152,37 @@
goto out;
}
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "ACC cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->un.rcvels.remoteID);
+
/* ELS response tag <ulpIoTag> completes */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0110 ELS response tag x%x completes "
+ "%d (%d):0110 ELS response tag x%x completes "
"Data: x%x x%x x%x x%x x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
- ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi);
if (mbox) {
if ((rspiocb->iocb.ulpStatus == 0)
&& (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
- lpfc_unreg_rpi(phba, ndlp);
- mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
+ lpfc_unreg_rpi(vport, ndlp);
mbox->context2 = lpfc_nlp_get(ndlp);
- ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE);
+ mbox->vport = vport;
+ if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) {
+ mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
+ }
+ else {
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
+ ndlp->nlp_prev_state = ndlp->nlp_state;
+ lpfc_nlp_set_state(vport, ndlp,
+ NLP_STE_REG_LOGIN_ISSUE);
+ }
if (lpfc_sli_issue_mbox(phba, mbox,
(MBX_NOWAIT | MBX_STOP_IOCB))
!= MBX_NOT_FINISHED) {
@@ -1886,15 +2192,11 @@
/* NOTE: we should have messages for unsuccessful
reglogin */
} else {
- /* Do not call NO_LIST for lpfc_els_abort'ed ELS cmds */
- if (!((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
- (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
- (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) {
- if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
- lpfc_drop_node(phba, ndlp);
- ndlp = NULL;
- }
+ /* Do not drop node for lpfc_els_abort'ed ELS cmds */
+ if (!lpfc_error_lost_link(irsp) &&
+ ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
+ lpfc_drop_node(vport, ndlp);
+ ndlp = NULL;
}
}
mp = (struct lpfc_dmabuf *) mbox->context1;
@@ -1906,19 +2208,21 @@
}
out:
if (ndlp) {
- spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
+ spin_unlock_irq(shost->host_lock);
}
lpfc_els_free_iocb(phba, cmdiocb);
return;
}
int
-lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
- struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp,
- LPFC_MBOXQ_t * mbox, uint8_t newnode)
+lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
+ struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
+ LPFC_MBOXQ_t *mbox, uint8_t newnode)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
IOCB_t *icmd;
IOCB_t *oldcmd;
struct lpfc_iocbq *elsiocb;
@@ -1935,23 +2239,30 @@
switch (flag) {
case ELS_CMD_ACC:
- cmdsize = sizeof (uint32_t);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
- ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+ cmdsize = sizeof(uint32_t);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
+ ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
if (!elsiocb) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_LOGO_ACC;
+ spin_unlock_irq(shost->host_lock);
return 1;
}
+
icmd = &elsiocb->iocb;
icmd->ulpContext = oldcmd->ulpContext; /* Xri */
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
case ELS_CMD_PLOGI:
- cmdsize = (sizeof (struct serv_parm) + sizeof (uint32_t));
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
- ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+ cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
+ ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
if (!elsiocb)
return 1;
@@ -1963,12 +2274,16 @@
elsiocb->context_un.mbox = mbox;
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
- pcmd += sizeof (uint32_t);
- memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm));
+ pcmd += sizeof(uint32_t);
+ memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC PLOGI: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
case ELS_CMD_PRLO:
- cmdsize = sizeof (uint32_t) + sizeof (PRLO);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+ cmdsize = sizeof(uint32_t) + sizeof(PRLO);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
ndlp, ndlp->nlp_DID, ELS_CMD_PRLO);
if (!elsiocb)
return 1;
@@ -1978,10 +2293,14 @@
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
- sizeof (uint32_t) + sizeof (PRLO));
+ sizeof(uint32_t) + sizeof(PRLO));
*((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC;
els_pkt_ptr = (ELS_PKT *) pcmd;
els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC PRLO: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
default:
return 1;
@@ -1994,25 +2313,23 @@
/* Xmit ELS ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
+ "%d (%d):0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
"DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
- phba->brd_no, elsiocb->iotag,
+ phba->brd_no, vport->vpi, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
if (ndlp->nlp_flag & NLP_LOGO_ACC) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_LOGO_ACC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc;
} else {
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
}
phba->fc_stat.elsXmitACC++;
- spin_lock_irq(phba->host->host_lock);
rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
- spin_unlock_irq(phba->host->host_lock);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -2021,9 +2338,11 @@
}
int
-lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
- struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
+ struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
+ LPFC_MBOXQ_t *mbox)
{
+ struct lpfc_hba *phba = vport->phba;
IOCB_t *icmd;
IOCB_t *oldcmd;
struct lpfc_iocbq *elsiocb;
@@ -2036,9 +2355,9 @@
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
- cmdsize = 2 * sizeof (uint32_t);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
- ndlp, ndlp->nlp_DID, ELS_CMD_LS_RJT);
+ cmdsize = 2 * sizeof(uint32_t);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_LS_RJT);
if (!elsiocb)
return 1;
@@ -2048,22 +2367,30 @@
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
*((uint32_t *) (pcmd)) = rejectError;
+ if (mbox) {
+ elsiocb->context_un.mbox = mbox;
+ elsiocb->context1 = lpfc_nlp_get(ndlp);
+ }
+
/* Xmit ELS RJT <err> response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0129 Xmit ELS RJT x%x response tag x%x xri x%x, "
- "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
- phba->brd_no, rejectError, elsiocb->iotag,
+ "%d (%d):0129 Xmit ELS RJT x%x response tag x%x "
+ "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
+ "rpi x%x\n",
+ phba->brd_no, vport->vpi, rejectError, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue LS_RJT: did:x%x flg:x%x err:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, rejectError);
+
phba->fc_stat.elsXmitLSRJT++;
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
- spin_lock_irq(phba->host->host_lock);
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
- spin_unlock_irq(phba->host->host_lock);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -2072,25 +2399,22 @@
}
int
-lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
- struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
+ struct lpfc_nodelist *ndlp)
{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
ADISC *ap;
- IOCB_t *icmd;
- IOCB_t *oldcmd;
+ IOCB_t *icmd, *oldcmd;
struct lpfc_iocbq *elsiocb;
- struct lpfc_sli_ring *pring;
- struct lpfc_sli *psli;
uint8_t *pcmd;
uint16_t cmdsize;
int rc;
- psli = &phba->sli;
- pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
-
- cmdsize = sizeof (uint32_t) + sizeof (ADISC);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
- ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+ cmdsize = sizeof(uint32_t) + sizeof(ADISC);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
if (!elsiocb)
return 1;
@@ -2100,28 +2424,30 @@
/* Xmit ADISC ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0130 Xmit ADISC ACC response iotag x%x xri: "
+ "%d (%d):0130 Xmit ADISC ACC response iotag x%x xri: "
"x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
- phba->brd_no, elsiocb->iotag,
+ phba->brd_no, vport->vpi, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
ap = (ADISC *) (pcmd);
ap->hardAL_PA = phba->fc_pref_ALPA;
- memcpy(&ap->portName, &phba->fc_portname, sizeof (struct lpfc_name));
- memcpy(&ap->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
- ap->DID = be32_to_cpu(phba->fc_myDID);
+ memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name));
+ memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
+ ap->DID = be32_to_cpu(vport->fc_myDID);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC ADISC: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
phba->fc_stat.elsXmitACC++;
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
- spin_lock_irq(phba->host->host_lock);
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
- spin_unlock_irq(phba->host->host_lock);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -2130,9 +2456,10 @@
}
int
-lpfc_els_rsp_prli_acc(struct lpfc_hba *phba, struct lpfc_iocbq *oldiocb,
+lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
struct lpfc_nodelist *ndlp)
{
+ struct lpfc_hba *phba = vport->phba;
PRLI *npr;
lpfc_vpd_t *vpd;
IOCB_t *icmd;
@@ -2147,8 +2474,8 @@
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
- cmdsize = sizeof (uint32_t) + sizeof (PRLI);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, ndlp,
+ cmdsize = sizeof(uint32_t) + sizeof(PRLI);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
if (!elsiocb)
return 1;
@@ -2159,19 +2486,19 @@
/* Xmit PRLI ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0131 Xmit PRLI ACC response tag x%x xri x%x, "
+ "%d (%d):0131 Xmit PRLI ACC response tag x%x xri x%x, "
"did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
- phba->brd_no, elsiocb->iotag,
+ phba->brd_no, vport->vpi, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
/* For PRLI, remainder of payload is PRLI parameter page */
- memset(pcmd, 0, sizeof (PRLI));
+ memset(pcmd, 0, sizeof(PRLI));
npr = (PRLI *) pcmd;
vpd = &phba->vpd;
@@ -2193,12 +2520,14 @@
npr->prliType = PRLI_FCP_TYPE;
npr->initiatorFunc = 1;
- phba->fc_stat.elsXmitACC++;
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC PRLI: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
- spin_lock_irq(phba->host->host_lock);
+ phba->fc_stat.elsXmitACC++;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+
rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
- spin_unlock_irq(phba->host->host_lock);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -2207,12 +2536,12 @@
}
static int
-lpfc_els_rsp_rnid_acc(struct lpfc_hba *phba, uint8_t format,
+lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
{
+ struct lpfc_hba *phba = vport->phba;
RNID *rn;
- IOCB_t *icmd;
- IOCB_t *oldcmd;
+ IOCB_t *icmd, *oldcmd;
struct lpfc_iocbq *elsiocb;
struct lpfc_sli_ring *pring;
struct lpfc_sli *psli;
@@ -2223,13 +2552,13 @@
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING];
- cmdsize = sizeof (uint32_t) + sizeof (uint32_t)
- + (2 * sizeof (struct lpfc_name));
+ cmdsize = sizeof(uint32_t) + sizeof(uint32_t)
+ + (2 * sizeof(struct lpfc_name));
if (format)
- cmdsize += sizeof (RNID_TOP_DISC);
+ cmdsize += sizeof(RNID_TOP_DISC);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
- ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
if (!elsiocb)
return 1;
@@ -2239,30 +2568,30 @@
/* Xmit RNID ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0132 Xmit RNID ACC response tag x%x "
+ "%d (%d):0132 Xmit RNID ACC response tag x%x "
"xri x%x\n",
- phba->brd_no, elsiocb->iotag,
+ phba->brd_no, vport->vpi, elsiocb->iotag,
elsiocb->iocb.ulpContext);
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
- memset(pcmd, 0, sizeof (RNID));
+ memset(pcmd, 0, sizeof(RNID));
rn = (RNID *) (pcmd);
rn->Format = format;
- rn->CommonLen = (2 * sizeof (struct lpfc_name));
- memcpy(&rn->portName, &phba->fc_portname, sizeof (struct lpfc_name));
- memcpy(&rn->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
+ rn->CommonLen = (2 * sizeof(struct lpfc_name));
+ memcpy(&rn->portName, &vport->fc_portname, sizeof(struct lpfc_name));
+ memcpy(&rn->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
switch (format) {
case 0:
rn->SpecificLen = 0;
break;
case RNID_TOPOLOGY_DISC:
- rn->SpecificLen = sizeof (RNID_TOP_DISC);
+ rn->SpecificLen = sizeof(RNID_TOP_DISC);
memcpy(&rn->un.topologyDisc.portName,
- &phba->fc_portname, sizeof (struct lpfc_name));
+ &vport->fc_portname, sizeof(struct lpfc_name));
rn->un.topologyDisc.unitType = RNID_HBA;
rn->un.topologyDisc.physPort = 0;
rn->un.topologyDisc.attachedNodes = 0;
@@ -2273,15 +2602,17 @@
break;
}
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC RNID: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
phba->fc_stat.elsXmitACC++;
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
lpfc_nlp_put(ndlp);
elsiocb->context1 = NULL; /* Don't need ndlp for cmpl,
* it could be freed */
- spin_lock_irq(phba->host->host_lock);
rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
- spin_unlock_irq(phba->host->host_lock);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -2290,168 +2621,153 @@
}
int
-lpfc_els_disc_adisc(struct lpfc_hba *phba)
+lpfc_els_disc_adisc(struct lpfc_vport *vport)
{
- int sentadisc;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp, *next_ndlp;
+ int sentadisc = 0;
- sentadisc = 0;
/* go thru NPR nodes and issue any remaining ELS ADISCs */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
(ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
(ndlp->nlp_flag & NLP_NPR_ADISC) != 0) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
- lpfc_issue_els_adisc(phba, ndlp, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
+ lpfc_issue_els_adisc(vport, ndlp, 0);
sentadisc++;
- phba->num_disc_nodes++;
- if (phba->num_disc_nodes >=
- phba->cfg_discovery_threads) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_NLP_MORE;
- spin_unlock_irq(phba->host->host_lock);
+ vport->num_disc_nodes++;
+ if (vport->num_disc_nodes >=
+ vport->phba->cfg_discovery_threads) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_NLP_MORE;
+ spin_unlock_irq(shost->host_lock);
break;
}
}
}
if (sentadisc == 0) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_NLP_MORE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NLP_MORE;
+ spin_unlock_irq(shost->host_lock);
}
return sentadisc;
}
int
-lpfc_els_disc_plogi(struct lpfc_hba * phba)
+lpfc_els_disc_plogi(struct lpfc_vport *vport)
{
- int sentplogi;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp, *next_ndlp;
+ int sentplogi = 0;
- sentplogi = 0;
- /* go thru NPR list and issue any remaining ELS PLOGIs */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+ /* go thru NPR nodes and issue any remaining ELS PLOGIs */
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
(ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
(ndlp->nlp_flag & NLP_DELAY_TMO) == 0 &&
(ndlp->nlp_flag & NLP_NPR_ADISC) == 0) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
sentplogi++;
- phba->num_disc_nodes++;
- if (phba->num_disc_nodes >=
- phba->cfg_discovery_threads) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_NLP_MORE;
- spin_unlock_irq(phba->host->host_lock);
+ vport->num_disc_nodes++;
+ if (vport->num_disc_nodes >=
+ vport->phba->cfg_discovery_threads) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_NLP_MORE;
+ spin_unlock_irq(shost->host_lock);
break;
}
}
}
if (sentplogi == 0) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_NLP_MORE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NLP_MORE;
+ spin_unlock_irq(shost->host_lock);
}
return sentplogi;
}
-int
-lpfc_els_flush_rscn(struct lpfc_hba * phba)
+void
+lpfc_els_flush_rscn(struct lpfc_vport *vport)
{
- struct lpfc_dmabuf *mp;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
int i;
- for (i = 0; i < phba->fc_rscn_id_cnt; i++) {
- mp = phba->fc_rscn_id_list[i];
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- phba->fc_rscn_id_list[i] = NULL;
+ for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
+ lpfc_in_buf_free(phba, vport->fc_rscn_id_list[i]);
+ vport->fc_rscn_id_list[i] = NULL;
}
- phba->fc_rscn_id_cnt = 0;
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY);
- spin_unlock_irq(phba->host->host_lock);
- lpfc_can_disctmo(phba);
- return 0;
+ spin_lock_irq(shost->host_lock);
+ vport->fc_rscn_id_cnt = 0;
+ vport->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
}
int
-lpfc_rscn_payload_check(struct lpfc_hba * phba, uint32_t did)
+lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did)
{
D_ID ns_did;
D_ID rscn_did;
- struct lpfc_dmabuf *mp;
uint32_t *lp;
- uint32_t payload_len, cmd, i, match;
+ uint32_t payload_len, i;
+ struct lpfc_hba *phba = vport->phba;
ns_did.un.word = did;
- match = 0;
/* Never match fabric nodes for RSCNs */
if ((did & Fabric_DID_MASK) == Fabric_DID_MASK)
- return(0);
+ return 0;
/* If we are doing a FULL RSCN rediscovery, match everything */
- if (phba->fc_flag & FC_RSCN_DISCOVERY) {
+ if (vport->fc_flag & FC_RSCN_DISCOVERY)
return did;
- }
- for (i = 0; i < phba->fc_rscn_id_cnt; i++) {
- mp = phba->fc_rscn_id_list[i];
- lp = (uint32_t *) mp->virt;
- cmd = *lp++;
- payload_len = be32_to_cpu(cmd) & 0xffff; /* payload length */
- payload_len -= sizeof (uint32_t); /* take off word 0 */
+ for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
+ lp = vport->fc_rscn_id_list[i]->virt;
+ payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
+ payload_len -= sizeof(uint32_t); /* take off word 0 */
while (payload_len) {
- rscn_did.un.word = *lp++;
- rscn_did.un.word = be32_to_cpu(rscn_did.un.word);
- payload_len -= sizeof (uint32_t);
+ rscn_did.un.word = be32_to_cpu(*lp++);
+ payload_len -= sizeof(uint32_t);
switch (rscn_did.un.b.resv) {
case 0: /* Single N_Port ID effected */
- if (ns_did.un.word == rscn_did.un.word) {
- match = did;
- }
+ if (ns_did.un.word == rscn_did.un.word)
+ return did;
break;
case 1: /* Whole N_Port Area effected */
if ((ns_did.un.b.domain == rscn_did.un.b.domain)
&& (ns_did.un.b.area == rscn_did.un.b.area))
- {
- match = did;
- }
+ return did;
break;
case 2: /* Whole N_Port Domain effected */
if (ns_did.un.b.domain == rscn_did.un.b.domain)
- {
- match = did;
- }
- break;
- case 3: /* Whole Fabric effected */
- match = did;
+ return did;
break;
default:
- /* Unknown Identifier in RSCN list */
+ /* Unknown Identifier in RSCN node */
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0217 Unknown Identifier in "
- "RSCN payload Data: x%x\n",
- phba->brd_no, rscn_did.un.word);
- break;
- }
- if (match) {
- break;
+ "%d (%d):0217 Unknown "
+ "Identifier in RSCN payload "
+ "Data: x%x\n",
+ phba->brd_no, vport->vpi,
+ rscn_did.un.word);
+ case 3: /* Whole Fabric effected */
+ return did;
}
}
}
- return match;
+ return 0;
}
static int
-lpfc_rscn_recovery_check(struct lpfc_hba *phba)
+lpfc_rscn_recovery_check(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp = NULL;
@@ -2459,188 +2775,261 @@
* them to NPR state.
*/
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
- lpfc_rscn_payload_check(phba, ndlp->nlp_DID) == 0)
+ lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0)
continue;
- lpfc_disc_state_machine(phba, ndlp, NULL,
- NLP_EVT_DEVICE_RECOVERY);
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+ NLP_EVT_DEVICE_RECOVERY);
/*
* Make sure NLP_DELAY_TMO is NOT running after a device
* recovery event.
*/
if (ndlp->nlp_flag & NLP_DELAY_TMO)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
}
return 0;
}
static int
-lpfc_els_rcv_rscn(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb,
- struct lpfc_nodelist * ndlp, uint8_t newnode)
+lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp, uint8_t newnode)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd;
- uint32_t *lp;
+ struct lpfc_vport *next_vport;
+ uint32_t *lp, *datap;
IOCB_t *icmd;
- uint32_t payload_len, cmd;
+ uint32_t payload_len, length, nportid, *cmd;
+ int rscn_cnt = vport->fc_rscn_id_cnt;
+ int rscn_id = 0, hba_id = 0;
int i;
icmd = &cmdiocb->iocb;
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
- cmd = *lp++;
- payload_len = be32_to_cpu(cmd) & 0xffff; /* payload length */
- payload_len -= sizeof (uint32_t); /* take off word 0 */
- cmd &= ELS_CMD_MASK;
+ payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
+ payload_len -= sizeof(uint32_t); /* take off word 0 */
/* RSCN received */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0214 RSCN received Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- phba->fc_flag, payload_len, *lp, phba->fc_rscn_id_cnt);
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0214 RSCN received Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi, vport->fc_flag, payload_len,
+ *lp, rscn_cnt);
for (i = 0; i < payload_len/sizeof(uint32_t); i++)
- fc_host_post_event(phba->host, fc_get_event_number(),
+ fc_host_post_event(shost, fc_get_event_number(),
FCH_EVT_RSCN, lp[i]);
/* If we are about to begin discovery, just ACC the RSCN.
* Discovery processing will satisfy it.
*/
- if (phba->hba_state <= LPFC_NS_QRY) {
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
- newnode);
+ if (vport->port_state <= LPFC_NS_QRY) {
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RSCN ignore: did:x%x/ste:x%x flg:x%x",
+ ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
+
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
+ newnode);
return 0;
}
+ /* If this RSCN just contains NPortIDs for other vports on this HBA,
+ * just ACC and ignore it.
+ */
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ !(phba->cfg_peer_port_login)) {
+ i = payload_len;
+ datap = lp;
+ while (i > 0) {
+ nportid = *datap++;
+ nportid = ((be32_to_cpu(nportid)) & Mask_DID);
+ i -= sizeof(uint32_t);
+ rscn_id++;
+ list_for_each_entry(next_vport, &phba->port_list,
+ listentry) {
+ if (nportid == next_vport->fc_myDID) {
+ hba_id++;
+ break;
+ }
+ }
+ }
+ if (rscn_id == hba_id) {
+ /* ALL NPortIDs in RSCN are on HBA */
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0214 Ignore RSCN Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi, vport->fc_flag, payload_len,
+ *lp, rscn_cnt);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RSCN vport: did:x%x/ste:x%x flg:x%x",
+ ndlp->nlp_DID, vport->port_state,
+ ndlp->nlp_flag);
+
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb,
+ ndlp, NULL, newnode);
+ return 0;
+ }
+ }
+
/* If we are already processing an RSCN, save the received
* RSCN payload buffer, cmdiocb->context2 to process later.
*/
- if (phba->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
- if ((phba->fc_rscn_id_cnt < FC_MAX_HOLD_RSCN) &&
- !(phba->fc_flag & FC_RSCN_DISCOVERY)) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_RSCN_MODE;
- spin_unlock_irq(phba->host->host_lock);
- phba->fc_rscn_id_list[phba->fc_rscn_id_cnt++] = pcmd;
+ if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RSCN defer: did:x%x/ste:x%x flg:x%x",
+ ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
- /* If we zero, cmdiocb->context2, the calling
- * routine will not try to free it.
- */
- cmdiocb->context2 = NULL;
+ vport->fc_flag |= FC_RSCN_DEFERRED;
+ if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
+ !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_RSCN_MODE;
+ spin_unlock_irq(shost->host_lock);
+ if (rscn_cnt) {
+ cmd = vport->fc_rscn_id_list[rscn_cnt-1]->virt;
+ length = be32_to_cpu(*cmd & ~ELS_CMD_MASK);
+ }
+ if ((rscn_cnt) &&
+ (payload_len + length <= LPFC_BPL_SIZE)) {
+ *cmd &= ELS_CMD_MASK;
+ *cmd |= be32_to_cpu(payload_len + length);
+ memcpy(((uint8_t *)cmd) + length, lp,
+ payload_len);
+ } else {
+ vport->fc_rscn_id_list[rscn_cnt] = pcmd;
+ vport->fc_rscn_id_cnt++;
+ /* If we zero, cmdiocb->context2, the calling
+ * routine will not try to free it.
+ */
+ cmdiocb->context2 = NULL;
+ }
/* Deferred RSCN */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0235 Deferred RSCN "
+ "%d (%d):0235 Deferred RSCN "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->fc_rscn_id_cnt,
- phba->fc_flag, phba->hba_state);
+ phba->brd_no, vport->vpi,
+ vport->fc_rscn_id_cnt, vport->fc_flag,
+ vport->port_state);
} else {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_RSCN_DISCOVERY;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_RSCN_DISCOVERY;
+ spin_unlock_irq(shost->host_lock);
/* ReDiscovery RSCN */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0234 ReDiscovery RSCN "
+ "%d (%d):0234 ReDiscovery RSCN "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->fc_rscn_id_cnt,
- phba->fc_flag, phba->hba_state);
+ phba->brd_no, vport->vpi,
+ vport->fc_rscn_id_cnt, vport->fc_flag,
+ vport->port_state);
}
/* Send back ACC */
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
newnode);
/* send RECOVERY event for ALL nodes that match RSCN payload */
- lpfc_rscn_recovery_check(phba);
+ lpfc_rscn_recovery_check(vport);
+ vport->fc_flag &= ~FC_RSCN_DEFERRED;
return 0;
}
- phba->fc_flag |= FC_RSCN_MODE;
- phba->fc_rscn_id_list[phba->fc_rscn_id_cnt++] = pcmd;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RSCN: did:x%x/ste:x%x flg:x%x",
+ ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
+
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_RSCN_MODE;
+ spin_unlock_irq(shost->host_lock);
+ vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd;
/*
* If we zero, cmdiocb->context2, the calling routine will
* not try to free it.
*/
cmdiocb->context2 = NULL;
- lpfc_set_disctmo(phba);
+ lpfc_set_disctmo(vport);
/* Send back ACC */
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode);
/* send RECOVERY event for ALL nodes that match RSCN payload */
- lpfc_rscn_recovery_check(phba);
+ lpfc_rscn_recovery_check(vport);
- return lpfc_els_handle_rscn(phba);
+ return lpfc_els_handle_rscn(vport);
}
int
-lpfc_els_handle_rscn(struct lpfc_hba * phba)
+lpfc_els_handle_rscn(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp;
+ struct lpfc_hba *phba = vport->phba;
+
+ /* Ignore RSCN if the port is being torn down. */
+ if (vport->load_flag & FC_UNLOADING) {
+ lpfc_els_flush_rscn(vport);
+ return 0;
+ }
/* Start timer for RSCN processing */
- lpfc_set_disctmo(phba);
+ lpfc_set_disctmo(vport);
/* RSCN processed */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0215 RSCN processed Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- phba->fc_flag, 0, phba->fc_rscn_id_cnt,
- phba->hba_state);
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0215 RSCN processed Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi,
+ vport->fc_flag, 0, vport->fc_rscn_id_cnt,
+ vport->port_state);
/* To process RSCN, first compare RSCN data with NameServer */
- phba->fc_ns_retry = 0;
- ndlp = lpfc_findnode_did(phba, NameServer_DID);
+ vport->fc_ns_retry = 0;
+ ndlp = lpfc_findnode_did(vport, NameServer_DID);
if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
/* Good ndlp, issue CT Request to NameServer */
- if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) == 0) {
+ if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0) == 0)
/* Wait for NameServer query cmpl before we can
continue */
return 1;
- }
} else {
/* If login to NameServer does not exist, issue one */
/* Good status, issue PLOGI to NameServer */
- ndlp = lpfc_findnode_did(phba, NameServer_DID);
- if (ndlp) {
+ ndlp = lpfc_findnode_did(vport, NameServer_DID);
+ if (ndlp)
/* Wait for NameServer login cmpl before we can
continue */
return 1;
- }
+
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp) {
- lpfc_els_flush_rscn(phba);
+ lpfc_els_flush_rscn(vport);
return 0;
} else {
- lpfc_nlp_init(phba, ndlp, NameServer_DID);
+ lpfc_nlp_init(vport, ndlp, NameServer_DID);
ndlp->nlp_type |= NLP_FABRIC;
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, NameServer_DID, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, NameServer_DID, 0);
/* Wait for NameServer login cmpl before we can
continue */
return 1;
}
}
- lpfc_els_flush_rscn(phba);
+ lpfc_els_flush_rscn(vport);
return 0;
}
static int
-lpfc_els_rcv_flogi(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb,
- struct lpfc_nodelist * ndlp, uint8_t newnode)
+lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp, uint8_t newnode)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
uint32_t *lp = (uint32_t *) pcmd->virt;
IOCB_t *icmd = &cmdiocb->iocb;
@@ -2655,7 +3044,7 @@
/* FLOGI received */
- lpfc_set_disctmo(phba);
+ lpfc_set_disctmo(vport);
if (phba->fc_topology == TOPOLOGY_LOOP) {
/* We should never receive a FLOGI in loop mode, ignore it */
@@ -2664,33 +3053,34 @@
/* An FLOGI ELS command <elsCmd> was received from DID <did> in
Loop Mode */
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d:0113 An FLOGI ELS command x%x was received "
- "from DID x%x in Loop Mode\n",
- phba->brd_no, cmd, did);
+ "%d (%d):0113 An FLOGI ELS command x%x was "
+ "received from DID x%x in Loop Mode\n",
+ phba->brd_no, vport->vpi, cmd, did);
return 1;
}
did = Fabric_DID;
- if ((lpfc_check_sparm(phba, ndlp, sp, CLASS3))) {
+ if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) {
/* For a FLOGI we accept, then if our portname is greater
* then the remote portname we initiate Nport login.
*/
- rc = memcmp(&phba->fc_portname, &sp->portName,
- sizeof (struct lpfc_name));
+ rc = memcmp(&vport->fc_portname, &sp->portName,
+ sizeof(struct lpfc_name));
if (!rc) {
- if ((mbox = mempool_alloc(phba->mbox_mem_pool,
- GFP_KERNEL)) == 0) {
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
return 1;
- }
+
lpfc_linkdown(phba);
lpfc_init_link(phba, mbox,
phba->cfg_topology,
phba->cfg_link_speed);
mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
rc = lpfc_sli_issue_mbox
(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
lpfc_set_loopback_flag(phba);
@@ -2699,31 +3089,34 @@
}
return 1;
} else if (rc > 0) { /* greater than */
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_PT2PT_PLOGI;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_PT2PT_PLOGI;
+ spin_unlock_irq(shost->host_lock);
}
- phba->fc_flag |= FC_PT2PT;
- phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_PT2PT;
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
} else {
/* Reject this request because invalid parameters */
stat.un.b.lsRjtRsvd0 = 0;
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+ NULL);
return 1;
}
/* Send back ACC */
- lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, newnode);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, newnode);
return 0;
}
static int
-lpfc_els_rcv_rnid(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
@@ -2746,7 +3139,7 @@
case 0:
case RNID_TOPOLOGY_DISC:
/* Send back ACC */
- lpfc_els_rsp_rnid_acc(phba, rn->Format, cmdiocb, ndlp);
+ lpfc_els_rsp_rnid_acc(vport, rn->Format, cmdiocb, ndlp);
break;
default:
/* Reject this request because format not supported */
@@ -2754,14 +3147,15 @@
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+ NULL);
}
return 0;
}
static int
-lpfc_els_rcv_lirr(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- struct lpfc_nodelist *ndlp)
+lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
struct ls_rjt stat;
@@ -2770,15 +3164,15 @@
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
return 0;
}
static void
lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli;
- struct lpfc_sli_ring *pring;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
MAILBOX_t *mb;
IOCB_t *icmd;
RPS_RSP *rps_rsp;
@@ -2788,8 +3182,6 @@
uint16_t xri, status;
uint32_t cmdsize;
- psli = &phba->sli;
- pring = &psli->ring[LPFC_ELS_RING];
mb = &pmb->mb;
ndlp = (struct lpfc_nodelist *) pmb->context2;
@@ -2804,8 +3196,9 @@
cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
mempool_free(pmb, phba->mbox_mem_pool);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, lpfc_max_els_tries, ndlp,
- ndlp->nlp_DID, ELS_CMD_ACC);
+ elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
+ lpfc_max_els_tries, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
lpfc_nlp_put(ndlp);
if (!elsiocb)
return;
@@ -2815,14 +3208,14 @@
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
- pcmd += sizeof (uint32_t); /* Skip past command */
+ pcmd += sizeof(uint32_t); /* Skip past command */
rps_rsp = (RPS_RSP *)pcmd;
if (phba->fc_topology != TOPOLOGY_LOOP)
status = 0x10;
else
status = 0x8;
- if (phba->fc_flag & FC_FABRIC)
+ if (phba->pport->fc_flag & FC_FABRIC)
status |= 0x4;
rps_rsp->rsvd1 = 0;
@@ -2836,25 +3229,25 @@
/* Xmit ELS RPS ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
- "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
- phba->brd_no, elsiocb->iotag,
+ "%d (%d):0118 Xmit ELS RPS ACC response tag x%x "
+ "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
+ "rpi x%x\n",
+ phba->brd_no, ndlp->vport->vpi, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
phba->fc_stat.elsXmitACC++;
-
- if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+ if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
lpfc_els_free_iocb(phba, elsiocb);
- }
return;
}
static int
-lpfc_els_rcv_rps(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
+ struct lpfc_hba *phba = vport->phba;
uint32_t *lp;
uint8_t flag;
LPFC_MBOXQ_t *mbox;
@@ -2868,7 +3261,8 @@
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+ NULL);
}
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
@@ -2878,19 +3272,24 @@
if ((flag == 0) ||
((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) ||
- ((flag == 2) && (memcmp(&rps->un.portName, &phba->fc_portname,
- sizeof (struct lpfc_name)) == 0))) {
- if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC))) {
+ ((flag == 2) && (memcmp(&rps->un.portName, &vport->fc_portname,
+ sizeof(struct lpfc_name)) == 0))) {
+
+ printk("Fix me....\n");
+ dump_stack();
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
+ if (mbox) {
lpfc_read_lnk_stat(phba, mbox);
mbox->context1 =
- (void *)((unsigned long)cmdiocb->iocb.ulpContext);
+ (void *)((unsigned long) cmdiocb->iocb.ulpContext);
mbox->context2 = lpfc_nlp_get(ndlp);
+ mbox->vport = vport;
mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
if (lpfc_sli_issue_mbox (phba, mbox,
- (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) {
+ (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED)
/* Mbox completion will send ELS Response */
return 0;
- }
+
lpfc_nlp_put(ndlp);
mempool_free(mbox, phba->mbox_mem_pool);
}
@@ -2899,27 +3298,25 @@
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
return 0;
}
static int
-lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
- struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
+ struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
{
- IOCB_t *icmd;
- IOCB_t *oldcmd;
+ struct lpfc_hba *phba = vport->phba;
+ IOCB_t *icmd, *oldcmd;
RPL_RSP rpl_rsp;
struct lpfc_iocbq *elsiocb;
- struct lpfc_sli_ring *pring;
- struct lpfc_sli *psli;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
uint8_t *pcmd;
- psli = &phba->sli;
- pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
- ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
if (!elsiocb)
return 1;
@@ -2929,7 +3326,7 @@
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
- pcmd += sizeof (uint16_t);
+ pcmd += sizeof(uint16_t);
*((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize);
pcmd += sizeof(uint16_t);
@@ -2937,8 +3334,8 @@
rpl_rsp.listLen = be32_to_cpu(1);
rpl_rsp.index = 0;
rpl_rsp.port_num_blk.portNum = 0;
- rpl_rsp.port_num_blk.portID = be32_to_cpu(phba->fc_myDID);
- memcpy(&rpl_rsp.port_num_blk.portName, &phba->fc_portname,
+ rpl_rsp.port_num_blk.portID = be32_to_cpu(vport->fc_myDID);
+ memcpy(&rpl_rsp.port_num_blk.portName, &vport->fc_portname,
sizeof(struct lpfc_name));
memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t));
@@ -2946,13 +3343,14 @@
/* Xmit ELS RPL ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0120 Xmit ELS RPL ACC response tag x%x xri x%x, "
- "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
- phba->brd_no, elsiocb->iotag,
+ "%d (%d):0120 Xmit ELS RPL ACC response tag x%x "
+ "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
+ "rpi x%x\n",
+ phba->brd_no, vport->vpi, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
phba->fc_stat.elsXmitACC++;
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
@@ -2963,8 +3361,8 @@
}
static int
-lpfc_els_rcv_rpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
@@ -2979,7 +3377,8 @@
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+ NULL);
}
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
@@ -2996,15 +3395,16 @@
} else {
cmdsize = sizeof(uint32_t) + maxsize * sizeof(uint32_t);
}
- lpfc_els_rsp_rpl_acc(phba, cmdsize, cmdiocb, ndlp);
+ lpfc_els_rsp_rpl_acc(vport, cmdsize, cmdiocb, ndlp);
return 0;
}
static int
-lpfc_els_rcv_farp(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
IOCB_t *icmd;
@@ -3020,11 +3420,9 @@
fp = (FARP *) lp;
/* FARP-REQ received from DID <did> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_ELS,
- "%d:0601 FARP-REQ received from DID x%x\n",
- phba->brd_no, did);
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0601 FARP-REQ received from DID x%x\n",
+ phba->brd_no, vport->vpi, did);
/* We will only support match on WWPN or WWNN */
if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) {
@@ -3034,15 +3432,15 @@
cnt = 0;
/* If this FARP command is searching for my portname */
if (fp->Mflags & FARP_MATCH_PORT) {
- if (memcmp(&fp->RportName, &phba->fc_portname,
- sizeof (struct lpfc_name)) == 0)
+ if (memcmp(&fp->RportName, &vport->fc_portname,
+ sizeof(struct lpfc_name)) == 0)
cnt = 1;
}
/* If this FARP command is searching for my nodename */
if (fp->Mflags & FARP_MATCH_NODE) {
- if (memcmp(&fp->RnodeName, &phba->fc_nodename,
- sizeof (struct lpfc_name)) == 0)
+ if (memcmp(&fp->RnodeName, &vport->fc_nodename,
+ sizeof(struct lpfc_name)) == 0)
cnt = 1;
}
@@ -3052,28 +3450,28 @@
/* Log back into the node before sending the FARP. */
if (fp->Rflags & FARP_REQUEST_PLOGI) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp,
+ lpfc_nlp_set_state(vport, ndlp,
NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
}
/* Send a FARP response to that node */
- if (fp->Rflags & FARP_REQUEST_FARPR) {
- lpfc_issue_els_farpr(phba, did, 0);
- }
+ if (fp->Rflags & FARP_REQUEST_FARPR)
+ lpfc_issue_els_farpr(vport, did, 0);
}
}
return 0;
}
static int
-lpfc_els_rcv_farpr(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
IOCB_t *icmd;
uint32_t cmd, did;
+ struct lpfc_hba *phba = vport->phba;
icmd = &cmdiocb->iocb;
did = icmd->un.elsreq64.remoteID;
@@ -3082,21 +3480,18 @@
cmd = *lp++;
/* FARP-RSP received from DID <did> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_ELS,
- "%d:0600 FARP-RSP received from DID x%x\n",
- phba->brd_no, did);
-
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0600 FARP-RSP received from DID x%x\n",
+ phba->brd_no, vport->vpi, did);
/* ACCEPT the Farp resp request */
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
return 0;
}
static int
-lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_nodelist * fan_ndlp)
+lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *fan_ndlp)
{
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
@@ -3104,10 +3499,12 @@
uint32_t cmd, did;
FAN *fp;
struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct lpfc_hba *phba = vport->phba;
/* FAN received */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0265 FAN received\n",
- phba->brd_no);
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0265 FAN received\n",
+ phba->brd_no, vport->vpi);
icmd = &cmdiocb->iocb;
did = icmd->un.elsreq64.remoteID;
@@ -3115,11 +3512,11 @@
lp = (uint32_t *)pcmd->virt;
cmd = *lp++;
- fp = (FAN *)lp;
+ fp = (FAN *) lp;
/* FAN received; Fan does not have a reply sequence */
- if (phba->hba_state == LPFC_LOCAL_CFG_LINK) {
+ if (phba->pport->port_state == LPFC_LOCAL_CFG_LINK) {
if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName,
sizeof(struct lpfc_name)) != 0) ||
(memcmp(&phba->fc_fabparam.portName, &fp->FportName,
@@ -3130,7 +3527,7 @@
*/
list_for_each_entry_safe(ndlp, next_ndlp,
- &phba->fc_nodes, nlp_listp) {
+ &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state != NLP_STE_NPR_NODE)
continue;
if (ndlp->nlp_type & NLP_FABRIC) {
@@ -3138,24 +3535,24 @@
* Clean up old Fabric, Nameserver and
* other NLP_FABRIC logins
*/
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
/* Fail outstanding I/O now since this
* device is marked for PLOGI
*/
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
}
}
- phba->hba_state = LPFC_FLOGI;
- lpfc_set_disctmo(phba);
- lpfc_initial_flogi(phba);
+ vport->port_state = LPFC_FLOGI;
+ lpfc_set_disctmo(vport);
+ lpfc_initial_flogi(vport);
return 0;
}
/* Discovery not needed,
* move the nodes to their original state.
*/
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
nlp_listp) {
if (ndlp->nlp_state != NLP_STE_NPR_NODE)
continue;
@@ -3163,13 +3560,13 @@
switch (ndlp->nlp_prev_state) {
case NLP_STE_UNMAPPED_NODE:
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp,
+ lpfc_nlp_set_state(vport, ndlp,
NLP_STE_UNMAPPED_NODE);
break;
case NLP_STE_MAPPED_NODE:
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp,
+ lpfc_nlp_set_state(vport, ndlp,
NLP_STE_MAPPED_NODE);
break;
@@ -3179,7 +3576,7 @@
}
/* Start discovery - this should just do CLEAR_LA */
- lpfc_disc_start(phba);
+ lpfc_disc_start(vport);
}
return 0;
}
@@ -3187,42 +3584,42 @@
void
lpfc_els_timeout(unsigned long ptr)
{
- struct lpfc_hba *phba;
+ struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
+ struct lpfc_hba *phba = vport->phba;
unsigned long iflag;
- phba = (struct lpfc_hba *)ptr;
- if (phba == 0)
- return;
- spin_lock_irqsave(phba->host->host_lock, iflag);
- if (!(phba->work_hba_events & WORKER_ELS_TMO)) {
- phba->work_hba_events |= WORKER_ELS_TMO;
+ spin_lock_irqsave(&vport->work_port_lock, iflag);
+ if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
+ vport->work_port_events |= WORKER_ELS_TMO;
+ spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+
+ spin_lock_irqsave(&phba->hbalock, iflag);
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
}
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ else
+ spin_unlock_irqrestore(&vport->work_port_lock, iflag);
return;
}
void
-lpfc_els_timeout_handler(struct lpfc_hba *phba)
+lpfc_els_timeout_handler(struct lpfc_vport *vport)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_sli_ring *pring;
struct lpfc_iocbq *tmp_iocb, *piocb;
IOCB_t *cmd = NULL;
struct lpfc_dmabuf *pcmd;
- uint32_t *elscmd;
- uint32_t els_command=0;
+ uint32_t els_command = 0;
uint32_t timeout;
- uint32_t remote_ID;
+ uint32_t remote_ID = 0xffffffff;
- if (phba == 0)
- return;
- spin_lock_irq(phba->host->host_lock);
/* If the timer is already canceled do nothing */
- if (!(phba->work_hba_events & WORKER_ELS_TMO)) {
- spin_unlock_irq(phba->host->host_lock);
+ if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
return;
}
+ spin_lock_irq(&phba->hbalock);
timeout = (uint32_t)(phba->fc_ratov << 1);
pring = &phba->sli.ring[LPFC_ELS_RING];
@@ -3230,63 +3627,70 @@
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
cmd = &piocb->iocb;
- if ((piocb->iocb_flag & LPFC_IO_LIBDFC) ||
- (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN) ||
- (piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)) {
+ if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
+ piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
+ piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
continue;
- }
- pcmd = (struct lpfc_dmabuf *) piocb->context2;
- if (pcmd) {
- elscmd = (uint32_t *) (pcmd->virt);
- els_command = *elscmd;
- }
- if ((els_command == ELS_CMD_FARP)
- || (els_command == ELS_CMD_FARPR)) {
+ if (piocb->vport != vport)
continue;
- }
+
+ pcmd = (struct lpfc_dmabuf *) piocb->context2;
+ if (pcmd)
+ els_command = *(uint32_t *) (pcmd->virt);
+
+ if (els_command == ELS_CMD_FARP ||
+ els_command == ELS_CMD_FARPR ||
+ els_command == ELS_CMD_FDISC)
+ continue;
+
+ if (vport != piocb->vport)
+ continue;
if (piocb->drvrTimeout > 0) {
- if (piocb->drvrTimeout >= timeout) {
+ if (piocb->drvrTimeout >= timeout)
piocb->drvrTimeout -= timeout;
- } else {
+ else
piocb->drvrTimeout = 0;
- }
continue;
}
- if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
- struct lpfc_nodelist *ndlp;
- ndlp = __lpfc_findnode_rpi(phba, cmd->ulpContext);
- remote_ID = ndlp->nlp_DID;
- } else {
+ remote_ID = 0xffffffff;
+ if (cmd->ulpCommand != CMD_GEN_REQUEST64_CR)
remote_ID = cmd->un.elsreq64.remoteID;
+ else {
+ struct lpfc_nodelist *ndlp;
+ ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext);
+ if (ndlp)
+ remote_ID = ndlp->nlp_DID;
}
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_ELS,
- "%d:0127 ELS timeout Data: x%x x%x x%x x%x\n",
- phba->brd_no, els_command,
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0127 ELS timeout Data: x%x x%x x%x "
+ "x%x\n",
+ phba->brd_no, vport->vpi, els_command,
remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
lpfc_sli_issue_abort_iotag(phba, pring, piocb);
}
- if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
- mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
+ spin_unlock_irq(&phba->hbalock);
- spin_unlock_irq(phba->host->host_lock);
+ if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
+ mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
}
void
-lpfc_els_flush_cmd(struct lpfc_hba *phba)
+lpfc_els_flush_cmd(struct lpfc_vport *vport)
{
LIST_HEAD(completions);
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
struct lpfc_iocbq *tmp_iocb, *piocb;
IOCB_t *cmd = NULL;
- spin_lock_irq(phba->host->host_lock);
+ lpfc_fabric_abort_vport(vport);
+
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
cmd = &piocb->iocb;
@@ -3301,271 +3705,1042 @@
cmd->ulpCommand == CMD_ABORT_XRI_CN)
continue;
+ if (piocb->vport != vport)
+ continue;
+
list_move_tail(&piocb->list, &completions);
pring->txq_cnt--;
-
}
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
- cmd = &piocb->iocb;
-
if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
continue;
}
+ if (piocb->vport != vport)
+ continue;
+
lpfc_sli_issue_abort_iotag(phba, pring, piocb);
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
- while(!list_empty(&completions)) {
+ while (!list_empty(&completions)) {
piocb = list_get_first(&completions, struct lpfc_iocbq, list);
cmd = &piocb->iocb;
- list_del(&piocb->list);
+ list_del_init(&piocb->list);
- if (piocb->iocb_cmpl) {
+ if (!piocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, piocb);
+ else {
cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
(piocb->iocb_cmpl) (phba, piocb, piocb);
- } else
- lpfc_sli_release_iocbq(phba, piocb);
+ }
}
return;
}
-void
-lpfc_els_unsol_event(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring, struct lpfc_iocbq * elsiocb)
+static void
+lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
{
- struct lpfc_sli *psli;
struct lpfc_nodelist *ndlp;
- struct lpfc_dmabuf *mp;
- uint32_t *lp;
- IOCB_t *icmd;
struct ls_rjt stat;
- uint32_t cmd;
- uint32_t did;
- uint32_t newnode;
- uint32_t drop_cmd = 0; /* by default do NOT drop received cmd */
- uint32_t rjt_err = 0;
+ uint32_t *payload;
+ uint32_t cmd, did, newnode, rjt_err = 0;
+ IOCB_t *icmd = &elsiocb->iocb;
- psli = &phba->sli;
- icmd = &elsiocb->iocb;
-
- if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
- /* Not enough posted buffers; Try posting more buffers */
- phba->fc_stat.NoRcvBuf++;
- lpfc_post_buffer(phba, pring, 0, 1);
- return;
- }
-
- /* If there are no BDEs associated with this IOCB,
- * there is nothing to do.
- */
- if (icmd->ulpBdeCount == 0)
- return;
-
- /* type of ELS cmd is first 32bit word in packet */
- mp = lpfc_sli_ringpostbuf_get(phba, pring, getPaddr(icmd->un.
- cont64[0].
- addrHigh,
- icmd->un.
- cont64[0].addrLow));
- if (mp == 0) {
- drop_cmd = 1;
+ if (vport == NULL || elsiocb->context2 == NULL)
goto dropit;
- }
newnode = 0;
- lp = (uint32_t *) mp->virt;
- cmd = *lp++;
- lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], 1, 1);
+ payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt;
+ cmd = *payload;
+ if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0)
+ lpfc_post_buffer(phba, pring, 1, 1);
+ did = icmd->un.rcvels.remoteID;
if (icmd->ulpStatus) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- drop_cmd = 1;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV Unsol ELS: status:x%x/x%x did:x%x",
+ icmd->ulpStatus, icmd->un.ulpWord[4], did);
goto dropit;
}
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba)) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- drop_cmd = 1;
+ if (lpfc_els_chk_latt(vport))
goto dropit;
- }
- did = icmd->un.rcvels.remoteID;
- ndlp = lpfc_findnode_did(phba, did);
+ /* Ignore traffic recevied during vport shutdown. */
+ if (vport->load_flag & FC_UNLOADING)
+ goto dropit;
+
+ ndlp = lpfc_findnode_did(vport, did);
if (!ndlp) {
/* Cannot find existing Fabric ndlp, so allocate a new one */
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
- if (!ndlp) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- drop_cmd = 1;
+ if (!ndlp)
goto dropit;
- }
- lpfc_nlp_init(phba, ndlp, did);
+ lpfc_nlp_init(vport, ndlp, did);
newnode = 1;
if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
ndlp->nlp_type |= NLP_FABRIC;
}
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
}
phba->fc_stat.elsRcvFrame++;
if (elsiocb->context1)
lpfc_nlp_put(elsiocb->context1);
elsiocb->context1 = lpfc_nlp_get(ndlp);
- elsiocb->context2 = mp;
+ elsiocb->vport = vport;
if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
cmd &= ELS_CMD_MASK;
}
/* ELS command <elsCmd> received from NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0112 ELS command x%x received from NPORT x%x "
- "Data: x%x\n", phba->brd_no, cmd, did, phba->hba_state);
+ "%d (%d):0112 ELS command x%x received from NPORT x%x "
+ "Data: x%x\n", phba->brd_no, vport->vpi, cmd, did,
+ vport->port_state);
switch (cmd) {
case ELS_CMD_PLOGI:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV PLOGI: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvPLOGI++;
- if (phba->hba_state < LPFC_DISC_AUTH) {
- rjt_err = 1;
+ ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp);
+
+ if (vport->port_state < LPFC_DISC_AUTH) {
+ rjt_err = LSRJT_UNABLE_TPC;
break;
}
- ndlp = lpfc_plogi_confirm_nport(phba, mp, ndlp);
- lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PLOGI);
+ lpfc_disc_state_machine(vport, ndlp, elsiocb,
+ NLP_EVT_RCV_PLOGI);
+
break;
case ELS_CMD_FLOGI:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV FLOGI: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvFLOGI++;
- lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode);
+ lpfc_els_rcv_flogi(vport, elsiocb, ndlp, newnode);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
case ELS_CMD_LOGO:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV LOGO: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvLOGO++;
- if (phba->hba_state < LPFC_DISC_AUTH) {
- rjt_err = 1;
+ if (vport->port_state < LPFC_DISC_AUTH) {
+ rjt_err = LSRJT_UNABLE_TPC;
break;
}
- lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
+ lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
break;
case ELS_CMD_PRLO:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV PRLO: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvPRLO++;
- if (phba->hba_state < LPFC_DISC_AUTH) {
- rjt_err = 1;
+ if (vport->port_state < LPFC_DISC_AUTH) {
+ rjt_err = LSRJT_UNABLE_TPC;
break;
}
- lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
+ lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
break;
case ELS_CMD_RSCN:
phba->fc_stat.elsRcvRSCN++;
- lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode);
+ lpfc_els_rcv_rscn(vport, elsiocb, ndlp, newnode);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
case ELS_CMD_ADISC:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV ADISC: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvADISC++;
- if (phba->hba_state < LPFC_DISC_AUTH) {
- rjt_err = 1;
+ if (vport->port_state < LPFC_DISC_AUTH) {
+ rjt_err = LSRJT_UNABLE_TPC;
break;
}
- lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_ADISC);
+ lpfc_disc_state_machine(vport, ndlp, elsiocb,
+ NLP_EVT_RCV_ADISC);
break;
case ELS_CMD_PDISC:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV PDISC: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvPDISC++;
- if (phba->hba_state < LPFC_DISC_AUTH) {
- rjt_err = 1;
+ if (vport->port_state < LPFC_DISC_AUTH) {
+ rjt_err = LSRJT_UNABLE_TPC;
break;
}
- lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PDISC);
+ lpfc_disc_state_machine(vport, ndlp, elsiocb,
+ NLP_EVT_RCV_PDISC);
break;
case ELS_CMD_FARPR:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV FARPR: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvFARPR++;
- lpfc_els_rcv_farpr(phba, elsiocb, ndlp);
+ lpfc_els_rcv_farpr(vport, elsiocb, ndlp);
break;
case ELS_CMD_FARP:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV FARP: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvFARP++;
- lpfc_els_rcv_farp(phba, elsiocb, ndlp);
+ lpfc_els_rcv_farp(vport, elsiocb, ndlp);
break;
case ELS_CMD_FAN:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV FAN: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvFAN++;
- lpfc_els_rcv_fan(phba, elsiocb, ndlp);
+ lpfc_els_rcv_fan(vport, elsiocb, ndlp);
break;
case ELS_CMD_PRLI:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV PRLI: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvPRLI++;
- if (phba->hba_state < LPFC_DISC_AUTH) {
- rjt_err = 1;
+ if (vport->port_state < LPFC_DISC_AUTH) {
+ rjt_err = LSRJT_UNABLE_TPC;
break;
}
- lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
+ lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
break;
case ELS_CMD_LIRR:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV LIRR: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvLIRR++;
- lpfc_els_rcv_lirr(phba, elsiocb, ndlp);
+ lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
case ELS_CMD_RPS:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RPS: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvRPS++;
- lpfc_els_rcv_rps(phba, elsiocb, ndlp);
+ lpfc_els_rcv_rps(vport, elsiocb, ndlp);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
case ELS_CMD_RPL:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RPL: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvRPL++;
- lpfc_els_rcv_rpl(phba, elsiocb, ndlp);
+ lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
case ELS_CMD_RNID:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RNID: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvRNID++;
- lpfc_els_rcv_rnid(phba, elsiocb, ndlp);
+ lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
default:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x",
+ cmd, did, vport->port_state);
+
/* Unsupported ELS command, reject */
- rjt_err = 1;
+ rjt_err = LSRJT_INVALID_CMD;
/* Unknown ELS command <elsCmd> received from NPORT <did> */
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d:0115 Unknown ELS command x%x received from "
- "NPORT x%x\n", phba->brd_no, cmd, did);
+ "%d (%d):0115 Unknown ELS command x%x "
+ "received from NPORT x%x\n",
+ phba->brd_no, vport->vpi, cmd, did);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
}
/* check if need to LS_RJT received ELS cmd */
if (rjt_err) {
- stat.un.b.lsRjtRsvd0 = 0;
- stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+ memset(&stat, 0, sizeof(stat));
+ stat.un.b.lsRjtRsnCode = rjt_err;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
- stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, elsiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp,
+ NULL);
+ if (newnode)
+ lpfc_drop_node(vport, ndlp);
}
+ return;
+
+dropit:
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0111 Dropping received ELS cmd "
+ "Data: x%x x%x x%x\n",
+ phba->brd_no, vport ? vport->vpi : 0xffff,
+ icmd->ulpStatus, icmd->un.ulpWord[4],
+ icmd->ulpTimeout);
+ phba->fc_stat.elsRcvDrop++;
+}
+
+static struct lpfc_vport *
+lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
+{
+ struct lpfc_vport *vport;
+
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ if (vport->vpi == vpi)
+ return vport;
+ }
+ return NULL;
+}
+
+void
+lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *elsiocb)
+{
+ struct lpfc_vport *vport = phba->pport;
+ IOCB_t *icmd = &elsiocb->iocb;
+ dma_addr_t paddr;
+ struct lpfc_dmabuf *bdeBuf1 = elsiocb->context2;
+ struct lpfc_dmabuf *bdeBuf2 = elsiocb->context3;
+
+ elsiocb->context2 = NULL;
+ elsiocb->context3 = NULL;
+
+ if (icmd->ulpStatus == IOSTAT_NEED_BUFFER) {
+ lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
+ } else if (icmd->ulpStatus == IOSTAT_LOCAL_REJECT &&
+ (icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING) {
+ phba->fc_stat.NoRcvBuf++;
+ /* Not enough posted buffers; Try posting more buffers */
+ if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
+ lpfc_post_buffer(phba, pring, 0, 1);
+ return;
+ }
+
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ (icmd->ulpCommand == CMD_IOCB_RCV_ELS64_CX ||
+ icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
+ if (icmd->unsli3.rcvsli3.vpi == 0xffff)
+ vport = phba->pport;
+ else {
+ uint16_t vpi = icmd->unsli3.rcvsli3.vpi;
+ vport = lpfc_find_vport_by_vpid(phba, vpi);
+ }
+ }
+ /* If there are no BDEs associated
+ * with this IOCB, there is nothing to do.
+ */
+ if (icmd->ulpBdeCount == 0)
+ return;
+
+ /* type of ELS cmd is first 32bit word
+ * in packet
+ */
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ elsiocb->context2 = bdeBuf1;
+ } else {
+ paddr = getPaddr(icmd->un.cont64[0].addrHigh,
+ icmd->un.cont64[0].addrLow);
+ elsiocb->context2 = lpfc_sli_ringpostbuf_get(phba, pring,
+ paddr);
+ }
+
+ lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
+ /*
+ * The different unsolicited event handlers would tell us
+ * if they are done with "mp" by setting context2 to NULL.
+ */
lpfc_nlp_put(elsiocb->context1);
elsiocb->context1 = NULL;
if (elsiocb->context2) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
+ lpfc_in_buf_free(phba, (struct lpfc_dmabuf *)elsiocb->context2);
+ elsiocb->context2 = NULL;
}
-dropit:
- /* check if need to drop received ELS cmd */
- if (drop_cmd == 1) {
+
+ /* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */
+ if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) &&
+ icmd->ulpBdeCount == 2) {
+ elsiocb->context2 = bdeBuf2;
+ lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
+ /* free mp if we are done with it */
+ if (elsiocb->context2) {
+ lpfc_in_buf_free(phba, elsiocb->context2);
+ elsiocb->context2 = NULL;
+ }
+ }
+}
+
+void
+lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
+{
+ struct lpfc_nodelist *ndlp, *ndlp_fdmi;
+
+ ndlp = lpfc_findnode_did(vport, NameServer_DID);
+ if (!ndlp) {
+ ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+ if (!ndlp) {
+ if (phba->fc_topology == TOPOLOGY_LOOP) {
+ lpfc_disc_start(vport);
+ return;
+ }
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0251 NameServer login: no memory\n",
+ phba->brd_no, vport->vpi);
+ return;
+ }
+ lpfc_nlp_init(vport, ndlp, NameServer_DID);
+ ndlp->nlp_type |= NLP_FABRIC;
+ }
+
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+
+ if (lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0)) {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d:0111 Dropping received ELS cmd "
- "Data: x%x x%x x%x\n", phba->brd_no,
- icmd->ulpStatus, icmd->un.ulpWord[4],
- icmd->ulpTimeout);
- phba->fc_stat.elsRcvDrop++;
+ "%d (%d):0252 Cannot issue NameServer login\n",
+ phba->brd_no, vport->vpi);
+ return;
+ }
+
+ if (phba->cfg_fdmi_on) {
+ ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
+ GFP_KERNEL);
+ if (ndlp_fdmi) {
+ lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
+ ndlp_fdmi->nlp_type |= NLP_FABRIC;
+ ndlp_fdmi->nlp_state =
+ NLP_STE_PLOGI_ISSUE;
+ lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID,
+ 0);
+ }
}
return;
}
+
+static void
+lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ struct lpfc_vport *vport = pmb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+ MAILBOX_t *mb = &pmb->mb;
+
+ vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+ lpfc_nlp_put(ndlp);
+
+ if (mb->mbxStatus) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "%d (%d):0915 Register VPI failed: 0x%x\n",
+ phba->brd_no, vport->vpi, mb->mbxStatus);
+
+ switch (mb->mbxStatus) {
+ case 0x11: /* unsupported feature */
+ case 0x9603: /* max_vpi exceeded */
+ /* giving up on vport registration */
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
+ break;
+ default:
+ /* Try to recover from this error */
+ lpfc_mbx_unreg_vpi(vport);
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ lpfc_initial_fdisc(vport);
+ break;
+ }
+
+ } else {
+ if (vport == phba->pport)
+ lpfc_issue_fabric_reglogin(vport);
+ else
+ lpfc_do_scr_ns_plogi(phba, vport);
+ }
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return;
+}
+
+void
+lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp)
+{
+ LPFC_MBOXQ_t *mbox;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox) {
+ lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, mbox);
+ mbox->vport = vport;
+ mbox->context2 = lpfc_nlp_get(ndlp);
+ mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
+ if (lpfc_sli_issue_mbox(phba, mbox,
+ MBX_NOWAIT | MBX_STOP_IOCB)
+ == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "%d (%d):0253 Register VPI: Cannot send mbox\n",
+ phba->brd_no, vport->vpi);
+ }
+ } else {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "%d (%d):0254 Register VPI: no memory\n",
+ phba->brd_no, vport->vpi);
+
+ vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+ lpfc_nlp_put(ndlp);
+ }
+}
+
+static void
+lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_nodelist *np;
+ struct lpfc_nodelist *next_np;
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_iocbq *piocb;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0123 FDISC completes. x%x/x%x prevDID: x%x\n",
+ phba->brd_no, vport->vpi,
+ irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
+
+ /* Since all FDISCs are being single threaded, we
+ * must reset the discovery timer for ALL vports
+ * waiting to send FDISC when one completes.
+ */
+ list_for_each_entry(piocb, &phba->fabric_iocb_list, list) {
+ lpfc_set_disctmo(piocb->vport);
+ }
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "FDISC cmpl: status:x%x/x%x prevdid:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
+
+ if (irsp->ulpStatus) {
+ /* Check for retry */
+ if (lpfc_els_retry(phba, cmdiocb, rspiocb))
+ goto out;
+
+ /* FDISC failed */
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0124 FDISC failed. (%d/%d)\n",
+ phba->brd_no, vport->vpi,
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
+
+ if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+
+ lpfc_nlp_put(ndlp);
+ /* giving up on FDISC. Cancel discovery timer */
+ lpfc_can_disctmo(vport);
+ } else {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_FABRIC;
+ if (vport->phba->fc_topology == TOPOLOGY_LOOP)
+ vport->fc_flag |= FC_PUBLIC_LOOP;
+ spin_unlock_irq(shost->host_lock);
+
+ vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
+ lpfc_vport_set_state(vport, FC_VPORT_ACTIVE);
+ if ((vport->fc_prevDID != vport->fc_myDID) &&
+ !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
+ /* If our NportID changed, we need to ensure all
+ * remaining NPORTs get unreg_login'ed so we can
+ * issue unreg_vpi.
+ */
+ list_for_each_entry_safe(np, next_np,
+ &vport->fc_nodes, nlp_listp) {
+ if (np->nlp_state != NLP_STE_NPR_NODE
+ || !(np->nlp_flag & NLP_NPR_ADISC))
+ continue;
+ spin_lock_irq(shost->host_lock);
+ np->nlp_flag &= ~NLP_NPR_ADISC;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_unreg_rpi(vport, np);
+ }
+ lpfc_mbx_unreg_vpi(vport);
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ }
+
+ if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
+ lpfc_register_new_vport(phba, vport, ndlp);
+ else
+ lpfc_do_scr_ns_plogi(phba, vport);
+
+ lpfc_nlp_put(ndlp); /* Free Fabric ndlp for vports */
+ }
+
+out:
+ lpfc_els_free_iocb(phba, cmdiocb);
+}
+
+int
+lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ uint8_t retry)
+{
+ struct lpfc_hba *phba = vport->phba;
+ IOCB_t *icmd;
+ struct lpfc_iocbq *elsiocb;
+ struct serv_parm *sp;
+ uint8_t *pcmd;
+ uint16_t cmdsize;
+ int did = ndlp->nlp_DID;
+ int rc;
+
+ cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
+ ELS_CMD_FDISC);
+ if (!elsiocb) {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0255 Issue FDISC: no IOCB\n",
+ phba->brd_no, vport->vpi);
+ return 1;
+ }
+
+ icmd = &elsiocb->iocb;
+ icmd->un.elsreq64.myID = 0;
+ icmd->un.elsreq64.fl = 1;
+
+ /* For FDISC, Let FDISC rsp set the NPortID for this VPI */
+ icmd->ulpCt_h = 1;
+ icmd->ulpCt_l = 0;
+
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ *((uint32_t *) (pcmd)) = ELS_CMD_FDISC;
+ pcmd += sizeof(uint32_t); /* CSP Word 1 */
+ memcpy(pcmd, &vport->phba->pport->fc_sparam, sizeof(struct serv_parm));
+ sp = (struct serv_parm *) pcmd;
+ /* Setup CSPs accordingly for Fabric */
+ sp->cmn.e_d_tov = 0;
+ sp->cmn.w2.r_a_tov = 0;
+ sp->cls1.classValid = 0;
+ sp->cls2.seqDelivery = 1;
+ sp->cls3.seqDelivery = 1;
+
+ pcmd += sizeof(uint32_t); /* CSP Word 2 */
+ pcmd += sizeof(uint32_t); /* CSP Word 3 */
+ pcmd += sizeof(uint32_t); /* CSP Word 4 */
+ pcmd += sizeof(uint32_t); /* Port Name */
+ memcpy(pcmd, &vport->fc_portname, 8);
+ pcmd += sizeof(uint32_t); /* Node Name */
+ pcmd += sizeof(uint32_t); /* Node Name */
+ memcpy(pcmd, &vport->fc_nodename, 8);
+
+ lpfc_set_disctmo(vport);
+
+ phba->fc_stat.elsXmitFDISC++;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_fdisc;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue FDISC: did:x%x",
+ did, 0, 0);
+
+ rc = lpfc_issue_fabric_iocb(phba, elsiocb);
+ if (rc == IOCB_ERROR) {
+ lpfc_els_free_iocb(phba, elsiocb);
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0256 Issue FDISC: Cannot send IOCB\n",
+ phba->brd_no, vport->vpi);
+
+ return 1;
+ }
+ lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING);
+ vport->port_state = LPFC_FDISC;
+ return 0;
+}
+
+static void
+lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ IOCB_t *irsp;
+
+ irsp = &rspiocb->iocb;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "LOGO npiv cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4], irsp->un.rcvels.remoteID);
+
+ lpfc_els_free_iocb(phba, cmdiocb);
+ vport->unreg_vpi_cmpl = VPORT_ERROR;
+}
+
+int
+lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ IOCB_t *icmd;
+ struct lpfc_iocbq *elsiocb;
+ uint8_t *pcmd;
+ uint16_t cmdsize;
+
+ cmdsize = 2 * sizeof(uint32_t) + sizeof(struct lpfc_name);
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, ndlp->nlp_DID,
+ ELS_CMD_LOGO);
+ if (!elsiocb)
+ return 1;
+
+ icmd = &elsiocb->iocb;
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ *((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
+ pcmd += sizeof(uint32_t);
+
+ /* Fill in LOGO payload */
+ *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
+ pcmd += sizeof(uint32_t);
+ memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue LOGO npiv did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_npiv_logo;
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_LOGO_SND;
+ spin_unlock_irq(shost->host_lock);
+ if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag &= ~NLP_LOGO_SND;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_els_free_iocb(phba, elsiocb);
+ return 1;
+ }
+ return 0;
+}
+
+void
+lpfc_fabric_block_timeout(unsigned long ptr)
+{
+ struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
+ unsigned long iflags;
+ uint32_t tmo_posted;
+ spin_lock_irqsave(&phba->pport->work_port_lock, iflags);
+ tmo_posted = phba->pport->work_port_events & WORKER_FABRIC_BLOCK_TMO;
+ if (!tmo_posted)
+ phba->pport->work_port_events |= WORKER_FABRIC_BLOCK_TMO;
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags);
+
+ if (!tmo_posted) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ if (phba->work_wait)
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ }
+}
+
+static void
+lpfc_resume_fabric_iocbs(struct lpfc_hba *phba)
+{
+ struct lpfc_iocbq *iocb;
+ unsigned long iflags;
+ int ret;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ IOCB_t *cmd;
+
+repeat:
+ iocb = NULL;
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ /* Post any pending iocb to the SLI layer */
+ if (atomic_read(&phba->fabric_iocb_count) == 0) {
+ list_remove_head(&phba->fabric_iocb_list, iocb, typeof(*iocb),
+ list);
+ if (iocb)
+ atomic_inc(&phba->fabric_iocb_count);
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ if (iocb) {
+ iocb->fabric_iocb_cmpl = iocb->iocb_cmpl;
+ iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
+ iocb->iocb_flag |= LPFC_IO_FABRIC;
+
+ lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
+ "Fabric sched1: ste:x%x",
+ iocb->vport->port_state, 0, 0);
+
+ ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
+
+ if (ret == IOCB_ERROR) {
+ iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
+ iocb->fabric_iocb_cmpl = NULL;
+ iocb->iocb_flag &= ~LPFC_IO_FABRIC;
+ cmd = &iocb->iocb;
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ iocb->iocb_cmpl(phba, iocb, iocb);
+
+ atomic_dec(&phba->fabric_iocb_count);
+ goto repeat;
+ }
+ }
+
+ return;
+}
+
+void
+lpfc_unblock_fabric_iocbs(struct lpfc_hba *phba)
+{
+ clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
+
+ lpfc_resume_fabric_iocbs(phba);
+ return;
+}
+
+static void
+lpfc_block_fabric_iocbs(struct lpfc_hba *phba)
+{
+ int blocked;
+
+ blocked = test_and_set_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
+ /* Start a timer to unblock fabric
+ * iocbs after 100ms
+ */
+ if (!blocked)
+ mod_timer(&phba->fabric_block_timer, jiffies + HZ/10 );
+
+ return;
+}
+
+static void
+lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct ls_rjt stat;
+
+ if ((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC)
+ BUG();
+
+ switch (rspiocb->iocb.ulpStatus) {
+ case IOSTAT_NPORT_RJT:
+ case IOSTAT_FABRIC_RJT:
+ if (rspiocb->iocb.un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
+ lpfc_block_fabric_iocbs(phba);
+ }
+ break;
+
+ case IOSTAT_NPORT_BSY:
+ case IOSTAT_FABRIC_BSY:
+ lpfc_block_fabric_iocbs(phba);
+ break;
+
+ case IOSTAT_LS_RJT:
+ stat.un.lsRjtError =
+ be32_to_cpu(rspiocb->iocb.un.ulpWord[4]);
+ if ((stat.un.b.lsRjtRsnCode == LSRJT_UNABLE_TPC) ||
+ (stat.un.b.lsRjtRsnCode == LSRJT_LOGICAL_BSY))
+ lpfc_block_fabric_iocbs(phba);
+ break;
+ }
+
+ if (atomic_read(&phba->fabric_iocb_count) == 0)
+ BUG();
+
+ cmdiocb->iocb_cmpl = cmdiocb->fabric_iocb_cmpl;
+ cmdiocb->fabric_iocb_cmpl = NULL;
+ cmdiocb->iocb_flag &= ~LPFC_IO_FABRIC;
+ cmdiocb->iocb_cmpl(phba, cmdiocb, rspiocb);
+
+ atomic_dec(&phba->fabric_iocb_count);
+ if (!test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags)) {
+ /* Post any pending iocbs to HBA */
+ lpfc_resume_fabric_iocbs(phba);
+ }
+}
+
+int
+lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
+{
+ unsigned long iflags;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ int ready;
+ int ret;
+
+ if (atomic_read(&phba->fabric_iocb_count) > 1)
+ BUG();
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ ready = atomic_read(&phba->fabric_iocb_count) == 0 &&
+ !test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
+
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ if (ready) {
+ iocb->fabric_iocb_cmpl = iocb->iocb_cmpl;
+ iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
+ iocb->iocb_flag |= LPFC_IO_FABRIC;
+
+ lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
+ "Fabric sched2: ste:x%x",
+ iocb->vport->port_state, 0, 0);
+
+ atomic_inc(&phba->fabric_iocb_count);
+ ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
+
+ if (ret == IOCB_ERROR) {
+ iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
+ iocb->fabric_iocb_cmpl = NULL;
+ iocb->iocb_flag &= ~LPFC_IO_FABRIC;
+ atomic_dec(&phba->fabric_iocb_count);
+ }
+ } else {
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ list_add_tail(&iocb->list, &phba->fabric_iocb_list);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ ret = IOCB_SUCCESS;
+ }
+ return ret;
+}
+
+
+void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
+{
+ LIST_HEAD(completions);
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *tmp_iocb, *piocb;
+ IOCB_t *cmd;
+
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
+ list) {
+
+ if (piocb->vport != vport)
+ continue;
+
+ list_move_tail(&piocb->list, &completions);
+ }
+ spin_unlock_irq(&phba->hbalock);
+
+ while (!list_empty(&completions)) {
+ piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ list_del_init(&piocb->list);
+
+ cmd = &piocb->iocb;
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (piocb->iocb_cmpl) (phba, piocb, piocb);
+ }
+}
+
+void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp)
+{
+ LIST_HEAD(completions);
+ struct lpfc_hba *phba = ndlp->vport->phba;
+ struct lpfc_iocbq *tmp_iocb, *piocb;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ IOCB_t *cmd;
+
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
+ list) {
+ if ((lpfc_check_sli_ndlp(phba, pring, piocb, ndlp))) {
+
+ list_move_tail(&piocb->list, &completions);
+ }
+ }
+ spin_unlock_irq(&phba->hbalock);
+
+ while (!list_empty(&completions)) {
+ piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ list_del_init(&piocb->list);
+
+ cmd = &piocb->iocb;
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (piocb->iocb_cmpl) (phba, piocb, piocb);
+ }
+}
+
+void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
+{
+ LIST_HEAD(completions);
+ struct lpfc_iocbq *piocb;
+ IOCB_t *cmd;
+
+ spin_lock_irq(&phba->hbalock);
+ list_splice_init(&phba->fabric_iocb_list, &completions);
+ spin_unlock_irq(&phba->hbalock);
+
+ while (!list_empty(&completions)) {
+ piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ list_del_init(&piocb->list);
+
+ cmd = &piocb->iocb;
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (piocb->iocb_cmpl) (phba, piocb, piocb);
+ }
+}
+
+
+void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
+{
+ LIST_HEAD(completions);
+ struct lpfc_iocbq *tmp_iocb, *piocb;
+ IOCB_t *cmd;
+ struct lpfc_nodelist *ndlp;
+
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
+ list) {
+
+ cmd = &piocb->iocb;
+ ndlp = (struct lpfc_nodelist *) piocb->context1;
+ if (cmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
+ ndlp != NULL &&
+ ndlp->nlp_DID == Fabric_DID)
+ list_move_tail(&piocb->list, &completions);
+ }
+ spin_unlock_irq(&phba->hbalock);
+
+ while (!list_empty(&completions)) {
+ piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ list_del_init(&piocb->list);
+
+ cmd = &piocb->iocb;
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (piocb->iocb_cmpl) (phba, piocb, piocb);
+ }
+}
+
+
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 61caa8d..f2f4639 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -36,6 +36,8 @@
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
/* AlpaArray for assignment of scsid for scan-down and bind_method */
static uint8_t lpfcAlpaArray[] = {
@@ -54,7 +56,7 @@
0x10, 0x0F, 0x08, 0x04, 0x02, 0x01
};
-static void lpfc_disc_timeout_handler(struct lpfc_hba *);
+static void lpfc_disc_timeout_handler(struct lpfc_vport *);
void
lpfc_terminate_rport_io(struct fc_rport *rport)
@@ -74,14 +76,16 @@
return;
}
- phba = ndlp->nlp_phba;
+ phba = ndlp->vport->phba;
- spin_lock_irq(phba->host->host_lock);
+ lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT,
+ "rport terminate: sid:x%x did:x%x flg:x%x",
+ ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
+
if (ndlp->nlp_sid != NLP_NO_SID) {
lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
}
- spin_unlock_irq(phba->host->host_lock);
return;
}
@@ -94,105 +98,213 @@
{
struct lpfc_rport_data *rdata;
struct lpfc_nodelist * ndlp;
- uint8_t *name;
- int warn_on = 0;
- struct lpfc_hba *phba;
+ struct lpfc_vport *vport;
+ struct lpfc_hba *phba;
+ struct completion devloss_compl;
+ struct lpfc_work_evt *evtp;
rdata = rport->dd_data;
ndlp = rdata->pnode;
if (!ndlp) {
- if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+ if (rport->scsi_target_id != -1) {
printk(KERN_ERR "Cannot find remote node"
- " for rport in dev_loss_tmo_callbk x%x\n",
- rport->port_id);
+ " for rport in dev_loss_tmo_callbk x%x\n",
+ rport->port_id);
+ }
return;
}
- if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+ vport = ndlp->vport;
+ phba = vport->phba;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+ "rport devlosscb: sid:x%x did:x%x flg:x%x",
+ ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
+
+ init_completion(&devloss_compl);
+ evtp = &ndlp->dev_loss_evt;
+
+ if (!list_empty(&evtp->evt_listp))
return;
- name = (uint8_t *)&ndlp->nlp_portname;
- phba = ndlp->nlp_phba;
+ spin_lock_irq(&phba->hbalock);
+ evtp->evt_arg1 = ndlp;
+ evtp->evt_arg2 = &devloss_compl;
+ evtp->evt = LPFC_EVT_DEV_LOSS;
+ list_add_tail(&evtp->evt_listp, &phba->work_list);
+ if (phba->work_wait)
+ wake_up(phba->work_wait);
- spin_lock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
+
+ wait_for_completion(&devloss_compl);
+
+ return;
+}
+
+/*
+ * This function is called from the worker thread when dev_loss_tmo
+ * expire.
+ */
+void
+lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_rport_data *rdata;
+ struct fc_rport *rport;
+ struct lpfc_vport *vport;
+ struct lpfc_hba *phba;
+ uint8_t *name;
+ int warn_on = 0;
+
+ rport = ndlp->rport;
+
+ if (!rport)
+ return;
+
+ rdata = rport->dd_data;
+ name = (uint8_t *) &ndlp->nlp_portname;
+ vport = ndlp->vport;
+ phba = vport->phba;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+ "rport devlosstmo:did:x%x type:x%x id:x%x",
+ ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id);
+
+ if (!(vport->load_flag & FC_UNLOADING) &&
+ ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+ return;
+
+ if (ndlp->nlp_type & NLP_FABRIC) {
+ int put_node;
+ int put_rport;
+
+ /* We will clean up these Nodes in linkup */
+ put_node = rdata->pnode != NULL;
+ put_rport = ndlp->rport != NULL;
+ rdata->pnode = NULL;
+ ndlp->rport = NULL;
+ if (put_node)
+ lpfc_nlp_put(ndlp);
+ if (put_rport)
+ put_device(&rport->dev);
+ return;
+ }
if (ndlp->nlp_sid != NLP_NO_SID) {
warn_on = 1;
/* flush the target */
lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
- ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+ ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
}
- if (phba->fc_flag & FC_UNLOADING)
+ if (vport->load_flag & FC_UNLOADING)
warn_on = 0;
- spin_unlock_irq(phba->host->host_lock);
-
if (warn_on) {
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0203 Devloss timeout on "
+ "%d (%d):0203 Devloss timeout on "
"WWPN %x:%x:%x:%x:%x:%x:%x:%x "
"NPort x%x Data: x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
*name, *(name+1), *(name+2), *(name+3),
*(name+4), *(name+5), *(name+6), *(name+7),
ndlp->nlp_DID, ndlp->nlp_flag,
ndlp->nlp_state, ndlp->nlp_rpi);
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0204 Devloss timeout on "
+ "%d (%d):0204 Devloss timeout on "
"WWPN %x:%x:%x:%x:%x:%x:%x:%x "
"NPort x%x Data: x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
*name, *(name+1), *(name+2), *(name+3),
*(name+4), *(name+5), *(name+6), *(name+7),
ndlp->nlp_DID, ndlp->nlp_flag,
ndlp->nlp_state, ndlp->nlp_rpi);
}
- if (!(phba->fc_flag & FC_UNLOADING) &&
+ if (!(vport->load_flag & FC_UNLOADING) &&
!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
!(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
(ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
- lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
+ lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
else {
+ int put_node;
+ int put_rport;
+
+ put_node = rdata->pnode != NULL;
+ put_rport = ndlp->rport != NULL;
rdata->pnode = NULL;
ndlp->rport = NULL;
- lpfc_nlp_put(ndlp);
- put_device(&rport->dev);
+ if (put_node)
+ lpfc_nlp_put(ndlp);
+ if (put_rport)
+ put_device(&rport->dev);
}
+}
+
+void
+lpfc_worker_wake_up(struct lpfc_hba *phba)
+{
+ wake_up(phba->work_wait);
return;
}
static void
-lpfc_work_list_done(struct lpfc_hba * phba)
+lpfc_work_list_done(struct lpfc_hba *phba)
{
struct lpfc_work_evt *evtp = NULL;
struct lpfc_nodelist *ndlp;
+ struct lpfc_vport *vport;
int free_evt;
- spin_lock_irq(phba->host->host_lock);
- while(!list_empty(&phba->work_list)) {
+ spin_lock_irq(&phba->hbalock);
+ while (!list_empty(&phba->work_list)) {
list_remove_head((&phba->work_list), evtp, typeof(*evtp),
evt_listp);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
free_evt = 1;
switch (evtp->evt) {
+ case LPFC_EVT_DEV_LOSS_DELAY:
+ free_evt = 0; /* evt is part of ndlp */
+ ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
+ vport = ndlp->vport;
+ if (!vport)
+ break;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+ "rport devlossdly:did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
+ if (!(vport->load_flag & FC_UNLOADING) &&
+ !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
+ !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+ NLP_EVT_DEVICE_RM);
+ }
+ break;
case LPFC_EVT_ELS_RETRY:
- ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
+ ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
lpfc_els_retry_delay_handler(ndlp);
+ free_evt = 0; /* evt is part of ndlp */
+ break;
+ case LPFC_EVT_DEV_LOSS:
+ ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
+ lpfc_nlp_get(ndlp);
+ lpfc_dev_loss_tmo_handler(ndlp);
free_evt = 0;
+ complete((struct completion *)(evtp->evt_arg2));
+ lpfc_nlp_put(ndlp);
break;
case LPFC_EVT_ONLINE:
- if (phba->hba_state < LPFC_LINK_DOWN)
- *(int *)(evtp->evt_arg1) = lpfc_online(phba);
+ if (phba->link_state < LPFC_LINK_DOWN)
+ *(int *) (evtp->evt_arg1) = lpfc_online(phba);
else
- *(int *)(evtp->evt_arg1) = 0;
+ *(int *) (evtp->evt_arg1) = 0;
complete((struct completion *)(evtp->evt_arg2));
break;
case LPFC_EVT_OFFLINE_PREP:
- if (phba->hba_state >= LPFC_LINK_DOWN)
+ if (phba->link_state >= LPFC_LINK_DOWN)
lpfc_offline_prep(phba);
*(int *)(evtp->evt_arg1) = 0;
complete((struct completion *)(evtp->evt_arg2));
@@ -218,33 +330,31 @@
case LPFC_EVT_KILL:
lpfc_offline(phba);
*(int *)(evtp->evt_arg1)
- = (phba->stopped) ? 0 : lpfc_sli_brdkill(phba);
+ = (phba->pport->stopped)
+ ? 0 : lpfc_sli_brdkill(phba);
lpfc_unblock_mgmt_io(phba);
complete((struct completion *)(evtp->evt_arg2));
break;
}
if (free_evt)
kfree(evtp);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
}
-static void
-lpfc_work_done(struct lpfc_hba * phba)
+void
+lpfc_work_done(struct lpfc_hba *phba)
{
struct lpfc_sli_ring *pring;
- int i;
- uint32_t ha_copy;
- uint32_t control;
- uint32_t work_hba_events;
+ uint32_t ha_copy, status, control, work_port_events;
+ struct lpfc_vport *vport;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
ha_copy = phba->work_ha;
phba->work_ha = 0;
- work_hba_events=phba->work_hba_events;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
if (ha_copy & HA_ERATT)
lpfc_handle_eratt(phba);
@@ -255,66 +365,111 @@
if (ha_copy & HA_LATT)
lpfc_handle_latt(phba);
- if (work_hba_events & WORKER_DISC_TMO)
- lpfc_disc_timeout_handler(phba);
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- if (work_hba_events & WORKER_ELS_TMO)
- lpfc_els_timeout_handler(phba);
+ if (!scsi_host_get(shost)) {
+ continue;
+ }
+ spin_unlock_irq(&phba->hbalock);
+ work_port_events = vport->work_port_events;
- if (work_hba_events & WORKER_MBOX_TMO)
- lpfc_mbox_timeout_handler(phba);
+ if (work_port_events & WORKER_DISC_TMO)
+ lpfc_disc_timeout_handler(vport);
- if (work_hba_events & WORKER_FDMI_TMO)
- lpfc_fdmi_tmo_handler(phba);
+ if (work_port_events & WORKER_ELS_TMO)
+ lpfc_els_timeout_handler(vport);
- spin_lock_irq(phba->host->host_lock);
- phba->work_hba_events &= ~work_hba_events;
- spin_unlock_irq(phba->host->host_lock);
+ if (work_port_events & WORKER_HB_TMO)
+ lpfc_hb_timeout_handler(phba);
- for (i = 0; i < phba->sli.num_rings; i++, ha_copy >>= 4) {
- pring = &phba->sli.ring[i];
- if ((ha_copy & HA_RXATT)
- || (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
- if (pring->flag & LPFC_STOP_IOCB_MASK) {
- pring->flag |= LPFC_DEFERRED_RING_EVENT;
- } else {
- lpfc_sli_handle_slow_ring_event(phba, pring,
- (ha_copy &
- HA_RXMASK));
- pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
- }
- /*
- * Turn on Ring interrupts
- */
- spin_lock_irq(phba->host->host_lock);
- control = readl(phba->HCregaddr);
- control |= (HC_R0INT_ENA << i);
+ if (work_port_events & WORKER_MBOX_TMO)
+ lpfc_mbox_timeout_handler(phba);
+
+ if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
+ lpfc_unblock_fabric_iocbs(phba);
+
+ if (work_port_events & WORKER_FDMI_TMO)
+ lpfc_fdmi_timeout_handler(vport);
+
+ if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
+ lpfc_ramp_down_queue_handler(phba);
+
+ if (work_port_events & WORKER_RAMP_UP_QUEUE)
+ lpfc_ramp_up_queue_handler(phba);
+
+ spin_lock_irq(&vport->work_port_lock);
+ vport->work_port_events &= ~work_port_events;
+ spin_unlock_irq(&vport->work_port_lock);
+ scsi_host_put(shost);
+ spin_lock_irq(&phba->hbalock);
+ }
+ spin_unlock_irq(&phba->hbalock);
+
+ pring = &phba->sli.ring[LPFC_ELS_RING];
+ status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING)));
+ status >>= (4*LPFC_ELS_RING);
+ if ((status & HA_RXMASK)
+ || (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
+ if (pring->flag & LPFC_STOP_IOCB_MASK) {
+ pring->flag |= LPFC_DEFERRED_RING_EVENT;
+ } else {
+ lpfc_sli_handle_slow_ring_event(phba, pring,
+ (status &
+ HA_RXMASK));
+ pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
+ }
+ /*
+ * Turn on Ring interrupts
+ */
+ spin_lock_irq(&phba->hbalock);
+ control = readl(phba->HCregaddr);
+ if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) {
+ control |= (HC_R0INT_ENA << LPFC_ELS_RING);
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- spin_unlock_irq(phba->host->host_lock);
}
+ spin_unlock_irq(&phba->hbalock);
}
-
- lpfc_work_list_done (phba);
-
+ lpfc_work_list_done(phba);
}
static int
-check_work_wait_done(struct lpfc_hba *phba) {
+check_work_wait_done(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport;
+ struct lpfc_sli_ring *pring;
+ int rc = 0;
- spin_lock_irq(phba->host->host_lock);
- if (phba->work_ha ||
- phba->work_hba_events ||
- (!list_empty(&phba->work_list)) ||
- kthread_should_stop()) {
- spin_unlock_irq(phba->host->host_lock);
- return 1;
- } else {
- spin_unlock_irq(phba->host->host_lock);
- return 0;
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ if (vport->work_port_events) {
+ rc = 1;
+ goto exit;
+ }
}
+
+ if (phba->work_ha || (!list_empty(&phba->work_list)) ||
+ kthread_should_stop()) {
+ rc = 1;
+ goto exit;
+ }
+
+ pring = &phba->sli.ring[LPFC_ELS_RING];
+ if (pring->flag & LPFC_DEFERRED_RING_EVENT)
+ rc = 1;
+exit:
+ if (rc)
+ phba->work_found++;
+ else
+ phba->work_found = 0;
+
+ spin_unlock_irq(&phba->hbalock);
+ return rc;
}
+
int
lpfc_do_work(void *p)
{
@@ -324,11 +479,13 @@
set_user_nice(current, -20);
phba->work_wait = &work_waitq;
+ phba->work_found = 0;
while (1) {
rc = wait_event_interruptible(work_waitq,
- check_work_wait_done(phba));
+ check_work_wait_done(phba));
+
BUG_ON(rc);
if (kthread_should_stop())
@@ -336,6 +493,17 @@
lpfc_work_done(phba);
+ /* If there is alot of slow ring work, like during link up
+ * check_work_wait_done() may cause this thread to not give
+ * up the CPU for very long periods of time. This may cause
+ * soft lockups or other problems. To avoid these situations
+ * give up the CPU here after LPFC_MAX_WORKER_ITERATION
+ * consecutive iterations.
+ */
+ if (phba->work_found >= LPFC_MAX_WORKER_ITERATION) {
+ phba->work_found = 0;
+ schedule();
+ }
}
phba->work_wait = NULL;
return 0;
@@ -347,16 +515,17 @@
* embedding it in the IOCB.
*/
int
-lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2,
+lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2,
uint32_t evt)
{
struct lpfc_work_evt *evtp;
+ unsigned long flags;
/*
* All Mailbox completions and LPFC_ELS_RING rcv ring IOCB events will
* be queued to worker thread for processing
*/
- evtp = kmalloc(sizeof(struct lpfc_work_evt), GFP_KERNEL);
+ evtp = kmalloc(sizeof(struct lpfc_work_evt), GFP_ATOMIC);
if (!evtp)
return 0;
@@ -364,136 +533,210 @@
evtp->evt_arg2 = arg2;
evtp->evt = evt;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irqsave(&phba->hbalock, flags);
list_add_tail(&evtp->evt_listp, &phba->work_list);
if (phba->work_wait)
- wake_up(phba->work_wait);
- spin_unlock_irq(phba->host->host_lock);
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return 1;
}
+void
+lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp, *next_ndlp;
+ int rc;
+
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+ continue;
+
+ if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN)
+ lpfc_unreg_rpi(vport, ndlp);
+
+ /* Leave Fabric nodes alone on link down */
+ if (!remove && ndlp->nlp_type & NLP_FABRIC)
+ continue;
+ rc = lpfc_disc_state_machine(vport, ndlp, NULL,
+ remove
+ ? NLP_EVT_DEVICE_RM
+ : NLP_EVT_DEVICE_RECOVERY);
+ }
+ if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) {
+ lpfc_mbx_unreg_vpi(vport);
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ }
+}
+
+static void
+lpfc_linkdown_port(struct lpfc_vport *vport)
+{
+ struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Link Down: state:x%x rtry:x%x flg:x%x",
+ vport->port_state, vport->fc_ns_retry, vport->fc_flag);
+
+ /* Cleanup any outstanding RSCN activity */
+ lpfc_els_flush_rscn(vport);
+
+ /* Cleanup any outstanding ELS commands */
+ lpfc_els_flush_cmd(vport);
+
+ lpfc_cleanup_rpis(vport, 0);
+
+ /* free any ndlp's on unused list */
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
+ /* free any ndlp's in unused state */
+ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+ lpfc_drop_node(vport, ndlp);
+
+ /* Turn off discovery timer if its running */
+ lpfc_can_disctmo(vport);
+}
+
int
lpfc_linkdown(struct lpfc_hba *phba)
{
- struct lpfc_sli *psli;
- struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct lpfc_vport *vport = phba->pport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_vport *port_iterator;
LPFC_MBOXQ_t *mb;
- int rc;
- psli = &phba->sli;
- /* sysfs or selective reset may call this routine to clean up */
- if (phba->hba_state >= LPFC_LINK_DOWN) {
- if (phba->hba_state == LPFC_LINK_DOWN)
- return 0;
-
- spin_lock_irq(phba->host->host_lock);
- phba->hba_state = LPFC_LINK_DOWN;
- spin_unlock_irq(phba->host->host_lock);
+ if (phba->link_state == LPFC_LINK_DOWN) {
+ return 0;
}
+ spin_lock_irq(&phba->hbalock);
+ if (phba->link_state > LPFC_LINK_DOWN) {
+ phba->link_state = LPFC_LINK_DOWN;
+ phba->pport->fc_flag &= ~FC_LBIT;
+ }
+ spin_unlock_irq(&phba->hbalock);
- fc_host_post_event(phba->host, fc_get_event_number(),
- FCH_EVT_LINKDOWN, 0);
+ list_for_each_entry(port_iterator, &phba->port_list, listentry) {
+
+ /* Issue a LINK DOWN event to all nodes */
+ lpfc_linkdown_port(port_iterator);
+ }
/* Clean up any firmware default rpi's */
- if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
- lpfc_unreg_did(phba, 0xffffffff, mb);
- mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
+ mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mb) {
+ lpfc_unreg_did(phba, 0xffff, 0xffffffff, mb);
+ mb->vport = vport;
+ mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))
== MBX_NOT_FINISHED) {
- mempool_free( mb, phba->mbox_mem_pool);
+ mempool_free(mb, phba->mbox_mem_pool);
}
}
- /* Cleanup any outstanding RSCN activity */
- lpfc_els_flush_rscn(phba);
-
- /* Cleanup any outstanding ELS commands */
- lpfc_els_flush_cmd(phba);
-
- /*
- * Issue a LINK DOWN event to all nodes.
- */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
- /* free any ndlp's on unused list */
- if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
- lpfc_drop_node(phba, ndlp);
- else /* otherwise, force node recovery. */
- rc = lpfc_disc_state_machine(phba, ndlp, NULL,
- NLP_EVT_DEVICE_RECOVERY);
- }
-
/* Setup myDID for link up if we are in pt2pt mode */
- if (phba->fc_flag & FC_PT2PT) {
- phba->fc_myDID = 0;
- if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
+ if (phba->pport->fc_flag & FC_PT2PT) {
+ phba->pport->fc_myDID = 0;
+ mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mb) {
lpfc_config_link(phba, mb);
- mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
- if (lpfc_sli_issue_mbox
- (phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))
+ mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mb->vport = vport;
+ if (lpfc_sli_issue_mbox(phba, mb,
+ (MBX_NOWAIT | MBX_STOP_IOCB))
== MBX_NOT_FINISHED) {
- mempool_free( mb, phba->mbox_mem_pool);
+ mempool_free(mb, phba->mbox_mem_pool);
}
}
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI);
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ phba->pport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI);
+ spin_unlock_irq(shost->host_lock);
}
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_LBIT;
- spin_unlock_irq(phba->host->host_lock);
- /* Turn off discovery timer if its running */
- lpfc_can_disctmo(phba);
-
- /* Must process IOCBs on all rings to handle ABORTed I/Os */
return 0;
}
+static void
+lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport)
+{
+ struct lpfc_nodelist *ndlp;
+
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+ continue;
+
+ if (ndlp->nlp_type & NLP_FABRIC) {
+ /* On Linkup its safe to clean up the ndlp
+ * from Fabric connections.
+ */
+ if (ndlp->nlp_DID != Fabric_DID)
+ lpfc_unreg_rpi(vport, ndlp);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
+ /* Fail outstanding IO now since device is
+ * marked for PLOGI.
+ */
+ lpfc_unreg_rpi(vport, ndlp);
+ }
+ }
+}
+
+static void
+lpfc_linkup_port(struct lpfc_vport *vport)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct lpfc_hba *phba = vport->phba;
+
+ if ((vport->load_flag & FC_UNLOADING) != 0)
+ return;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Link Up: top:x%x speed:x%x flg:x%x",
+ phba->fc_topology, phba->fc_linkspeed, phba->link_flag);
+
+ /* If NPIV is not enabled, only bring the physical port up */
+ if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ (vport != phba->pport))
+ return;
+
+ fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKUP, 0);
+
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY |
+ FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY);
+ vport->fc_flag |= FC_NDISC_ACTIVE;
+ vport->fc_ns_retry = 0;
+ spin_unlock_irq(shost->host_lock);
+
+ if (vport->fc_flag & FC_LBIT)
+ lpfc_linkup_cleanup_nodes(vport);
+
+ /* free any ndlp's in unused state */
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
+ nlp_listp)
+ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+ lpfc_drop_node(vport, ndlp);
+}
+
static int
lpfc_linkup(struct lpfc_hba *phba)
{
- struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct lpfc_vport *vport;
- fc_host_post_event(phba->host, fc_get_event_number(),
- FCH_EVT_LINKUP, 0);
+ phba->link_state = LPFC_LINK_UP;
- spin_lock_irq(phba->host->host_lock);
- phba->hba_state = LPFC_LINK_UP;
- phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY |
- FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY);
- phba->fc_flag |= FC_NDISC_ACTIVE;
- phba->fc_ns_retry = 0;
- spin_unlock_irq(phba->host->host_lock);
+ /* Unblock fabric iocbs if they are blocked */
+ clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
+ del_timer_sync(&phba->fabric_block_timer);
-
- if (phba->fc_flag & FC_LBIT) {
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
- if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) {
- if (ndlp->nlp_type & NLP_FABRIC) {
- /*
- * On Linkup its safe to clean up the
- * ndlp from Fabric connections.
- */
- lpfc_nlp_set_state(phba, ndlp,
- NLP_STE_UNUSED_NODE);
- } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
- /*
- * Fail outstanding IO now since
- * device is marked for PLOGI.
- */
- lpfc_unreg_rpi(phba, ndlp);
- }
- }
- }
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ lpfc_linkup_port(vport);
}
-
- /* free any ndlp's on unused list */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
- nlp_listp) {
- if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
- lpfc_drop_node(phba, ndlp);
- }
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+ lpfc_issue_clear_la(phba, phba->pport);
return 0;
}
@@ -505,14 +748,14 @@
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli;
- MAILBOX_t *mb;
+ struct lpfc_vport *vport = pmb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_sli *psli = &phba->sli;
+ MAILBOX_t *mb = &pmb->mb;
uint32_t control;
- psli = &phba->sli;
- mb = &pmb->mb;
/* Since we don't do discovery right now, turn these off here */
psli->ring[psli->extra_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->ring[psli->fcp_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
@@ -522,69 +765,74 @@
if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) {
/* CLEAR_LA mbox error <mbxStatus> state <hba_state> */
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d:0320 CLEAR_LA mbxStatus error x%x hba "
+ "%d (%d):0320 CLEAR_LA mbxStatus error x%x hba "
"state x%x\n",
- phba->brd_no, mb->mbxStatus, phba->hba_state);
+ phba->brd_no, vport->vpi, mb->mbxStatus,
+ vport->port_state);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
goto out;
}
- if (phba->fc_flag & FC_ABORT_DISCOVERY)
- goto out;
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ phba->link_state = LPFC_HBA_READY;
- phba->num_disc_nodes = 0;
- /* go thru NPR list and issue ELS PLOGIs */
- if (phba->fc_npr_cnt) {
- lpfc_els_disc_plogi(phba);
- }
-
- if (!phba->num_disc_nodes) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_NDISC_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
- }
-
- phba->hba_state = LPFC_HBA_READY;
-
-out:
- /* Device Discovery completes */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0225 Device Discovery completes\n",
- phba->brd_no);
-
- mempool_free( pmb, phba->mbox_mem_pool);
-
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_ABORT_DISCOVERY;
- if (phba->fc_flag & FC_ESTABLISH_LINK) {
- phba->fc_flag &= ~FC_ESTABLISH_LINK;
- }
- spin_unlock_irq(phba->host->host_lock);
-
- del_timer_sync(&phba->fc_estabtmo);
-
- lpfc_can_disctmo(phba);
-
- /* turn on Link Attention interrupts */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag |= LPFC_PROCESS_LA;
control = readl(phba->HCregaddr);
control |= HC_LAINT_ENA;
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
+ return;
+
+ vport->num_disc_nodes = 0;
+ /* go thru NPR nodes and issue ELS PLOGIs */
+ if (vport->fc_npr_cnt)
+ lpfc_els_disc_plogi(vport);
+
+ if (!vport->num_disc_nodes) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(shost->host_lock);
+ }
+
+ vport->port_state = LPFC_VPORT_READY;
+
+out:
+ /* Device Discovery completes */
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0225 Device Discovery completes\n",
+ phba->brd_no, vport->vpi);
+
+ mempool_free(pmb, phba->mbox_mem_pool);
+
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~(FC_ABORT_DISCOVERY | FC_ESTABLISH_LINK);
+ spin_unlock_irq(shost->host_lock);
+
+ del_timer_sync(&phba->fc_estabtmo);
+
+ lpfc_can_disctmo(vport);
+
+ /* turn on Link Attention interrupts */
+
+ spin_lock_irq(&phba->hbalock);
+ psli->sli_flag |= LPFC_PROCESS_LA;
+ control = readl(phba->HCregaddr);
+ control |= HC_LAINT_ENA;
+ writel(control, phba->HCregaddr);
+ readl(phba->HCregaddr); /* flush */
+ spin_unlock_irq(&phba->hbalock);
return;
}
+
static void
lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli = &phba->sli;
- int rc;
+ struct lpfc_vport *vport = pmb->vport;
if (pmb->mb.mbxStatus)
goto out;
@@ -592,154 +840,139 @@
mempool_free(pmb, phba->mbox_mem_pool);
if (phba->fc_topology == TOPOLOGY_LOOP &&
- phba->fc_flag & FC_PUBLIC_LOOP &&
- !(phba->fc_flag & FC_LBIT)) {
+ vport->fc_flag & FC_PUBLIC_LOOP &&
+ !(vport->fc_flag & FC_LBIT)) {
/* Need to wait for FAN - use discovery timer
- * for timeout. hba_state is identically
+ * for timeout. port_state is identically
* LPFC_LOCAL_CFG_LINK while waiting for FAN
*/
- lpfc_set_disctmo(phba);
+ lpfc_set_disctmo(vport);
return;
- }
+ }
- /* Start discovery by sending a FLOGI. hba_state is identically
+ /* Start discovery by sending a FLOGI. port_state is identically
* LPFC_FLOGI while waiting for FLOGI cmpl
*/
- phba->hba_state = LPFC_FLOGI;
- lpfc_set_disctmo(phba);
- lpfc_initial_flogi(phba);
+ if (vport->port_state != LPFC_FLOGI) {
+ vport->port_state = LPFC_FLOGI;
+ lpfc_set_disctmo(vport);
+ lpfc_initial_flogi(vport);
+ }
return;
out:
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d:0306 CONFIG_LINK mbxStatus error x%x "
+ "%d (%d):0306 CONFIG_LINK mbxStatus error x%x "
"HBA state x%x\n",
- phba->brd_no, pmb->mb.mbxStatus, phba->hba_state);
+ phba->brd_no, vport->vpi, pmb->mb.mbxStatus,
+ vport->port_state);
+
+ mempool_free(pmb, phba->mbox_mem_pool);
lpfc_linkdown(phba);
- phba->hba_state = LPFC_HBA_ERROR;
-
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0200 CONFIG_LINK bad hba state x%x\n",
- phba->brd_no, phba->hba_state);
+ "%d (%d):0200 CONFIG_LINK bad hba state x%x\n",
+ phba->brd_no, vport->vpi, vport->port_state);
- lpfc_clear_la(phba, pmb);
- pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- rc = lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(pmb, phba->mbox_mem_pool);
- lpfc_disc_flush_list(phba);
- psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
- phba->hba_state = LPFC_HBA_READY;
- }
+ lpfc_issue_clear_la(phba, vport);
return;
}
static void
-lpfc_mbx_cmpl_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli = &phba->sli;
MAILBOX_t *mb = &pmb->mb;
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1;
+ struct lpfc_vport *vport = pmb->vport;
/* Check for error */
if (mb->mbxStatus) {
/* READ_SPARAM mbox error <mbxStatus> state <hba_state> */
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d:0319 READ_SPARAM mbxStatus error x%x "
+ "%d (%d):0319 READ_SPARAM mbxStatus error x%x "
"hba state x%x>\n",
- phba->brd_no, mb->mbxStatus, phba->hba_state);
+ phba->brd_no, vport->vpi, mb->mbxStatus,
+ vport->port_state);
lpfc_linkdown(phba);
- phba->hba_state = LPFC_HBA_ERROR;
goto out;
}
- memcpy((uint8_t *) & phba->fc_sparam, (uint8_t *) mp->virt,
+ memcpy((uint8_t *) &vport->fc_sparam, (uint8_t *) mp->virt,
sizeof (struct serv_parm));
if (phba->cfg_soft_wwnn)
- u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn);
+ u64_to_wwn(phba->cfg_soft_wwnn,
+ vport->fc_sparam.nodeName.u.wwn);
if (phba->cfg_soft_wwpn)
- u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
- memcpy((uint8_t *) & phba->fc_nodename,
- (uint8_t *) & phba->fc_sparam.nodeName,
- sizeof (struct lpfc_name));
- memcpy((uint8_t *) & phba->fc_portname,
- (uint8_t *) & phba->fc_sparam.portName,
- sizeof (struct lpfc_name));
+ u64_to_wwn(phba->cfg_soft_wwpn,
+ vport->fc_sparam.portName.u.wwn);
+ memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
+ sizeof(vport->fc_nodename));
+ memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
+ sizeof(vport->fc_portname));
+ if (vport->port_type == LPFC_PHYSICAL_PORT) {
+ memcpy(&phba->wwnn, &vport->fc_nodename, sizeof(phba->wwnn));
+ memcpy(&phba->wwpn, &vport->fc_portname, sizeof(phba->wwnn));
+ }
+
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
out:
pmb->context1 = NULL;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- if (phba->hba_state != LPFC_CLEAR_LA) {
- lpfc_clear_la(phba, pmb);
- pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- if (lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB))
- == MBX_NOT_FINISHED) {
- mempool_free( pmb, phba->mbox_mem_pool);
- lpfc_disc_flush_list(phba);
- psli->ring[(psli->extra_ring)].flag &=
- ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->fcp_ring)].flag &=
- ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->next_ring)].flag &=
- ~LPFC_STOP_IOCB_EVENT;
- phba->hba_state = LPFC_HBA_READY;
- }
- } else {
- mempool_free( pmb, phba->mbox_mem_pool);
- }
+ lpfc_issue_clear_la(phba, vport);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
}
static void
lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
{
- int i;
+ struct lpfc_vport *vport = phba->pport;
LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox;
+ int i;
struct lpfc_dmabuf *mp;
int rc;
sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
switch (la->UlnkSpeed) {
- case LA_1GHZ_LINK:
- phba->fc_linkspeed = LA_1GHZ_LINK;
- break;
- case LA_2GHZ_LINK:
- phba->fc_linkspeed = LA_2GHZ_LINK;
- break;
- case LA_4GHZ_LINK:
- phba->fc_linkspeed = LA_4GHZ_LINK;
- break;
- case LA_8GHZ_LINK:
- phba->fc_linkspeed = LA_8GHZ_LINK;
- break;
- default:
- phba->fc_linkspeed = LA_UNKNW_LINK;
- break;
+ case LA_1GHZ_LINK:
+ phba->fc_linkspeed = LA_1GHZ_LINK;
+ break;
+ case LA_2GHZ_LINK:
+ phba->fc_linkspeed = LA_2GHZ_LINK;
+ break;
+ case LA_4GHZ_LINK:
+ phba->fc_linkspeed = LA_4GHZ_LINK;
+ break;
+ case LA_8GHZ_LINK:
+ phba->fc_linkspeed = LA_8GHZ_LINK;
+ break;
+ default:
+ phba->fc_linkspeed = LA_UNKNW_LINK;
+ break;
}
phba->fc_topology = la->topology;
+ phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
if (phba->fc_topology == TOPOLOGY_LOOP) {
- /* Get Loop Map information */
+ phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
+ /* Get Loop Map information */
if (la->il)
- phba->fc_flag |= FC_LBIT;
+ vport->fc_flag |= FC_LBIT;
- phba->fc_myDID = la->granted_AL_PA;
+ vport->fc_myDID = la->granted_AL_PA;
i = la->un.lilpBde64.tus.f.bdeSize;
if (i == 0) {
@@ -769,29 +1002,35 @@
}
/* Link Up Event ALPA map */
lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_LINK_EVENT,
- "%d:1304 Link Up Event "
- "ALPA map Data: x%x "
- "x%x x%x x%x\n",
- phba->brd_no,
- un.pa.wd1, un.pa.wd2,
- un.pa.wd3, un.pa.wd4);
+ KERN_WARNING,
+ LOG_LINK_EVENT,
+ "%d:1304 Link Up Event "
+ "ALPA map Data: x%x "
+ "x%x x%x x%x\n",
+ phba->brd_no,
+ un.pa.wd1, un.pa.wd2,
+ un.pa.wd3, un.pa.wd4);
}
}
}
} else {
- phba->fc_myDID = phba->fc_pref_DID;
- phba->fc_flag |= FC_LBIT;
+ if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
+ if (phba->max_vpi && phba->cfg_npiv_enable &&
+ (phba->sli_rev == 3))
+ phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
+ }
+ vport->fc_myDID = phba->fc_pref_DID;
+ vport->fc_flag |= FC_LBIT;
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
lpfc_linkup(phba);
if (sparam_mbox) {
- lpfc_read_sparam(phba, sparam_mbox);
+ lpfc_read_sparam(phba, sparam_mbox, 0);
+ sparam_mbox->vport = vport;
sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
rc = lpfc_sli_issue_mbox(phba, sparam_mbox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
+ (MBX_NOWAIT | MBX_STOP_IOCB));
if (rc == MBX_NOT_FINISHED) {
mp = (struct lpfc_dmabuf *) sparam_mbox->context1;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -799,36 +1038,48 @@
mempool_free(sparam_mbox, phba->mbox_mem_pool);
if (cfglink_mbox)
mempool_free(cfglink_mbox, phba->mbox_mem_pool);
- return;
+ goto out;
}
}
if (cfglink_mbox) {
- phba->hba_state = LPFC_LOCAL_CFG_LINK;
+ vport->port_state = LPFC_LOCAL_CFG_LINK;
lpfc_config_link(phba, cfglink_mbox);
+ cfglink_mbox->vport = vport;
cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
rc = lpfc_sli_issue_mbox(phba, cfglink_mbox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED)
- mempool_free(cfglink_mbox, phba->mbox_mem_pool);
+ (MBX_NOWAIT | MBX_STOP_IOCB));
+ if (rc != MBX_NOT_FINISHED)
+ return;
+ mempool_free(cfglink_mbox, phba->mbox_mem_pool);
}
+out:
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "%d (%d):0263 Discovery Mailbox error: state: 0x%x : %p %p\n",
+ phba->brd_no, vport->vpi,
+ vport->port_state, sparam_mbox, cfglink_mbox);
+
+ lpfc_issue_clear_la(phba, vport);
+ return;
}
static void
-lpfc_mbx_issue_link_down(struct lpfc_hba *phba) {
+lpfc_mbx_issue_link_down(struct lpfc_hba *phba)
+{
uint32_t control;
struct lpfc_sli *psli = &phba->sli;
lpfc_linkdown(phba);
/* turn on Link Attention interrupts - no CLEAR_LA needed */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag |= LPFC_PROCESS_LA;
control = readl(phba->HCregaddr);
control |= HC_LAINT_ENA;
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
}
/*
@@ -838,22 +1089,21 @@
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
+ struct lpfc_vport *vport = pmb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
READ_LA_VAR *la;
MAILBOX_t *mb = &pmb->mb;
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
/* Check for error */
if (mb->mbxStatus) {
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_LINK_EVENT,
+ lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
"%d:1307 READ_LA mbox error x%x state x%x\n",
- phba->brd_no,
- mb->mbxStatus, phba->hba_state);
+ phba->brd_no, mb->mbxStatus, vport->port_state);
lpfc_mbx_issue_link_down(phba);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
goto lpfc_mbx_cmpl_read_la_free_mbuf;
}
@@ -861,27 +1111,26 @@
memcpy(&phba->alpa_map[0], mp->virt, 128);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
if (la->pb)
- phba->fc_flag |= FC_BYPASSED_MODE;
+ vport->fc_flag |= FC_BYPASSED_MODE;
else
- phba->fc_flag &= ~FC_BYPASSED_MODE;
- spin_unlock_irq(phba->host->host_lock);
+ vport->fc_flag &= ~FC_BYPASSED_MODE;
+ spin_unlock_irq(shost->host_lock);
if (((phba->fc_eventTag + 1) < la->eventTag) ||
- (phba->fc_eventTag == la->eventTag)) {
+ (phba->fc_eventTag == la->eventTag)) {
phba->fc_stat.LinkMultiEvent++;
- if (la->attType == AT_LINK_UP) {
+ if (la->attType == AT_LINK_UP)
if (phba->fc_eventTag != 0)
lpfc_linkdown(phba);
- }
}
phba->fc_eventTag = la->eventTag;
if (la->attType == AT_LINK_UP) {
phba->fc_stat.LinkUp++;
- if (phba->fc_flag & FC_LOOPBACK_MODE) {
+ if (phba->link_flag & LS_LOOPBACK_MODE) {
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
"%d:1306 Link Up Event in loop back mode "
"x%x received Data: x%x x%x x%x x%x\n",
@@ -903,7 +1152,7 @@
"%d:1305 Link Down Event x%x received "
"Data: x%x x%x x%x\n",
phba->brd_no, la->eventTag, phba->fc_eventTag,
- phba->hba_state, phba->fc_flag);
+ phba->pport->port_state, vport->fc_flag);
lpfc_mbx_issue_link_down(phba);
}
@@ -921,31 +1170,115 @@
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli;
- MAILBOX_t *mb;
- struct lpfc_dmabuf *mp;
- struct lpfc_nodelist *ndlp;
-
- psli = &phba->sli;
- mb = &pmb->mb;
-
- ndlp = (struct lpfc_nodelist *) pmb->context2;
- mp = (struct lpfc_dmabuf *) (pmb->context1);
+ struct lpfc_vport *vport = pmb->vport;
+ struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
pmb->context1 = NULL;
/* Good status, call state machine */
- lpfc_disc_state_machine(phba, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
+ lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
lpfc_nlp_put(ndlp);
return;
}
+static void
+lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb = &pmb->mb;
+ struct lpfc_vport *vport = pmb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ switch (mb->mbxStatus) {
+ case 0x0011:
+ case 0x0020:
+ case 0x9700:
+ lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+ "%d (%d):0911 cmpl_unreg_vpi, "
+ "mb status = 0x%x\n",
+ phba->brd_no, vport->vpi, mb->mbxStatus);
+ break;
+ }
+ vport->unreg_vpi_cmpl = VPORT_OK;
+ mempool_free(pmb, phba->mbox_mem_pool);
+ /*
+ * This shost reference might have been taken at the beginning of
+ * lpfc_vport_delete()
+ */
+ if (vport->load_flag & FC_UNLOADING)
+ scsi_host_put(shost);
+}
+
+void
+lpfc_mbx_unreg_vpi(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mbox;
+ int rc;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ return;
+
+ lpfc_unreg_vpi(phba, vport->vpi, mbox);
+ mbox->vport = vport;
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi;
+ rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT,
+ "%d (%d):1800 Could not issue unreg_vpi\n",
+ phba->brd_no, vport->vpi);
+ mempool_free(mbox, phba->mbox_mem_pool);
+ vport->unreg_vpi_cmpl = VPORT_ERROR;
+ }
+}
+
+static void
+lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ struct lpfc_vport *vport = pmb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ MAILBOX_t *mb = &pmb->mb;
+
+ switch (mb->mbxStatus) {
+ case 0x0011:
+ case 0x9601:
+ case 0x9602:
+ lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+ "%d (%d):0912 cmpl_reg_vpi, mb status = 0x%x\n",
+ phba->brd_no, vport->vpi, mb->mbxStatus);
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
+ vport->fc_myDID = 0;
+ goto out;
+ }
+
+ vport->num_disc_nodes = 0;
+ /* go thru NPR list and issue ELS PLOGIs */
+ if (vport->fc_npr_cnt)
+ lpfc_els_disc_plogi(vport);
+
+ if (!vport->num_disc_nodes) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
+ }
+ vport->port_state = LPFC_VPORT_READY;
+
+out:
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return;
+}
+
/*
* This routine handles processing a Fabric REG_LOGIN mailbox
* command upon completion. It is setup in the LPFC_MBOXQ
@@ -953,20 +1286,14 @@
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli;
- MAILBOX_t *mb;
- struct lpfc_dmabuf *mp;
+ struct lpfc_vport *vport = pmb->vport;
+ struct lpfc_vport *next_vport;
+ MAILBOX_t *mb = &pmb->mb;
+ struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
struct lpfc_nodelist *ndlp;
- struct lpfc_nodelist *ndlp_fdmi;
-
-
- psli = &phba->sli;
- mb = &pmb->mb;
-
ndlp = (struct lpfc_nodelist *) pmb->context2;
- mp = (struct lpfc_dmabuf *) (pmb->context1);
pmb->context1 = NULL;
pmb->context2 = NULL;
@@ -977,60 +1304,46 @@
mempool_free(pmb, phba->mbox_mem_pool);
lpfc_nlp_put(ndlp);
- /* FLOGI failed, so just use loop map to make discovery list */
- lpfc_disc_list_loopmap(phba);
+ if (phba->fc_topology == TOPOLOGY_LOOP) {
+ /* FLOGI failed, use loop map to make discovery list */
+ lpfc_disc_list_loopmap(vport);
- /* Start discovery */
- lpfc_disc_start(phba);
+ /* Start discovery */
+ lpfc_disc_start(vport);
+ return;
+ }
+
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "%d (%d):0258 Register Fabric login error: 0x%x\n",
+ phba->brd_no, vport->vpi, mb->mbxStatus);
+
return;
}
ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_type |= NLP_FABRIC;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */
- if (phba->hba_state == LPFC_FABRIC_CFG_LINK) {
- /* This NPort has been assigned an NPort_ID by the fabric as a
- * result of the completed fabric login. Issue a State Change
- * Registration (SCR) ELS request to the fabric controller
- * (SCR_DID) so that this NPort gets RSCN events from the
- * fabric.
- */
- lpfc_issue_els_scr(phba, SCR_DID, 0);
+ if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
+ list_for_each_entry(next_vport, &phba->port_list, listentry) {
+ if (next_vport->port_type == LPFC_PHYSICAL_PORT)
+ continue;
- ndlp = lpfc_findnode_did(phba, NameServer_DID);
- if (!ndlp) {
- /* Allocate a new node instance. If the pool is empty,
- * start the discovery process and skip the Nameserver
- * login process. This is attempted again later on.
- * Otherwise, issue a Port Login (PLOGI) to NameServer.
- */
- ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
- if (!ndlp) {
- lpfc_disc_start(phba);
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
- return;
- } else {
- lpfc_nlp_init(phba, ndlp, NameServer_DID);
- ndlp->nlp_type |= NLP_FABRIC;
+ if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
+ lpfc_initial_fdisc(next_vport);
+ else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ lpfc_vport_set_state(vport,
+ FC_VPORT_NO_FABRIC_SUPP);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0259 No NPIV Fabric "
+ "support\n",
+ phba->brd_no, vport->vpi);
}
}
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, NameServer_DID, 0);
- if (phba->cfg_fdmi_on) {
- ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
- GFP_KERNEL);
- if (ndlp_fdmi) {
- lpfc_nlp_init(phba, ndlp_fdmi, FDMI_DID);
- ndlp_fdmi->nlp_type |= NLP_FABRIC;
- ndlp_fdmi->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_issue_els_plogi(phba, FDMI_DID, 0);
- }
- }
+ lpfc_do_scr_ns_plogi(phba, vport);
}
lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -1046,32 +1359,36 @@
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli;
- MAILBOX_t *mb;
- struct lpfc_dmabuf *mp;
- struct lpfc_nodelist *ndlp;
-
- psli = &phba->sli;
- mb = &pmb->mb;
-
- ndlp = (struct lpfc_nodelist *) pmb->context2;
- mp = (struct lpfc_dmabuf *) (pmb->context1);
+ MAILBOX_t *mb = &pmb->mb;
+ struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+ struct lpfc_vport *vport = pmb->vport;
if (mb->mbxStatus) {
+out:
lpfc_nlp_put(ndlp);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool);
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
- /* RegLogin failed, so just use loop map to make discovery
- list */
- lpfc_disc_list_loopmap(phba);
+ if (phba->fc_topology == TOPOLOGY_LOOP) {
+ /*
+ * RegLogin failed, use loop map to make discovery
+ * list
+ */
+ lpfc_disc_list_loopmap(vport);
- /* Start discovery */
- lpfc_disc_start(phba);
+ /* Start discovery */
+ lpfc_disc_start(vport);
+ return;
+ }
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0260 Register NameServer error: 0x%x\n",
+ phba->brd_no, vport->vpi, mb->mbxStatus);
return;
}
@@ -1079,37 +1396,43 @@
ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_type |= NLP_FABRIC;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
- if (phba->hba_state < LPFC_HBA_READY) {
- /* Link up discovery requires Fabrib registration. */
- lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RNN_ID);
- lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RSNN_NN);
- lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFT_ID);
- lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFF_ID);
+ if (vport->port_state < LPFC_VPORT_READY) {
+ /* Link up discovery requires Fabric registration. */
+ lpfc_ns_cmd(vport, SLI_CTNS_RFF_ID, 0, 0); /* Do this first! */
+ lpfc_ns_cmd(vport, SLI_CTNS_RNN_ID, 0, 0);
+ lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0);
+ lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0);
+ lpfc_ns_cmd(vport, SLI_CTNS_RFT_ID, 0, 0);
+
+ /* Issue SCR just before NameServer GID_FT Query */
+ lpfc_issue_els_scr(vport, SCR_DID, 0);
}
- phba->fc_ns_retry = 0;
+ vport->fc_ns_retry = 0;
/* Good status, issue CT Request to NameServer */
- if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT)) {
+ if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0)) {
/* Cannot issue NameServer Query, so finish up discovery */
- lpfc_disc_start(phba);
+ goto out;
}
lpfc_nlp_put(ndlp);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
}
static void
-lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
- struct fc_rport *rport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct fc_rport *rport;
struct lpfc_rport_data *rdata;
struct fc_rport_identifiers rport_ids;
+ struct lpfc_hba *phba = vport->phba;
/* Remote port has reappeared. Re-register w/ FC transport */
rport_ids.node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn);
@@ -1125,10 +1448,15 @@
* registered the port.
*/
if (ndlp->rport && ndlp->rport->dd_data &&
- *(struct lpfc_rport_data **) ndlp->rport->dd_data) {
+ ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) {
lpfc_nlp_put(ndlp);
}
- ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+ "rport add: did:x%x flg:x%x type x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
+
+ ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids);
if (!rport || !get_device(&rport->dev)) {
dev_printk(KERN_WARNING, &phba->pcidev->dev,
"Warning: fc_remote_port_add failed\n");
@@ -1151,25 +1479,20 @@
fc_remote_port_rolechg(rport, rport_ids.roles);
if ((rport->scsi_target_id != -1) &&
- (rport->scsi_target_id < LPFC_MAX_TARGET)) {
+ (rport->scsi_target_id < LPFC_MAX_TARGET)) {
ndlp->nlp_sid = rport->scsi_target_id;
}
-
return;
}
static void
-lpfc_unregister_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp)
{
struct fc_rport *rport = ndlp->rport;
- struct lpfc_rport_data *rdata = rport->dd_data;
- if (rport->scsi_target_id == -1) {
- ndlp->rport = NULL;
- rdata->pnode = NULL;
- lpfc_nlp_put(ndlp);
- put_device(&rport->dev);
- }
+ lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT,
+ "rport delete: did:x%x flg:x%x type x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
fc_remote_port_delete(rport);
@@ -1177,42 +1500,46 @@
}
static void
-lpfc_nlp_counters(struct lpfc_hba *phba, int state, int count)
+lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count)
{
- spin_lock_irq(phba->host->host_lock);
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ spin_lock_irq(shost->host_lock);
switch (state) {
case NLP_STE_UNUSED_NODE:
- phba->fc_unused_cnt += count;
+ vport->fc_unused_cnt += count;
break;
case NLP_STE_PLOGI_ISSUE:
- phba->fc_plogi_cnt += count;
+ vport->fc_plogi_cnt += count;
break;
case NLP_STE_ADISC_ISSUE:
- phba->fc_adisc_cnt += count;
+ vport->fc_adisc_cnt += count;
break;
case NLP_STE_REG_LOGIN_ISSUE:
- phba->fc_reglogin_cnt += count;
+ vport->fc_reglogin_cnt += count;
break;
case NLP_STE_PRLI_ISSUE:
- phba->fc_prli_cnt += count;
+ vport->fc_prli_cnt += count;
break;
case NLP_STE_UNMAPPED_NODE:
- phba->fc_unmap_cnt += count;
+ vport->fc_unmap_cnt += count;
break;
case NLP_STE_MAPPED_NODE:
- phba->fc_map_cnt += count;
+ vport->fc_map_cnt += count;
break;
case NLP_STE_NPR_NODE:
- phba->fc_npr_cnt += count;
+ vport->fc_npr_cnt += count;
break;
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
}
static void
-lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
int old_state, int new_state)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
if (new_state == NLP_STE_UNMAPPED_NODE) {
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
@@ -1226,35 +1553,34 @@
/* Transport interface */
if (ndlp->rport && (old_state == NLP_STE_MAPPED_NODE ||
old_state == NLP_STE_UNMAPPED_NODE)) {
- phba->nport_event_cnt++;
- lpfc_unregister_remote_port(phba, ndlp);
+ vport->phba->nport_event_cnt++;
+ lpfc_unregister_remote_port(ndlp);
}
if (new_state == NLP_STE_MAPPED_NODE ||
new_state == NLP_STE_UNMAPPED_NODE) {
- phba->nport_event_cnt++;
- /*
- * Tell the fc transport about the port, if we haven't
- * already. If we have, and it's a scsi entity, be
- * sure to unblock any attached scsi devices
- */
- lpfc_register_remote_port(phba, ndlp);
+ vport->phba->nport_event_cnt++;
+ /*
+ * Tell the fc transport about the port, if we haven't
+ * already. If we have, and it's a scsi entity, be
+ * sure to unblock any attached scsi devices
+ */
+ lpfc_register_remote_port(vport, ndlp);
}
-
- /*
- * if we added to Mapped list, but the remote port
- * registration failed or assigned a target id outside
- * our presentable range - move the node to the
- * Unmapped List
- */
+ /*
+ * if we added to Mapped list, but the remote port
+ * registration failed or assigned a target id outside
+ * our presentable range - move the node to the
+ * Unmapped List
+ */
if (new_state == NLP_STE_MAPPED_NODE &&
(!ndlp->rport ||
ndlp->rport->scsi_target_id == -1 ||
ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_TGT_NO_SCSIID;
- spin_unlock_irq(phba->host->host_lock);
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
}
}
@@ -1280,61 +1606,74 @@
}
void
-lpfc_nlp_set_state(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, int state)
+lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ int state)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
int old_state = ndlp->nlp_state;
char name1[16], name2[16];
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0904 NPort state transition x%06x, %s -> %s\n",
- phba->brd_no,
+ lpfc_printf_log(vport->phba, KERN_INFO, LOG_NODE,
+ "%d (%d):0904 NPort state transition x%06x, %s -> %s\n",
+ vport->phba->brd_no, vport->vpi,
ndlp->nlp_DID,
lpfc_nlp_state_name(name1, sizeof(name1), old_state),
lpfc_nlp_state_name(name2, sizeof(name2), state));
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
+ "node statechg did:x%x old:%d ste:%d",
+ ndlp->nlp_DID, old_state, state);
+
if (old_state == NLP_STE_NPR_NODE &&
(ndlp->nlp_flag & NLP_DELAY_TMO) != 0 &&
state != NLP_STE_NPR_NODE)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
if (old_state == NLP_STE_UNMAPPED_NODE) {
ndlp->nlp_flag &= ~NLP_TGT_NO_SCSIID;
ndlp->nlp_type &= ~NLP_FC_NODE;
}
if (list_empty(&ndlp->nlp_listp)) {
- spin_lock_irq(phba->host->host_lock);
- list_add_tail(&ndlp->nlp_listp, &phba->fc_nodes);
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes);
+ spin_unlock_irq(shost->host_lock);
} else if (old_state)
- lpfc_nlp_counters(phba, old_state, -1);
+ lpfc_nlp_counters(vport, old_state, -1);
ndlp->nlp_state = state;
- lpfc_nlp_counters(phba, state, 1);
- lpfc_nlp_state_cleanup(phba, ndlp, old_state, state);
+ lpfc_nlp_counters(vport, state, 1);
+ lpfc_nlp_state_cleanup(vport, ndlp, old_state, state);
}
void
-lpfc_dequeue_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
- lpfc_nlp_counters(phba, ndlp->nlp_state, -1);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
+ spin_lock_irq(shost->host_lock);
list_del_init(&ndlp->nlp_listp);
- spin_unlock_irq(phba->host->host_lock);
- lpfc_nlp_state_cleanup(phba, ndlp, ndlp->nlp_state, 0);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state,
+ NLP_STE_UNUSED_NODE);
}
void
-lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
- lpfc_nlp_counters(phba, ndlp->nlp_state, -1);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
+ spin_lock_irq(shost->host_lock);
list_del_init(&ndlp->nlp_listp);
- spin_unlock_irq(phba->host->host_lock);
+ ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
+ spin_unlock_irq(shost->host_lock);
lpfc_nlp_put(ndlp);
}
@@ -1342,11 +1681,13 @@
* Start / ReStart rescue timer for Discovery / RSCN handling
*/
void
-lpfc_set_disctmo(struct lpfc_hba * phba)
+lpfc_set_disctmo(struct lpfc_vport *vport)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
uint32_t tmo;
- if (phba->hba_state == LPFC_LOCAL_CFG_LINK) {
+ if (vport->port_state == LPFC_LOCAL_CFG_LINK) {
/* For FAN, timeout should be greater then edtov */
tmo = (((phba->fc_edtov + 999) / 1000) + 1);
} else {
@@ -1356,18 +1697,25 @@
tmo = ((phba->fc_ratov * 3) + 3);
}
- mod_timer(&phba->fc_disctmo, jiffies + HZ * tmo);
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_DISC_TMO;
- spin_unlock_irq(phba->host->host_lock);
+
+ if (!timer_pending(&vport->fc_disctmo)) {
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "set disc timer: tmo:x%x state:x%x flg:x%x",
+ tmo, vport->port_state, vport->fc_flag);
+ }
+
+ mod_timer(&vport->fc_disctmo, jiffies + HZ * tmo);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_DISC_TMO;
+ spin_unlock_irq(shost->host_lock);
/* Start Discovery Timer state <hba_state> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0247 Start Discovery Timer state x%x "
+ "%d (%d):0247 Start Discovery Timer state x%x "
"Data: x%x x%lx x%x x%x\n",
- phba->brd_no,
- phba->hba_state, tmo, (unsigned long)&phba->fc_disctmo,
- phba->fc_plogi_cnt, phba->fc_adisc_cnt);
+ phba->brd_no, vport->vpi, vport->port_state, tmo,
+ (unsigned long)&vport->fc_disctmo, vport->fc_plogi_cnt,
+ vport->fc_adisc_cnt);
return;
}
@@ -1376,23 +1724,34 @@
* Cancel rescue timer for Discovery / RSCN handling
*/
int
-lpfc_can_disctmo(struct lpfc_hba * phba)
+lpfc_can_disctmo(struct lpfc_vport *vport)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ unsigned long iflags;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "can disc timer: state:x%x rtry:x%x flg:x%x",
+ vport->port_state, vport->fc_ns_retry, vport->fc_flag);
+
/* Turn off discovery timer if its running */
- if (phba->fc_flag & FC_DISC_TMO) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_DISC_TMO;
- spin_unlock_irq(phba->host->host_lock);
- del_timer_sync(&phba->fc_disctmo);
- phba->work_hba_events &= ~WORKER_DISC_TMO;
+ if (vport->fc_flag & FC_DISC_TMO) {
+ spin_lock_irqsave(shost->host_lock, iflags);
+ vport->fc_flag &= ~FC_DISC_TMO;
+ spin_unlock_irqrestore(shost->host_lock, iflags);
+ del_timer_sync(&vport->fc_disctmo);
+ spin_lock_irqsave(&vport->work_port_lock, iflags);
+ vport->work_port_events &= ~WORKER_DISC_TMO;
+ spin_unlock_irqrestore(&vport->work_port_lock, iflags);
}
/* Cancel Discovery Timer state <hba_state> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0248 Cancel Discovery Timer state x%x "
+ "%d (%d):0248 Cancel Discovery Timer state x%x "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->hba_state, phba->fc_flag,
- phba->fc_plogi_cnt, phba->fc_adisc_cnt);
+ phba->brd_no, vport->vpi, vport->port_state,
+ vport->fc_flag, vport->fc_plogi_cnt,
+ vport->fc_adisc_cnt);
return 0;
}
@@ -1402,15 +1761,18 @@
* Return true if iocb matches the specified nport
*/
int
-lpfc_check_sli_ndlp(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring,
- struct lpfc_iocbq * iocb, struct lpfc_nodelist * ndlp)
+lpfc_check_sli_ndlp(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *iocb,
+ struct lpfc_nodelist *ndlp)
{
- struct lpfc_sli *psli;
- IOCB_t *icmd;
+ struct lpfc_sli *psli = &phba->sli;
+ IOCB_t *icmd = &iocb->iocb;
+ struct lpfc_vport *vport = ndlp->vport;
- psli = &phba->sli;
- icmd = &iocb->iocb;
+ if (iocb->vport != vport)
+ return 0;
+
if (pring->ringno == LPFC_ELS_RING) {
switch (icmd->ulpCommand) {
case CMD_GEN_REQUEST64_CR:
@@ -1428,7 +1790,7 @@
} else if (pring->ringno == psli->fcp_ring) {
/* Skip match check if waiting to relogin to FCP target */
if ((ndlp->nlp_type & NLP_FCP_TARGET) &&
- (ndlp->nlp_flag & NLP_DELAY_TMO)) {
+ (ndlp->nlp_flag & NLP_DELAY_TMO)) {
return 0;
}
if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi) {
@@ -1445,7 +1807,7 @@
* associated with nlp_rpi in the LPFC_NODELIST entry.
*/
static int
-lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
LIST_HEAD(completions);
struct lpfc_sli *psli;
@@ -1454,6 +1816,8 @@
IOCB_t *icmd;
uint32_t rpi, i;
+ lpfc_fabric_abort_nport(ndlp);
+
/*
* Everything that matches on txcmplq will be returned
* by firmware with a no rpi error.
@@ -1465,15 +1829,15 @@
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(iocb, next_iocb, &pring->txq,
- list) {
+ list) {
/*
* Check to see if iocb matches the nport we are
* looking for
*/
- if ((lpfc_check_sli_ndlp
- (phba, pring, iocb, ndlp))) {
+ if ((lpfc_check_sli_ndlp(phba, pring, iocb,
+ ndlp))) {
/* It matches, so deque and call compl
with an error */
list_move_tail(&iocb->list,
@@ -1481,22 +1845,22 @@
pring->txq_cnt--;
}
}
- spin_unlock_irq(phba->host->host_lock);
-
+ spin_unlock_irq(&phba->hbalock);
}
}
while (!list_empty(&completions)) {
iocb = list_get_first(&completions, struct lpfc_iocbq, list);
- list_del(&iocb->list);
+ list_del_init(&iocb->list);
- if (iocb->iocb_cmpl) {
+ if (!iocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, iocb);
+ else {
icmd = &iocb->iocb;
icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
- (iocb->iocb_cmpl) (phba, iocb, iocb);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
+ (iocb->iocb_cmpl)(phba, iocb, iocb);
+ }
}
return 0;
@@ -1512,19 +1876,22 @@
* we are waiting to PLOGI back to the remote NPort.
*/
int
-lpfc_unreg_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
- LPFC_MBOXQ_t *mbox;
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mbox;
int rc;
if (ndlp->nlp_rpi) {
- if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
- lpfc_unreg_login(phba, ndlp->nlp_rpi, mbox);
- mbox->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
- rc = lpfc_sli_issue_mbox
- (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox) {
+ lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox);
+ mbox->vport = vport;
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, mbox,
+ (MBX_NOWAIT | MBX_STOP_IOCB));
if (rc == MBX_NOT_FINISHED)
- mempool_free( mbox, phba->mbox_mem_pool);
+ mempool_free(mbox, phba->mbox_mem_pool);
}
lpfc_no_rpi(phba, ndlp);
ndlp->nlp_rpi = 0;
@@ -1533,25 +1900,70 @@
return 0;
}
+void
+lpfc_unreg_all_rpis(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mbox;
+ int rc;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox) {
+ lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox);
+ mbox->vport = vport;
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, mbox,
+ (MBX_NOWAIT | MBX_STOP_IOCB));
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
+ }
+}
+
+void
+lpfc_unreg_default_rpis(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mbox;
+ int rc;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox) {
+ lpfc_unreg_did(phba, vport->vpi, 0xffffffff, mbox);
+ mbox->vport = vport;
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, mbox,
+ (MBX_NOWAIT | MBX_STOP_IOCB));
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT,
+ "%d (%d):1815 Could not issue "
+ "unreg_did (default rpis)\n",
+ phba->brd_no, vport->vpi);
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
+ }
+}
+
/*
* Free resources associated with LPFC_NODELIST entry
* so it can be freed.
*/
static int
-lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
- LPFC_MBOXQ_t *mb;
- LPFC_MBOXQ_t *nextmb;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mb, *nextmb;
struct lpfc_dmabuf *mp;
/* Cleanup node for NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0900 Cleanup node for NPort x%x "
+ "%d (%d):0900 Cleanup node for NPort x%x "
"Data: x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
+ phba->brd_no, vport->vpi, ndlp->nlp_DID, ndlp->nlp_flag,
ndlp->nlp_state, ndlp->nlp_rpi);
- lpfc_dequeue_node(phba, ndlp);
+ lpfc_dequeue_node(vport, ndlp);
/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
if ((mb = phba->sli.mbox_active)) {
@@ -1562,13 +1974,13 @@
}
}
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
- (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+ (ndlp == (struct lpfc_nodelist *) mb->context2)) {
mp = (struct lpfc_dmabuf *) (mb->context1);
if (mp) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ __lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
}
list_del(&mb->list);
@@ -1576,20 +1988,27 @@
lpfc_nlp_put(ndlp);
}
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
lpfc_els_abort(phba,ndlp);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = 0;
del_timer_sync(&ndlp->nlp_delayfunc);
if (!list_empty(&ndlp->els_retry_evt.evt_listp))
list_del_init(&ndlp->els_retry_evt.evt_listp);
+ if (!list_empty(&ndlp->dev_loss_evt.evt_listp))
+ list_del_init(&ndlp->dev_loss_evt.evt_listp);
- lpfc_unreg_rpi(phba, ndlp);
+ if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) {
+ list_del_init(&ndlp->dev_loss_evt.evt_listp);
+ complete((struct completion *)(ndlp->dev_loss_evt.evt_arg2));
+ }
+
+ lpfc_unreg_rpi(vport, ndlp);
return 0;
}
@@ -1600,18 +2019,22 @@
* machine, defer the free till we reach the end of the state machine.
*/
static void
-lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
struct lpfc_rport_data *rdata;
if (ndlp->nlp_flag & NLP_DELAY_TMO) {
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
}
- lpfc_cleanup_node(phba, ndlp);
+ lpfc_cleanup_node(vport, ndlp);
- if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) {
- put_device(&ndlp->rport->dev);
+ /*
+ * We can get here with a non-NULL ndlp->rport because when we
+ * unregister a rport we don't break the rport/node linkage. So if we
+ * do, make sure we don't leaving any dangling pointers behind.
+ */
+ if (ndlp->rport) {
rdata = ndlp->rport->dd_data;
rdata->pnode = NULL;
ndlp->rport = NULL;
@@ -1619,11 +2042,10 @@
}
static int
-lpfc_matchdid(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
+lpfc_matchdid(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ uint32_t did)
{
- D_ID mydid;
- D_ID ndlpdid;
- D_ID matchdid;
+ D_ID mydid, ndlpdid, matchdid;
if (did == Bcast_DID)
return 0;
@@ -1637,7 +2059,7 @@
return 1;
/* Next check for area/domain identically equals 0 match */
- mydid.un.word = phba->fc_myDID;
+ mydid.un.word = vport->fc_myDID;
if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) {
return 0;
}
@@ -1669,101 +2091,116 @@
}
/* Search for a nodelist entry */
-struct lpfc_nodelist *
-lpfc_findnode_did(struct lpfc_hba *phba, uint32_t did)
+static struct lpfc_nodelist *
+__lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp;
uint32_t data1;
- spin_lock_irq(phba->host->host_lock);
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
- if (lpfc_matchdid(phba, ndlp, did)) {
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+ if (lpfc_matchdid(vport, ndlp, did)) {
data1 = (((uint32_t) ndlp->nlp_state << 24) |
((uint32_t) ndlp->nlp_xri << 16) |
((uint32_t) ndlp->nlp_type << 8) |
((uint32_t) ndlp->nlp_rpi & 0xff));
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0929 FIND node DID "
+ "%d (%d):0929 FIND node DID "
" Data: x%p x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
ndlp, ndlp->nlp_DID,
ndlp->nlp_flag, data1);
- spin_unlock_irq(phba->host->host_lock);
return ndlp;
}
}
- spin_unlock_irq(phba->host->host_lock);
/* FIND node did <did> NOT FOUND */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0932 FIND node did x%x NOT FOUND.\n",
- phba->brd_no, did);
+ "%d (%d):0932 FIND node did x%x NOT FOUND.\n",
+ phba->brd_no, vport->vpi, did);
return NULL;
}
struct lpfc_nodelist *
-lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
+lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp;
- ndlp = lpfc_findnode_did(phba, did);
+ spin_lock_irq(shost->host_lock);
+ ndlp = __lpfc_findnode_did(vport, did);
+ spin_unlock_irq(shost->host_lock);
+ return ndlp;
+}
+
+struct lpfc_nodelist *
+lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_nodelist *ndlp;
+
+ ndlp = lpfc_findnode_did(vport, did);
if (!ndlp) {
- if ((phba->fc_flag & FC_RSCN_MODE) &&
- ((lpfc_rscn_payload_check(phba, did) == 0)))
+ if ((vport->fc_flag & FC_RSCN_MODE) != 0 &&
+ lpfc_rscn_payload_check(vport, did) == 0)
return NULL;
ndlp = (struct lpfc_nodelist *)
- mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+ mempool_alloc(vport->phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp)
return NULL;
- lpfc_nlp_init(phba, ndlp, did);
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_init(vport, ndlp, did);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+ spin_unlock_irq(shost->host_lock);
return ndlp;
}
- if (phba->fc_flag & FC_RSCN_MODE) {
- if (lpfc_rscn_payload_check(phba, did)) {
+ if (vport->fc_flag & FC_RSCN_MODE) {
+ if (lpfc_rscn_payload_check(vport, did)) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+ spin_unlock_irq(shost->host_lock);
/* Since this node is marked for discovery,
* delay timeout is not needed.
*/
if (ndlp->nlp_flag & NLP_DELAY_TMO)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
} else
ndlp = NULL;
} else {
if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
ndlp->nlp_state == NLP_STE_PLOGI_ISSUE)
return NULL;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+ spin_unlock_irq(shost->host_lock);
}
return ndlp;
}
/* Build a list of nodes to discover based on the loopmap */
void
-lpfc_disc_list_loopmap(struct lpfc_hba * phba)
+lpfc_disc_list_loopmap(struct lpfc_vport *vport)
{
+ struct lpfc_hba *phba = vport->phba;
int j;
uint32_t alpa, index;
- if (phba->hba_state <= LPFC_LINK_DOWN) {
+ if (!lpfc_is_link_up(phba))
return;
- }
- if (phba->fc_topology != TOPOLOGY_LOOP) {
+
+ if (phba->fc_topology != TOPOLOGY_LOOP)
return;
- }
/* Check for loop map present or not */
if (phba->alpa_map[0]) {
for (j = 1; j <= phba->alpa_map[0]; j++) {
alpa = phba->alpa_map[j];
-
- if (((phba->fc_myDID & 0xff) == alpa) || (alpa == 0)) {
+ if (((vport->fc_myDID & 0xff) == alpa) || (alpa == 0))
continue;
- }
- lpfc_setup_disc_node(phba, alpa);
+ lpfc_setup_disc_node(vport, alpa);
}
} else {
/* No alpamap, so try all alpa's */
@@ -1776,113 +2213,167 @@
else
index = FC_MAXLOOP - j - 1;
alpa = lpfcAlpaArray[index];
- if ((phba->fc_myDID & 0xff) == alpa) {
+ if ((vport->fc_myDID & 0xff) == alpa)
continue;
- }
-
- lpfc_setup_disc_node(phba, alpa);
+ lpfc_setup_disc_node(vport, alpa);
}
}
return;
}
-/* Start Link up / RSCN discovery on NPR list */
void
-lpfc_disc_start(struct lpfc_hba * phba)
+lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport)
{
- struct lpfc_sli *psli;
LPFC_MBOXQ_t *mbox;
- struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *extra_ring = &psli->ring[psli->extra_ring];
+ struct lpfc_sli_ring *fcp_ring = &psli->ring[psli->fcp_ring];
+ struct lpfc_sli_ring *next_ring = &psli->ring[psli->next_ring];
+ int rc;
+
+ /*
+ * if it's not a physical port or if we already send
+ * clear_la then don't send it.
+ */
+ if ((phba->link_state >= LPFC_CLEAR_LA) ||
+ (vport->port_type != LPFC_PHYSICAL_PORT))
+ return;
+
+ /* Link up discovery */
+ if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) != NULL) {
+ phba->link_state = LPFC_CLEAR_LA;
+ lpfc_clear_la(phba, mbox);
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT |
+ MBX_STOP_IOCB));
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ lpfc_disc_flush_list(vport);
+ extra_ring->flag &= ~LPFC_STOP_IOCB_EVENT;
+ fcp_ring->flag &= ~LPFC_STOP_IOCB_EVENT;
+ next_ring->flag &= ~LPFC_STOP_IOCB_EVENT;
+ phba->link_state = LPFC_HBA_ERROR;
+ }
+ }
+}
+
+/* Reg_vpi to tell firmware to resume normal operations */
+void
+lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport)
+{
+ LPFC_MBOXQ_t *regvpimbox;
+
+ regvpimbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (regvpimbox) {
+ lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, regvpimbox);
+ regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi;
+ regvpimbox->vport = vport;
+ if (lpfc_sli_issue_mbox(phba, regvpimbox,
+ (MBX_NOWAIT | MBX_STOP_IOCB))
+ == MBX_NOT_FINISHED) {
+ mempool_free(regvpimbox, phba->mbox_mem_pool);
+ }
+ }
+}
+
+/* Start Link up / RSCN discovery on NPR nodes */
+void
+lpfc_disc_start(struct lpfc_vport *vport)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
uint32_t num_sent;
uint32_t clear_la_pending;
int did_changed;
- int rc;
- psli = &phba->sli;
-
- if (phba->hba_state <= LPFC_LINK_DOWN) {
+ if (!lpfc_is_link_up(phba))
return;
- }
- if (phba->hba_state == LPFC_CLEAR_LA)
+
+ if (phba->link_state == LPFC_CLEAR_LA)
clear_la_pending = 1;
else
clear_la_pending = 0;
- if (phba->hba_state < LPFC_HBA_READY) {
- phba->hba_state = LPFC_DISC_AUTH;
- }
- lpfc_set_disctmo(phba);
+ if (vport->port_state < LPFC_VPORT_READY)
+ vport->port_state = LPFC_DISC_AUTH;
- if (phba->fc_prevDID == phba->fc_myDID) {
+ lpfc_set_disctmo(vport);
+
+ if (vport->fc_prevDID == vport->fc_myDID)
did_changed = 0;
- } else {
+ else
did_changed = 1;
- }
- phba->fc_prevDID = phba->fc_myDID;
- phba->num_disc_nodes = 0;
+
+ vport->fc_prevDID = vport->fc_myDID;
+ vport->num_disc_nodes = 0;
/* Start Discovery state <hba_state> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0202 Start Discovery hba state x%x "
+ "%d (%d):0202 Start Discovery hba state x%x "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->hba_state, phba->fc_flag,
- phba->fc_plogi_cnt, phba->fc_adisc_cnt);
-
- /* If our did changed, we MUST do PLOGI */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
- if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
- (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
- did_changed) {
- spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
- }
- }
+ phba->brd_no, vport->vpi, vport->port_state,
+ vport->fc_flag, vport->fc_plogi_cnt,
+ vport->fc_adisc_cnt);
/* First do ADISCs - if any */
- num_sent = lpfc_els_disc_adisc(phba);
+ num_sent = lpfc_els_disc_adisc(vport);
if (num_sent)
return;
- if ((phba->hba_state < LPFC_HBA_READY) && (!clear_la_pending)) {
+ /*
+ * For SLI3, cmpl_reg_vpi will set port_state to READY, and
+ * continue discovery.
+ */
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ !(vport->fc_flag & FC_RSCN_MODE)) {
+ lpfc_issue_reg_vpi(phba, vport);
+ return;
+ }
+
+ /*
+ * For SLI2, we need to set port_state to READY and continue
+ * discovery.
+ */
+ if (vport->port_state < LPFC_VPORT_READY && !clear_la_pending) {
/* If we get here, there is nothing to ADISC */
- if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
- phba->hba_state = LPFC_CLEAR_LA;
- lpfc_clear_la(phba, mbox);
- mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- rc = lpfc_sli_issue_mbox(phba, mbox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED) {
- mempool_free( mbox, phba->mbox_mem_pool);
- lpfc_disc_flush_list(phba);
- psli->ring[(psli->extra_ring)].flag &=
- ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->fcp_ring)].flag &=
- ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->next_ring)].flag &=
- ~LPFC_STOP_IOCB_EVENT;
- phba->hba_state = LPFC_HBA_READY;
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ lpfc_issue_clear_la(phba, vport);
+
+ if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
+ vport->num_disc_nodes = 0;
+ /* go thru NPR nodes and issue ELS PLOGIs */
+ if (vport->fc_npr_cnt)
+ lpfc_els_disc_plogi(vport);
+
+ if (!vport->num_disc_nodes) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
}
}
+ vport->port_state = LPFC_VPORT_READY;
} else {
/* Next do PLOGIs - if any */
- num_sent = lpfc_els_disc_plogi(phba);
+ num_sent = lpfc_els_disc_plogi(vport);
if (num_sent)
return;
- if (phba->fc_flag & FC_RSCN_MODE) {
+ if (vport->fc_flag & FC_RSCN_MODE) {
/* Check to see if more RSCNs came in while we
* were processing this one.
*/
- if ((phba->fc_rscn_id_cnt == 0) &&
- (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_RSCN_MODE;
- spin_unlock_irq(phba->host->host_lock);
+ if ((vport->fc_rscn_id_cnt == 0) &&
+ (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_RSCN_MODE;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
} else
- lpfc_els_handle_rscn(phba);
+ lpfc_els_handle_rscn(vport);
}
}
return;
@@ -1893,7 +2384,7 @@
* ring the match the sppecified nodelist.
*/
static void
-lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
LIST_HEAD(completions);
struct lpfc_sli *psli;
@@ -1907,7 +2398,7 @@
/* Error matching iocb on txq or txcmplq
* First check the txq.
*/
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
if (iocb->context1 != ndlp) {
continue;
@@ -1927,36 +2418,36 @@
continue;
}
icmd = &iocb->iocb;
- if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
- (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
+ if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR ||
+ icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX) {
lpfc_sli_issue_abort_iotag(phba, pring, iocb);
}
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
while (!list_empty(&completions)) {
iocb = list_get_first(&completions, struct lpfc_iocbq, list);
- list_del(&iocb->list);
+ list_del_init(&iocb->list);
- if (iocb->iocb_cmpl) {
+ if (!iocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, iocb);
+ else {
icmd = &iocb->iocb;
icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
(iocb->iocb_cmpl) (phba, iocb, iocb);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
+ }
}
-
- return;
}
void
-lpfc_disc_flush_list(struct lpfc_hba * phba)
+lpfc_disc_flush_list(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct lpfc_hba *phba = vport->phba;
- if (phba->fc_plogi_cnt || phba->fc_adisc_cnt) {
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+ if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) {
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
nlp_listp) {
if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
ndlp->nlp_state == NLP_STE_ADISC_ISSUE) {
@@ -1967,6 +2458,14 @@
}
}
+void
+lpfc_cleanup_discovery_resources(struct lpfc_vport *vport)
+{
+ lpfc_els_flush_rscn(vport);
+ lpfc_els_flush_cmd(vport);
+ lpfc_disc_flush_list(vport);
+}
+
/*****************************************************************************/
/*
* NAME: lpfc_disc_timeout
@@ -1985,158 +2484,154 @@
void
lpfc_disc_timeout(unsigned long ptr)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
+ struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
+ struct lpfc_hba *phba = vport->phba;
unsigned long flags = 0;
if (unlikely(!phba))
return;
- spin_lock_irqsave(phba->host->host_lock, flags);
- if (!(phba->work_hba_events & WORKER_DISC_TMO)) {
- phba->work_hba_events |= WORKER_DISC_TMO;
+ if ((vport->work_port_events & WORKER_DISC_TMO) == 0) {
+ spin_lock_irqsave(&vport->work_port_lock, flags);
+ vport->work_port_events |= WORKER_DISC_TMO;
+ spin_unlock_irqrestore(&vport->work_port_lock, flags);
+
+ spin_lock_irqsave(&phba->hbalock, flags);
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
}
- spin_unlock_irqrestore(phba->host->host_lock, flags);
return;
}
static void
-lpfc_disc_timeout_handler(struct lpfc_hba *phba)
+lpfc_disc_timeout_handler(struct lpfc_vport *vport)
{
- struct lpfc_sli *psli;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
struct lpfc_nodelist *ndlp, *next_ndlp;
- LPFC_MBOXQ_t *clearlambox, *initlinkmbox;
+ LPFC_MBOXQ_t *initlinkmbox;
int rc, clrlaerr = 0;
- if (unlikely(!phba))
+ if (!(vport->fc_flag & FC_DISC_TMO))
return;
- if (!(phba->fc_flag & FC_DISC_TMO))
- return;
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_DISC_TMO;
+ spin_unlock_irq(shost->host_lock);
- psli = &phba->sli;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "disc timeout: state:x%x rtry:x%x flg:x%x",
+ vport->port_state, vport->fc_ns_retry, vport->fc_flag);
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_DISC_TMO;
- spin_unlock_irq(phba->host->host_lock);
-
- switch (phba->hba_state) {
+ switch (vport->port_state) {
case LPFC_LOCAL_CFG_LINK:
- /* hba_state is identically LPFC_LOCAL_CFG_LINK while waiting for FAN */
- /* FAN timeout */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_DISCOVERY,
- "%d:0221 FAN timeout\n",
- phba->brd_no);
+ /* port_state is identically LPFC_LOCAL_CFG_LINK while waiting for
+ * FAN
+ */
+ /* FAN timeout */
+ lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY,
+ "%d (%d):0221 FAN timeout\n",
+ phba->brd_no, vport->vpi);
/* Start discovery by sending FLOGI, clean up old rpis */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
nlp_listp) {
if (ndlp->nlp_state != NLP_STE_NPR_NODE)
continue;
if (ndlp->nlp_type & NLP_FABRIC) {
/* Clean up the ndlp on Fabric connections */
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
/* Fail outstanding IO now since device
* is marked for PLOGI.
*/
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
}
}
- phba->hba_state = LPFC_FLOGI;
- lpfc_set_disctmo(phba);
- lpfc_initial_flogi(phba);
+ if (vport->port_state != LPFC_FLOGI) {
+ vport->port_state = LPFC_FLOGI;
+ lpfc_set_disctmo(vport);
+ lpfc_initial_flogi(vport);
+ }
break;
+ case LPFC_FDISC:
case LPFC_FLOGI:
- /* hba_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */
+ /* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */
/* Initial FLOGI timeout */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_DISCOVERY,
- "%d:0222 Initial FLOGI timeout\n",
- phba->brd_no);
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0222 Initial %s timeout\n",
+ phba->brd_no, vport->vpi,
+ vport->vpi ? "FLOGI" : "FDISC");
/* Assume no Fabric and go on with discovery.
* Check for outstanding ELS FLOGI to abort.
*/
/* FLOGI failed, so just use loop map to make discovery list */
- lpfc_disc_list_loopmap(phba);
+ lpfc_disc_list_loopmap(vport);
/* Start discovery */
- lpfc_disc_start(phba);
+ lpfc_disc_start(vport);
break;
case LPFC_FABRIC_CFG_LINK:
/* hba_state is identically LPFC_FABRIC_CFG_LINK while waiting for
NameServer login */
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0223 Timeout while waiting for NameServer "
- "login\n", phba->brd_no);
+ "%d (%d):0223 Timeout while waiting for "
+ "NameServer login\n",
+ phba->brd_no, vport->vpi);
/* Next look for NameServer ndlp */
- ndlp = lpfc_findnode_did(phba, NameServer_DID);
+ ndlp = lpfc_findnode_did(vport, NameServer_DID);
if (ndlp)
lpfc_nlp_put(ndlp);
/* Start discovery */
- lpfc_disc_start(phba);
+ lpfc_disc_start(vport);
break;
case LPFC_NS_QRY:
/* Check for wait for NameServer Rsp timeout */
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0224 NameServer Query timeout "
+ "%d (%d):0224 NameServer Query timeout "
"Data: x%x x%x\n",
- phba->brd_no,
- phba->fc_ns_retry, LPFC_MAX_NS_RETRY);
+ phba->brd_no, vport->vpi,
+ vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
- ndlp = lpfc_findnode_did(phba, NameServer_DID);
- if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
- if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
- /* Try it one more time */
- rc = lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT);
- if (rc == 0)
- break;
- }
- phba->fc_ns_retry = 0;
+ if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
+ /* Try it one more time */
+ vport->fc_ns_retry++;
+ rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
+ vport->fc_ns_retry, 0);
+ if (rc == 0)
+ break;
}
+ vport->fc_ns_retry = 0;
- /* Nothing to authenticate, so CLEAR_LA right now */
- clearlambox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!clearlambox) {
- clrlaerr = 1;
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0226 Device Discovery "
- "completion error\n",
- phba->brd_no);
- phba->hba_state = LPFC_HBA_ERROR;
- break;
- }
-
- phba->hba_state = LPFC_CLEAR_LA;
- lpfc_clear_la(phba, clearlambox);
- clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- rc = lpfc_sli_issue_mbox(phba, clearlambox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(clearlambox, phba->mbox_mem_pool);
- clrlaerr = 1;
- break;
+ /*
+ * Discovery is over.
+ * set port_state to PORT_READY if SLI2.
+ * cmpl_reg_vpi will set port_state to READY for SLI3.
+ */
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+ lpfc_issue_reg_vpi(phba, vport);
+ else { /* NPIV Not enabled */
+ lpfc_issue_clear_la(phba, vport);
+ vport->port_state = LPFC_VPORT_READY;
}
/* Setup and issue mailbox INITIALIZE LINK command */
initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!initlinkmbox) {
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0206 Device Discovery "
+ "%d (%d):0206 Device Discovery "
"completion error\n",
- phba->brd_no);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->brd_no, vport->vpi);
+ phba->link_state = LPFC_HBA_ERROR;
break;
}
@@ -2144,6 +2639,8 @@
lpfc_init_link(phba, initlinkmbox, phba->cfg_topology,
phba->cfg_link_speed);
initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
+ initlinkmbox->vport = vport;
+ initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
rc = lpfc_sli_issue_mbox(phba, initlinkmbox,
(MBX_NOWAIT | MBX_STOP_IOCB));
lpfc_set_loopback_flag(phba);
@@ -2154,67 +2651,81 @@
case LPFC_DISC_AUTH:
/* Node Authentication timeout */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_DISCOVERY,
- "%d:0227 Node Authentication timeout\n",
- phba->brd_no);
- lpfc_disc_flush_list(phba);
- clearlambox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!clearlambox) {
- clrlaerr = 1;
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0207 Device Discovery "
- "completion error\n",
- phba->brd_no);
- phba->hba_state = LPFC_HBA_ERROR;
- break;
- }
- phba->hba_state = LPFC_CLEAR_LA;
- lpfc_clear_la(phba, clearlambox);
- clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- rc = lpfc_sli_issue_mbox(phba, clearlambox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(clearlambox, phba->mbox_mem_pool);
- clrlaerr = 1;
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0227 Node Authentication timeout\n",
+ phba->brd_no, vport->vpi);
+ lpfc_disc_flush_list(vport);
+
+ /*
+ * set port_state to PORT_READY if SLI2.
+ * cmpl_reg_vpi will set port_state to READY for SLI3.
+ */
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+ lpfc_issue_reg_vpi(phba, vport);
+ else { /* NPIV Not enabled */
+ lpfc_issue_clear_la(phba, vport);
+ vport->port_state = LPFC_VPORT_READY;
}
break;
+ case LPFC_VPORT_READY:
+ if (vport->fc_flag & FC_RSCN_MODE) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0231 RSCN timeout Data: x%x "
+ "x%x\n",
+ phba->brd_no, vport->vpi,
+ vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
+
+ /* Cleanup any outstanding ELS commands */
+ lpfc_els_flush_cmd(vport);
+
+ lpfc_els_flush_rscn(vport);
+ lpfc_disc_flush_list(vport);
+ }
+ break;
+
+ default:
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0229 Unexpected discovery timeout, "
+ "vport State x%x\n",
+ phba->brd_no, vport->vpi, vport->port_state);
+
+ break;
+ }
+
+ switch (phba->link_state) {
case LPFC_CLEAR_LA:
- /* CLEAR LA timeout */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_DISCOVERY,
- "%d:0228 CLEAR LA timeout\n",
- phba->brd_no);
+ /* CLEAR LA timeout */
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0228 CLEAR LA timeout\n",
+ phba->brd_no, vport->vpi);
+ clrlaerr = 1;
+ break;
+
+ case LPFC_LINK_UNKNOWN:
+ case LPFC_WARM_START:
+ case LPFC_INIT_START:
+ case LPFC_INIT_MBX_CMDS:
+ case LPFC_LINK_DOWN:
+ case LPFC_LINK_UP:
+ case LPFC_HBA_ERROR:
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0230 Unexpected timeout, hba link "
+ "state x%x\n",
+ phba->brd_no, vport->vpi, phba->link_state);
clrlaerr = 1;
break;
case LPFC_HBA_READY:
- if (phba->fc_flag & FC_RSCN_MODE) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_DISCOVERY,
- "%d:0231 RSCN timeout Data: x%x x%x\n",
- phba->brd_no,
- phba->fc_ns_retry, LPFC_MAX_NS_RETRY);
-
- /* Cleanup any outstanding ELS commands */
- lpfc_els_flush_cmd(phba);
-
- lpfc_els_flush_rscn(phba);
- lpfc_disc_flush_list(phba);
- }
break;
}
if (clrlaerr) {
- lpfc_disc_flush_list(phba);
+ lpfc_disc_flush_list(vport);
psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
- phba->hba_state = LPFC_HBA_READY;
+ vport->port_state = LPFC_VPORT_READY;
}
return;
@@ -2227,37 +2738,29 @@
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli;
- MAILBOX_t *mb;
- struct lpfc_dmabuf *mp;
- struct lpfc_nodelist *ndlp;
-
- psli = &phba->sli;
- mb = &pmb->mb;
-
- ndlp = (struct lpfc_nodelist *) pmb->context2;
- mp = (struct lpfc_dmabuf *) (pmb->context1);
+ MAILBOX_t *mb = &pmb->mb;
+ struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+ struct lpfc_vport *vport = pmb->vport;
pmb->context1 = NULL;
ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_type |= NLP_FABRIC;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
- /* Start issuing Fabric-Device Management Interface (FDMI)
- * command to 0xfffffa (FDMI well known port)
+ /*
+ * Start issuing Fabric-Device Management Interface (FDMI) command to
+ * 0xfffffa (FDMI well known port) or Delay issuing FDMI command if
+ * fdmi-on=2 (supporting RPA/hostnmae)
*/
- if (phba->cfg_fdmi_on == 1) {
- lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
- } else {
- /*
- * Delay issuing FDMI command if fdmi-on=2
- * (supporting RPA/hostnmae)
- */
- mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
- }
+
+ if (phba->cfg_fdmi_on == 1)
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
+ else
+ mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60);
/* Mailbox took a reference to the node */
lpfc_nlp_put(ndlp);
@@ -2283,16 +2786,12 @@
sizeof(ndlp->nlp_portname)) == 0;
}
-/*
- * Search node lists for a remote port matching filter criteria
- * Caller needs to hold host_lock before calling this routine.
- */
struct lpfc_nodelist *
-__lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
+__lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
{
struct lpfc_nodelist *ndlp;
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state != NLP_STE_UNUSED_NODE &&
filter(ndlp, param))
return ndlp;
@@ -2302,68 +2801,104 @@
/*
* Search node lists for a remote port matching filter criteria
- * This routine is used when the caller does NOT have host_lock.
+ * Caller needs to hold host_lock before calling this routine.
*/
struct lpfc_nodelist *
-lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
+lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp;
- spin_lock_irq(phba->host->host_lock);
- ndlp = __lpfc_find_node(phba, filter, param);
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ ndlp = __lpfc_find_node(vport, filter, param);
+ spin_unlock_irq(shost->host_lock);
return ndlp;
}
/*
* This routine looks up the ndlp lists for the given RPI. If rpi found it
- * returns the node list pointer else return NULL.
+ * returns the node list element pointer else return NULL.
*/
struct lpfc_nodelist *
-__lpfc_findnode_rpi(struct lpfc_hba *phba, uint16_t rpi)
+__lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
{
- return __lpfc_find_node(phba, lpfc_filter_by_rpi, &rpi);
+ return __lpfc_find_node(vport, lpfc_filter_by_rpi, &rpi);
}
struct lpfc_nodelist *
-lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi)
+lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp;
- spin_lock_irq(phba->host->host_lock);
- ndlp = __lpfc_findnode_rpi(phba, rpi);
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ ndlp = __lpfc_findnode_rpi(vport, rpi);
+ spin_unlock_irq(shost->host_lock);
return ndlp;
}
/*
* This routine looks up the ndlp lists for the given WWPN. If WWPN found it
- * returns the node list pointer else return NULL.
+ * returns the node element list pointer else return NULL.
*/
struct lpfc_nodelist *
-lpfc_findnode_wwpn(struct lpfc_hba *phba, struct lpfc_name *wwpn)
+lpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp;
- spin_lock_irq(phba->host->host_lock);
- ndlp = __lpfc_find_node(phba, lpfc_filter_by_wwpn, wwpn);
- spin_unlock_irq(phba->host->host_lock);
- return NULL;
+ spin_lock_irq(shost->host_lock);
+ ndlp = __lpfc_find_node(vport, lpfc_filter_by_wwpn, wwpn);
+ spin_unlock_irq(shost->host_lock);
+ return ndlp;
}
void
-lpfc_nlp_init(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
+lpfc_dev_loss_delay(unsigned long ptr)
+{
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
+ struct lpfc_vport *vport = ndlp->vport;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_work_evt *evtp = &ndlp->dev_loss_evt;
+ unsigned long flags;
+
+ evtp = &ndlp->dev_loss_evt;
+
+ spin_lock_irqsave(&phba->hbalock, flags);
+ if (!list_empty(&evtp->evt_listp)) {
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ return;
+ }
+
+ evtp->evt_arg1 = ndlp;
+ evtp->evt = LPFC_EVT_DEV_LOSS_DELAY;
+ list_add_tail(&evtp->evt_listp, &phba->work_list);
+ if (phba->work_wait)
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ return;
+}
+
+void
+lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ uint32_t did)
{
memset(ndlp, 0, sizeof (struct lpfc_nodelist));
INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
+ INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp);
init_timer(&ndlp->nlp_delayfunc);
ndlp->nlp_delayfunc.function = lpfc_els_retry_delay;
ndlp->nlp_delayfunc.data = (unsigned long)ndlp;
ndlp->nlp_DID = did;
- ndlp->nlp_phba = phba;
+ ndlp->vport = vport;
ndlp->nlp_sid = NLP_NO_SID;
INIT_LIST_HEAD(&ndlp->nlp_listp);
kref_init(&ndlp->kref);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
+ "node init: did:x%x",
+ ndlp->nlp_DID, 0, 0);
+
return;
}
@@ -2372,8 +2907,13 @@
{
struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist,
kref);
- lpfc_nlp_remove(ndlp->nlp_phba, ndlp);
- mempool_free(ndlp, ndlp->nlp_phba->nlp_mem_pool);
+
+ lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
+ "node release: did:x%x flg:x%x type:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
+
+ lpfc_nlp_remove(ndlp->vport, ndlp);
+ mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool);
}
struct lpfc_nodelist *
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 2623a9b..c2fb59f 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -59,6 +59,12 @@
#define SLI2_IOCB_CMD_R3XTRA_ENTRIES 24
#define SLI2_IOCB_RSP_R3XTRA_ENTRIES 32
+#define SLI2_IOCB_CMD_SIZE 32
+#define SLI2_IOCB_RSP_SIZE 32
+#define SLI3_IOCB_CMD_SIZE 128
+#define SLI3_IOCB_RSP_SIZE 64
+
+
/* Common Transport structures and definitions */
union CtRevisionId {
@@ -79,6 +85,9 @@
uint32_t word;
};
+#define FC4_FEATURE_INIT 0x2
+#define FC4_FEATURE_TARGET 0x1
+
struct lpfc_sli_ct_request {
/* Structure is in Big Endian format */
union CtRevisionId RevisionId;
@@ -121,20 +130,6 @@
uint32_t rsvd[7];
} rft;
- struct rff {
- uint32_t PortId;
- uint8_t reserved[2];
-#ifdef __BIG_ENDIAN_BITFIELD
- uint8_t feature_res:6;
- uint8_t feature_init:1;
- uint8_t feature_tgt:1;
-#else /* __LITTLE_ENDIAN_BITFIELD */
- uint8_t feature_tgt:1;
- uint8_t feature_init:1;
- uint8_t feature_res:6;
-#endif
- uint8_t type_code; /* type=8 for FCP */
- } rff;
struct rnn {
uint32_t PortId; /* For RNN_ID requests */
uint8_t wwnn[8];
@@ -144,15 +139,42 @@
uint8_t len;
uint8_t symbname[255];
} rsnn;
+ struct rspn { /* For RSPN_ID requests */
+ uint32_t PortId;
+ uint8_t len;
+ uint8_t symbname[255];
+ } rspn;
+ struct gff {
+ uint32_t PortId;
+ } gff;
+ struct gff_acc {
+ uint8_t fbits[128];
+ } gff_acc;
+#define FCP_TYPE_FEATURE_OFFSET 4
+ struct rff {
+ uint32_t PortId;
+ uint8_t reserved[2];
+ uint8_t fbits;
+ uint8_t type_code; /* type=8 for FCP */
+ } rff;
} un;
};
#define SLI_CT_REVISION 1
-#define GID_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 260)
-#define RFT_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 228)
-#define RFF_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 235)
-#define RNN_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 252)
-#define RSNN_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request))
+#define GID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct gid))
+#define GFF_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct gff))
+#define RFT_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct rft))
+#define RFF_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct rff))
+#define RNN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct rnn))
+#define RSNN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct rsnn))
+#define RSPN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct rspn))
/*
* FsType Definitions
@@ -227,6 +249,7 @@
#define SLI_CTNS_GFT_ID 0x0117
#define SLI_CTNS_GSPN_ID 0x0118
#define SLI_CTNS_GPT_ID 0x011A
+#define SLI_CTNS_GFF_ID 0x011F
#define SLI_CTNS_GID_PN 0x0121
#define SLI_CTNS_GID_NN 0x0131
#define SLI_CTNS_GIP_NN 0x0135
@@ -240,9 +263,9 @@
#define SLI_CTNS_RNN_ID 0x0213
#define SLI_CTNS_RCS_ID 0x0214
#define SLI_CTNS_RFT_ID 0x0217
-#define SLI_CTNS_RFF_ID 0x021F
#define SLI_CTNS_RSPN_ID 0x0218
#define SLI_CTNS_RPT_ID 0x021A
+#define SLI_CTNS_RFF_ID 0x021F
#define SLI_CTNS_RIP_NN 0x0235
#define SLI_CTNS_RIPA_NN 0x0236
#define SLI_CTNS_RSNN_NN 0x0239
@@ -311,9 +334,9 @@
uint8_t bbCreditlsb; /* FC Word 0, byte 3 */
#ifdef __BIG_ENDIAN_BITFIELD
- uint16_t increasingOffset:1; /* FC Word 1, bit 31 */
+ uint16_t request_multiple_Nport:1; /* FC Word 1, bit 31 */
uint16_t randomOffset:1; /* FC Word 1, bit 30 */
- uint16_t word1Reserved2:1; /* FC Word 1, bit 29 */
+ uint16_t response_multiple_NPort:1; /* FC Word 1, bit 29 */
uint16_t fPort:1; /* FC Word 1, bit 28 */
uint16_t altBbCredit:1; /* FC Word 1, bit 27 */
uint16_t edtovResolution:1; /* FC Word 1, bit 26 */
@@ -332,9 +355,9 @@
uint16_t edtovResolution:1; /* FC Word 1, bit 26 */
uint16_t altBbCredit:1; /* FC Word 1, bit 27 */
uint16_t fPort:1; /* FC Word 1, bit 28 */
- uint16_t word1Reserved2:1; /* FC Word 1, bit 29 */
+ uint16_t response_multiple_NPort:1; /* FC Word 1, bit 29 */
uint16_t randomOffset:1; /* FC Word 1, bit 30 */
- uint16_t increasingOffset:1; /* FC Word 1, bit 31 */
+ uint16_t request_multiple_Nport:1; /* FC Word 1, bit 31 */
uint16_t payloadlength:1; /* FC Word 1, bit 16 */
uint16_t contIncSeqCnt:1; /* FC Word 1, bit 17 */
@@ -1255,7 +1278,9 @@
#define MBX_KILL_BOARD 0x24
#define MBX_CONFIG_FARP 0x25
#define MBX_BEACON 0x2A
+#define MBX_HEARTBEAT 0x31
+#define MBX_CONFIG_HBQ 0x7C
#define MBX_LOAD_AREA 0x81
#define MBX_RUN_BIU_DIAG64 0x84
#define MBX_CONFIG_PORT 0x88
@@ -1263,6 +1288,10 @@
#define MBX_READ_RPI64 0x8F
#define MBX_REG_LOGIN64 0x93
#define MBX_READ_LA64 0x95
+#define MBX_REG_VPI 0x96
+#define MBX_UNREG_VPI 0x97
+#define MBX_REG_VNPID 0x96
+#define MBX_UNREG_VNPID 0x97
#define MBX_FLASH_WR_ULA 0x98
#define MBX_SET_DEBUG 0x99
@@ -1335,6 +1364,10 @@
#define CMD_FCP_TRECEIVE64_CX 0xA1
#define CMD_FCP_TRSP64_CX 0xA3
+#define CMD_IOCB_RCV_SEQ64_CX 0xB5
+#define CMD_IOCB_RCV_ELS64_CX 0xB7
+#define CMD_IOCB_RCV_CONT64_CX 0xBB
+
#define CMD_GEN_REQUEST64_CR 0xC2
#define CMD_GEN_REQUEST64_CX 0xC3
@@ -1561,6 +1594,7 @@
#define FLAGS_TOPOLOGY_MODE_PT_PT 0x02 /* Attempt pt-pt only */
#define FLAGS_TOPOLOGY_MODE_LOOP 0x04 /* Attempt loop only */
#define FLAGS_TOPOLOGY_MODE_PT_LOOP 0x06 /* Attempt pt-pt then loop */
+#define FLAGS_UNREG_LOGIN_ALL 0x08 /* UNREG_LOGIN all on link down */
#define FLAGS_LIRP_LILP 0x80 /* LIRP / LILP is disabled */
#define FLAGS_TOPOLOGY_FAILOVER 0x0400 /* Bit 10 */
@@ -1744,8 +1778,6 @@
#define LMT_4Gb 0x040
#define LMT_8Gb 0x080
#define LMT_10Gb 0x100
-
-
uint32_t rsvd2;
uint32_t rsvd3;
uint32_t max_xri;
@@ -1754,7 +1786,10 @@
uint32_t avail_xri;
uint32_t avail_iocb;
uint32_t avail_rpi;
- uint32_t default_rpi;
+ uint32_t max_vpi;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+ uint32_t avail_vpi;
} READ_CONFIG_VAR;
/* Structure for MB Command READ_RCONFIG (12) */
@@ -1818,6 +1853,13 @@
structure */
struct ulp_bde64 sp64;
} un;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint16_t rsvd3;
+ uint16_t vpi;
+#else /* __LITTLE_ENDIAN_BITFIELD */
+ uint16_t vpi;
+ uint16_t rsvd3;
+#endif
} READ_SPARM_VAR;
/* Structure for MB Command READ_STATUS (14) */
@@ -1918,11 +1960,17 @@
#ifdef __BIG_ENDIAN_BITFIELD
uint32_t cv:1;
uint32_t rr:1;
- uint32_t rsvd1:29;
+ uint32_t rsvd2:2;
+ uint32_t v3req:1;
+ uint32_t v3rsp:1;
+ uint32_t rsvd1:25;
uint32_t rv:1;
#else /* __LITTLE_ENDIAN_BITFIELD */
uint32_t rv:1;
- uint32_t rsvd1:29;
+ uint32_t rsvd1:25;
+ uint32_t v3rsp:1;
+ uint32_t v3req:1;
+ uint32_t rsvd2:2;
uint32_t rr:1;
uint32_t cv:1;
#endif
@@ -1972,8 +2020,8 @@
uint8_t sli1FwName[16];
uint32_t sli2FwRev;
uint8_t sli2FwName[16];
- uint32_t rsvd2;
- uint32_t RandomData[7];
+ uint32_t sli3Feat;
+ uint32_t RandomData[6];
} READ_REV_VAR;
/* Structure for MB Command READ_LINK_STAT (18) */
@@ -2013,6 +2061,14 @@
struct ulp_bde64 sp64;
} un;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint16_t rsvd6;
+ uint16_t vpi;
+#else /* __LITTLE_ENDIAN_BITFIELD */
+ uint16_t vpi;
+ uint16_t rsvd6;
+#endif
+
} REG_LOGIN_VAR;
/* Word 30 contents for REG_LOGIN */
@@ -2037,16 +2093,78 @@
#ifdef __BIG_ENDIAN_BITFIELD
uint16_t rsvd1;
uint16_t rpi;
+ uint32_t rsvd2;
+ uint32_t rsvd3;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+ uint16_t rsvd6;
+ uint16_t vpi;
#else /* __LITTLE_ENDIAN_BITFIELD */
uint16_t rpi;
uint16_t rsvd1;
+ uint32_t rsvd2;
+ uint32_t rsvd3;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+ uint16_t vpi;
+ uint16_t rsvd6;
#endif
} UNREG_LOGIN_VAR;
+/* Structure for MB Command REG_VPI (0x96) */
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd1;
+ uint32_t rsvd2:8;
+ uint32_t sid:24;
+ uint32_t rsvd3;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+ uint16_t rsvd6;
+ uint16_t vpi;
+#else /* __LITTLE_ENDIAN */
+ uint32_t rsvd1;
+ uint32_t sid:24;
+ uint32_t rsvd2:8;
+ uint32_t rsvd3;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+ uint16_t vpi;
+ uint16_t rsvd6;
+#endif
+} REG_VPI_VAR;
+
+/* Structure for MB Command UNREG_VPI (0x97) */
+typedef struct {
+ uint32_t rsvd1;
+ uint32_t rsvd2;
+ uint32_t rsvd3;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint16_t rsvd6;
+ uint16_t vpi;
+#else /* __LITTLE_ENDIAN */
+ uint16_t vpi;
+ uint16_t rsvd6;
+#endif
+} UNREG_VPI_VAR;
+
/* Structure for MB Command UNREG_D_ID (0x23) */
typedef struct {
uint32_t did;
+ uint32_t rsvd2;
+ uint32_t rsvd3;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint16_t rsvd6;
+ uint16_t vpi;
+#else
+ uint16_t vpi;
+ uint16_t rsvd6;
+#endif
} UNREG_D_ID_VAR;
/* Structure for MB Command READ_LA (21) */
@@ -2178,13 +2296,240 @@
#define DMP_RSP_OFFSET 0x14 /* word 5 contains first word of rsp */
#define DMP_RSP_SIZE 0x6C /* maximum of 27 words of rsp data */
-/* Structure for MB Command CONFIG_PORT (0x88) */
+struct hbq_mask {
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint8_t tmatch;
+ uint8_t tmask;
+ uint8_t rctlmatch;
+ uint8_t rctlmask;
+#else /* __LITTLE_ENDIAN */
+ uint8_t rctlmask;
+ uint8_t rctlmatch;
+ uint8_t tmask;
+ uint8_t tmatch;
+#endif
+};
+
+/* Structure for MB Command CONFIG_HBQ (7c) */
+
+struct config_hbq_var {
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd1 :7;
+ uint32_t recvNotify :1; /* Receive Notification */
+ uint32_t numMask :8; /* # Mask Entries */
+ uint32_t profile :8; /* Selection Profile */
+ uint32_t rsvd2 :8;
+#else /* __LITTLE_ENDIAN */
+ uint32_t rsvd2 :8;
+ uint32_t profile :8; /* Selection Profile */
+ uint32_t numMask :8; /* # Mask Entries */
+ uint32_t recvNotify :1; /* Receive Notification */
+ uint32_t rsvd1 :7;
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t hbqId :16;
+ uint32_t rsvd3 :12;
+ uint32_t ringMask :4;
+#else /* __LITTLE_ENDIAN */
+ uint32_t ringMask :4;
+ uint32_t rsvd3 :12;
+ uint32_t hbqId :16;
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t entry_count :16;
+ uint32_t rsvd4 :8;
+ uint32_t headerLen :8;
+#else /* __LITTLE_ENDIAN */
+ uint32_t headerLen :8;
+ uint32_t rsvd4 :8;
+ uint32_t entry_count :16;
+#endif
+
+ uint32_t hbqaddrLow;
+ uint32_t hbqaddrHigh;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd5 :31;
+ uint32_t logEntry :1;
+#else /* __LITTLE_ENDIAN */
+ uint32_t logEntry :1;
+ uint32_t rsvd5 :31;
+#endif
+
+ uint32_t rsvd6; /* w7 */
+ uint32_t rsvd7; /* w8 */
+ uint32_t rsvd8; /* w9 */
+
+ struct hbq_mask hbqMasks[6];
+
+
+ union {
+ uint32_t allprofiles[12];
+
+ struct {
+ #ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t seqlenoff :16;
+ uint32_t maxlen :16;
+ #else /* __LITTLE_ENDIAN */
+ uint32_t maxlen :16;
+ uint32_t seqlenoff :16;
+ #endif
+ #ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd1 :28;
+ uint32_t seqlenbcnt :4;
+ #else /* __LITTLE_ENDIAN */
+ uint32_t seqlenbcnt :4;
+ uint32_t rsvd1 :28;
+ #endif
+ uint32_t rsvd[10];
+ } profile2;
+
+ struct {
+ #ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t seqlenoff :16;
+ uint32_t maxlen :16;
+ #else /* __LITTLE_ENDIAN */
+ uint32_t maxlen :16;
+ uint32_t seqlenoff :16;
+ #endif
+ #ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t cmdcodeoff :28;
+ uint32_t rsvd1 :12;
+ uint32_t seqlenbcnt :4;
+ #else /* __LITTLE_ENDIAN */
+ uint32_t seqlenbcnt :4;
+ uint32_t rsvd1 :12;
+ uint32_t cmdcodeoff :28;
+ #endif
+ uint32_t cmdmatch[8];
+
+ uint32_t rsvd[2];
+ } profile3;
+
+ struct {
+ #ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t seqlenoff :16;
+ uint32_t maxlen :16;
+ #else /* __LITTLE_ENDIAN */
+ uint32_t maxlen :16;
+ uint32_t seqlenoff :16;
+ #endif
+ #ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t cmdcodeoff :28;
+ uint32_t rsvd1 :12;
+ uint32_t seqlenbcnt :4;
+ #else /* __LITTLE_ENDIAN */
+ uint32_t seqlenbcnt :4;
+ uint32_t rsvd1 :12;
+ uint32_t cmdcodeoff :28;
+ #endif
+ uint32_t cmdmatch[8];
+
+ uint32_t rsvd[2];
+ } profile5;
+
+ } profiles;
+
+};
+
+
+
+/* Structure for MB Command CONFIG_PORT (0x88) */
typedef struct {
- uint32_t pcbLen;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t cBE : 1;
+ uint32_t cET : 1;
+ uint32_t cHpcb : 1;
+ uint32_t cMA : 1;
+ uint32_t sli_mode : 4;
+ uint32_t pcbLen : 24; /* bit 23:0 of memory based port
+ * config block */
+#else /* __LITTLE_ENDIAN */
+ uint32_t pcbLen : 24; /* bit 23:0 of memory based port
+ * config block */
+ uint32_t sli_mode : 4;
+ uint32_t cMA : 1;
+ uint32_t cHpcb : 1;
+ uint32_t cET : 1;
+ uint32_t cBE : 1;
+#endif
+
uint32_t pcbLow; /* bit 31:0 of memory based port config block */
uint32_t pcbHigh; /* bit 63:32 of memory based port config block */
- uint32_t hbainit[5];
+ uint32_t hbainit[6];
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd : 24; /* Reserved */
+ uint32_t cmv : 1; /* Configure Max VPIs */
+ uint32_t ccrp : 1; /* Config Command Ring Polling */
+ uint32_t csah : 1; /* Configure Synchronous Abort Handling */
+ uint32_t chbs : 1; /* Cofigure Host Backing store */
+ uint32_t cinb : 1; /* Enable Interrupt Notification Block */
+ uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */
+ uint32_t cmx : 1; /* Configure Max XRIs */
+ uint32_t cmr : 1; /* Configure Max RPIs */
+#else /* __LITTLE_ENDIAN */
+ uint32_t cmr : 1; /* Configure Max RPIs */
+ uint32_t cmx : 1; /* Configure Max XRIs */
+ uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */
+ uint32_t cinb : 1; /* Enable Interrupt Notification Block */
+ uint32_t chbs : 1; /* Cofigure Host Backing store */
+ uint32_t csah : 1; /* Configure Synchronous Abort Handling */
+ uint32_t ccrp : 1; /* Config Command Ring Polling */
+ uint32_t cmv : 1; /* Configure Max VPIs */
+ uint32_t rsvd : 24; /* Reserved */
+#endif
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd2 : 24; /* Reserved */
+ uint32_t gmv : 1; /* Grant Max VPIs */
+ uint32_t gcrp : 1; /* Grant Command Ring Polling */
+ uint32_t gsah : 1; /* Grant Synchronous Abort Handling */
+ uint32_t ghbs : 1; /* Grant Host Backing Store */
+ uint32_t ginb : 1; /* Grant Interrupt Notification Block */
+ uint32_t gerbm : 1; /* Grant ERBM Request */
+ uint32_t gmx : 1; /* Grant Max XRIs */
+ uint32_t gmr : 1; /* Grant Max RPIs */
+#else /* __LITTLE_ENDIAN */
+ uint32_t gmr : 1; /* Grant Max RPIs */
+ uint32_t gmx : 1; /* Grant Max XRIs */
+ uint32_t gerbm : 1; /* Grant ERBM Request */
+ uint32_t ginb : 1; /* Grant Interrupt Notification Block */
+ uint32_t ghbs : 1; /* Grant Host Backing Store */
+ uint32_t gsah : 1; /* Grant Synchronous Abort Handling */
+ uint32_t gcrp : 1; /* Grant Command Ring Polling */
+ uint32_t gmv : 1; /* Grant Max VPIs */
+ uint32_t rsvd2 : 24; /* Reserved */
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t max_rpi : 16; /* Max RPIs Port should configure */
+ uint32_t max_xri : 16; /* Max XRIs Port should configure */
+#else /* __LITTLE_ENDIAN */
+ uint32_t max_xri : 16; /* Max XRIs Port should configure */
+ uint32_t max_rpi : 16; /* Max RPIs Port should configure */
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t max_hbq : 16; /* Max HBQs Host expect to configure */
+ uint32_t rsvd3 : 16; /* Max HBQs Host expect to configure */
+#else /* __LITTLE_ENDIAN */
+ uint32_t rsvd3 : 16; /* Max HBQs Host expect to configure */
+ uint32_t max_hbq : 16; /* Max HBQs Host expect to configure */
+#endif
+
+ uint32_t rsvd4; /* Reserved */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd5 : 16; /* Reserved */
+ uint32_t max_vpi : 16; /* Max number of virt N-Ports */
+#else /* __LITTLE_ENDIAN */
+ uint32_t max_vpi : 16; /* Max number of virt N-Ports */
+ uint32_t rsvd5 : 16; /* Reserved */
+#endif
+
} CONFIG_PORT_VAR;
/* SLI-2 Port Control Block */
@@ -2262,33 +2607,40 @@
#define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t))
typedef union {
- uint32_t varWords[MAILBOX_CMD_WSIZE - 1];
- LOAD_SM_VAR varLdSM; /* cmd = 1 (LOAD_SM) */
- READ_NV_VAR varRDnvp; /* cmd = 2 (READ_NVPARMS) */
- WRITE_NV_VAR varWTnvp; /* cmd = 3 (WRITE_NVPARMS) */
- BIU_DIAG_VAR varBIUdiag; /* cmd = 4 (RUN_BIU_DIAG) */
- INIT_LINK_VAR varInitLnk; /* cmd = 5 (INIT_LINK) */
+ uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/
+ * feature/max ring number
+ */
+ LOAD_SM_VAR varLdSM; /* cmd = 1 (LOAD_SM) */
+ READ_NV_VAR varRDnvp; /* cmd = 2 (READ_NVPARMS) */
+ WRITE_NV_VAR varWTnvp; /* cmd = 3 (WRITE_NVPARMS) */
+ BIU_DIAG_VAR varBIUdiag; /* cmd = 4 (RUN_BIU_DIAG) */
+ INIT_LINK_VAR varInitLnk; /* cmd = 5 (INIT_LINK) */
DOWN_LINK_VAR varDwnLnk; /* cmd = 6 (DOWN_LINK) */
- CONFIG_LINK varCfgLnk; /* cmd = 7 (CONFIG_LINK) */
- PART_SLIM_VAR varSlim; /* cmd = 8 (PART_SLIM) */
+ CONFIG_LINK varCfgLnk; /* cmd = 7 (CONFIG_LINK) */
+ PART_SLIM_VAR varSlim; /* cmd = 8 (PART_SLIM) */
CONFIG_RING_VAR varCfgRing; /* cmd = 9 (CONFIG_RING) */
RESET_RING_VAR varRstRing; /* cmd = 10 (RESET_RING) */
READ_CONFIG_VAR varRdConfig; /* cmd = 11 (READ_CONFIG) */
READ_RCONF_VAR varRdRConfig; /* cmd = 12 (READ_RCONFIG) */
READ_SPARM_VAR varRdSparm; /* cmd = 13 (READ_SPARM(64)) */
READ_STATUS_VAR varRdStatus; /* cmd = 14 (READ_STATUS) */
- READ_RPI_VAR varRdRPI; /* cmd = 15 (READ_RPI(64)) */
- READ_XRI_VAR varRdXRI; /* cmd = 16 (READ_XRI) */
- READ_REV_VAR varRdRev; /* cmd = 17 (READ_REV) */
- READ_LNK_VAR varRdLnk; /* cmd = 18 (READ_LNK_STAT) */
+ READ_RPI_VAR varRdRPI; /* cmd = 15 (READ_RPI(64)) */
+ READ_XRI_VAR varRdXRI; /* cmd = 16 (READ_XRI) */
+ READ_REV_VAR varRdRev; /* cmd = 17 (READ_REV) */
+ READ_LNK_VAR varRdLnk; /* cmd = 18 (READ_LNK_STAT) */
REG_LOGIN_VAR varRegLogin; /* cmd = 19 (REG_LOGIN(64)) */
UNREG_LOGIN_VAR varUnregLogin; /* cmd = 20 (UNREG_LOGIN) */
- READ_LA_VAR varReadLA; /* cmd = 21 (READ_LA(64)) */
+ READ_LA_VAR varReadLA; /* cmd = 21 (READ_LA(64)) */
CLEAR_LA_VAR varClearLA; /* cmd = 22 (CLEAR_LA) */
- DUMP_VAR varDmp; /* Warm Start DUMP mbx cmd */
- UNREG_D_ID_VAR varUnregDID; /* cmd = 0x23 (UNREG_D_ID) */
- CONFIG_FARP_VAR varCfgFarp; /* cmd = 0x25 (CONFIG_FARP) NEW_FEATURE */
- CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */
+ DUMP_VAR varDmp; /* Warm Start DUMP mbx cmd */
+ UNREG_D_ID_VAR varUnregDID; /* cmd = 0x23 (UNREG_D_ID) */
+ CONFIG_FARP_VAR varCfgFarp; /* cmd = 0x25 (CONFIG_FARP)
+ * NEW_FEATURE
+ */
+ struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ) */
+ CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */
+ REG_VPI_VAR varRegVpi; /* cmd = 0x96 (REG_VPI) */
+ UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */
} MAILVARIANTS;
/*
@@ -2305,14 +2657,27 @@
__le32 rspPutInx;
};
-typedef struct _SLI2_DESC {
- struct lpfc_hgp host[MAX_RINGS];
+struct sli2_desc {
uint32_t unused1[16];
+ struct lpfc_hgp host[MAX_RINGS];
struct lpfc_pgp port[MAX_RINGS];
-} SLI2_DESC;
+};
+
+struct sli3_desc {
+ struct lpfc_hgp host[MAX_RINGS];
+ uint32_t reserved[8];
+ uint32_t hbq_put[16];
+};
+
+struct sli3_pgp {
+ struct lpfc_pgp port[MAX_RINGS];
+ uint32_t hbq_get[16];
+};
typedef union {
- SLI2_DESC s2;
+ struct sli2_desc s2;
+ struct sli3_desc s3;
+ struct sli3_pgp s3_pgp;
} SLI_VAR;
typedef struct {
@@ -2618,6 +2983,25 @@
uint32_t fcpt_Length; /* transfer ready for IWRITE */
} FCPT_FIELDS64;
+/* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7)
+ or CMD_IOCB_RCV_SEQ64_CX (0xB5) */
+
+struct rcv_sli3 {
+ uint32_t word8Rsvd;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint16_t vpi;
+ uint16_t word9Rsvd;
+#else /* __LITTLE_ENDIAN */
+ uint16_t word9Rsvd;
+ uint16_t vpi;
+#endif
+ uint32_t word10Rsvd;
+ uint32_t acc_len; /* accumulated length */
+ struct ulp_bde64 bde2;
+};
+
+
+
typedef struct _IOCB { /* IOCB structure */
union {
GENERIC_RSP grsp; /* Generic response */
@@ -2632,8 +3016,8 @@
/* SLI-2 structures */
- struct ulp_bde64 cont64[2]; /* up to 2 64 bit continuation
- bde_64s */
+ struct ulp_bde64 cont64[2]; /* up to 2 64 bit continuation
+ * bde_64s */
ELS_REQUEST64 elsreq64; /* ELS_REQUEST template */
GEN_REQUEST64 genreq64; /* GEN_REQUEST template */
RCV_ELS_REQ64 rcvels64; /* RCV_ELS_REQ template */
@@ -2695,9 +3079,20 @@
uint32_t ulpTimeout:8;
#endif
+ union {
+ struct rcv_sli3 rcvsli3; /* words 8 - 15 */
+ uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */
+ } unsli3;
+
+#define ulpCt_h ulpXS
+#define ulpCt_l ulpFCP2Rcvy
+
+#define IOCB_FCP 1 /* IOCB is used for FCP ELS cmds-ulpRsvByte */
+#define IOCB_IP 2 /* IOCB is used for IP ELS cmds */
#define PARM_UNUSED 0 /* PU field (Word 4) not used */
#define PARM_REL_OFF 1 /* PU field (Word 4) = R. O. */
#define PARM_READ_CHECK 2 /* PU field (Word 4) = Data Transfer Length */
+#define PARM_NPIV_DID 3
#define CLASS1 0 /* Class 1 */
#define CLASS2 1 /* Class 2 */
#define CLASS3 2 /* Class 3 */
@@ -2718,39 +3113,51 @@
#define IOSTAT_RSVD2 0xC
#define IOSTAT_RSVD3 0xD
#define IOSTAT_RSVD4 0xE
-#define IOSTAT_RSVD5 0xF
+#define IOSTAT_NEED_BUFFER 0xF
#define IOSTAT_DRIVER_REJECT 0x10 /* ulpStatus - Driver defined */
#define IOSTAT_DEFAULT 0xF /* Same as rsvd5 for now */
#define IOSTAT_CNT 0x11
} IOCB_t;
+/* Structure used for a single HBQ entry */
+struct lpfc_hbq_entry {
+ struct ulp_bde64 bde;
+ uint32_t buffer_tag;
+};
+
#define SLI1_SLIM_SIZE (4 * 1024)
/* Up to 498 IOCBs will fit into 16k
* 256 (MAILBOX_t) + 140 (PCB_t) + ( 32 (IOCB_t) * 498 ) = < 16384
*/
-#define SLI2_SLIM_SIZE (16 * 1024)
+#define SLI2_SLIM_SIZE (64 * 1024)
/* Maximum IOCBs that will fit in SLI2 slim */
#define MAX_SLI2_IOCB 498
+#define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \
+ (sizeof(MAILBOX_t) + sizeof(PCB_t)))
+
+/* HBQ entries are 4 words each = 4k */
+#define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) * \
+ lpfc_sli_hbq_count())
struct lpfc_sli2_slim {
MAILBOX_t mbx;
PCB_t pcb;
- IOCB_t IOCBs[MAX_SLI2_IOCB];
+ IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE];
};
-/*******************************************************************
-This macro check PCI device to allow special handling for LC HBAs.
-
-Parameters:
-device : struct pci_dev 's device field
-
-return 1 => TRUE
- 0 => FALSE
- *******************************************************************/
+/*
+ * This function checks PCI device to allow special handling for LC HBAs.
+ *
+ * Parameters:
+ * device : struct pci_dev 's device field
+ *
+ * return 1 => TRUE
+ * 0 => FALSE
+ */
static inline int
lpfc_is_LC_HBA(unsigned short device)
{
@@ -2766,3 +3173,16 @@
else
return 0;
}
+
+/*
+ * Determine if an IOCB failed because of a link event or firmware reset.
+ */
+
+static inline int
+lpfc_error_lost_link(IOCB_t *iocbp)
+{
+ return (iocbp->ulpStatus == IOSTAT_LOCAL_REJECT &&
+ (iocbp->un.ulpWord[4] == IOERR_SLI_ABORTED ||
+ iocbp->un.ulpWord[4] == IOERR_LINK_DOWN ||
+ iocbp->un.ulpWord[4] == IOERR_SLI_DOWN));
+}
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 955b2e4..f81f85e 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -27,6 +27,7 @@
#include <linux/kthread.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
+#include <linux/ctype.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
@@ -40,15 +41,20 @@
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
#include "lpfc_version.h"
+#include "lpfc_vport.h"
static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
static int lpfc_post_rcv_buf(struct lpfc_hba *);
static struct scsi_transport_template *lpfc_transport_template = NULL;
+static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
static DEFINE_IDR(lpfc_hba_index);
+
+
/************************************************************************/
/* */
/* lpfc_config_port_prep */
@@ -61,7 +67,7 @@
/* */
/************************************************************************/
int
-lpfc_config_port_prep(struct lpfc_hba * phba)
+lpfc_config_port_prep(struct lpfc_hba *phba)
{
lpfc_vpd_t *vp = &phba->vpd;
int i = 0, rc;
@@ -75,12 +81,12 @@
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
return -ENOMEM;
}
mb = &pmb->mb;
- phba->hba_state = LPFC_INIT_MBX_CMDS;
+ phba->link_state = LPFC_INIT_MBX_CMDS;
if (lpfc_is_LC_HBA(phba->pcidev->device)) {
if (init_key) {
@@ -100,9 +106,7 @@
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_MBOX,
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
"%d:0324 Config Port initialization "
"error, mbxCmd x%x READ_NVPARM, "
"mbxStatus x%x\n",
@@ -112,16 +116,18 @@
return -ERESTART;
}
memcpy(phba->wwnn, (char *)mb->un.varRDnvp.nodename,
- sizeof (mb->un.varRDnvp.nodename));
+ sizeof(phba->wwnn));
+ memcpy(phba->wwpn, (char *)mb->un.varRDnvp.portname,
+ sizeof(phba->wwpn));
}
+ phba->sli3_options = 0x0;
+
/* Setup and issue mailbox READ REV command */
lpfc_read_rev(phba, pmb);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0439 Adapter failed to init, mbxCmd x%x "
"READ_REV, mbxStatus x%x\n",
phba->brd_no,
@@ -130,6 +136,7 @@
return -ERESTART;
}
+
/*
* The value of rr must be 1 since the driver set the cv field to 1.
* This setting requires the FW to set all revision fields.
@@ -144,8 +151,12 @@
return -ERESTART;
}
+ if (phba->sli_rev == 3 && !mb->un.varRdRev.v3rsp)
+ return -EINVAL;
+
/* Save information as VPD data */
vp->rev.rBit = 1;
+ memcpy(&vp->sli3Feat, &mb->un.varRdRev.sli3Feat, sizeof(uint32_t));
vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev;
memcpy(vp->rev.sli1FwName, (char*) mb->un.varRdRev.sli1FwName, 16);
vp->rev.sli2FwRev = mb->un.varRdRev.sli2FwRev;
@@ -161,6 +172,13 @@
vp->rev.postKernRev = mb->un.varRdRev.postKernRev;
vp->rev.opFwRev = mb->un.varRdRev.opFwRev;
+ /* If the sli feature level is less then 9, we must
+ * tear down all RPIs and VPIs on link down if NPIV
+ * is enabled.
+ */
+ if (vp->rev.feaLevelHigh < 9)
+ phba->sli3_options |= LPFC_SLI3_VPORT_TEARDOWN;
+
if (lpfc_is_LC_HBA(phba->pcidev->device))
memcpy(phba->RandomData, (char *)&mb->un.varWords[24],
sizeof (phba->RandomData));
@@ -188,7 +206,7 @@
if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset)
mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset;
lpfc_sli_pcimem_bcopy(pmb->context2, lpfc_vpd_data + offset,
- mb->un.varDmp.word_cnt);
+ mb->un.varDmp.word_cnt);
offset += mb->un.varDmp.word_cnt;
} while (mb->un.varDmp.word_cnt && offset < DMP_VPD_SIZE);
lpfc_parse_vpd(phba, lpfc_vpd_data, offset);
@@ -212,48 +230,34 @@
/* */
/************************************************************************/
int
-lpfc_config_port_post(struct lpfc_hba * phba)
+lpfc_config_port_post(struct lpfc_hba *phba)
{
+ struct lpfc_vport *vport = phba->pport;
LPFC_MBOXQ_t *pmb;
MAILBOX_t *mb;
struct lpfc_dmabuf *mp;
struct lpfc_sli *psli = &phba->sli;
uint32_t status, timeout;
- int i, j, rc;
+ int i, j;
+ int rc;
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
return -ENOMEM;
}
mb = &pmb->mb;
- lpfc_config_link(phba, pmb);
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
- if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
- "%d:0447 Adapter failed init, mbxCmd x%x "
- "CONFIG_LINK mbxStatus x%x\n",
- phba->brd_no,
- mb->mbxCommand, mb->mbxStatus);
- phba->hba_state = LPFC_HBA_ERROR;
- mempool_free( pmb, phba->mbox_mem_pool);
- return -EIO;
- }
-
/* Get login parameters for NID. */
- lpfc_read_sparam(phba, pmb);
+ lpfc_read_sparam(phba, pmb, 0);
+ pmb->vport = vport;
if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0448 Adapter failed init, mbxCmd x%x "
"READ_SPARM mbxStatus x%x\n",
phba->brd_no,
mb->mbxCommand, mb->mbxStatus);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
mp = (struct lpfc_dmabuf *) pmb->context1;
mempool_free( pmb, phba->mbox_mem_pool);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -263,25 +267,27 @@
mp = (struct lpfc_dmabuf *) pmb->context1;
- memcpy(&phba->fc_sparam, mp->virt, sizeof (struct serv_parm));
+ memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
pmb->context1 = NULL;
if (phba->cfg_soft_wwnn)
- u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn);
+ u64_to_wwn(phba->cfg_soft_wwnn,
+ vport->fc_sparam.nodeName.u.wwn);
if (phba->cfg_soft_wwpn)
- u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
- memcpy(&phba->fc_nodename, &phba->fc_sparam.nodeName,
+ u64_to_wwn(phba->cfg_soft_wwpn,
+ vport->fc_sparam.portName.u.wwn);
+ memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
sizeof (struct lpfc_name));
- memcpy(&phba->fc_portname, &phba->fc_sparam.portName,
+ memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
sizeof (struct lpfc_name));
/* If no serial number in VPD data, use low 6 bytes of WWNN */
/* This should be consolidated into parse_vpd ? - mr */
if (phba->SerialNumber[0] == 0) {
uint8_t *outptr;
- outptr = &phba->fc_nodename.u.s.IEEE[0];
+ outptr = &vport->fc_nodename.u.s.IEEE[0];
for (i = 0; i < 12; i++) {
status = *outptr++;
j = ((status & 0xf0) >> 4);
@@ -303,15 +309,14 @@
}
lpfc_read_config(phba, pmb);
+ pmb->vport = vport;
if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0453 Adapter failed to init, mbxCmd x%x "
"READ_CONFIG, mbxStatus x%x\n",
phba->brd_no,
mb->mbxCommand, mb->mbxStatus);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
mempool_free( pmb, phba->mbox_mem_pool);
return -EIO;
}
@@ -338,9 +343,7 @@
|| ((phba->cfg_link_speed == LINK_SPEED_10G)
&& !(phba->lmt & LMT_10Gb))) {
/* Reset link speed to auto */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_LINK_EVENT,
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LINK_EVENT,
"%d:1302 Invalid speed for this board: "
"Reset link speed to auto: x%x\n",
phba->brd_no,
@@ -348,7 +351,7 @@
phba->cfg_link_speed = LINK_SPEED_AUTO;
}
- phba->hba_state = LPFC_LINK_DOWN;
+ phba->link_state = LPFC_LINK_DOWN;
/* Only process IOCBs on ring 0 till hba_state is READY */
if (psli->ring[psli->extra_ring].cmdringaddr)
@@ -359,10 +362,11 @@
psli->ring[psli->next_ring].flag |= LPFC_STOP_IOCB_EVENT;
/* Post receive buffers for desired rings */
- lpfc_post_rcv_buf(phba);
+ if (phba->sli_rev != 3)
+ lpfc_post_rcv_buf(phba);
/* Enable appropriate host interrupts */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
status = readl(phba->HCregaddr);
status |= HC_MBINT_ENA | HC_ERINT_ENA | HC_LAINT_ENA;
if (psli->num_rings > 0)
@@ -380,22 +384,24 @@
writel(status, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
/*
* Setup the ring 0 (els) timeout handler
*/
timeout = phba->fc_ratov << 1;
- mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
+ mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
+ mod_timer(&phba->hb_tmofunc, jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+ phba->hb_outstanding = 0;
+ phba->last_completion_time = jiffies;
lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ pmb->vport = vport;
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
lpfc_set_loopback_flag(phba);
if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0454 Adapter failed to init, mbxCmd x%x "
"INIT_LINK, mbxStatus x%x\n",
phba->brd_no,
@@ -408,7 +414,7 @@
writel(0xffffffff, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
if (rc != MBX_BUSY)
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
@@ -429,18 +435,19 @@
/* */
/************************************************************************/
int
-lpfc_hba_down_prep(struct lpfc_hba * phba)
+lpfc_hba_down_prep(struct lpfc_hba *phba)
{
+ struct lpfc_vport *vport = phba->pport;
+
/* Disable interrupts */
writel(0, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- /* Cleanup potential discovery resources */
- lpfc_els_flush_rscn(phba);
- lpfc_els_flush_cmd(phba);
- lpfc_disc_flush_list(phba);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ lpfc_cleanup_discovery_resources(vport);
+ }
- return (0);
+ return 0;
}
/************************************************************************/
@@ -453,20 +460,24 @@
/* */
/************************************************************************/
int
-lpfc_hba_down_post(struct lpfc_hba * phba)
+lpfc_hba_down_post(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
struct lpfc_dmabuf *mp, *next_mp;
int i;
- /* Cleanup preposted buffers on the ELS ring */
- pring = &psli->ring[LPFC_ELS_RING];
- list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
- list_del(&mp->list);
- pring->postbufq_cnt--;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
+ lpfc_sli_hbqbuf_free_all(phba);
+ else {
+ /* Cleanup preposted buffers on the ELS ring */
+ pring = &psli->ring[LPFC_ELS_RING];
+ list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
+ list_del(&mp->list);
+ pring->postbufq_cnt--;
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ }
}
for (i = 0; i < psli->num_rings; i++) {
@@ -477,6 +488,119 @@
return 0;
}
+/* HBA heart beat timeout handler */
+void
+lpfc_hb_timeout(unsigned long ptr)
+{
+ struct lpfc_hba *phba;
+ unsigned long iflag;
+
+ phba = (struct lpfc_hba *)ptr;
+ spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
+ if (!(phba->pport->work_port_events & WORKER_HB_TMO))
+ phba->pport->work_port_events |= WORKER_HB_TMO;
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
+
+ if (phba->work_wait)
+ wake_up(phba->work_wait);
+ return;
+}
+
+static void
+lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
+{
+ unsigned long drvr_flag;
+
+ spin_lock_irqsave(&phba->hbalock, drvr_flag);
+ phba->hb_outstanding = 0;
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
+
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) &&
+ !(phba->link_state == LPFC_HBA_ERROR) &&
+ !(phba->pport->fc_flag & FC_UNLOADING))
+ mod_timer(&phba->hb_tmofunc,
+ jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+ return;
+}
+
+void
+lpfc_hb_timeout_handler(struct lpfc_hba *phba)
+{
+ LPFC_MBOXQ_t *pmboxq;
+ int retval;
+ struct lpfc_sli *psli = &phba->sli;
+
+ if ((phba->link_state == LPFC_HBA_ERROR) ||
+ (phba->pport->fc_flag & FC_UNLOADING) ||
+ (phba->pport->fc_flag & FC_OFFLINE_MODE))
+ return;
+
+ spin_lock_irq(&phba->pport->work_port_lock);
+ /* If the timer is already canceled do nothing */
+ if (!(phba->pport->work_port_events & WORKER_HB_TMO)) {
+ spin_unlock_irq(&phba->pport->work_port_lock);
+ return;
+ }
+
+ if (time_after(phba->last_completion_time + LPFC_HB_MBOX_INTERVAL * HZ,
+ jiffies)) {
+ spin_unlock_irq(&phba->pport->work_port_lock);
+ if (!phba->hb_outstanding)
+ mod_timer(&phba->hb_tmofunc,
+ jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+ else
+ mod_timer(&phba->hb_tmofunc,
+ jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
+ return;
+ }
+ spin_unlock_irq(&phba->pport->work_port_lock);
+
+ /* If there is no heart beat outstanding, issue a heartbeat command */
+ if (!phba->hb_outstanding) {
+ pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
+ if (!pmboxq) {
+ mod_timer(&phba->hb_tmofunc,
+ jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+ return;
+ }
+
+ lpfc_heart_beat(phba, pmboxq);
+ pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
+ pmboxq->vport = phba->pport;
+ retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+
+ if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ mod_timer(&phba->hb_tmofunc,
+ jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+ return;
+ }
+ mod_timer(&phba->hb_tmofunc,
+ jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
+ phba->hb_outstanding = 1;
+ return;
+ } else {
+ /*
+ * If heart beat timeout called with hb_outstanding set we
+ * need to take the HBA offline.
+ */
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0459 Adapter heartbeat failure, taking "
+ "this port offline.\n", phba->brd_no);
+
+ spin_lock_irq(&phba->hbalock);
+ psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+ spin_unlock_irq(&phba->hbalock);
+
+ lpfc_offline_prep(phba);
+ lpfc_offline(phba);
+ lpfc_unblock_mgmt_io(phba);
+ phba->link_state = LPFC_HBA_ERROR;
+ lpfc_hba_down_post(phba);
+ }
+}
+
/************************************************************************/
/* */
/* lpfc_handle_eratt */
@@ -486,11 +610,15 @@
/* */
/************************************************************************/
void
-lpfc_handle_eratt(struct lpfc_hba * phba)
+lpfc_handle_eratt(struct lpfc_hba *phba)
{
- struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_vport *vport = phba->pport;
+ struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
+ struct lpfc_vport *port_iterator;
uint32_t event_data;
+ struct Scsi_Host *shost;
+
/* If the pci channel is offline, ignore possible errors,
* since we cannot communicate with the pci card anyway. */
if (pci_channel_offline(phba->pcidev))
@@ -504,10 +632,17 @@
"Data: x%x x%x x%x\n",
phba->brd_no, phba->work_hs,
phba->work_status[0], phba->work_status[1]);
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_ESTABLISH_LINK;
+ list_for_each_entry(port_iterator, &phba->port_list,
+ listentry) {
+ shost = lpfc_shost_from_vport(port_iterator);
+
+ spin_lock_irq(shost->host_lock);
+ port_iterator->fc_flag |= FC_ESTABLISH_LINK;
+ spin_unlock_irq(shost->host_lock);
+ }
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
/*
* Firmware stops when it triggled erratt with HS_FFER6.
@@ -544,15 +679,18 @@
phba->work_status[0], phba->work_status[1]);
event_data = FC_REG_DUMP_EVENT;
- fc_host_post_vendor_event(phba->host, fc_get_event_number(),
+ shost = lpfc_shost_from_vport(vport);
+ fc_host_post_vendor_event(shost, fc_get_event_number(),
sizeof(event_data), (char *) &event_data,
SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+ spin_unlock_irq(&phba->hbalock);
lpfc_offline_prep(phba);
lpfc_offline(phba);
lpfc_unblock_mgmt_io(phba);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
lpfc_hba_down_post(phba);
}
}
@@ -566,9 +704,11 @@
/* */
/************************************************************************/
void
-lpfc_handle_latt(struct lpfc_hba * phba)
+lpfc_handle_latt(struct lpfc_hba *phba)
{
- struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_vport *vport = phba->pport;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_vport *port_iterator;
LPFC_MBOXQ_t *pmb;
volatile uint32_t control;
struct lpfc_dmabuf *mp;
@@ -589,20 +729,22 @@
rc = -EIO;
/* Cleanup any outstanding ELS commands */
- lpfc_els_flush_cmd(phba);
+ list_for_each_entry(port_iterator, &phba->port_list, listentry)
+ lpfc_els_flush_cmd(port_iterator);
psli->slistat.link_event++;
lpfc_read_la(phba, pmb, mp);
pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
+ pmb->vport = vport;
rc = lpfc_sli_issue_mbox (phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB));
if (rc == MBX_NOT_FINISHED)
goto lpfc_handle_latt_free_mbuf;
/* Clear Link Attention in HA REG */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
writel(HA_LATT, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return;
@@ -614,7 +756,7 @@
mempool_free(pmb, phba->mbox_mem_pool);
lpfc_handle_latt_err_exit:
/* Enable Link attention interrupts */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag |= LPFC_PROCESS_LA;
control = readl(phba->HCregaddr);
control |= HC_LAINT_ENA;
@@ -624,15 +766,13 @@
/* Clear Link Attention in HA REG */
writel(HA_LATT, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
lpfc_linkdown(phba);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
/* The other case is an error from issue_mbox */
if (rc == -ENOMEM)
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_MBOX,
+ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
"%d:0300 READ_LA: no buffers\n",
phba->brd_no);
@@ -646,7 +786,7 @@
/* */
/************************************************************************/
static int
-lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd, int len)
+lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len)
{
uint8_t lenlo, lenhi;
int Length;
@@ -658,9 +798,7 @@
return 0;
/* Vital Product */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"%d:0455 Vital Product Data: x%x x%x x%x x%x\n",
phba->brd_no,
(uint32_t) vpd[0], (uint32_t) vpd[1], (uint32_t) vpd[2],
@@ -785,7 +923,7 @@
}
static void
-lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
+lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
{
lpfc_vpd_t *vp;
uint16_t dev_id = phba->pcidev->device;
@@ -943,7 +1081,7 @@
/* Returns the number of buffers NOT posted. */
/**************************************************/
int
-lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
+lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt,
int type)
{
IOCB_t *icmd;
@@ -955,9 +1093,7 @@
/* While there are buffers to post */
while (cnt > 0) {
/* Allocate buffer for command iocb */
- spin_lock_irq(phba->host->host_lock);
iocb = lpfc_sli_get_iocbq(phba);
- spin_unlock_irq(phba->host->host_lock);
if (iocb == NULL) {
pring->missbufcnt = cnt;
return cnt;
@@ -972,9 +1108,7 @@
&mp1->phys);
if (mp1 == 0 || mp1->virt == 0) {
kfree(mp1);
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_release_iocbq(phba, iocb);
- spin_unlock_irq(phba->host->host_lock);
pring->missbufcnt = cnt;
return cnt;
}
@@ -990,9 +1124,7 @@
kfree(mp2);
lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
kfree(mp1);
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_release_iocbq(phba, iocb);
- spin_unlock_irq(phba->host->host_lock);
pring->missbufcnt = cnt;
return cnt;
}
@@ -1018,7 +1150,6 @@
icmd->ulpCommand = CMD_QUE_RING_BUF64_CN;
icmd->ulpLe = 1;
- spin_lock_irq(phba->host->host_lock);
if (lpfc_sli_issue_iocb(phba, pring, iocb, 0) == IOCB_ERROR) {
lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
kfree(mp1);
@@ -1030,14 +1161,11 @@
}
lpfc_sli_release_iocbq(phba, iocb);
pring->missbufcnt = cnt;
- spin_unlock_irq(phba->host->host_lock);
return cnt;
}
- spin_unlock_irq(phba->host->host_lock);
lpfc_sli_ringpostbuf_put(phba, pring, mp1);
- if (mp2) {
+ if (mp2)
lpfc_sli_ringpostbuf_put(phba, pring, mp2);
- }
}
pring->missbufcnt = 0;
return 0;
@@ -1050,7 +1178,7 @@
/* */
/************************************************************************/
static int
-lpfc_post_rcv_buf(struct lpfc_hba * phba)
+lpfc_post_rcv_buf(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
@@ -1151,7 +1279,7 @@
{
int t;
uint32_t *HashWorking;
- uint32_t *pwwnn = phba->wwnn;
+ uint32_t *pwwnn = (uint32_t *) phba->wwnn;
HashWorking = kmalloc(80 * sizeof(uint32_t), GFP_KERNEL);
if (!HashWorking)
@@ -1170,64 +1298,76 @@
}
static void
-lpfc_cleanup(struct lpfc_hba * phba)
+lpfc_cleanup(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp, *next_ndlp;
/* clean up phba - lpfc specific */
- lpfc_can_disctmo(phba);
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+ lpfc_can_disctmo(vport);
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
lpfc_nlp_put(ndlp);
-
- INIT_LIST_HEAD(&phba->fc_nodes);
-
return;
}
static void
lpfc_establish_link_tmo(unsigned long ptr)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
+ struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
+ struct lpfc_vport *vport = phba->pport;
unsigned long iflag;
-
/* Re-establishing Link, timer expired */
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"%d:1300 Re-establishing Link, timer expired "
"Data: x%x x%x\n",
- phba->brd_no, phba->fc_flag, phba->hba_state);
- spin_lock_irqsave(phba->host->host_lock, iflag);
- phba->fc_flag &= ~FC_ESTABLISH_LINK;
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ phba->brd_no, vport->fc_flag,
+ vport->port_state);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ spin_lock_irqsave(shost->host_lock, iflag);
+ vport->fc_flag &= ~FC_ESTABLISH_LINK;
+ spin_unlock_irqrestore(shost->host_lock, iflag);
+ }
}
-static int
-lpfc_stop_timer(struct lpfc_hba * phba)
+void
+lpfc_stop_vport_timers(struct lpfc_vport *vport)
{
- struct lpfc_sli *psli = &phba->sli;
+ del_timer_sync(&vport->els_tmofunc);
+ del_timer_sync(&vport->fc_fdmitmo);
+ lpfc_can_disctmo(vport);
+ return;
+}
+
+static void
+lpfc_stop_phba_timers(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport;
del_timer_sync(&phba->fcp_poll_timer);
del_timer_sync(&phba->fc_estabtmo);
- del_timer_sync(&phba->fc_disctmo);
- del_timer_sync(&phba->fc_fdmitmo);
- del_timer_sync(&phba->els_tmofunc);
- psli = &phba->sli;
- del_timer_sync(&psli->mbox_tmo);
- return(1);
+ list_for_each_entry(vport, &phba->port_list, listentry)
+ lpfc_stop_vport_timers(vport);
+ del_timer_sync(&phba->sli.mbox_tmo);
+ del_timer_sync(&phba->fabric_block_timer);
+ phba->hb_outstanding = 0;
+ del_timer_sync(&phba->hb_tmofunc);
+ return;
}
int
-lpfc_online(struct lpfc_hba * phba)
+lpfc_online(struct lpfc_hba *phba)
{
+ struct lpfc_vport *vport = phba->pport;
+
if (!phba)
return 0;
- if (!(phba->fc_flag & FC_OFFLINE_MODE))
+ if (!(vport->fc_flag & FC_OFFLINE_MODE))
return 0;
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
"%d:0458 Bring Adapter online\n",
phba->brd_no);
@@ -1243,9 +1383,14 @@
return 1;
}
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_OFFLINE_MODE;
- spin_unlock_irq(phba->host->host_lock);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_OFFLINE_MODE;
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ spin_unlock_irq(shost->host_lock);
+ }
lpfc_unblock_mgmt_io(phba);
return 0;
@@ -1256,9 +1401,9 @@
{
unsigned long iflag;
- spin_lock_irqsave(phba->host->host_lock, iflag);
- phba->fc_flag |= FC_BLOCK_MGMT_IO;
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
}
void
@@ -1266,17 +1411,18 @@
{
unsigned long iflag;
- spin_lock_irqsave(phba->host->host_lock, iflag);
- phba->fc_flag &= ~FC_BLOCK_MGMT_IO;
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ phba->sli.sli_flag &= ~LPFC_BLOCK_MGMT_IO;
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
}
void
lpfc_offline_prep(struct lpfc_hba * phba)
{
+ struct lpfc_vport *vport = phba->pport;
struct lpfc_nodelist *ndlp, *next_ndlp;
- if (phba->fc_flag & FC_OFFLINE_MODE)
+ if (vport->fc_flag & FC_OFFLINE_MODE)
return;
lpfc_block_mgmt_io(phba);
@@ -1284,39 +1430,49 @@
lpfc_linkdown(phba);
/* Issue an unreg_login to all nodes */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
lpfc_sli_flush_mbox_queue(phba);
}
void
-lpfc_offline(struct lpfc_hba * phba)
+lpfc_offline(struct lpfc_hba *phba)
{
- unsigned long iflag;
+ struct lpfc_vport *vport = phba->pport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_vport *port_iterator;
- if (phba->fc_flag & FC_OFFLINE_MODE)
+ if (vport->fc_flag & FC_OFFLINE_MODE)
return;
/* stop all timers associated with this hba */
- lpfc_stop_timer(phba);
+ lpfc_stop_phba_timers(phba);
+ list_for_each_entry(port_iterator, &phba->port_list, listentry) {
+ port_iterator->work_port_events = 0;
+ }
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
"%d:0460 Bring Adapter offline\n",
phba->brd_no);
/* Bring down the SLI Layer and cleanup. The HBA is offline
now. */
lpfc_sli_hba_down(phba);
- lpfc_cleanup(phba);
- spin_lock_irqsave(phba->host->host_lock, iflag);
- phba->work_hba_events = 0;
+ spin_lock_irq(&phba->hbalock);
phba->work_ha = 0;
- phba->fc_flag |= FC_OFFLINE_MODE;
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ vport->fc_flag |= FC_OFFLINE_MODE;
+ spin_unlock_irq(&phba->hbalock);
+ list_for_each_entry(port_iterator, &phba->port_list, listentry) {
+ shost = lpfc_shost_from_vport(port_iterator);
+
+ lpfc_cleanup(port_iterator);
+ spin_lock_irq(shost->host_lock);
+ vport->work_port_events = 0;
+ vport->fc_flag |= FC_OFFLINE_MODE;
+ spin_unlock_irq(shost->host_lock);
+ }
}
/******************************************************************************
@@ -1326,17 +1482,17 @@
*
******************************************************************************/
static int
-lpfc_scsi_free(struct lpfc_hba * phba)
+lpfc_scsi_free(struct lpfc_hba *phba)
{
struct lpfc_scsi_buf *sb, *sb_next;
struct lpfc_iocbq *io, *io_next;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
/* Release all the lpfc_scsi_bufs maintained by this host. */
list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) {
list_del(&sb->list);
pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data,
- sb->dma_handle);
+ sb->dma_handle);
kfree(sb);
phba->total_scsi_bufs--;
}
@@ -1348,134 +1504,183 @@
phba->total_iocbq_bufs--;
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return 0;
}
-void lpfc_remove_device(struct lpfc_hba *phba)
+
+struct lpfc_vport *
+lpfc_create_port(struct lpfc_hba *phba, int instance, struct fc_vport *fc_vport)
{
- unsigned long iflag;
+ struct lpfc_vport *vport;
+ struct Scsi_Host *shost;
+ int error = 0;
- lpfc_free_sysfs_attr(phba);
+ shost = scsi_host_alloc(&lpfc_template, sizeof(struct lpfc_vport));
+ if (!shost)
+ goto out;
- spin_lock_irqsave(phba->host->host_lock, iflag);
- phba->fc_flag |= FC_UNLOADING;
+ vport = (struct lpfc_vport *) shost->hostdata;
+ vport->phba = phba;
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ vport->load_flag |= FC_LOADING;
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
- fc_remove_host(phba->host);
- scsi_remove_host(phba->host);
-
- kthread_stop(phba->worker_thread);
-
+ shost->unique_id = instance;
+ shost->max_id = LPFC_MAX_TARGET;
+ shost->max_lun = phba->cfg_max_luns;
+ shost->this_id = -1;
+ shost->max_cmd_len = 16;
/*
- * Bring down the SLI Layer. This step disable all interrupts,
- * clears the rings, discards all mailbox commands, and resets
- * the HBA.
+ * Set initial can_queue value since 0 is no longer supported and
+ * scsi_add_host will fail. This will be adjusted later based on the
+ * max xri value determined in hba setup.
*/
- lpfc_sli_hba_down(phba);
- lpfc_sli_brdrestart(phba);
+ shost->can_queue = phba->cfg_hba_queue_depth - 10;
+ if (fc_vport != NULL) {
+ shost->transportt = lpfc_vport_transport_template;
+ vport->port_type = LPFC_NPIV_PORT;
+ } else {
+ shost->transportt = lpfc_transport_template;
+ vport->port_type = LPFC_PHYSICAL_PORT;
+ }
- /* Release the irq reservation */
- free_irq(phba->pcidev->irq, phba);
- pci_disable_msi(phba->pcidev);
+ /* Initialize all internally managed lists. */
+ INIT_LIST_HEAD(&vport->fc_nodes);
+ spin_lock_init(&vport->work_port_lock);
- lpfc_cleanup(phba);
- lpfc_stop_timer(phba);
- phba->work_hba_events = 0;
+ init_timer(&vport->fc_disctmo);
+ vport->fc_disctmo.function = lpfc_disc_timeout;
+ vport->fc_disctmo.data = (unsigned long)vport;
- /*
- * Call scsi_free before mem_free since scsi bufs are released to their
- * corresponding pools here.
- */
- lpfc_scsi_free(phba);
- lpfc_mem_free(phba);
+ init_timer(&vport->fc_fdmitmo);
+ vport->fc_fdmitmo.function = lpfc_fdmi_tmo;
+ vport->fc_fdmitmo.data = (unsigned long)vport;
- /* Free resources associated with SLI2 interface */
- dma_free_coherent(&phba->pcidev->dev, SLI2_SLIM_SIZE,
- phba->slim2p, phba->slim2p_mapping);
+ init_timer(&vport->els_tmofunc);
+ vport->els_tmofunc.function = lpfc_els_timeout;
+ vport->els_tmofunc.data = (unsigned long)vport;
- /* unmap adapter SLIM and Control Registers */
- iounmap(phba->ctrl_regs_memmap_p);
- iounmap(phba->slim_memmap_p);
+ if (fc_vport != NULL) {
+ error = scsi_add_host(shost, &fc_vport->dev);
+ } else {
+ error = scsi_add_host(shost, &phba->pcidev->dev);
+ }
+ if (error)
+ goto out_put_shost;
- pci_release_regions(phba->pcidev);
- pci_disable_device(phba->pcidev);
+ list_add_tail(&vport->listentry, &phba->port_list);
+ return vport;
- idr_remove(&lpfc_hba_index, phba->brd_no);
- scsi_host_put(phba->host);
+out_put_shost:
+ scsi_host_put(shost);
+out:
+ return NULL;
}
-void lpfc_scan_start(struct Scsi_Host *host)
+void
+destroy_port(struct lpfc_vport *vport)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
- if (lpfc_alloc_sysfs_attr(phba))
- goto error;
+ kfree(vport->vname);
- phba->MBslimaddr = phba->slim_memmap_p;
- phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
- phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
- phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
- phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+ lpfc_debugfs_terminate(vport);
+ fc_remove_host(shost);
+ scsi_remove_host(shost);
- if (lpfc_sli_hba_setup(phba))
- goto error;
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&vport->listentry);
+ spin_unlock_irq(&phba->hbalock);
- /*
- * hba setup may have changed the hba_queue_depth so we need to adjust
- * the value of can_queue.
- */
- host->can_queue = phba->cfg_hba_queue_depth - 10;
+ lpfc_cleanup(vport);
return;
-
-error:
- lpfc_remove_device(phba);
}
+int
+lpfc_get_instance(void)
+{
+ int instance = 0;
+
+ /* Assign an unused number */
+ if (!idr_pre_get(&lpfc_hba_index, GFP_KERNEL))
+ return -1;
+ if (idr_get_new(&lpfc_hba_index, NULL, &instance))
+ return -1;
+ return instance;
+}
+
+/*
+ * Note: there is no scan_start function as adapter initialization
+ * will have asynchronously kicked off the link initialization.
+ */
+
int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ int stat = 0;
- if (!phba->host)
- return 1;
- if (time >= 30 * HZ)
+ spin_lock_irq(shost->host_lock);
+
+ if (vport->fc_flag & FC_UNLOADING) {
+ stat = 1;
goto finished;
-
- if (phba->hba_state != LPFC_HBA_READY)
- return 0;
- if (phba->num_disc_nodes || phba->fc_prli_sent)
- return 0;
- if ((phba->fc_map_cnt == 0) && (time < 2 * HZ))
- return 0;
- if (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)
- return 0;
- if ((phba->hba_state > LPFC_LINK_DOWN) || (time < 15 * HZ))
- return 0;
-
-finished:
- if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
- spin_lock_irq(shost->host_lock);
- lpfc_poll_start_timer(phba);
- spin_unlock_irq(shost->host_lock);
+ }
+ if (time >= 30 * HZ) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "%d:0461 Scanning longer than 30 "
+ "seconds. Continuing initialization\n",
+ phba->brd_no);
+ stat = 1;
+ goto finished;
+ }
+ if (time >= 15 * HZ && phba->link_state <= LPFC_LINK_DOWN) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "%d:0465 Link down longer than 15 "
+ "seconds. Continuing initialization\n",
+ phba->brd_no);
+ stat = 1;
+ goto finished;
}
+ if (vport->port_state != LPFC_VPORT_READY)
+ goto finished;
+ if (vport->num_disc_nodes || vport->fc_prli_sent)
+ goto finished;
+ if (vport->fc_map_cnt == 0 && time < 2 * HZ)
+ goto finished;
+ if ((phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) != 0)
+ goto finished;
+
+ stat = 1;
+
+finished:
+ spin_unlock_irq(shost->host_lock);
+ return stat;
+}
+
+void lpfc_host_attrib_init(struct Scsi_Host *shost)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
/*
- * set fixed host attributes
- * Must done after lpfc_sli_hba_setup()
+ * Set fixed host attributes. Must done after lpfc_sli_hba_setup().
*/
- fc_host_node_name(shost) = wwn_to_u64(phba->fc_nodename.u.wwn);
- fc_host_port_name(shost) = wwn_to_u64(phba->fc_portname.u.wwn);
+ fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
+ fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn);
fc_host_supported_classes(shost) = FC_COS_CLASS3;
memset(fc_host_supported_fc4s(shost), 0,
- sizeof(fc_host_supported_fc4s(shost)));
+ sizeof(fc_host_supported_fc4s(shost)));
fc_host_supported_fc4s(shost)[2] = 1;
fc_host_supported_fc4s(shost)[7] = 1;
- lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
+ lpfc_vport_symbolic_node_name(vport, fc_host_symbolic_name(shost),
+ sizeof fc_host_symbolic_name(shost));
fc_host_supported_speeds(shost) = 0;
if (phba->lmt & LMT_10Gb)
@@ -1488,31 +1693,31 @@
fc_host_supported_speeds(shost) |= FC_PORTSPEED_1GBIT;
fc_host_maxframe_size(shost) =
- ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
- (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
+ (((uint32_t) vport->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
+ (uint32_t) vport->fc_sparam.cmn.bbRcvSizeLsb;
/* This value is also unchanging */
memset(fc_host_active_fc4s(shost), 0,
- sizeof(fc_host_active_fc4s(shost)));
+ sizeof(fc_host_active_fc4s(shost)));
fc_host_active_fc4s(shost)[2] = 1;
fc_host_active_fc4s(shost)[7] = 1;
+ fc_host_max_npiv_vports(shost) = phba->max_vpi;
spin_lock_irq(shost->host_lock);
- phba->fc_flag &= ~FC_LOADING;
+ vport->fc_flag &= ~FC_LOADING;
spin_unlock_irq(shost->host_lock);
-
- return 1;
}
static int __devinit
lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
{
- struct Scsi_Host *host;
- struct lpfc_hba *phba;
- struct lpfc_sli *psli;
+ struct lpfc_vport *vport = NULL;
+ struct lpfc_hba *phba;
+ struct lpfc_sli *psli;
struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL;
+ struct Scsi_Host *shost = NULL;
unsigned long bar0map_len, bar2map_len;
- int error = -ENODEV, retval;
+ int error = -ENODEV;
int i;
uint16_t iotag;
@@ -1521,61 +1726,46 @@
if (pci_request_regions(pdev, LPFC_DRIVER_NAME))
goto out_disable_device;
- host = scsi_host_alloc(&lpfc_template, sizeof (struct lpfc_hba));
- if (!host)
+ phba = kzalloc(sizeof (struct lpfc_hba), GFP_KERNEL);
+ if (!phba)
goto out_release_regions;
- phba = (struct lpfc_hba*)host->hostdata;
- memset(phba, 0, sizeof (struct lpfc_hba));
- phba->host = host;
+ spin_lock_init(&phba->hbalock);
- phba->fc_flag |= FC_LOADING;
phba->pcidev = pdev;
/* Assign an unused board number */
- if (!idr_pre_get(&lpfc_hba_index, GFP_KERNEL))
- goto out_put_host;
+ if ((phba->brd_no = lpfc_get_instance()) < 0)
+ goto out_free_phba;
- error = idr_get_new(&lpfc_hba_index, NULL, &phba->brd_no);
- if (error)
- goto out_put_host;
-
- host->unique_id = phba->brd_no;
+ INIT_LIST_HEAD(&phba->port_list);
+ INIT_LIST_HEAD(&phba->hbq_buffer_list);
+ /*
+ * Get all the module params for configuring this host and then
+ * establish the host.
+ */
+ lpfc_get_cfgparam(phba);
+ phba->max_vpi = LPFC_MAX_VPI;
/* Initialize timers used by driver */
init_timer(&phba->fc_estabtmo);
phba->fc_estabtmo.function = lpfc_establish_link_tmo;
phba->fc_estabtmo.data = (unsigned long)phba;
- init_timer(&phba->fc_disctmo);
- phba->fc_disctmo.function = lpfc_disc_timeout;
- phba->fc_disctmo.data = (unsigned long)phba;
- init_timer(&phba->fc_fdmitmo);
- phba->fc_fdmitmo.function = lpfc_fdmi_tmo;
- phba->fc_fdmitmo.data = (unsigned long)phba;
- init_timer(&phba->els_tmofunc);
- phba->els_tmofunc.function = lpfc_els_timeout;
- phba->els_tmofunc.data = (unsigned long)phba;
+ init_timer(&phba->hb_tmofunc);
+ phba->hb_tmofunc.function = lpfc_hb_timeout;
+ phba->hb_tmofunc.data = (unsigned long)phba;
+
psli = &phba->sli;
init_timer(&psli->mbox_tmo);
psli->mbox_tmo.function = lpfc_mbox_timeout;
- psli->mbox_tmo.data = (unsigned long)phba;
-
+ psli->mbox_tmo.data = (unsigned long) phba;
init_timer(&phba->fcp_poll_timer);
phba->fcp_poll_timer.function = lpfc_poll_timeout;
- phba->fcp_poll_timer.data = (unsigned long)phba;
-
- /*
- * Get all the module params for configuring this host and then
- * establish the host parameters.
- */
- lpfc_get_cfgparam(phba);
-
- host->max_id = LPFC_MAX_TARGET;
- host->max_lun = phba->cfg_max_luns;
- host->this_id = -1;
-
- INIT_LIST_HEAD(&phba->fc_nodes);
+ phba->fcp_poll_timer.data = (unsigned long) phba;
+ init_timer(&phba->fabric_block_timer);
+ phba->fabric_block_timer.function = lpfc_fabric_block_timeout;
+ phba->fabric_block_timer.data = (unsigned long) phba;
pci_set_master(pdev);
pci_try_set_mwi(pdev);
@@ -1620,13 +1810,22 @@
memset(phba->slim2p, 0, SLI2_SLIM_SIZE);
+ phba->hbqslimp.virt = dma_alloc_coherent(&phba->pcidev->dev,
+ lpfc_sli_hbq_size(),
+ &phba->hbqslimp.phys,
+ GFP_KERNEL);
+ if (!phba->hbqslimp.virt)
+ goto out_free_slim;
+
+ memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size());
+
/* Initialize the SLI Layer to run with lpfc HBAs. */
lpfc_sli_setup(phba);
lpfc_sli_queue_setup(phba);
error = lpfc_mem_alloc(phba);
if (error)
- goto out_free_slim;
+ goto out_free_hbqslimp;
/* Initialize and populate the iocb list per host. */
INIT_LIST_HEAD(&phba->lpfc_iocb_list);
@@ -1650,10 +1849,11 @@
error = -ENOMEM;
goto out_free_iocbq;
}
- spin_lock_irq(phba->host->host_lock);
+
+ spin_lock_irq(&phba->hbalock);
list_add(&iocbq_entry->list, &phba->lpfc_iocb_list);
phba->total_iocbq_bufs++;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
}
/* Initialize HBA structure */
@@ -1674,22 +1874,22 @@
goto out_free_iocbq;
}
- /*
- * Set initial can_queue value since 0 is no longer supported and
- * scsi_add_host will fail. This will be adjusted later based on the
- * max xri value determined in hba setup.
- */
- host->can_queue = phba->cfg_hba_queue_depth - 10;
-
- /* Tell the midlayer we support 16 byte commands */
- host->max_cmd_len = 16;
-
/* Initialize the list of scsi buffers used by driver for scsi IO. */
spin_lock_init(&phba->scsi_buf_list_lock);
INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list);
- host->transportt = lpfc_transport_template;
- pci_set_drvdata(pdev, host);
+ /* Initialize list of fabric iocbs */
+ INIT_LIST_HEAD(&phba->fabric_iocb_list);
+
+ vport = lpfc_create_port(phba, phba->brd_no, NULL);
+ if (!vport)
+ goto out_kthread_stop;
+
+ shost = lpfc_shost_from_vport(vport);
+ phba->pport = vport;
+ lpfc_debugfs_initialize(vport);
+
+ pci_set_drvdata(pdev, shost);
if (phba->cfg_use_msi) {
error = pci_enable_msi(phba->pcidev);
@@ -1700,38 +1900,68 @@
}
error = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
- LPFC_DRIVER_NAME, phba);
+ LPFC_DRIVER_NAME, phba);
if (error) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0451 Enable interrupt handler failed\n",
phba->brd_no);
- goto out_kthread_stop;
+ goto out_disable_msi;
}
- error = scsi_add_host(host, &pdev->dev);
- if (error)
+ phba->MBslimaddr = phba->slim_memmap_p;
+ phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
+ phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
+ phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
+ phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+
+ if (lpfc_alloc_sysfs_attr(vport))
goto out_free_irq;
- scsi_scan_host(host);
+ if (lpfc_sli_hba_setup(phba))
+ goto out_remove_device;
+
+ /*
+ * hba setup may have changed the hba_queue_depth so we need to adjust
+ * the value of can_queue.
+ */
+ shost->can_queue = phba->cfg_hba_queue_depth - 10;
+
+ lpfc_host_attrib_init(shost);
+
+ if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
+ spin_lock_irq(shost->host_lock);
+ lpfc_poll_start_timer(phba);
+ spin_unlock_irq(shost->host_lock);
+ }
+
+ scsi_scan_host(shost);
return 0;
+out_remove_device:
+ lpfc_free_sysfs_attr(vport);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_UNLOADING;
+ spin_unlock_irq(shost->host_lock);
out_free_irq:
- lpfc_stop_timer(phba);
- phba->work_hba_events = 0;
+ lpfc_stop_phba_timers(phba);
+ phba->pport->work_port_events = 0;
free_irq(phba->pcidev->irq, phba);
+out_disable_msi:
pci_disable_msi(phba->pcidev);
+ destroy_port(vport);
out_kthread_stop:
kthread_stop(phba->worker_thread);
out_free_iocbq:
list_for_each_entry_safe(iocbq_entry, iocbq_next,
&phba->lpfc_iocb_list, list) {
- spin_lock_irq(phba->host->host_lock);
kfree(iocbq_entry);
phba->total_iocbq_bufs--;
- spin_unlock_irq(phba->host->host_lock);
}
lpfc_mem_free(phba);
+out_free_hbqslimp:
+ dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), phba->hbqslimp.virt,
+ phba->hbqslimp.phys);
out_free_slim:
dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, phba->slim2p,
phba->slim2p_mapping);
@@ -1741,27 +1971,85 @@
iounmap(phba->slim_memmap_p);
out_idr_remove:
idr_remove(&lpfc_hba_index, phba->brd_no);
-out_put_host:
- phba->host = NULL;
- scsi_host_put(host);
+out_free_phba:
+ kfree(phba);
out_release_regions:
pci_release_regions(pdev);
out_disable_device:
pci_disable_device(pdev);
out:
pci_set_drvdata(pdev, NULL);
+ if (shost)
+ scsi_host_put(shost);
return error;
}
static void __devexit
lpfc_pci_remove_one(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(pdev);
- struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_vport *port_iterator;
+ list_for_each_entry(port_iterator, &phba->port_list, listentry)
+ port_iterator->load_flag |= FC_UNLOADING;
- lpfc_remove_device(phba);
+ kfree(vport->vname);
+ lpfc_free_sysfs_attr(vport);
+
+ fc_remove_host(shost);
+ scsi_remove_host(shost);
+
+ /*
+ * Bring down the SLI Layer. This step disable all interrupts,
+ * clears the rings, discards all mailbox commands, and resets
+ * the HBA.
+ */
+ lpfc_sli_hba_down(phba);
+ lpfc_sli_brdrestart(phba);
+
+ lpfc_stop_phba_timers(phba);
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&vport->listentry);
+ spin_unlock_irq(&phba->hbalock);
+
+
+ lpfc_debugfs_terminate(vport);
+ lpfc_cleanup(vport);
+
+ kthread_stop(phba->worker_thread);
+
+ /* Release the irq reservation */
+ free_irq(phba->pcidev->irq, phba);
+ pci_disable_msi(phba->pcidev);
pci_set_drvdata(pdev, NULL);
+ scsi_host_put(shost);
+
+ /*
+ * Call scsi_free before mem_free since scsi bufs are released to their
+ * corresponding pools here.
+ */
+ lpfc_scsi_free(phba);
+ lpfc_mem_free(phba);
+
+ dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), phba->hbqslimp.virt,
+ phba->hbqslimp.phys);
+
+ /* Free resources associated with SLI2 interface */
+ dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
+ phba->slim2p, phba->slim2p_mapping);
+
+ /* unmap adapter SLIM and Control Registers */
+ iounmap(phba->ctrl_regs_memmap_p);
+ iounmap(phba->slim_memmap_p);
+
+ idr_remove(&lpfc_hba_index, phba->brd_no);
+
+ kfree(phba);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
}
/**
@@ -1819,10 +2107,13 @@
pci_set_master(pdev);
/* Re-establishing Link */
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_ESTABLISH_LINK;
+ spin_lock_irq(host->host_lock);
+ phba->pport->fc_flag |= FC_ESTABLISH_LINK;
+ spin_unlock_irq(host->host_lock);
+
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
/* Take device offline; this will perform cleanup */
@@ -1932,7 +2223,7 @@
.id_table = lpfc_id_table,
.probe = lpfc_pci_probe_one,
.remove = __devexit_p(lpfc_pci_remove_one),
- .err_handler = &lpfc_err_handler,
+ .err_handler = &lpfc_err_handler,
};
static int __init
@@ -1945,11 +2236,15 @@
lpfc_transport_template =
fc_attach_transport(&lpfc_transport_functions);
- if (!lpfc_transport_template)
+ lpfc_vport_transport_template =
+ fc_attach_transport(&lpfc_vport_transport_functions);
+ if (!lpfc_transport_template || !lpfc_vport_transport_template)
return -ENOMEM;
error = pci_register_driver(&lpfc_driver);
- if (error)
+ if (error) {
fc_release_transport(lpfc_transport_template);
+ fc_release_transport(lpfc_vport_transport_template);
+ }
return error;
}
@@ -1959,6 +2254,7 @@
{
pci_unregister_driver(&lpfc_driver);
fc_release_transport(lpfc_transport_template);
+ fc_release_transport(lpfc_vport_transport_template);
}
module_init(lpfc_init);
diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
index 438cbcd..8a6ceff 100644
--- a/drivers/scsi/lpfc/lpfc_logmsg.h
+++ b/drivers/scsi/lpfc/lpfc_logmsg.h
@@ -30,6 +30,7 @@
#define LOG_SLI 0x800 /* SLI events */
#define LOG_FCP_ERROR 0x1000 /* log errors, not underruns */
#define LOG_LIBDFC 0x2000 /* Libdfc events */
+#define LOG_VPORT 0x4000 /* NPIV events */
#define LOG_ALL_MSG 0xffff /* LOG all messages */
#define lpfc_printf_log(phba, level, mask, fmt, arg...) \
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 8041c3f..8f42fbf 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -82,6 +82,22 @@
}
/**********************************************/
+/* lpfc_heart_beat Issue a HEART_BEAT */
+/* mailbox command */
+/**********************************************/
+void
+lpfc_heart_beat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+ MAILBOX_t *mb;
+
+ mb = &pmb->mb;
+ memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+ mb->mbxCommand = MBX_HEARTBEAT;
+ mb->mbxOwner = OWN_HOST;
+ return;
+}
+
+/**********************************************/
/* lpfc_read_la Issue a READ LA */
/* mailbox command */
/**********************************************/
@@ -134,6 +150,7 @@
void
lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
+ struct lpfc_vport *vport = phba->pport;
MAILBOX_t *mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
@@ -147,7 +164,7 @@
mb->un.varCfgLnk.cr_count = phba->cfg_cr_count;
}
- mb->un.varCfgLnk.myId = phba->fc_myDID;
+ mb->un.varCfgLnk.myId = vport->fc_myDID;
mb->un.varCfgLnk.edtov = phba->fc_edtov;
mb->un.varCfgLnk.arbtov = phba->fc_arbtov;
mb->un.varCfgLnk.ratov = phba->fc_ratov;
@@ -239,7 +256,7 @@
/* mailbox command */
/**********************************************/
int
-lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
{
struct lpfc_dmabuf *mp;
MAILBOX_t *mb;
@@ -270,6 +287,7 @@
mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys);
mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(mp->phys);
+ mb->un.varRdSparm.vpi = vpi;
/* save address for completion */
pmb->context1 = mp;
@@ -282,7 +300,8 @@
/* mailbox command */
/********************************************/
void
-lpfc_unreg_did(struct lpfc_hba * phba, uint32_t did, LPFC_MBOXQ_t * pmb)
+lpfc_unreg_did(struct lpfc_hba * phba, uint16_t vpi, uint32_t did,
+ LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb;
@@ -290,6 +309,7 @@
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->un.varUnregDID.did = did;
+ mb->un.varUnregDID.vpi = vpi;
mb->mbxCommand = MBX_UNREG_D_ID;
mb->mbxOwner = OWN_HOST;
@@ -335,19 +355,17 @@
/* mailbox command */
/********************************************/
int
-lpfc_reg_login(struct lpfc_hba * phba,
- uint32_t did, uint8_t * param, LPFC_MBOXQ_t * pmb, uint32_t flag)
+lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
+ uint8_t *param, LPFC_MBOXQ_t *pmb, uint32_t flag)
{
+ MAILBOX_t *mb = &pmb->mb;
uint8_t *sparam;
struct lpfc_dmabuf *mp;
- MAILBOX_t *mb;
- struct lpfc_sli *psli;
- psli = &phba->sli;
- mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->un.varRegLogin.rpi = 0;
+ mb->un.varRegLogin.vpi = vpi;
mb->un.varRegLogin.did = did;
mb->un.varWords[30] = flag; /* Set flag to issue action on cmpl */
@@ -359,12 +377,10 @@
kfree(mp);
mb->mbxCommand = MBX_REG_LOGIN64;
/* REG_LOGIN: no buffers */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_MBOX,
- "%d:0302 REG_LOGIN: no buffers Data x%x x%x\n",
- phba->brd_no,
- (uint32_t) did, (uint32_t) flag);
+ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
+ "%d (%d):0302 REG_LOGIN: no buffers, DID x%x, "
+ "flag x%x\n",
+ phba->brd_no, vpi, did, flag);
return (1);
}
INIT_LIST_HEAD(&mp->list);
@@ -389,7 +405,8 @@
/* mailbox command */
/**********************************************/
void
-lpfc_unreg_login(struct lpfc_hba * phba, uint32_t rpi, LPFC_MBOXQ_t * pmb)
+lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi,
+ LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb;
@@ -398,12 +415,52 @@
mb->un.varUnregLogin.rpi = (uint16_t) rpi;
mb->un.varUnregLogin.rsvd1 = 0;
+ mb->un.varUnregLogin.vpi = vpi;
mb->mbxCommand = MBX_UNREG_LOGIN;
mb->mbxOwner = OWN_HOST;
return;
}
+/**************************************************/
+/* lpfc_reg_vpi Issue a REG_VPI */
+/* mailbox command */
+/**************************************************/
+void
+lpfc_reg_vpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t sid,
+ LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb = &pmb->mb;
+
+ memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+ mb->un.varRegVpi.vpi = vpi;
+ mb->un.varRegVpi.sid = sid;
+
+ mb->mbxCommand = MBX_REG_VPI;
+ mb->mbxOwner = OWN_HOST;
+ return;
+
+}
+
+/**************************************************/
+/* lpfc_unreg_vpi Issue a UNREG_VNPI */
+/* mailbox command */
+/**************************************************/
+void
+lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb = &pmb->mb;
+ memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+ mb->un.varUnregVpi.vpi = vpi;
+
+ mb->mbxCommand = MBX_UNREG_VPI;
+ mb->mbxOwner = OWN_HOST;
+ return;
+
+}
+
static void
lpfc_config_pcb_setup(struct lpfc_hba * phba)
{
@@ -412,14 +469,18 @@
PCB_t *pcbp = &phba->slim2p->pcb;
dma_addr_t pdma_addr;
uint32_t offset;
- uint32_t iocbCnt;
+ uint32_t iocbCnt = 0;
int i;
pcbp->maxRing = (psli->num_rings - 1);
- iocbCnt = 0;
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
+
+ pring->sizeCiocb = phba->sli_rev == 3 ? SLI3_IOCB_CMD_SIZE:
+ SLI2_IOCB_CMD_SIZE;
+ pring->sizeRiocb = phba->sli_rev == 3 ? SLI3_IOCB_RSP_SIZE:
+ SLI2_IOCB_RSP_SIZE;
/* A ring MUST have both cmd and rsp entries defined to be
valid */
if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) {
@@ -434,20 +495,18 @@
continue;
}
/* Command ring setup for ring */
- pring->cmdringaddr =
- (void *)&phba->slim2p->IOCBs[iocbCnt];
+ pring->cmdringaddr = (void *) &phba->slim2p->IOCBs[iocbCnt];
pcbp->rdsc[i].cmdEntries = pring->numCiocb;
- offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
- (uint8_t *)phba->slim2p;
+ offset = (uint8_t *) &phba->slim2p->IOCBs[iocbCnt] -
+ (uint8_t *) phba->slim2p;
pdma_addr = phba->slim2p_mapping + offset;
pcbp->rdsc[i].cmdAddrHigh = putPaddrHigh(pdma_addr);
pcbp->rdsc[i].cmdAddrLow = putPaddrLow(pdma_addr);
iocbCnt += pring->numCiocb;
/* Response ring setup for ring */
- pring->rspringaddr =
- (void *)&phba->slim2p->IOCBs[iocbCnt];
+ pring->rspringaddr = (void *) &phba->slim2p->IOCBs[iocbCnt];
pcbp->rdsc[i].rspEntries = pring->numRiocb;
offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
@@ -462,16 +521,108 @@
void
lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
- MAILBOX_t *mb;
-
- mb = &pmb->mb;
+ MAILBOX_t *mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->un.varRdRev.cv = 1;
+ mb->un.varRdRev.v3req = 1; /* Request SLI3 info */
mb->mbxCommand = MBX_READ_REV;
mb->mbxOwner = OWN_HOST;
return;
}
+static void
+lpfc_build_hbq_profile2(struct config_hbq_var *hbqmb,
+ struct lpfc_hbq_init *hbq_desc)
+{
+ hbqmb->profiles.profile2.seqlenbcnt = hbq_desc->seqlenbcnt;
+ hbqmb->profiles.profile2.maxlen = hbq_desc->maxlen;
+ hbqmb->profiles.profile2.seqlenoff = hbq_desc->seqlenoff;
+}
+
+static void
+lpfc_build_hbq_profile3(struct config_hbq_var *hbqmb,
+ struct lpfc_hbq_init *hbq_desc)
+{
+ hbqmb->profiles.profile3.seqlenbcnt = hbq_desc->seqlenbcnt;
+ hbqmb->profiles.profile3.maxlen = hbq_desc->maxlen;
+ hbqmb->profiles.profile3.cmdcodeoff = hbq_desc->cmdcodeoff;
+ hbqmb->profiles.profile3.seqlenoff = hbq_desc->seqlenoff;
+ memcpy(&hbqmb->profiles.profile3.cmdmatch, hbq_desc->cmdmatch,
+ sizeof(hbqmb->profiles.profile3.cmdmatch));
+}
+
+static void
+lpfc_build_hbq_profile5(struct config_hbq_var *hbqmb,
+ struct lpfc_hbq_init *hbq_desc)
+{
+ hbqmb->profiles.profile5.seqlenbcnt = hbq_desc->seqlenbcnt;
+ hbqmb->profiles.profile5.maxlen = hbq_desc->maxlen;
+ hbqmb->profiles.profile5.cmdcodeoff = hbq_desc->cmdcodeoff;
+ hbqmb->profiles.profile5.seqlenoff = hbq_desc->seqlenoff;
+ memcpy(&hbqmb->profiles.profile5.cmdmatch, hbq_desc->cmdmatch,
+ sizeof(hbqmb->profiles.profile5.cmdmatch));
+}
+
+void
+lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc,
+ uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb)
+{
+ int i;
+ MAILBOX_t *mb = &pmb->mb;
+ struct config_hbq_var *hbqmb = &mb->un.varCfgHbq;
+
+ memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+ hbqmb->entry_count = hbq_desc->entry_count; /* # entries in HBQ */
+ hbqmb->recvNotify = hbq_desc->rn; /* Receive
+ * Notification */
+ hbqmb->numMask = hbq_desc->mask_count; /* # R_CTL/TYPE masks
+ * # in words 0-19 */
+ hbqmb->profile = hbq_desc->profile; /* Selection profile:
+ * 0 = all,
+ * 7 = logentry */
+ hbqmb->ringMask = hbq_desc->ring_mask; /* Binds HBQ to a ring
+ * e.g. Ring0=b0001,
+ * ring2=b0100 */
+ hbqmb->headerLen = hbq_desc->headerLen; /* 0 if not profile 4
+ * or 5 */
+ hbqmb->logEntry = hbq_desc->logEntry; /* Set to 1 if this
+ * HBQ will be used
+ * for LogEntry
+ * buffers */
+ hbqmb->hbqaddrLow = putPaddrLow(phba->hbqslimp.phys) +
+ hbq_entry_index * sizeof(struct lpfc_hbq_entry);
+ hbqmb->hbqaddrHigh = putPaddrHigh(phba->hbqslimp.phys);
+
+ mb->mbxCommand = MBX_CONFIG_HBQ;
+ mb->mbxOwner = OWN_HOST;
+
+ /* Copy info for profiles 2,3,5. Other
+ * profiles this area is reserved
+ */
+ if (hbq_desc->profile == 2)
+ lpfc_build_hbq_profile2(hbqmb, hbq_desc);
+ else if (hbq_desc->profile == 3)
+ lpfc_build_hbq_profile3(hbqmb, hbq_desc);
+ else if (hbq_desc->profile == 5)
+ lpfc_build_hbq_profile5(hbqmb, hbq_desc);
+
+ /* Return if no rctl / type masks for this HBQ */
+ if (!hbq_desc->mask_count)
+ return;
+
+ /* Otherwise we setup specific rctl / type masks for this HBQ */
+ for (i = 0; i < hbq_desc->mask_count; i++) {
+ hbqmb->hbqMasks[i].tmatch = hbq_desc->hbqMasks[i].tmatch;
+ hbqmb->hbqMasks[i].tmask = hbq_desc->hbqMasks[i].tmask;
+ hbqmb->hbqMasks[i].rctlmatch = hbq_desc->hbqMasks[i].rctlmatch;
+ hbqmb->hbqMasks[i].rctlmask = hbq_desc->hbqMasks[i].rctlmask;
+ }
+
+ return;
+}
+
+
+
void
lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
{
@@ -514,15 +665,16 @@
}
void
-lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
+ MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr;
MAILBOX_t *mb = &pmb->mb;
dma_addr_t pdma_addr;
uint32_t bar_low, bar_high;
size_t offset;
struct lpfc_hgp hgp;
- void __iomem *to_slim;
int i;
+ uint32_t pgp_offset;
memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
mb->mbxCommand = MBX_CONFIG_PORT;
@@ -535,12 +687,29 @@
mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr);
mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr);
+ /* If HBA supports SLI=3 ask for it */
+
+ if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) {
+ mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
+ mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */
+ if (phba->max_vpi && phba->cfg_npiv_enable &&
+ phba->vpd.sli3Feat.cmv) {
+ mb->un.varCfgPort.max_vpi = phba->max_vpi;
+ mb->un.varCfgPort.cmv = 1;
+ phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
+ } else
+ mb->un.varCfgPort.max_vpi = phba->max_vpi = 0;
+ } else
+ phba->sli_rev = 2;
+ mb->un.varCfgPort.sli_mode = phba->sli_rev;
+
/* Now setup pcb */
phba->slim2p->pcb.type = TYPE_NATIVE_SLI2;
phba->slim2p->pcb.feature = FEATURE_INITIAL_SLI2;
/* Setup Mailbox pointers */
- phba->slim2p->pcb.mailBoxSize = sizeof(MAILBOX_t);
+ phba->slim2p->pcb.mailBoxSize = offsetof(MAILBOX_t, us) +
+ sizeof(struct sli2_desc);
offset = (uint8_t *)&phba->slim2p->mbx - (uint8_t *)phba->slim2p;
pdma_addr = phba->slim2p_mapping + offset;
phba->slim2p->pcb.mbAddrHigh = putPaddrHigh(pdma_addr);
@@ -568,29 +737,70 @@
pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_0, &bar_low);
pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_1, &bar_high);
+ /*
+ * Set up HGP - Port Memory
+ *
+ * The port expects the host get/put pointers to reside in memory
+ * following the "non-diagnostic" mode mailbox (32 words, 0x80 bytes)
+ * area of SLIM. In SLI-2 mode, there's an additional 16 reserved
+ * words (0x40 bytes). This area is not reserved if HBQs are
+ * configured in SLI-3.
+ *
+ * CR0Put - SLI2(no HBQs) = 0xc0, With HBQs = 0x80
+ * RR0Get 0xc4 0x84
+ * CR1Put 0xc8 0x88
+ * RR1Get 0xcc 0x8c
+ * CR2Put 0xd0 0x90
+ * RR2Get 0xd4 0x94
+ * CR3Put 0xd8 0x98
+ * RR3Get 0xdc 0x9c
+ *
+ * Reserved 0xa0-0xbf
+ * If HBQs configured:
+ * HBQ 0 Put ptr 0xc0
+ * HBQ 1 Put ptr 0xc4
+ * HBQ 2 Put ptr 0xc8
+ * ......
+ * HBQ(M-1)Put Pointer 0xc0+(M-1)*4
+ *
+ */
+
+ if (phba->sli_rev == 3) {
+ phba->host_gp = &mb_slim->us.s3.host[0];
+ phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
+ } else {
+ phba->host_gp = &mb_slim->us.s2.host[0];
+ phba->hbq_put = NULL;
+ }
/* mask off BAR0's flag bits 0 - 3 */
phba->slim2p->pcb.hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
- (SLIMOFF*sizeof(uint32_t));
+ (void __iomem *) phba->host_gp -
+ (void __iomem *)phba->MBslimaddr;
if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
phba->slim2p->pcb.hgpAddrHigh = bar_high;
else
phba->slim2p->pcb.hgpAddrHigh = 0;
/* write HGP data to SLIM at the required longword offset */
memset(&hgp, 0, sizeof(struct lpfc_hgp));
- to_slim = phba->MBslimaddr + (SLIMOFF*sizeof (uint32_t));
for (i=0; i < phba->sli.num_rings; i++) {
- lpfc_memcpy_to_slim(to_slim, &hgp, sizeof(struct lpfc_hgp));
- to_slim += sizeof (struct lpfc_hgp);
+ lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
+ sizeof(*phba->host_gp));
}
/* Setup Port Group ring pointer */
- offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port -
- (uint8_t *)phba->slim2p;
- pdma_addr = phba->slim2p_mapping + offset;
+ if (phba->sli_rev == 3)
+ pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s3_pgp.port -
+ (uint8_t *)phba->slim2p;
+ else
+ pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port -
+ (uint8_t *)phba->slim2p;
+
+ pdma_addr = phba->slim2p_mapping + pgp_offset;
phba->slim2p->pcb.pgpAddrHigh = putPaddrHigh(pdma_addr);
phba->slim2p->pcb.pgpAddrLow = putPaddrLow(pdma_addr);
+ phba->hbq_get = &phba->slim2p->mbx.us.s3_pgp.hbq_get[0];
/* Use callback routine to setp rings in the pcb */
lpfc_config_pcb_setup(phba);
@@ -606,11 +816,7 @@
/* Swap PCB if needed */
lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb,
- sizeof (PCB_t));
-
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "%d:0405 Service Level Interface (SLI) 2 selected\n",
- phba->brd_no);
+ sizeof(PCB_t));
}
void
@@ -644,15 +850,23 @@
LPFC_MBOXQ_t *mbq = NULL;
struct lpfc_sli *psli = &phba->sli;
- list_remove_head((&psli->mboxq), mbq, LPFC_MBOXQ_t,
- list);
- if (mbq) {
+ list_remove_head((&psli->mboxq), mbq, LPFC_MBOXQ_t, list);
+ if (mbq)
psli->mboxq_cnt--;
- }
return mbq;
}
+void
+lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
+{
+ /* This function expects to be called from interupt context */
+ spin_lock(&phba->hbalock);
+ list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl);
+ spin_unlock(&phba->hbalock);
+ return;
+}
+
int
lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd)
{
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index ec3bbbd..3594c46 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2005 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2006 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -38,10 +38,13 @@
#define LPFC_MBUF_POOL_SIZE 64 /* max elements in MBUF safety pool */
#define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */
+
+
int
lpfc_mem_alloc(struct lpfc_hba * phba)
{
struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+ int longs;
int i;
phba->lpfc_scsi_dma_buf_pool = pci_pool_create("lpfc_scsi_dma_buf_pool",
@@ -80,10 +83,27 @@
if (!phba->nlp_mem_pool)
goto fail_free_mbox_pool;
+ phba->lpfc_hbq_pool = pci_pool_create("lpfc_hbq_pool",phba->pcidev,
+ LPFC_BPL_SIZE, 8, 0);
+ if (!phba->lpfc_hbq_pool)
+ goto fail_free_nlp_mem_pool;
+
+ /* vpi zero is reserved for the physical port so add 1 to max */
+ longs = ((phba->max_vpi + 1) + BITS_PER_LONG - 1) / BITS_PER_LONG;
+ phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL);
+ if (!phba->vpi_bmask)
+ goto fail_free_hbq_pool;
+
return 0;
+ fail_free_hbq_pool:
+ lpfc_sli_hbqbuf_free_all(phba);
+ fail_free_nlp_mem_pool:
+ mempool_destroy(phba->nlp_mem_pool);
+ phba->nlp_mem_pool = NULL;
fail_free_mbox_pool:
mempool_destroy(phba->mbox_mem_pool);
+ phba->mbox_mem_pool = NULL;
fail_free_mbuf_pool:
while (i--)
pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
@@ -91,8 +111,10 @@
kfree(pool->elements);
fail_free_lpfc_mbuf_pool:
pci_pool_destroy(phba->lpfc_mbuf_pool);
+ phba->lpfc_mbuf_pool = NULL;
fail_free_dma_buf_pool:
pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
+ phba->lpfc_scsi_dma_buf_pool = NULL;
fail:
return -ENOMEM;
}
@@ -106,6 +128,9 @@
struct lpfc_dmabuf *mp;
int i;
+ kfree(phba->vpi_bmask);
+ lpfc_sli_hbqbuf_free_all(phba);
+
list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) {
mp = (struct lpfc_dmabuf *) (mbox->context1);
if (mp) {
@@ -115,6 +140,15 @@
list_del(&mbox->list);
mempool_free(mbox, phba->mbox_mem_pool);
}
+ list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq_cmpl, list) {
+ mp = (struct lpfc_dmabuf *) (mbox->context1);
+ if (mp) {
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ }
+ list_del(&mbox->list);
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
if (psli->mbox_active) {
@@ -132,13 +166,21 @@
pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
pool->elements[i].phys);
kfree(pool->elements);
+
+ pci_pool_destroy(phba->lpfc_hbq_pool);
mempool_destroy(phba->nlp_mem_pool);
mempool_destroy(phba->mbox_mem_pool);
pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
pci_pool_destroy(phba->lpfc_mbuf_pool);
- /* Free the iocb lookup array */
+ phba->lpfc_hbq_pool = NULL;
+ phba->nlp_mem_pool = NULL;
+ phba->mbox_mem_pool = NULL;
+ phba->lpfc_scsi_dma_buf_pool = NULL;
+ phba->lpfc_mbuf_pool = NULL;
+
+ /* Free the iocb lookup array */
kfree(psli->iocbq_lookup);
psli->iocbq_lookup = NULL;
@@ -148,20 +190,23 @@
lpfc_mbuf_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
{
struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+ unsigned long iflags;
void *ret;
ret = pci_pool_alloc(phba->lpfc_mbuf_pool, GFP_KERNEL, handle);
- if (!ret && ( mem_flags & MEM_PRI) && pool->current_count) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ if (!ret && (mem_flags & MEM_PRI) && pool->current_count) {
pool->current_count--;
ret = pool->elements[pool->current_count].virt;
*handle = pool->elements[pool->current_count].phys;
}
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
return ret;
}
void
-lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
+__lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
{
struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
@@ -174,3 +219,51 @@
}
return;
}
+
+void
+lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
+{
+ unsigned long iflags;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ __lpfc_mbuf_free(phba, virt, dma);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return;
+}
+
+void *
+lpfc_hbq_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
+{
+ void *ret;
+ ret = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_ATOMIC, handle);
+ return ret;
+}
+
+void
+lpfc_hbq_free(struct lpfc_hba *phba, void *virt, dma_addr_t dma)
+{
+ pci_pool_free(phba->lpfc_hbq_pool, virt, dma);
+ return;
+}
+
+void
+lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
+{
+ struct hbq_dmabuf *hbq_entry;
+
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf);
+ if (hbq_entry->tag == -1) {
+ lpfc_hbq_free(phba, hbq_entry->dbuf.virt,
+ hbq_entry->dbuf.phys);
+ kfree(hbq_entry);
+ } else {
+ lpfc_sli_free_hbq(phba, hbq_entry);
+ }
+ } else {
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ }
+ return;
+}
+
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index b309841..bca2f5c 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -1,4 +1,4 @@
-/*******************************************************************
+ /*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2004-2007 Emulex. All rights reserved. *
@@ -35,20 +35,22 @@
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
/* Called to verify a rcv'ed ADISC was intended for us. */
static int
-lpfc_check_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
- struct lpfc_name * nn, struct lpfc_name * pn)
+lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct lpfc_name *nn, struct lpfc_name *pn)
{
/* Compare the ADISC rsp WWNN / WWPN matches our internal node
* table entry for that node.
*/
- if (memcmp(nn, &ndlp->nlp_nodename, sizeof (struct lpfc_name)) != 0)
+ if (memcmp(nn, &ndlp->nlp_nodename, sizeof (struct lpfc_name)))
return 0;
- if (memcmp(pn, &ndlp->nlp_portname, sizeof (struct lpfc_name)) != 0)
+ if (memcmp(pn, &ndlp->nlp_portname, sizeof (struct lpfc_name)))
return 0;
/* we match, return success */
@@ -56,11 +58,10 @@
}
int
-lpfc_check_sparm(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, struct serv_parm * sp,
- uint32_t class)
+lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct serv_parm * sp, uint32_t class)
{
- volatile struct serv_parm *hsp = &phba->fc_sparam;
+ volatile struct serv_parm *hsp = &vport->fc_sparam;
uint16_t hsp_value, ssp_value = 0;
/*
@@ -75,12 +76,14 @@
hsp->cls1.rcvDataSizeLsb;
ssp_value = (sp->cls1.rcvDataSizeMsb << 8) |
sp->cls1.rcvDataSizeLsb;
+ if (!ssp_value)
+ goto bad_service_param;
if (ssp_value > hsp_value) {
sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb;
sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb;
}
} else if (class == CLASS1) {
- return 0;
+ goto bad_service_param;
}
if (sp->cls2.classValid) {
@@ -88,12 +91,14 @@
hsp->cls2.rcvDataSizeLsb;
ssp_value = (sp->cls2.rcvDataSizeMsb << 8) |
sp->cls2.rcvDataSizeLsb;
+ if (!ssp_value)
+ goto bad_service_param;
if (ssp_value > hsp_value) {
sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb;
sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb;
}
} else if (class == CLASS2) {
- return 0;
+ goto bad_service_param;
}
if (sp->cls3.classValid) {
@@ -101,12 +106,14 @@
hsp->cls3.rcvDataSizeLsb;
ssp_value = (sp->cls3.rcvDataSizeMsb << 8) |
sp->cls3.rcvDataSizeLsb;
+ if (!ssp_value)
+ goto bad_service_param;
if (ssp_value > hsp_value) {
sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb;
sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb;
}
} else if (class == CLASS3) {
- return 0;
+ goto bad_service_param;
}
/*
@@ -125,12 +132,22 @@
memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name));
return 1;
+bad_service_param:
+ lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0207 Device %x "
+ "(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent "
+ "invalid service parameters. Ignoring device.\n",
+ vport->phba->brd_no, ndlp->vport->vpi, ndlp->nlp_DID,
+ sp->nodeName.u.wwn[0], sp->nodeName.u.wwn[1],
+ sp->nodeName.u.wwn[2], sp->nodeName.u.wwn[3],
+ sp->nodeName.u.wwn[4], sp->nodeName.u.wwn[5],
+ sp->nodeName.u.wwn[6], sp->nodeName.u.wwn[7]);
+ return 0;
}
static void *
-lpfc_check_elscmpl_iocb(struct lpfc_hba * phba,
- struct lpfc_iocbq *cmdiocb,
- struct lpfc_iocbq *rspiocb)
+lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
struct lpfc_dmabuf *pcmd, *prsp;
uint32_t *lp;
@@ -168,32 +185,29 @@
* routine effectively results in a "software abort".
*/
int
-lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
LIST_HEAD(completions);
- struct lpfc_sli *psli;
- struct lpfc_sli_ring *pring;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
struct lpfc_iocbq *iocb, *next_iocb;
IOCB_t *cmd;
/* Abort outstanding I/O on NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0205 Abort outstanding I/O on NPort x%x "
+ "%d (%d):0205 Abort outstanding I/O on NPort x%x "
"Data: x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
- ndlp->nlp_state, ndlp->nlp_rpi);
+ phba->brd_no, ndlp->vport->vpi, ndlp->nlp_DID,
+ ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
- psli = &phba->sli;
- pring = &psli->ring[LPFC_ELS_RING];
+ lpfc_fabric_abort_nport(ndlp);
/* First check the txq */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
- /* Check to see if iocb matches the nport we are looking
- for */
+ /* Check to see if iocb matches the nport we are looking for */
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
- /* It matches, so deque and call compl with an
- error */
+ /* It matches, so deque and call compl with anp error */
list_move_tail(&iocb->list, &completions);
pring->txq_cnt--;
}
@@ -201,37 +215,39 @@
/* Next check the txcmplq */
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
- /* Check to see if iocb matches the nport we are looking
- for */
- if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
+ /* Check to see if iocb matches the nport we are looking for */
+ if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+ }
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
while (!list_empty(&completions)) {
iocb = list_get_first(&completions, struct lpfc_iocbq, list);
cmd = &iocb->iocb;
- list_del(&iocb->list);
+ list_del_init(&iocb->list);
- if (iocb->iocb_cmpl) {
+ if (!iocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, iocb);
+ else {
cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
(iocb->iocb_cmpl) (phba, iocb, iocb);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
+ }
}
/* If we are delaying issuing an ELS command, cancel it */
if (ndlp->nlp_flag & NLP_DELAY_TMO)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
return 0;
}
static int
-lpfc_rcv_plogi(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp,
- struct lpfc_iocbq *cmdiocb)
+lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct lpfc_iocbq *cmdiocb)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
IOCB_t *icmd;
@@ -241,14 +257,14 @@
int rc;
memset(&stat, 0, sizeof (struct ls_rjt));
- if (phba->hba_state <= LPFC_FLOGI) {
+ if (vport->port_state <= LPFC_FLOGI) {
/* Before responding to PLOGI, check for pt2pt mode.
* If we are pt2pt, with an outstanding FLOGI, abort
* the FLOGI and resend it first.
*/
- if (phba->fc_flag & FC_PT2PT) {
- lpfc_els_abort_flogi(phba);
- if (!(phba->fc_flag & FC_PT2PT_PLOGI)) {
+ if (vport->fc_flag & FC_PT2PT) {
+ lpfc_els_abort_flogi(phba);
+ if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
/* If the other side is supposed to initiate
* the PLOGI anyway, just ACC it now and
* move on with discovery.
@@ -257,45 +273,42 @@
phba->fc_ratov = FF_DEF_RATOV;
/* Start discovery - this should just do
CLEAR_LA */
- lpfc_disc_start(phba);
- } else {
- lpfc_initial_flogi(phba);
- }
+ lpfc_disc_start(vport);
+ } else
+ lpfc_initial_flogi(vport);
} else {
stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb,
- ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
+ ndlp, NULL);
return 0;
}
}
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
- if ((lpfc_check_sparm(phba, ndlp, sp, CLASS3) == 0)) {
+ if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) {
/* Reject this request because invalid parameters */
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+ NULL);
return 0;
}
icmd = &cmdiocb->iocb;
/* PLOGI chkparm OK */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_ELS,
- "%d:0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
- phba->brd_no,
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi,
ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag,
ndlp->nlp_rpi);
- if ((phba->cfg_fcp_class == 2) &&
- (sp->cls2.classValid)) {
+ if (phba->cfg_fcp_class == 2 && sp->cls2.classValid)
ndlp->nlp_fcp_info |= CLASS2;
- } else {
+ else
ndlp->nlp_fcp_info |= CLASS3;
- }
+
ndlp->nlp_class_sup = 0;
if (sp->cls1.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS1;
@@ -317,35 +330,37 @@
case NLP_STE_PRLI_ISSUE:
case NLP_STE_UNMAPPED_NODE:
case NLP_STE_MAPPED_NODE:
- lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, 0);
return 1;
}
- if ((phba->fc_flag & FC_PT2PT)
- && !(phba->fc_flag & FC_PT2PT_PLOGI)) {
+ if ((vport->fc_flag & FC_PT2PT) &&
+ !(vport->fc_flag & FC_PT2PT_PLOGI)) {
/* rcv'ed PLOGI decides what our NPortId will be */
- phba->fc_myDID = icmd->un.rcvels.parmRo;
+ vport->fc_myDID = icmd->un.rcvels.parmRo;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (mbox == NULL)
goto out;
lpfc_config_link(phba, mbox);
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
rc = lpfc_sli_issue_mbox
(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
if (rc == MBX_NOT_FINISHED) {
- mempool_free( mbox, phba->mbox_mem_pool);
+ mempool_free(mbox, phba->mbox_mem_pool);
goto out;
}
- lpfc_can_disctmo(phba);
+ lpfc_can_disctmo(vport);
}
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (mbox == NULL)
+ if (!mbox)
goto out;
- if (lpfc_reg_login(phba, icmd->un.rcvels.remoteID,
- (uint8_t *) sp, mbox, 0)) {
- mempool_free( mbox, phba->mbox_mem_pool);
+ rc = lpfc_reg_login(phba, vport->vpi, icmd->un.rcvels.remoteID,
+ (uint8_t *) sp, mbox, 0);
+ if (rc) {
+ mempool_free(mbox, phba->mbox_mem_pool);
goto out;
}
@@ -357,7 +372,10 @@
* mbox->context2 = lpfc_nlp_get(ndlp) deferred until mailbox
* command issued in lpfc_cmpl_els_acc().
*/
+ mbox->vport = vport;
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
+ spin_unlock_irq(shost->host_lock);
/*
* If there is an outstanding PLOGI issued, abort it before
@@ -373,24 +391,41 @@
lpfc_els_abort(phba, ndlp);
}
- lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
+ if ((vport->port_type == LPFC_NPIV_PORT &&
+ phba->cfg_vport_restrict_login)) {
+
+ /* In order to preserve RPIs, we want to cleanup
+ * the default RPI the firmware created to rcv
+ * this ELS request. The only way to do this is
+ * to register, then unregister the RPI.
+ */
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_RM_DFLT_RPI;
+ spin_unlock_irq(shost->host_lock);
+ stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
+ stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
+ ndlp, mbox);
+ return 1;
+ }
+ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
return 1;
out:
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
return 0;
}
static int
-lpfc_rcv_padisc(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp,
+lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct lpfc_iocbq *cmdiocb)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_dmabuf *pcmd;
- struct serv_parm *sp;
- struct lpfc_name *pnn, *ppn;
+ struct serv_parm *sp;
+ struct lpfc_name *pnn, *ppn;
struct ls_rjt stat;
ADISC *ap;
IOCB_t *icmd;
@@ -412,13 +447,12 @@
}
icmd = &cmdiocb->iocb;
- if ((icmd->ulpStatus == 0) &&
- (lpfc_check_adisc(phba, ndlp, pnn, ppn))) {
+ if (icmd->ulpStatus == 0 && lpfc_check_adisc(vport, ndlp, pnn, ppn)) {
if (cmd == ELS_CMD_ADISC) {
- lpfc_els_rsp_adisc_acc(phba, cmdiocb, ndlp);
+ lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp);
} else {
- lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp,
- NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp,
+ NULL, 0);
}
return 1;
}
@@ -427,55 +461,57 @@
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
/* 1 sec timeout */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
return 0;
}
static int
-lpfc_rcv_logo(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp,
- struct lpfc_iocbq *cmdiocb,
- uint32_t els_cmd)
+lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct lpfc_iocbq *cmdiocb, uint32_t els_cmd)
{
- /* Put ndlp on NPR list with 1 sec timeout for plogi, ACC logo */
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ /* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */
/* Only call LOGO ACC for first LOGO, this avoids sending unnecessary
* PLOGIs during LOGO storms from a device.
*/
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_LOGO_ACC;
+ spin_unlock_irq(shost->host_lock);
if (els_cmd == ELS_CMD_PRLO)
- lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
else
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
if (!(ndlp->nlp_type & NLP_FABRIC) ||
- (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
+ (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
/* Only try to re-login if this is NOT a Fabric Node */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
} else {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
}
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
/* The driver has to wait until the ACC completes before it continues
* processing the LOGO. The action will resume in
* lpfc_cmpl_els_logo_acc routine. Since part of processing includes an
@@ -485,9 +521,8 @@
}
static void
-lpfc_rcv_prli(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp,
- struct lpfc_iocbq *cmdiocb)
+lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct lpfc_iocbq *cmdiocb)
{
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
@@ -501,8 +536,7 @@
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
- if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) &&
- (npr->prliType == PRLI_FCP_TYPE)) {
+ if (npr->prliType == PRLI_FCP_TYPE) {
if (npr->initiatorFunc)
ndlp->nlp_type |= NLP_FCP_INITIATOR;
if (npr->targetFunc)
@@ -517,36 +551,42 @@
roles |= FC_RPORT_ROLE_FCP_INITIATOR;
if (ndlp->nlp_type & NLP_FCP_TARGET)
roles |= FC_RPORT_ROLE_FCP_TARGET;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+ "rport rolechg: role:x%x did:x%x flg:x%x",
+ roles, ndlp->nlp_DID, ndlp->nlp_flag);
+
fc_remote_port_rolechg(rport, roles);
}
}
static uint32_t
-lpfc_disc_set_adisc(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp)
+lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+
/* Check config parameter use-adisc or FCP-2 */
- if ((phba->cfg_use_adisc == 0) &&
- !(phba->fc_flag & FC_RSCN_MODE)) {
- if (!(ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE))
- return 0;
+ if ((phba->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
+ ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_NPR_ADISC;
+ spin_unlock_irq(shost->host_lock);
+ return 1;
}
- spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag |= NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
- return 1;
+ ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+ lpfc_unreg_rpi(vport, ndlp);
+ return 0;
}
static uint32_t
-lpfc_disc_illegal(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_DISCOVERY,
- "%d:0253 Illegal State Transition: node x%x event x%x, "
- "state x%x Data: x%x x%x\n",
- phba->brd_no,
+ lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0253 Illegal State Transition: node x%x "
+ "event x%x, state x%x Data: x%x x%x\n",
+ vport->phba->brd_no, vport->vpi,
ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
ndlp->nlp_flag);
return ndlp->nlp_state;
@@ -555,151 +595,162 @@
/* Start of Discovery State Machine routines */
static uint32_t
-lpfc_rcv_plogi_unused_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
- if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
+ if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
}
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
static uint32_t
-lpfc_rcv_els_unused_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- lpfc_issue_els_logo(phba, ndlp, 0);
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
+ lpfc_issue_els_logo(vport, ndlp, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_unused_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_LOGO_ACC;
- spin_unlock_irq(phba->host->host_lock);
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_logo_unused_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
-{
- lpfc_drop_node(phba, ndlp);
- return NLP_STE_FREED_NODE;
-}
-
-static uint32_t
-lpfc_device_rm_unused_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
-{
- lpfc_drop_node(phba, ndlp);
- return NLP_STE_FREED_NODE;
-}
-
-static uint32_t
-lpfc_rcv_plogi_plogi_issue(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
void *arg, uint32_t evt)
{
+ lpfc_drop_node(vport, ndlp);
+ return NLP_STE_FREED_NODE;
+}
+
+static uint32_t
+lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
+{
+ lpfc_drop_node(vport, ndlp);
+ return NLP_STE_FREED_NODE;
+}
+
+static uint32_t
+lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
+{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb = arg;
- struct lpfc_dmabuf *pcmd;
- struct serv_parm *sp;
- uint32_t *lp;
+ struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ uint32_t *lp = (uint32_t *) pcmd->virt;
+ struct serv_parm *sp = (struct serv_parm *) (lp + 1);
struct ls_rjt stat;
int port_cmp;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
- lp = (uint32_t *) pcmd->virt;
- sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
-
memset(&stat, 0, sizeof (struct ls_rjt));
/* For a PLOGI, we only accept if our portname is less
* than the remote portname.
*/
phba->fc_stat.elsLogiCol++;
- port_cmp = memcmp(&phba->fc_portname, &sp->portName,
- sizeof (struct lpfc_name));
+ port_cmp = memcmp(&vport->fc_portname, &sp->portName,
+ sizeof(struct lpfc_name));
if (port_cmp >= 0) {
/* Reject this request because the remote node will accept
ours */
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+ NULL);
} else {
- lpfc_rcv_plogi(phba, ndlp, cmdiocb);
- } /* if our portname was less */
+ lpfc_rcv_plogi(vport, ndlp, cmdiocb);
+ } /* If our portname was less */
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_plogi_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prli_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
+ struct ls_rjt stat;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- /* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp);
-
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ memset(&stat, 0, sizeof (struct ls_rjt));
+ stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
+ stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_els_plogi_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
+ /* software abort outstanding PLOGI */
+ lpfc_els_abort(vport->phba, ndlp);
+
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
+ return ndlp->nlp_state;
+}
+
+static uint32_t
+lpfc_rcv_els_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
/* software abort outstanding PLOGI */
lpfc_els_abort(phba, ndlp);
if (evt == NLP_EVT_RCV_LOGO) {
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
} else {
- lpfc_issue_els_logo(phba, ndlp, 0);
+ lpfc_issue_els_logo(vport, ndlp, 0);
}
- /* Put ndlp in npr list set plogi timer for 1 sec */
+ /* Put ndlp in npr state set plogi timer for 1 sec */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb, *rspiocb;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *cmdiocb, *rspiocb;
struct lpfc_dmabuf *pcmd, *prsp, *mp;
uint32_t *lp;
IOCB_t *irsp;
@@ -721,31 +772,26 @@
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
- prsp = list_get_first(&pcmd->list,
- struct lpfc_dmabuf,
- list);
- lp = (uint32_t *) prsp->virt;
+ prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
+ lp = (uint32_t *) prsp->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
- if (!lpfc_check_sparm(phba, ndlp, sp, CLASS3))
+ if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3))
goto out;
/* PLOGI chkparm OK */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_ELS,
- "%d:0121 PLOGI chkparm OK "
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0121 PLOGI chkparm OK "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
ndlp->nlp_DID, ndlp->nlp_state,
ndlp->nlp_flag, ndlp->nlp_rpi);
- if ((phba->cfg_fcp_class == 2) &&
- (sp->cls2.classValid)) {
+ if (phba->cfg_fcp_class == 2 && (sp->cls2.classValid))
ndlp->nlp_fcp_info |= CLASS2;
- } else {
+ else
ndlp->nlp_fcp_info |= CLASS3;
- }
+
ndlp->nlp_class_sup = 0;
if (sp->cls1.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS1;
@@ -756,16 +802,23 @@
if (sp->cls4.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS4;
ndlp->nlp_maxframe =
- ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
- sp->cmn.bbRcvSizeLsb;
+ ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
- if (!(mbox = mempool_alloc(phba->mbox_mem_pool,
- GFP_KERNEL)))
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0133 PLOGI: no memory for reg_login "
+ "Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi,
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
goto out;
+ }
- lpfc_unreg_rpi(phba, ndlp);
- if (lpfc_reg_login(phba, irsp->un.elsreq64.remoteID, (uint8_t *) sp,
- mbox, 0) == 0) {
+ lpfc_unreg_rpi(vport, ndlp);
+
+ if (lpfc_reg_login(phba, vport->vpi, irsp->un.elsreq64.remoteID,
+ (uint8_t *) sp, mbox, 0) == 0) {
switch (ndlp->nlp_DID) {
case NameServer_DID:
mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
@@ -777,68 +830,104 @@
mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
}
mbox->context2 = lpfc_nlp_get(ndlp);
+ mbox->vport = vport;
if (lpfc_sli_issue_mbox(phba, mbox,
(MBX_NOWAIT | MBX_STOP_IOCB))
!= MBX_NOT_FINISHED) {
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE);
+ lpfc_nlp_set_state(vport, ndlp,
+ NLP_STE_REG_LOGIN_ISSUE);
return ndlp->nlp_state;
}
lpfc_nlp_put(ndlp);
- mp = (struct lpfc_dmabuf *)mbox->context1;
+ mp = (struct lpfc_dmabuf *) mbox->context1;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free(mbox, phba->mbox_mem_pool);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0134 PLOGI: cannot issue reg_login "
+ "Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi,
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
} else {
mempool_free(mbox, phba->mbox_mem_pool);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0135 PLOGI: cannot format reg_login "
+ "Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi,
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
}
- out:
+out:
+ if (ndlp->nlp_DID == NameServer_DID) {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0261 Cannot Register NameServer login\n",
+ phba->brd_no, vport->vpi);
+ }
+
/* Free this node since the driver cannot login or has the wrong
sparm */
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
static uint32_t
-lpfc_device_rm_plogi_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
- ndlp->nlp_flag |= NLP_NODEV_REMOVE;
- return ndlp->nlp_state;
- }
- else {
- /* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp);
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- lpfc_drop_node(phba, ndlp);
+ if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ spin_unlock_irq(shost->host_lock);
+ return ndlp->nlp_state;
+ } else {
+ /* software abort outstanding PLOGI */
+ lpfc_els_abort(vport->phba, ndlp);
+
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
}
static uint32_t
-lpfc_device_recov_plogi_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_recov_plogi_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+
+ /* Don't do anything that will mess up processing of the
+ * previous RSCN.
+ */
+ if (vport->fc_flag & FC_RSCN_DEFERRED)
+ return ndlp->nlp_state;
+
/* software abort outstanding PLOGI */
lpfc_els_abort(phba, ndlp);
ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb;
/* software abort outstanding ADISC */
@@ -846,34 +935,31 @@
cmdiocb = (struct lpfc_iocbq *) arg;
- if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
+ if (lpfc_rcv_plogi(vport, ndlp, cmdiocb))
return ndlp->nlp_state;
- }
+
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prli_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_prli_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+ lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_logo_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
@@ -881,42 +967,43 @@
/* software abort outstanding ADISC */
lpfc_els_abort(phba, ndlp);
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_padisc_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_padisc_adisc_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+ lpfc_rcv_padisc(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prlo_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_prlo_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
/* Treat like rcv logo */
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_PRLO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_adisc_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb, *rspiocb;
IOCB_t *irsp;
ADISC *ap;
@@ -928,101 +1015,112 @@
irsp = &rspiocb->iocb;
if ((irsp->ulpStatus) ||
- (!lpfc_check_adisc(phba, ndlp, &ap->nodeName, &ap->portName))) {
+ (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) {
/* 1 sec timeout */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
- memset(&ndlp->nlp_nodename, 0, sizeof (struct lpfc_name));
- memset(&ndlp->nlp_portname, 0, sizeof (struct lpfc_name));
+ memset(&ndlp->nlp_nodename, 0, sizeof(struct lpfc_name));
+ memset(&ndlp->nlp_portname, 0, sizeof(struct lpfc_name));
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ lpfc_unreg_rpi(vport, ndlp);
return ndlp->nlp_state;
}
if (ndlp->nlp_type & NLP_FCP_TARGET) {
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_MAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
} else {
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_device_rm_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_rm_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
- ndlp->nlp_flag |= NLP_NODEV_REMOVE;
- return ndlp->nlp_state;
- }
- else {
- /* software abort outstanding ADISC */
- lpfc_els_abort(phba, ndlp);
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- lpfc_drop_node(phba, ndlp);
+ if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ spin_unlock_irq(shost->host_lock);
+ return ndlp->nlp_state;
+ } else {
+ /* software abort outstanding ADISC */
+ lpfc_els_abort(vport->phba, ndlp);
+
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
}
static uint32_t
-lpfc_device_recov_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_recov_adisc_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+
+ /* Don't do anything that will mess up processing of the
+ * previous RSCN.
+ */
+ if (vport->fc_flag & FC_RSCN_DEFERRED)
+ return ndlp->nlp_state;
+
/* software abort outstanding ADISC */
lpfc_els_abort(phba, ndlp);
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- ndlp->nlp_flag |= NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
-
+ spin_unlock_irq(shost->host_lock);
+ lpfc_disc_set_adisc(vport, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_plogi_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_rcv_plogi_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+ lpfc_rcv_plogi(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prli_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+ lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
LPFC_MBOXQ_t *mb;
LPFC_MBOXQ_t *nextmb;
struct lpfc_dmabuf *mp;
@@ -1033,12 +1131,13 @@
if ((mb = phba->sli.mbox_active)) {
if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
(ndlp == (struct lpfc_nodelist *) mb->context2)) {
+ lpfc_nlp_put(ndlp);
mb->context2 = NULL;
mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
}
}
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
(ndlp == (struct lpfc_nodelist *) mb->context2)) {
@@ -1047,61 +1146,61 @@
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
}
+ lpfc_nlp_put(ndlp);
list_del(&mb->list);
mempool_free(mb, phba->mbox_mem_pool);
}
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_padisc_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_rcv_padisc_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+ lpfc_rcv_padisc(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prlo_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_rcv_prlo_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp,
- void *arg, uint32_t evt)
+lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
- LPFC_MBOXQ_t *pmb;
- MAILBOX_t *mb;
- uint32_t did;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
+ MAILBOX_t *mb = &pmb->mb;
+ uint32_t did = mb->un.varWords[1];
- pmb = (LPFC_MBOXQ_t *) arg;
- mb = &pmb->mb;
- did = mb->un.varWords[1];
if (mb->mbxStatus) {
/* RegLogin failed */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_DISCOVERY,
- "%d:0246 RegLogin failed Data: x%x x%x x%x\n",
- phba->brd_no,
- did, mb->mbxStatus, phba->hba_state);
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0246 RegLogin failed Data: x%x x%x "
+ "x%x\n",
+ phba->brd_no, vport->vpi,
+ did, mb->mbxStatus, vport->port_state);
/*
* If RegLogin failed due to lack of HBA resources do not
@@ -1109,20 +1208,20 @@
*/
if (mb->mbxStatus == MBXERR_RPI_FULL) {
ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
}
- /* Put ndlp in npr list set plogi timer for 1 sec */
+ /* Put ndlp in npr state set plogi timer for 1 sec */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
- lpfc_issue_els_logo(phba, ndlp, 0);
+ lpfc_issue_els_logo(vport, ndlp, 0);
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
return ndlp->nlp_state;
}
@@ -1131,91 +1230,99 @@
/* Only if we are not a fabric nport do we issue PRLI */
if (!(ndlp->nlp_type & NLP_FABRIC)) {
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
- lpfc_issue_els_prli(phba, ndlp, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
+ lpfc_issue_els_prli(vport, ndlp, 0);
} else {
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_device_rm_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_device_rm_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
- if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ spin_unlock_irq(shost->host_lock);
return ndlp->nlp_state;
- }
- else {
- lpfc_drop_node(phba, ndlp);
+ } else {
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
}
static uint32_t
-lpfc_device_recov_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ /* Don't do anything that will mess up processing of the
+ * previous RSCN.
+ */
+ if (vport->fc_flag & FC_RSCN_DEFERRED)
+ return ndlp->nlp_state;
+
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_disc_set_adisc(vport, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_plogi_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_plogi_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+ lpfc_rcv_plogi(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prli_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+ lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_logo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
/* Software abort outstanding PRLI before sending acc */
- lpfc_els_abort(phba, ndlp);
+ lpfc_els_abort(vport->phba, ndlp);
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_padisc_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_padisc_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+ lpfc_rcv_padisc(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
@@ -1225,21 +1332,22 @@
* NEXT STATE = PRLI_ISSUE
*/
static uint32_t
-lpfc_rcv_prlo_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prlo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_iocbq *cmdiocb, *rspiocb;
+ struct lpfc_hba *phba = vport->phba;
IOCB_t *irsp;
PRLI *npr;
@@ -1249,8 +1357,12 @@
irsp = &rspiocb->iocb;
if (irsp->ulpStatus) {
+ if ((vport->port_type == LPFC_NPIV_PORT) &&
+ phba->cfg_vport_restrict_login) {
+ goto out;
+ }
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
return ndlp->nlp_state;
}
@@ -1266,319 +1378,329 @@
if (npr->Retry)
ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
}
+ if (!(ndlp->nlp_type & NLP_FCP_TARGET) &&
+ (vport->port_type == LPFC_NPIV_PORT) &&
+ phba->cfg_vport_restrict_login) {
+out:
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_TARGET_REMOVE;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_issue_els_logo(vport, ndlp, 0);
+
+ ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+ return ndlp->nlp_state;
+ }
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_MAPPED_NODE);
+ if (ndlp->nlp_type & NLP_FCP_TARGET)
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
+ else
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
return ndlp->nlp_state;
}
/*! lpfc_device_rm_prli_issue
- *
- * \pre
- * \post
- * \param phba
- * \param ndlp
- * \param arg
- * \param evt
- * \return uint32_t
- *
- * \b Description:
- * This routine is envoked when we a request to remove a nport we are in the
- * process of PRLIing. We should software abort outstanding prli, unreg
- * login, send a logout. We will change node state to UNUSED_NODE, put it
- * on plogi list so it can be freed when LOGO completes.
- *
- */
-static uint32_t
-lpfc_device_rm_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
-{
- if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
- ndlp->nlp_flag |= NLP_NODEV_REMOVE;
- return ndlp->nlp_state;
- }
- else {
- /* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp);
+ *
+ * \pre
+ * \post
+ * \param phba
+ * \param ndlp
+ * \param arg
+ * \param evt
+ * \return uint32_t
+ *
+ * \b Description:
+ * This routine is envoked when we a request to remove a nport we are in the
+ * process of PRLIing. We should software abort outstanding prli, unreg
+ * login, send a logout. We will change node state to UNUSED_NODE, put it
+ * on plogi list so it can be freed when LOGO completes.
+ *
+ */
- lpfc_drop_node(phba, ndlp);
+static uint32_t
+lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ spin_unlock_irq(shost->host_lock);
+ return ndlp->nlp_state;
+ } else {
+ /* software abort outstanding PLOGI */
+ lpfc_els_abort(vport->phba, ndlp);
+
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
}
/*! lpfc_device_recov_prli_issue
- *
- * \pre
- * \post
- * \param phba
- * \param ndlp
- * \param arg
- * \param evt
- * \return uint32_t
- *
- * \b Description:
- * The routine is envoked when the state of a device is unknown, like
- * during a link down. We should remove the nodelist entry from the
- * unmapped list, issue a UNREG_LOGIN, do a software abort of the
- * outstanding PRLI command, then free the node entry.
- */
+ *
+ * \pre
+ * \post
+ * \param phba
+ * \param ndlp
+ * \param arg
+ * \param evt
+ * \return uint32_t
+ *
+ * \b Description:
+ * The routine is envoked when the state of a device is unknown, like
+ * during a link down. We should remove the nodelist entry from the
+ * unmapped list, issue a UNREG_LOGIN, do a software abort of the
+ * outstanding PRLI command, then free the node entry.
+ */
static uint32_t
-lpfc_device_recov_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_device_recov_prli_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+
+ /* Don't do anything that will mess up processing of the
+ * previous RSCN.
+ */
+ if (vport->fc_flag & FC_RSCN_DEFERRED)
+ return ndlp->nlp_state;
+
/* software abort outstanding PRLI */
lpfc_els_abort(phba, ndlp);
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_disc_set_adisc(vport, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_plogi_unmap_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_plogi_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+ lpfc_rcv_plogi(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prli_unmap_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prli_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_prli(phba, ndlp, cmdiocb);
- lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+ lpfc_rcv_prli(vport, ndlp, cmdiocb);
+ lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_unmap_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_logo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_padisc_unmap_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_padisc_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+ lpfc_rcv_padisc(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prlo_unmap_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prlo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_device_recov_unmap_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_device_recov_unmap_node(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- lpfc_disc_set_adisc(phba, ndlp);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_disc_set_adisc(vport, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_plogi_mapped_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_plogi_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+ lpfc_rcv_plogi(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prli_mapped_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prli_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+ lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_mapped_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_logo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_padisc_mapped_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_padisc_mapped_node(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+ lpfc_rcv_padisc(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prlo_mapped_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
/* flush the target */
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
- ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
- spin_unlock_irq(phba->host->host_lock);
+ ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
/* Treat like rcv logo */
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_PRLO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_device_recov_mapped_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_recov_mapped_node(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- spin_unlock_irq(phba->host->host_lock);
- lpfc_disc_set_adisc(phba, ndlp);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_disc_set_adisc(vport, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_plogi_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
/* Ignore PLOGI if we have an outstanding LOGO */
- if (ndlp->nlp_flag & NLP_LOGO_SND) {
+ if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC)) {
return ndlp->nlp_state;
}
- if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
- spin_lock_irq(phba->host->host_lock);
+ if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
return ndlp->nlp_state;
}
/* send PLOGI immediately, move to PLOGI issue state */
if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prli_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
- struct ls_rjt stat;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
+ struct ls_rjt stat;
memset(&stat, 0, sizeof (struct ls_rjt));
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
if (ndlp->nlp_flag & NLP_NPR_ADISC) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
- lpfc_issue_els_adisc(phba, ndlp, 0);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
+ lpfc_issue_els_adisc(vport, ndlp, 0);
} else {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
}
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_padisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+ lpfc_rcv_padisc(vport, ndlp, cmdiocb);
/*
* Do not start discovery if discovery is about to start
@@ -1586,53 +1708,52 @@
* here will affect the counting of discovery threads.
*/
if (!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
- !(ndlp->nlp_flag & NLP_NPR_2B_DISC)){
+ !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
if (ndlp->nlp_flag & NLP_NPR_ADISC) {
+ ndlp->nlp_flag &= ~NLP_NPR_ADISC;
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
- lpfc_issue_els_adisc(phba, ndlp, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
+ lpfc_issue_els_adisc(vport, ndlp, 0);
} else {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
}
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prlo_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_prlo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_LOGO_ACC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
- if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
+ if ((ndlp->nlp_flag & NLP_DELAY_TMO) == 0) {
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
} else {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_plogi_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb, *rspiocb;
IOCB_t *irsp;
@@ -1642,15 +1763,15 @@
irsp = &rspiocb->iocb;
if (irsp->ulpStatus) {
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_prli_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_cmpl_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb, *rspiocb;
IOCB_t *irsp;
@@ -1660,25 +1781,24 @@
irsp = &rspiocb->iocb;
if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_logo_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_cmpl_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
/* This routine does nothing, just return the current state */
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_adisc_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_cmpl_adisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb, *rspiocb;
IOCB_t *irsp;
@@ -1688,28 +1808,25 @@
irsp = &rspiocb->iocb;
if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_reglogin_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- LPFC_MBOXQ_t *pmb;
- MAILBOX_t *mb;
-
- pmb = (LPFC_MBOXQ_t *) arg;
- mb = &pmb->mb;
+ LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
+ MAILBOX_t *mb = &pmb->mb;
if (!mb->mbxStatus)
ndlp->nlp_rpi = mb->un.varWords[0];
else {
if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
}
@@ -1717,28 +1834,38 @@
}
static uint32_t
-lpfc_device_rm_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_rm_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ spin_unlock_irq(shost->host_lock);
return ndlp->nlp_state;
}
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
static uint32_t
-lpfc_device_recov_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- spin_lock_irq(phba->host->host_lock);
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ /* Don't do anything that will mess up processing of the
+ * previous RSCN.
+ */
+ if (vport->fc_flag & FC_RSCN_DEFERRED)
+ return ndlp->nlp_state;
+
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
if (ndlp->nlp_flag & NLP_DELAY_TMO) {
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
}
return ndlp->nlp_state;
}
@@ -1801,7 +1928,7 @@
*/
static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
- (struct lpfc_hba *, struct lpfc_nodelist *, void *, uint32_t) = {
+ (struct lpfc_vport *, struct lpfc_nodelist *, void *, uint32_t) = {
/* Action routine Event Current State */
lpfc_rcv_plogi_unused_node, /* RCV_PLOGI UNUSED_NODE */
lpfc_rcv_els_unused_node, /* RCV_PRLI */
@@ -1818,7 +1945,7 @@
lpfc_disc_illegal, /* DEVICE_RECOVERY */
lpfc_rcv_plogi_plogi_issue, /* RCV_PLOGI PLOGI_ISSUE */
- lpfc_rcv_els_plogi_issue, /* RCV_PRLI */
+ lpfc_rcv_prli_plogi_issue, /* RCV_PRLI */
lpfc_rcv_logo_plogi_issue, /* RCV_LOGO */
lpfc_rcv_els_plogi_issue, /* RCV_ADISC */
lpfc_rcv_els_plogi_issue, /* RCV_PDISC */
@@ -1917,35 +2044,41 @@
};
int
-lpfc_disc_state_machine(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
+ struct lpfc_hba *phba = vport->phba;
uint32_t cur_state, rc;
- uint32_t(*func) (struct lpfc_hba *, struct lpfc_nodelist *, void *,
+ uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *,
uint32_t);
lpfc_nlp_get(ndlp);
cur_state = ndlp->nlp_state;
/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0211 DSM in event x%x on NPort x%x in state %d "
- "Data: x%x\n",
- phba->brd_no,
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0211 DSM in event x%x on NPort x%x in "
+ "state %d Data: x%x\n",
+ phba->brd_no, vport->vpi,
evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag);
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
+ "DSM in: evt:%d ste:%d did:x%x",
+ evt, cur_state, ndlp->nlp_DID);
+
func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt];
- rc = (func) (phba, ndlp, arg, evt);
+ rc = (func) (vport, ndlp, arg, evt);
/* DSM out state <rc> on NPort <nlp_DID> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0212 DSM out state %d on NPort x%x Data: x%x\n",
- phba->brd_no,
- rc, ndlp->nlp_DID, ndlp->nlp_flag);
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0212 DSM out state %d on NPort x%x "
+ "Data: x%x\n",
+ phba->brd_no, vport->vpi,
+ rc, ndlp->nlp_DID, ndlp->nlp_flag);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
+ "DSM out: ste:%d did:x%x flg:x%x",
+ rc, ndlp->nlp_DID, ndlp->nlp_flag);
lpfc_nlp_put(ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 9a12d05..8f45bbc 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -37,10 +37,158 @@
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
#define LPFC_RESET_WAIT 2
#define LPFC_ABORT_WAIT 2
+/*
+ * This function is called with no lock held when there is a resource
+ * error in driver or in firmware.
+ */
+void
+lpfc_adjust_queue_depth(struct lpfc_hba *phba)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&phba->hbalock, flags);
+ atomic_inc(&phba->num_rsrc_err);
+ phba->last_rsrc_error_time = jiffies;
+
+ if ((phba->last_ramp_down_time + QUEUE_RAMP_DOWN_INTERVAL) > jiffies) {
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ return;
+ }
+
+ phba->last_ramp_down_time = jiffies;
+
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+
+ spin_lock_irqsave(&phba->pport->work_port_lock, flags);
+ if ((phba->pport->work_port_events &
+ WORKER_RAMP_DOWN_QUEUE) == 0) {
+ phba->pport->work_port_events |= WORKER_RAMP_DOWN_QUEUE;
+ }
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
+
+ spin_lock_irqsave(&phba->hbalock, flags);
+ if (phba->work_wait)
+ wake_up(phba->work_wait);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+
+ return;
+}
+
+/*
+ * This function is called with no lock held when there is a successful
+ * SCSI command completion.
+ */
+static inline void
+lpfc_rampup_queue_depth(struct lpfc_hba *phba,
+ struct scsi_device *sdev)
+{
+ unsigned long flags;
+ atomic_inc(&phba->num_cmd_success);
+
+ if (phba->cfg_lun_queue_depth <= sdev->queue_depth)
+ return;
+
+ spin_lock_irqsave(&phba->hbalock, flags);
+ if (((phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) > jiffies) ||
+ ((phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL ) > jiffies)) {
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ return;
+ }
+
+ phba->last_ramp_up_time = jiffies;
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+
+ spin_lock_irqsave(&phba->pport->work_port_lock, flags);
+ if ((phba->pport->work_port_events &
+ WORKER_RAMP_UP_QUEUE) == 0) {
+ phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE;
+ }
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
+
+ spin_lock_irqsave(&phba->hbalock, flags);
+ if (phba->work_wait)
+ wake_up(phba->work_wait);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+}
+
+void
+lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport;
+ struct Scsi_Host *host;
+ struct scsi_device *sdev;
+ unsigned long new_queue_depth;
+ unsigned long num_rsrc_err, num_cmd_success;
+
+ num_rsrc_err = atomic_read(&phba->num_rsrc_err);
+ num_cmd_success = atomic_read(&phba->num_cmd_success);
+
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ host = lpfc_shost_from_vport(vport);
+ if (!scsi_host_get(host))
+ continue;
+
+ spin_unlock_irq(&phba->hbalock);
+
+ shost_for_each_device(sdev, host) {
+ new_queue_depth = sdev->queue_depth * num_rsrc_err /
+ (num_rsrc_err + num_cmd_success);
+ if (!new_queue_depth)
+ new_queue_depth = sdev->queue_depth - 1;
+ else
+ new_queue_depth =
+ sdev->queue_depth - new_queue_depth;
+
+ if (sdev->ordered_tags)
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+ new_queue_depth);
+ else
+ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
+ new_queue_depth);
+ }
+ spin_lock_irq(&phba->hbalock);
+ scsi_host_put(host);
+ }
+ spin_unlock_irq(&phba->hbalock);
+ atomic_set(&phba->num_rsrc_err, 0);
+ atomic_set(&phba->num_cmd_success, 0);
+}
+
+void
+lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport;
+ struct Scsi_Host *host;
+ struct scsi_device *sdev;
+
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ host = lpfc_shost_from_vport(vport);
+ if (!scsi_host_get(host))
+ continue;
+
+ spin_unlock_irq(&phba->hbalock);
+ shost_for_each_device(sdev, host) {
+ if (sdev->ordered_tags)
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+ sdev->queue_depth+1);
+ else
+ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
+ sdev->queue_depth+1);
+ }
+ spin_lock_irq(&phba->hbalock);
+ scsi_host_put(host);
+ }
+ spin_unlock_irq(&phba->hbalock);
+ atomic_set(&phba->num_rsrc_err, 0);
+ atomic_set(&phba->num_cmd_success, 0);
+}
/*
* This routine allocates a scsi buffer, which contains all the necessary
@@ -51,8 +199,9 @@
* and the BPL BDE is setup in the IOCB.
*/
static struct lpfc_scsi_buf *
-lpfc_new_scsi_buf(struct lpfc_hba * phba)
+lpfc_new_scsi_buf(struct lpfc_vport *vport)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_scsi_buf *psb;
struct ulp_bde64 *bpl;
IOCB_t *iocb;
@@ -63,7 +212,6 @@
if (!psb)
return NULL;
memset(psb, 0, sizeof (struct lpfc_scsi_buf));
- psb->scsi_hba = phba;
/*
* Get memory from the pci pool to map the virt space to pci bus space
@@ -155,7 +303,7 @@
}
static void
-lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
+lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
{
unsigned long iflag = 0;
@@ -166,7 +314,7 @@
}
static int
-lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
+lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
{
struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
struct scatterlist *sgel = NULL;
@@ -175,8 +323,7 @@
IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
dma_addr_t physaddr;
uint32_t i, num_bde = 0;
- int datadir = scsi_cmnd->sc_data_direction;
- int dma_error;
+ int nseg, datadir = scsi_cmnd->sc_data_direction;
/*
* There are three possibilities here - use scatter-gather segment, use
@@ -185,26 +332,26 @@
* data bde entry.
*/
bpl += 2;
- if (scsi_cmnd->use_sg) {
+ if (scsi_sg_count(scsi_cmnd)) {
/*
* The driver stores the segment count returned from pci_map_sg
* because this a count of dma-mappings used to map the use_sg
* pages. They are not guaranteed to be the same for those
* architectures that implement an IOMMU.
*/
- sgel = (struct scatterlist *)scsi_cmnd->request_buffer;
- lpfc_cmd->seg_cnt = dma_map_sg(&phba->pcidev->dev, sgel,
- scsi_cmnd->use_sg, datadir);
- if (lpfc_cmd->seg_cnt == 0)
+
+ nseg = dma_map_sg(&phba->pcidev->dev, scsi_sglist(scsi_cmnd),
+ scsi_sg_count(scsi_cmnd), datadir);
+ if (unlikely(!nseg))
return 1;
+ lpfc_cmd->seg_cnt = nseg;
if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
printk(KERN_ERR "%s: Too many sg segments from "
"dma_map_sg. Config %d, seg_cnt %d",
__FUNCTION__, phba->cfg_sg_seg_cnt,
lpfc_cmd->seg_cnt);
- dma_unmap_sg(&phba->pcidev->dev, sgel,
- lpfc_cmd->seg_cnt, datadir);
+ scsi_dma_unmap(scsi_cmnd);
return 1;
}
@@ -214,7 +361,7 @@
* single scsi command. Just run through the seg_cnt and format
* the bde's.
*/
- for (i = 0; i < lpfc_cmd->seg_cnt; i++) {
+ scsi_for_each_sg(scsi_cmnd, sgel, nseg, i) {
physaddr = sg_dma_address(sgel);
bpl->addrLow = le32_to_cpu(putPaddrLow(physaddr));
bpl->addrHigh = le32_to_cpu(putPaddrHigh(physaddr));
@@ -225,34 +372,8 @@
bpl->tus.f.bdeFlags = BUFF_USE_RCV;
bpl->tus.w = le32_to_cpu(bpl->tus.w);
bpl++;
- sgel++;
num_bde++;
}
- } else if (scsi_cmnd->request_buffer && scsi_cmnd->request_bufflen) {
- physaddr = dma_map_single(&phba->pcidev->dev,
- scsi_cmnd->request_buffer,
- scsi_cmnd->request_bufflen,
- datadir);
- dma_error = dma_mapping_error(physaddr);
- if (dma_error) {
- lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0718 Unable to dma_map_single "
- "request_buffer: x%x\n",
- phba->brd_no, dma_error);
- return 1;
- }
-
- lpfc_cmd->nonsg_phys = physaddr;
- bpl->addrLow = le32_to_cpu(putPaddrLow(physaddr));
- bpl->addrHigh = le32_to_cpu(putPaddrHigh(physaddr));
- bpl->tus.f.bdeSize = scsi_cmnd->request_bufflen;
- if (datadir == DMA_TO_DEVICE)
- bpl->tus.f.bdeFlags = 0;
- else
- bpl->tus.f.bdeFlags = BUFF_USE_RCV;
- bpl->tus.w = le32_to_cpu(bpl->tus.w);
- num_bde = 1;
- bpl++;
}
/*
@@ -266,7 +387,7 @@
(num_bde * sizeof (struct ulp_bde64));
iocb_cmd->ulpBdeCount = 1;
iocb_cmd->ulpLe = 1;
- fcp_cmnd->fcpDl = be32_to_cpu(scsi_cmnd->request_bufflen);
+ fcp_cmnd->fcpDl = be32_to_cpu(scsi_bufflen(scsi_cmnd));
return 0;
}
@@ -279,26 +400,20 @@
* a request buffer, but did not request use_sg. There is a third
* case, but it does not require resource deallocation.
*/
- if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) {
- dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer,
- psb->seg_cnt, psb->pCmd->sc_data_direction);
- } else {
- if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) {
- dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys,
- psb->pCmd->request_bufflen,
- psb->pCmd->sc_data_direction);
- }
- }
+ if (psb->seg_cnt > 0)
+ scsi_dma_unmap(psb->pCmd);
}
static void
-lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb)
+lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+ struct lpfc_iocbq *rsp_iocb)
{
struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
- struct lpfc_hba *phba = lpfc_cmd->scsi_hba;
+ struct lpfc_hba *phba = vport->phba;
uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm;
+ uint32_t vpi = vport->vpi;
uint32_t resp_info = fcprsp->rspStatus2;
uint32_t scsi_status = fcprsp->rspStatus3;
uint32_t *lp;
@@ -331,9 +446,9 @@
logit = LOG_FCP;
lpfc_printf_log(phba, KERN_WARNING, logit,
- "%d:0730 FCP command x%x failed: x%x SNS x%x x%x "
+ "%d (%d):0730 FCP command x%x failed: x%x SNS x%x x%x "
"Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no, cmnd->cmnd[0], scsi_status,
+ phba->brd_no, vpi, cmnd->cmnd[0], scsi_status,
be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info,
be32_to_cpu(fcprsp->rspResId),
be32_to_cpu(fcprsp->rspSnsLen),
@@ -349,15 +464,16 @@
}
}
- cmnd->resid = 0;
+ scsi_set_resid(cmnd, 0);
if (resp_info & RESID_UNDER) {
- cmnd->resid = be32_to_cpu(fcprsp->rspResId);
+ scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0716 FCP Read Underrun, expected %d, "
- "residual %d Data: x%x x%x x%x\n", phba->brd_no,
- be32_to_cpu(fcpcmd->fcpDl), cmnd->resid,
- fcpi_parm, cmnd->cmnd[0], cmnd->underflow);
+ "%d (%d):0716 FCP Read Underrun, expected %d, "
+ "residual %d Data: x%x x%x x%x\n",
+ phba->brd_no, vpi, be32_to_cpu(fcpcmd->fcpDl),
+ scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
+ cmnd->underflow);
/*
* If there is an under run check if under run reported by
@@ -366,15 +482,16 @@
*/
if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) &&
fcpi_parm &&
- (cmnd->resid != fcpi_parm)) {
+ (scsi_get_resid(cmnd) != fcpi_parm)) {
lpfc_printf_log(phba, KERN_WARNING,
- LOG_FCP | LOG_FCP_ERROR,
- "%d:0735 FCP Read Check Error and Underrun "
- "Data: x%x x%x x%x x%x\n", phba->brd_no,
- be32_to_cpu(fcpcmd->fcpDl),
- cmnd->resid,
- fcpi_parm, cmnd->cmnd[0]);
- cmnd->resid = cmnd->request_bufflen;
+ LOG_FCP | LOG_FCP_ERROR,
+ "%d (%d):0735 FCP Read Check Error "
+ "and Underrun Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vpi,
+ be32_to_cpu(fcpcmd->fcpDl),
+ scsi_get_resid(cmnd), fcpi_parm,
+ cmnd->cmnd[0]);
+ scsi_set_resid(cmnd, scsi_bufflen(cmnd));
host_status = DID_ERROR;
}
/*
@@ -385,22 +502,23 @@
*/
if (!(resp_info & SNS_LEN_VALID) &&
(scsi_status == SAM_STAT_GOOD) &&
- (cmnd->request_bufflen - cmnd->resid) < cmnd->underflow) {
+ (scsi_bufflen(cmnd) - scsi_get_resid(cmnd)
+ < cmnd->underflow)) {
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0717 FCP command x%x residual "
+ "%d (%d):0717 FCP command x%x residual "
"underrun converted to error "
- "Data: x%x x%x x%x\n", phba->brd_no,
- cmnd->cmnd[0], cmnd->request_bufflen,
- cmnd->resid, cmnd->underflow);
-
+ "Data: x%x x%x x%x\n",
+ phba->brd_no, vpi, cmnd->cmnd[0],
+ scsi_bufflen(cmnd),
+ scsi_get_resid(cmnd), cmnd->underflow);
host_status = DID_ERROR;
}
} else if (resp_info & RESID_OVER) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0720 FCP command x%x residual "
+ "%d (%d):0720 FCP command x%x residual "
"overrun error. Data: x%x x%x \n",
- phba->brd_no, cmnd->cmnd[0],
- cmnd->request_bufflen, cmnd->resid);
+ phba->brd_no, vpi, cmnd->cmnd[0],
+ scsi_bufflen(cmnd), scsi_get_resid(cmnd));
host_status = DID_ERROR;
/*
@@ -410,13 +528,14 @@
} else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm &&
(cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
- "%d:0734 FCP Read Check Error Data: "
- "x%x x%x x%x x%x\n", phba->brd_no,
- be32_to_cpu(fcpcmd->fcpDl),
- be32_to_cpu(fcprsp->rspResId),
- fcpi_parm, cmnd->cmnd[0]);
+ "%d (%d):0734 FCP Read Check Error Data: "
+ "x%x x%x x%x x%x\n",
+ phba->brd_no, vpi,
+ be32_to_cpu(fcpcmd->fcpDl),
+ be32_to_cpu(fcprsp->rspResId),
+ fcpi_parm, cmnd->cmnd[0]);
host_status = DID_ERROR;
- cmnd->resid = cmnd->request_bufflen;
+ scsi_set_resid(cmnd, scsi_bufflen(cmnd));
}
out:
@@ -429,9 +548,13 @@
{
struct lpfc_scsi_buf *lpfc_cmd =
(struct lpfc_scsi_buf *) pIocbIn->context1;
+ struct lpfc_vport *vport = pIocbIn->vport;
struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
struct lpfc_nodelist *pnode = rdata->pnode;
struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
+ uint32_t vpi = (lpfc_cmd->cur_iocbq.vport
+ ? lpfc_cmd->cur_iocbq.vport->vpi
+ : 0);
int result;
struct scsi_device *sdev, *tmp_sdev;
int depth = 0;
@@ -447,22 +570,31 @@
lpfc_cmd->status = IOSTAT_DEFAULT;
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0729 FCP cmd x%x failed <%d/%d> status: "
- "x%x result: x%x Data: x%x x%x\n",
- phba->brd_no, cmd->cmnd[0], cmd->device->id,
- cmd->device->lun, lpfc_cmd->status,
- lpfc_cmd->result, pIocbOut->iocb.ulpContext,
+ "%d (%d):0729 FCP cmd x%x failed <%d/%d> "
+ "status: x%x result: x%x Data: x%x x%x\n",
+ phba->brd_no, vpi, cmd->cmnd[0],
+ cmd->device ? cmd->device->id : 0xffff,
+ cmd->device ? cmd->device->lun : 0xffff,
+ lpfc_cmd->status, lpfc_cmd->result,
+ pIocbOut->iocb.ulpContext,
lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
switch (lpfc_cmd->status) {
case IOSTAT_FCP_RSP_ERROR:
/* Call FCP RSP handler to determine result */
- lpfc_handle_fcp_err(lpfc_cmd,pIocbOut);
+ lpfc_handle_fcp_err(vport, lpfc_cmd, pIocbOut);
break;
case IOSTAT_NPORT_BSY:
case IOSTAT_FABRIC_BSY:
cmd->result = ScsiResult(DID_BUS_BUSY, 0);
break;
+ case IOSTAT_LOCAL_REJECT:
+ if (lpfc_cmd->result == RJT_UNAVAIL_PERM ||
+ lpfc_cmd->result == IOERR_NO_RESOURCES ||
+ lpfc_cmd->result == RJT_LOGIN_REQUIRED) {
+ cmd->result = ScsiResult(DID_REQUEUE, 0);
+ break;
+ } /* else: fall through */
default:
cmd->result = ScsiResult(DID_ERROR, 0);
break;
@@ -479,11 +611,12 @@
uint32_t *lp = (uint32_t *)cmd->sense_buffer;
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0710 Iodone <%d/%d> cmd %p, error x%x "
- "SNS x%x x%x Data: x%x x%x\n",
- phba->brd_no, cmd->device->id,
+ "%d (%d):0710 Iodone <%d/%d> cmd %p, error "
+ "x%x SNS x%x x%x Data: x%x x%x\n",
+ phba->brd_no, vpi, cmd->device->id,
cmd->device->lun, cmd, cmd->result,
- *lp, *(lp + 3), cmd->retries, cmd->resid);
+ *lp, *(lp + 3), cmd->retries,
+ scsi_get_resid(cmd));
}
result = cmd->result;
@@ -496,6 +629,10 @@
return;
}
+
+ if (!result)
+ lpfc_rampup_queue_depth(phba, sdev);
+
if (!result && pnode != NULL &&
((jiffies - pnode->last_ramp_up_time) >
LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
@@ -534,7 +671,7 @@
tmp_sdev->queue_depth - 1);
}
/*
- * The queue depth cannot be lowered any more.
+ * The queue depth cannot be lowered any more.
* Modify the returned error code to store
* the final depth value set by
* scsi_track_queue_full.
@@ -544,8 +681,9 @@
if (depth) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0711 detected queue full - lun queue depth "
- " adjusted to %d.\n", phba->brd_no, depth);
+ "%d (%d):0711 detected queue full - "
+ "lun queue depth adjusted to %d.\n",
+ phba->brd_no, vpi, depth);
}
}
@@ -553,9 +691,10 @@
}
static void
-lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd,
- struct lpfc_nodelist *pnode)
+lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+ struct lpfc_nodelist *pnode)
{
+ struct lpfc_hba *phba = vport->phba;
struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd;
IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
@@ -592,7 +731,7 @@
* bumping the bpl beyond the fcp_cmnd and fcp_rsp regions to the first
* data bde entry.
*/
- if (scsi_cmnd->use_sg) {
+ if (scsi_sg_count(scsi_cmnd)) {
if (datadir == DMA_TO_DEVICE) {
iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR;
iocb_cmd->un.fcpi.fcpi_parm = 0;
@@ -602,23 +741,7 @@
} else {
iocb_cmd->ulpCommand = CMD_FCP_IREAD64_CR;
iocb_cmd->ulpPU = PARM_READ_CHECK;
- iocb_cmd->un.fcpi.fcpi_parm =
- scsi_cmnd->request_bufflen;
- fcp_cmnd->fcpCntl3 = READ_DATA;
- phba->fc4InputRequests++;
- }
- } else if (scsi_cmnd->request_buffer && scsi_cmnd->request_bufflen) {
- if (datadir == DMA_TO_DEVICE) {
- iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR;
- iocb_cmd->un.fcpi.fcpi_parm = 0;
- iocb_cmd->ulpPU = 0;
- fcp_cmnd->fcpCntl3 = WRITE_DATA;
- phba->fc4OutputRequests++;
- } else {
- iocb_cmd->ulpCommand = CMD_FCP_IREAD64_CR;
- iocb_cmd->ulpPU = PARM_READ_CHECK;
- iocb_cmd->un.fcpi.fcpi_parm =
- scsi_cmnd->request_bufflen;
+ iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd);
fcp_cmnd->fcpCntl3 = READ_DATA;
phba->fc4InputRequests++;
}
@@ -642,15 +765,15 @@
piocbq->context1 = lpfc_cmd;
piocbq->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl;
piocbq->iocb.ulpTimeout = lpfc_cmd->timeout;
+ piocbq->vport = vport;
}
static int
-lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
+lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport,
struct lpfc_scsi_buf *lpfc_cmd,
unsigned int lun,
uint8_t task_mgmt_cmd)
{
- struct lpfc_sli *psli;
struct lpfc_iocbq *piocbq;
IOCB_t *piocb;
struct fcp_cmnd *fcp_cmnd;
@@ -661,8 +784,9 @@
return 0;
}
- psli = &phba->sli;
piocbq = &(lpfc_cmd->cur_iocbq);
+ piocbq->vport = vport;
+
piocb = &piocbq->iocb;
fcp_cmnd = lpfc_cmd->fcp_cmnd;
@@ -688,7 +812,7 @@
piocb->ulpTimeout = lpfc_cmd->timeout;
}
- return (1);
+ return 1;
}
static void
@@ -704,10 +828,11 @@
}
static int
-lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
+lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport,
unsigned tgt_id, unsigned int lun,
struct lpfc_rport_data *rdata)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *iocbq;
struct lpfc_iocbq *iocbqrsp;
int ret;
@@ -716,12 +841,11 @@
return FAILED;
lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, lun,
+ ret = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun,
FCP_TARGET_RESET);
if (!ret)
return FAILED;
- lpfc_cmd->scsi_hba = phba;
iocbq = &lpfc_cmd->cur_iocbq;
iocbqrsp = lpfc_sli_get_iocbq(phba);
@@ -730,10 +854,10 @@
/* Issue Target Reset to TGT <num> */
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0702 Issue Target Reset to TGT %d "
+ "%d (%d):0702 Issue Target Reset to TGT %d "
"Data: x%x x%x\n",
- phba->brd_no, tgt_id, rdata->pnode->nlp_rpi,
- rdata->pnode->nlp_flag);
+ phba->brd_no, vport->vpi, tgt_id,
+ rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
ret = lpfc_sli_issue_iocb_wait(phba,
&phba->sli.ring[phba->sli.fcp_ring],
@@ -758,7 +882,8 @@
const char *
lpfc_info(struct Scsi_Host *host)
{
- struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) host->hostdata;
+ struct lpfc_hba *phba = vport->phba;
int len;
static char lpfcinfobuf[384];
@@ -800,26 +925,22 @@
void lpfc_poll_timeout(unsigned long ptr)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
- unsigned long iflag;
-
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
lpfc_sli_poll_fcp_ring (phba);
if (phba->cfg_poll & DISABLE_FCP_RING_INT)
lpfc_poll_rearm_timer(phba);
}
-
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
}
static int
lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
{
- struct lpfc_hba *phba =
- (struct lpfc_hba *) cmnd->device->host->hostdata;
- struct lpfc_sli *psli = &phba->sli;
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
struct lpfc_nodelist *ndlp = rdata->pnode;
struct lpfc_scsi_buf *lpfc_cmd;
@@ -840,11 +961,14 @@
cmnd->result = ScsiResult(DID_BUS_BUSY, 0);
goto out_fail_command;
}
- lpfc_cmd = lpfc_get_scsi_buf (phba);
+ lpfc_cmd = lpfc_get_scsi_buf(phba);
if (lpfc_cmd == NULL) {
+ lpfc_adjust_queue_depth(phba);
+
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0707 driver's buffer pool is empty, "
- "IO busied\n", phba->brd_no);
+ "%d (%d):0707 driver's buffer pool is empty, "
+ "IO busied\n",
+ phba->brd_no, vport->vpi);
goto out_host_busy;
}
@@ -862,10 +986,10 @@
if (err)
goto out_host_busy_free_buf;
- lpfc_scsi_prep_cmnd(phba, lpfc_cmd, ndlp);
+ lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring],
- &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
+ &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
if (err)
goto out_host_busy_free_buf;
@@ -907,8 +1031,9 @@
static int
lpfc_abort_handler(struct scsi_cmnd *cmnd)
{
- struct Scsi_Host *shost = cmnd->device->host;
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_sli_ring *pring = &phba->sli.ring[phba->sli.fcp_ring];
struct lpfc_iocbq *iocb;
struct lpfc_iocbq *abtsiocb;
@@ -918,8 +1043,6 @@
int ret = SUCCESS;
lpfc_block_error_handler(cmnd);
- spin_lock_irq(shost->host_lock);
-
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
BUG_ON(!lpfc_cmd);
@@ -956,12 +1079,13 @@
icmd->ulpLe = 1;
icmd->ulpClass = cmd->ulpClass;
- if (phba->hba_state >= LPFC_LINK_UP)
+ if (lpfc_is_link_up(phba))
icmd->ulpCommand = CMD_ABORT_XRI_CN;
else
icmd->ulpCommand = CMD_CLOSE_XRI_CN;
abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
+ abtsiocb->vport = vport;
if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) == IOCB_ERROR) {
lpfc_sli_release_iocbq(phba, abtsiocb);
ret = FAILED;
@@ -977,9 +1101,7 @@
if (phba->cfg_poll & DISABLE_FCP_RING_INT)
lpfc_sli_poll_fcp_ring (phba);
- spin_unlock_irq(phba->host->host_lock);
- schedule_timeout_uninterruptible(LPFC_ABORT_WAIT*HZ);
- spin_lock_irq(phba->host->host_lock);
+ schedule_timeout_uninterruptible(LPFC_ABORT_WAIT * HZ);
if (++loop_count
> (2 * phba->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
break;
@@ -988,30 +1110,30 @@
if (lpfc_cmd->pCmd == cmnd) {
ret = FAILED;
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0748 abort handler timed out waiting for "
- "abort to complete: ret %#x, ID %d, LUN %d, "
- "snum %#lx\n",
- phba->brd_no, ret, cmnd->device->id,
- cmnd->device->lun, cmnd->serial_number);
+ "%d (%d):0748 abort handler timed out waiting "
+ "for abort to complete: ret %#x, ID %d, "
+ "LUN %d, snum %#lx\n",
+ phba->brd_no, vport->vpi, ret,
+ cmnd->device->id, cmnd->device->lun,
+ cmnd->serial_number);
}
out:
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0749 SCSI Layer I/O Abort Request "
+ "%d (%d):0749 SCSI Layer I/O Abort Request "
"Status x%x ID %d LUN %d snum %#lx\n",
- phba->brd_no, ret, cmnd->device->id,
+ phba->brd_no, vport->vpi, ret, cmnd->device->id,
cmnd->device->lun, cmnd->serial_number);
- spin_unlock_irq(shost->host_lock);
-
return ret;
}
static int
lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
{
- struct Scsi_Host *shost = cmnd->device->host;
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_scsi_buf *lpfc_cmd;
struct lpfc_iocbq *iocbq, *iocbqrsp;
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
@@ -1022,28 +1144,26 @@
int cnt, loopcnt;
lpfc_block_error_handler(cmnd);
- spin_lock_irq(shost->host_lock);
loopcnt = 0;
/*
* If target is not in a MAPPED state, delay the reset until
* target is rediscovered or devloss timeout expires.
*/
- while ( 1 ) {
+ while (1) {
if (!pnode)
goto out;
if (pnode->nlp_state != NLP_STE_MAPPED_NODE) {
- spin_unlock_irq(phba->host->host_lock);
schedule_timeout_uninterruptible(msecs_to_jiffies(500));
- spin_lock_irq(phba->host->host_lock);
loopcnt++;
rdata = cmnd->device->hostdata;
if (!rdata ||
(loopcnt > ((phba->cfg_devloss_tmo * 2) + 1))) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0721 LUN Reset rport failure:"
- " cnt x%x rdata x%p\n",
- phba->brd_no, loopcnt, rdata);
+ "%d (%d):0721 LUN Reset rport "
+ "failure: cnt x%x rdata x%p\n",
+ phba->brd_no, vport->vpi,
+ loopcnt, rdata);
goto out;
}
pnode = rdata->pnode;
@@ -1054,15 +1174,14 @@
break;
}
- lpfc_cmd = lpfc_get_scsi_buf (phba);
+ lpfc_cmd = lpfc_get_scsi_buf(phba);
if (lpfc_cmd == NULL)
goto out;
lpfc_cmd->timeout = 60;
- lpfc_cmd->scsi_hba = phba;
lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun,
+ ret = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, cmnd->device->lun,
FCP_TARGET_RESET);
if (!ret)
goto out_free_scsi_buf;
@@ -1075,8 +1194,9 @@
goto out_free_scsi_buf;
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0703 Issue target reset to TGT %d LUN %d rpi x%x "
- "nlp_flag x%x\n", phba->brd_no, cmnd->device->id,
+ "%d (%d):0703 Issue target reset to TGT %d LUN %d "
+ "rpi x%x nlp_flag x%x\n",
+ phba->brd_no, vport->vpi, cmnd->device->id,
cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
iocb_status = lpfc_sli_issue_iocb_wait(phba,
@@ -1111,9 +1231,7 @@
0, LPFC_CTX_LUN);
loopcnt = 0;
while(cnt) {
- spin_unlock_irq(phba->host->host_lock);
schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
- spin_lock_irq(phba->host->host_lock);
if (++loopcnt
> (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
@@ -1127,8 +1245,9 @@
if (cnt) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0719 device reset I/O flush failure: cnt x%x\n",
- phba->brd_no, cnt);
+ "%d (%d):0719 device reset I/O flush failure: "
+ "cnt x%x\n",
+ phba->brd_no, vport->vpi, cnt);
ret = FAILED;
}
@@ -1137,21 +1256,21 @@
lpfc_release_scsi_buf(phba, lpfc_cmd);
}
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0713 SCSI layer issued device reset (%d, %d) "
+ "%d (%d):0713 SCSI layer issued device reset (%d, %d) "
"return x%x status x%x result x%x\n",
- phba->brd_no, cmnd->device->id, cmnd->device->lun,
- ret, cmd_status, cmd_result);
+ phba->brd_no, vport->vpi, cmnd->device->id,
+ cmnd->device->lun, ret, cmd_status, cmd_result);
out:
- spin_unlock_irq(shost->host_lock);
return ret;
}
static int
lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
{
- struct Scsi_Host *shost = cmnd->device->host;
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp = NULL;
int match;
int ret = FAILED, i, err_count = 0;
@@ -1159,7 +1278,6 @@
struct lpfc_scsi_buf * lpfc_cmd;
lpfc_block_error_handler(cmnd);
- spin_lock_irq(shost->host_lock);
lpfc_cmd = lpfc_get_scsi_buf(phba);
if (lpfc_cmd == NULL)
@@ -1167,7 +1285,6 @@
/* The lpfc_cmd storage is reused. Set all loop invariants. */
lpfc_cmd->timeout = 60;
- lpfc_cmd->scsi_hba = phba;
/*
* Since the driver manages a single bus device, reset all
@@ -1177,7 +1294,8 @@
for (i = 0; i < LPFC_MAX_TARGET; i++) {
/* Search for mapped node by target ID */
match = 0;
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ spin_lock_irq(shost->host_lock);
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
i == ndlp->nlp_sid &&
ndlp->rport) {
@@ -1185,15 +1303,18 @@
break;
}
}
+ spin_unlock_irq(shost->host_lock);
if (!match)
continue;
- ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba, i, cmnd->device->lun,
+ ret = lpfc_scsi_tgt_reset(lpfc_cmd, vport, i,
+ cmnd->device->lun,
ndlp->rport->dd_data);
if (ret != SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0700 Bus Reset on target %d failed\n",
- phba->brd_no, i);
+ "%d (%d):0700 Bus Reset on target %d "
+ "failed\n",
+ phba->brd_no, vport->vpi, i);
err_count++;
break;
}
@@ -1219,9 +1340,7 @@
0, 0, 0, LPFC_CTX_HOST);
loopcnt = 0;
while(cnt) {
- spin_unlock_irq(phba->host->host_lock);
schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
- spin_lock_irq(phba->host->host_lock);
if (++loopcnt
> (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
@@ -1234,25 +1353,24 @@
if (cnt) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0715 Bus Reset I/O flush failure: cnt x%x left x%x\n",
- phba->brd_no, cnt, i);
+ "%d (%d):0715 Bus Reset I/O flush failure: "
+ "cnt x%x left x%x\n",
+ phba->brd_no, vport->vpi, cnt, i);
ret = FAILED;
}
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_FCP,
- "%d:0714 SCSI layer issued Bus Reset Data: x%x\n",
- phba->brd_no, ret);
+ lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+ "%d (%d):0714 SCSI layer issued Bus Reset Data: x%x\n",
+ phba->brd_no, vport->vpi, ret);
out:
- spin_unlock_irq(shost->host_lock);
return ret;
}
static int
lpfc_slave_alloc(struct scsi_device *sdev)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)sdev->host->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_scsi_buf *scsi_buf = NULL;
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
uint32_t total = 0, i;
@@ -1273,27 +1391,35 @@
*/
total = phba->total_scsi_bufs;
num_to_alloc = phba->cfg_lun_queue_depth + 2;
- if (total >= phba->cfg_hba_queue_depth) {
+
+ /* Allow some exchanges to be available always to complete discovery */
+ if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0704 At limitation of %d preallocated "
- "command buffers\n", phba->brd_no, total);
+ "%d (%d):0704 At limitation of %d "
+ "preallocated command buffers\n",
+ phba->brd_no, vport->vpi, total);
return 0;
- } else if (total + num_to_alloc > phba->cfg_hba_queue_depth) {
+
+ /* Allow some exchanges to be available always to complete discovery */
+ } else if (total + num_to_alloc >
+ phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0705 Allocation request of %d command "
- "buffers will exceed max of %d. Reducing "
- "allocation request to %d.\n", phba->brd_no,
- num_to_alloc, phba->cfg_hba_queue_depth,
+ "%d (%d):0705 Allocation request of %d "
+ "command buffers will exceed max of %d. "
+ "Reducing allocation request to %d.\n",
+ phba->brd_no, vport->vpi, num_to_alloc,
+ phba->cfg_hba_queue_depth,
(phba->cfg_hba_queue_depth - total));
num_to_alloc = phba->cfg_hba_queue_depth - total;
}
for (i = 0; i < num_to_alloc; i++) {
- scsi_buf = lpfc_new_scsi_buf(phba);
+ scsi_buf = lpfc_new_scsi_buf(vport);
if (!scsi_buf) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0706 Failed to allocate command "
- "buffer\n", phba->brd_no);
+ "%d (%d):0706 Failed to allocate "
+ "command buffer\n",
+ phba->brd_no, vport->vpi);
break;
}
@@ -1308,8 +1434,9 @@
static int
lpfc_slave_configure(struct scsi_device *sdev)
{
- struct lpfc_hba *phba = (struct lpfc_hba *) sdev->host->hostdata;
- struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
+ struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
if (sdev->tagged_supported)
scsi_activate_tcq(sdev, phba->cfg_lun_queue_depth);
@@ -1340,6 +1467,7 @@
return;
}
+
struct scsi_host_template lpfc_template = {
.module = THIS_MODULE,
.name = LPFC_DRIVER_NAME,
@@ -1352,11 +1480,10 @@
.slave_configure = lpfc_slave_configure,
.slave_destroy = lpfc_slave_destroy,
.scan_finished = lpfc_scan_finished,
- .scan_start = lpfc_scan_start,
.this_id = -1,
.sg_tablesize = LPFC_SG_SEG_CNT,
.cmd_per_lun = LPFC_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
- .shost_attrs = lpfc_host_attrs,
+ .shost_attrs = lpfc_hba_attrs,
.max_sectors = 0xFFFF,
};
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index cdcd253..31787bb 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2005 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2006 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -110,7 +110,6 @@
struct lpfc_scsi_buf {
struct list_head list;
struct scsi_cmnd *pCmd;
- struct lpfc_hba *scsi_hba;
struct lpfc_rport_data *rdata;
uint32_t timeout;
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index a1e7214..f4d5a6b 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -38,23 +38,25 @@
#include "lpfc_crtn.h"
#include "lpfc_logmsg.h"
#include "lpfc_compat.h"
+#include "lpfc_debugfs.h"
/*
* Define macro to log: Mailbox command x%x cannot issue Data
* This allows multiple uses of lpfc_msgBlk0311
* w/o perturbing log msg utility.
*/
-#define LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag) \
+#define LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag) \
lpfc_printf_log(phba, \
KERN_INFO, \
LOG_MBOX | LOG_SLI, \
- "%d:0311 Mailbox command x%x cannot issue " \
- "Data: x%x x%x x%x\n", \
+ "%d (%d):0311 Mailbox command x%x cannot " \
+ "issue Data: x%x x%x x%x\n", \
phba->brd_no, \
- mb->mbxCommand, \
- phba->hba_state, \
+ pmbox->vport ? pmbox->vport->vpi : 0, \
+ pmbox->mb.mbxCommand, \
+ phba->pport->port_state, \
psli->sli_flag, \
- flag);
+ flag)
/* There are only four IOCB completion types. */
@@ -65,8 +67,26 @@
LPFC_ABORT_IOCB
} lpfc_iocb_type;
-struct lpfc_iocbq *
-lpfc_sli_get_iocbq(struct lpfc_hba * phba)
+ /* SLI-2/SLI-3 provide different sized iocbs. Given a pointer
+ * to the start of the ring, and the slot number of the
+ * desired iocb entry, calc a pointer to that entry.
+ */
+static inline IOCB_t *
+lpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+{
+ return (IOCB_t *) (((char *) pring->cmdringaddr) +
+ pring->cmdidx * phba->iocb_cmd_size);
+}
+
+static inline IOCB_t *
+lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+{
+ return (IOCB_t *) (((char *) pring->rspringaddr) +
+ pring->rspidx * phba->iocb_rsp_size);
+}
+
+static struct lpfc_iocbq *
+__lpfc_sli_get_iocbq(struct lpfc_hba *phba)
{
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
struct lpfc_iocbq * iocbq = NULL;
@@ -75,10 +95,22 @@
return iocbq;
}
-void
-lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
+struct lpfc_iocbq *
+lpfc_sli_get_iocbq(struct lpfc_hba *phba)
{
- size_t start_clean = (size_t)(&((struct lpfc_iocbq *)NULL)->iocb);
+ struct lpfc_iocbq * iocbq = NULL;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ iocbq = __lpfc_sli_get_iocbq(phba);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return iocbq;
+}
+
+void
+__lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+{
+ size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
/*
* Clean all volatile data fields, preserve iotag and node struct.
@@ -87,6 +119,19 @@
list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
}
+void
+lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+{
+ unsigned long iflags;
+
+ /*
+ * Clean all volatile data fields, preserve iotag and node struct.
+ */
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ __lpfc_sli_release_iocbq(phba, iocbq);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+}
+
/*
* Translate the iocb command to an iocb command type used to decide the final
* disposition of each completed IOCB.
@@ -155,6 +200,9 @@
case CMD_RCV_ELS_REQ_CX:
case CMD_RCV_SEQUENCE64_CX:
case CMD_RCV_ELS_REQ64_CX:
+ case CMD_IOCB_RCV_SEQ64_CX:
+ case CMD_IOCB_RCV_ELS64_CX:
+ case CMD_IOCB_RCV_CONT64_CX:
type = LPFC_UNSOL_IOCB;
break;
default:
@@ -166,73 +214,77 @@
}
static int
-lpfc_sli_ring_map(struct lpfc_hba * phba, LPFC_MBOXQ_t *pmb)
+lpfc_sli_ring_map(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
- MAILBOX_t *pmbox = &pmb->mb;
- int i, rc;
+ LPFC_MBOXQ_t *pmb;
+ MAILBOX_t *pmbox;
+ int i, rc, ret = 0;
+ pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmb)
+ return -ENOMEM;
+ pmbox = &pmb->mb;
+ phba->link_state = LPFC_INIT_MBX_CMDS;
for (i = 0; i < psli->num_rings; i++) {
- phba->hba_state = LPFC_INIT_MBX_CMDS;
lpfc_config_ring(phba, i, pmb);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
- "%d:0446 Adapter failed to init, "
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0446 Adapter failed to init (%d), "
"mbxCmd x%x CFG_RING, mbxStatus x%x, "
"ring %d\n",
- phba->brd_no,
+ phba->brd_no, rc,
pmbox->mbxCommand,
pmbox->mbxStatus,
i);
- phba->hba_state = LPFC_HBA_ERROR;
- return -ENXIO;
+ phba->link_state = LPFC_HBA_ERROR;
+ ret = -ENXIO;
+ break;
}
}
- return 0;
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return ret;
}
static int
-lpfc_sli_ringtxcmpl_put(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring, struct lpfc_iocbq * piocb)
+lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocb)
{
list_add_tail(&piocb->list, &pring->txcmplq);
pring->txcmplq_cnt++;
- if (unlikely(pring->ringno == LPFC_ELS_RING))
- mod_timer(&phba->els_tmofunc,
- jiffies + HZ * (phba->fc_ratov << 1));
+ if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
+ (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
+ (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
+ if (!piocb->vport)
+ BUG();
+ else
+ mod_timer(&piocb->vport->els_tmofunc,
+ jiffies + HZ * (phba->fc_ratov << 1));
+ }
- return (0);
+
+ return 0;
}
static struct lpfc_iocbq *
-lpfc_sli_ringtx_get(struct lpfc_hba * phba, struct lpfc_sli_ring * pring)
+lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
- struct list_head *dlp;
struct lpfc_iocbq *cmd_iocb;
- dlp = &pring->txq;
- cmd_iocb = NULL;
- list_remove_head((&pring->txq), cmd_iocb,
- struct lpfc_iocbq,
- list);
- if (cmd_iocb) {
- /* If the first ptr is not equal to the list header,
- * deque the IOCBQ_t and return it.
- */
+ list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list);
+ if (cmd_iocb != NULL)
pring->txq_cnt--;
- }
- return (cmd_iocb);
+ return cmd_iocb;
}
static IOCB_t *
lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
- struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
+ struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+ &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+ &phba->slim2p->mbx.us.s2.port[pring->ringno];
uint32_t max_cmd_idx = pring->numCiocb;
- IOCB_t *iocb = NULL;
if ((pring->next_cmdidx == pring->cmdidx) &&
(++pring->next_cmdidx >= max_cmd_idx))
@@ -249,15 +301,17 @@
phba->brd_no, pring->ringno,
pring->local_getidx, max_cmd_idx);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
/*
* All error attention handlers are posted to
* worker thread
*/
phba->work_ha |= HA_ERATT;
phba->work_hs = HS_FFER3;
+
+ /* hbalock should already be held */
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
return NULL;
}
@@ -266,39 +320,34 @@
return NULL;
}
- iocb = IOCB_ENTRY(pring->cmdringaddr, pring->cmdidx);
-
- return iocb;
+ return lpfc_cmd_iocb(phba, pring);
}
uint16_t
-lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
+lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
- struct lpfc_iocbq ** new_arr;
- struct lpfc_iocbq ** old_arr;
+ struct lpfc_iocbq **new_arr;
+ struct lpfc_iocbq **old_arr;
size_t new_len;
struct lpfc_sli *psli = &phba->sli;
uint16_t iotag;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
iotag = psli->last_iotag;
if(++iotag < psli->iocbq_lookup_len) {
psli->last_iotag = iotag;
psli->iocbq_lookup[iotag] = iocbq;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
iocbq->iotag = iotag;
return iotag;
- }
- else if (psli->iocbq_lookup_len < (0xffff
+ } else if (psli->iocbq_lookup_len < (0xffff
- LPFC_IOCBQ_LOOKUP_INCREMENT)) {
new_len = psli->iocbq_lookup_len + LPFC_IOCBQ_LOOKUP_INCREMENT;
- spin_unlock_irq(phba->host->host_lock);
- new_arr = kmalloc(new_len * sizeof (struct lpfc_iocbq *),
+ spin_unlock_irq(&phba->hbalock);
+ new_arr = kzalloc(new_len * sizeof (struct lpfc_iocbq *),
GFP_KERNEL);
if (new_arr) {
- memset((char *)new_arr, 0,
- new_len * sizeof (struct lpfc_iocbq *));
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
old_arr = psli->iocbq_lookup;
if (new_len <= psli->iocbq_lookup_len) {
/* highly unprobable case */
@@ -307,11 +356,11 @@
if(++iotag < psli->iocbq_lookup_len) {
psli->last_iotag = iotag;
psli->iocbq_lookup[iotag] = iocbq;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
iocbq->iotag = iotag;
return iotag;
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return 0;
}
if (psli->iocbq_lookup)
@@ -322,13 +371,13 @@
psli->iocbq_lookup_len = new_len;
psli->last_iotag = iotag;
psli->iocbq_lookup[iotag] = iocbq;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
iocbq->iotag = iotag;
kfree(old_arr);
return iotag;
}
} else
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
lpfc_printf_log(phba, KERN_ERR,LOG_SLI,
"%d:0318 Failed to allocate IOTAG.last IOTAG is %d\n",
@@ -349,7 +398,7 @@
/*
* Issue iocb command to adapter
*/
- lpfc_sli_pcimem_bcopy(&nextiocb->iocb, iocb, sizeof (IOCB_t));
+ lpfc_sli_pcimem_bcopy(&nextiocb->iocb, iocb, phba->iocb_cmd_size);
wmb();
pring->stats.iocb_cmd++;
@@ -361,20 +410,18 @@
if (nextiocb->iocb_cmpl)
lpfc_sli_ringtxcmpl_put(phba, pring, nextiocb);
else
- lpfc_sli_release_iocbq(phba, nextiocb);
+ __lpfc_sli_release_iocbq(phba, nextiocb);
/*
* Let the HBA know what IOCB slot will be the next one the
* driver will put a command into.
*/
pring->cmdidx = pring->next_cmdidx;
- writel(pring->cmdidx, phba->MBslimaddr
- + (SLIMOFF + (pring->ringno * 2)) * 4);
+ writel(pring->cmdidx, &phba->host_gp[pring->ringno].cmdPutInx);
}
static void
-lpfc_sli_update_full_ring(struct lpfc_hba * phba,
- struct lpfc_sli_ring *pring)
+lpfc_sli_update_full_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
int ringno = pring->ringno;
@@ -393,8 +440,7 @@
}
static void
-lpfc_sli_update_ring(struct lpfc_hba * phba,
- struct lpfc_sli_ring *pring)
+lpfc_sli_update_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
int ringno = pring->ringno;
@@ -407,7 +453,7 @@
}
static void
-lpfc_sli_resume_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring)
+lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
IOCB_t *iocb;
struct lpfc_iocbq *nextiocb;
@@ -420,7 +466,7 @@
* (d) IOCB processing is not blocked by the outstanding mbox command.
*/
if (pring->txq_cnt &&
- (phba->hba_state > LPFC_LINK_DOWN) &&
+ lpfc_is_link_up(phba) &&
(pring->ringno != phba->sli.fcp_ring ||
phba->sli.sli_flag & LPFC_PROCESS_LA) &&
!(pring->flag & LPFC_STOP_IOCB_MBX)) {
@@ -440,11 +486,15 @@
/* lpfc_sli_turn_on_ring is only called by lpfc_sli_handle_mb_event below */
static void
-lpfc_sli_turn_on_ring(struct lpfc_hba * phba, int ringno)
+lpfc_sli_turn_on_ring(struct lpfc_hba *phba, int ringno)
{
- struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[ringno];
+ struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+ &phba->slim2p->mbx.us.s3_pgp.port[ringno] :
+ &phba->slim2p->mbx.us.s2.port[ringno];
+ unsigned long iflags;
/* If the ring is active, flag it */
+ spin_lock_irqsave(&phba->hbalock, iflags);
if (phba->sli.ring[ringno].cmdringaddr) {
if (phba->sli.ring[ringno].flag & LPFC_STOP_IOCB_MBX) {
phba->sli.ring[ringno].flag &= ~LPFC_STOP_IOCB_MBX;
@@ -453,11 +503,176 @@
*/
phba->sli.ring[ringno].local_getidx
= le32_to_cpu(pgp->cmdGetInx);
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_resume_iocb(phba, &phba->sli.ring[ringno]);
- spin_unlock_irq(phba->host->host_lock);
}
}
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+}
+
+struct lpfc_hbq_entry *
+lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
+{
+ struct hbq_s *hbqp = &phba->hbqs[hbqno];
+
+ if (hbqp->next_hbqPutIdx == hbqp->hbqPutIdx &&
+ ++hbqp->next_hbqPutIdx >= hbqp->entry_count)
+ hbqp->next_hbqPutIdx = 0;
+
+ if (unlikely(hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx)) {
+ uint32_t raw_index = phba->hbq_get[hbqno];
+ uint32_t getidx = le32_to_cpu(raw_index);
+
+ hbqp->local_hbqGetIdx = getidx;
+
+ if (unlikely(hbqp->local_hbqGetIdx >= hbqp->entry_count)) {
+ lpfc_printf_log(phba, KERN_ERR,
+ LOG_SLI | LOG_VPORT,
+ "%d:1802 HBQ %d: local_hbqGetIdx "
+ "%u is > than hbqp->entry_count %u\n",
+ phba->brd_no, hbqno,
+ hbqp->local_hbqGetIdx,
+ hbqp->entry_count);
+
+ phba->link_state = LPFC_HBA_ERROR;
+ return NULL;
+ }
+
+ if (hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx)
+ return NULL;
+ }
+
+ return (struct lpfc_hbq_entry *) phba->hbqslimp.virt + hbqp->hbqPutIdx;
+}
+
+void
+lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
+{
+ struct lpfc_dmabuf *dmabuf, *next_dmabuf;
+ struct hbq_dmabuf *hbq_buf;
+
+ /* Return all memory used by all HBQs */
+ list_for_each_entry_safe(dmabuf, next_dmabuf,
+ &phba->hbq_buffer_list, list) {
+ hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
+ list_del(&hbq_buf->dbuf.list);
+ lpfc_hbq_free(phba, hbq_buf->dbuf.virt, hbq_buf->dbuf.phys);
+ kfree(hbq_buf);
+ }
+}
+
+static void
+lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
+ struct hbq_dmabuf *hbq_buf)
+{
+ struct lpfc_hbq_entry *hbqe;
+ dma_addr_t physaddr = hbq_buf->dbuf.phys;
+
+ /* Get next HBQ entry slot to use */
+ hbqe = lpfc_sli_next_hbq_slot(phba, hbqno);
+ if (hbqe) {
+ struct hbq_s *hbqp = &phba->hbqs[hbqno];
+
+ hbqe->bde.addrHigh = le32_to_cpu(putPaddrHigh(physaddr));
+ hbqe->bde.addrLow = le32_to_cpu(putPaddrLow(physaddr));
+ hbqe->bde.tus.f.bdeSize = FCELSSIZE;
+ hbqe->bde.tus.f.bdeFlags = 0;
+ hbqe->bde.tus.w = le32_to_cpu(hbqe->bde.tus.w);
+ hbqe->buffer_tag = le32_to_cpu(hbq_buf->tag);
+ /* Sync SLIM */
+ hbqp->hbqPutIdx = hbqp->next_hbqPutIdx;
+ writel(hbqp->hbqPutIdx, phba->hbq_put + hbqno);
+ /* flush */
+ readl(phba->hbq_put + hbqno);
+ list_add_tail(&hbq_buf->dbuf.list, &phba->hbq_buffer_list);
+ }
+}
+
+static struct lpfc_hbq_init lpfc_els_hbq = {
+ .rn = 1,
+ .entry_count = 200,
+ .mask_count = 0,
+ .profile = 0,
+ .ring_mask = 1 << LPFC_ELS_RING,
+ .buffer_count = 0,
+ .init_count = 20,
+ .add_count = 5,
+};
+
+static struct lpfc_hbq_init *lpfc_hbq_defs[] = {
+ &lpfc_els_hbq,
+};
+
+int
+lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
+{
+ uint32_t i, start, end;
+ struct hbq_dmabuf *hbq_buffer;
+
+ start = lpfc_hbq_defs[hbqno]->buffer_count;
+ end = count + lpfc_hbq_defs[hbqno]->buffer_count;
+ if (end > lpfc_hbq_defs[hbqno]->entry_count) {
+ end = lpfc_hbq_defs[hbqno]->entry_count;
+ }
+
+ /* Populate HBQ entries */
+ for (i = start; i < end; i++) {
+ hbq_buffer = kmalloc(sizeof(struct hbq_dmabuf),
+ GFP_KERNEL);
+ if (!hbq_buffer)
+ return 1;
+ hbq_buffer->dbuf.virt = lpfc_hbq_alloc(phba, MEM_PRI,
+ &hbq_buffer->dbuf.phys);
+ if (hbq_buffer->dbuf.virt == NULL)
+ return 1;
+ hbq_buffer->tag = (i | (hbqno << 16));
+ lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer);
+ lpfc_hbq_defs[hbqno]->buffer_count++;
+ }
+ return 0;
+}
+
+int
+lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *phba, uint32_t qno)
+{
+ return(lpfc_sli_hbqbuf_fill_hbqs(phba, qno,
+ lpfc_hbq_defs[qno]->add_count));
+}
+
+int
+lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno)
+{
+ return(lpfc_sli_hbqbuf_fill_hbqs(phba, qno,
+ lpfc_hbq_defs[qno]->init_count));
+}
+
+struct hbq_dmabuf *
+lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
+{
+ struct lpfc_dmabuf *d_buf;
+ struct hbq_dmabuf *hbq_buf;
+
+ list_for_each_entry(d_buf, &phba->hbq_buffer_list, list) {
+ hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+ if ((hbq_buf->tag & 0xffff) == tag) {
+ return hbq_buf;
+ }
+ }
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT,
+ "%d:1803 Bad hbq tag. Data: x%x x%x\n",
+ phba->brd_no, tag,
+ lpfc_hbq_defs[tag >> 16]->buffer_count);
+ return NULL;
+}
+
+void
+lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *sp)
+{
+ uint32_t hbqno;
+
+ if (sp) {
+ hbqno = sp->tag >> 16;
+ lpfc_sli_hbq_to_firmware(phba, hbqno, sp);
+ }
}
static int
@@ -511,32 +726,38 @@
case MBX_FLASH_WR_ULA:
case MBX_SET_DEBUG:
case MBX_LOAD_EXP_ROM:
+ case MBX_REG_VPI:
+ case MBX_UNREG_VPI:
+ case MBX_HEARTBEAT:
ret = mbxCommand;
break;
default:
ret = MBX_SHUTDOWN;
break;
}
- return (ret);
+ return ret;
}
static void
-lpfc_sli_wake_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
+lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
{
wait_queue_head_t *pdone_q;
+ unsigned long drvr_flag;
/*
* If pdone_q is empty, the driver thread gave up waiting and
* continued running.
*/
pmboxq->mbox_flag |= LPFC_MBX_WAKE;
+ spin_lock_irqsave(&phba->hbalock, drvr_flag);
pdone_q = (wait_queue_head_t *) pmboxq->context1;
if (pdone_q)
wake_up_interruptible(pdone_q);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
return;
}
void
-lpfc_sli_def_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_dmabuf *mp;
uint16_t rpi;
@@ -553,79 +774,64 @@
* If a REG_LOGIN succeeded after node is destroyed or node
* is in re-discovery driver need to cleanup the RPI.
*/
- if (!(phba->fc_flag & FC_UNLOADING) &&
- (pmb->mb.mbxCommand == MBX_REG_LOGIN64) &&
- (!pmb->mb.mbxStatus)) {
+ if (!(phba->pport->load_flag & FC_UNLOADING) &&
+ pmb->mb.mbxCommand == MBX_REG_LOGIN64 &&
+ !pmb->mb.mbxStatus) {
rpi = pmb->mb.un.varWords[0];
- lpfc_unreg_login(phba, rpi, pmb);
- pmb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
+ lpfc_unreg_login(phba, pmb->mb.un.varRegLogin.vpi, rpi, pmb);
+ pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
if (rc != MBX_NOT_FINISHED)
return;
}
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
}
int
-lpfc_sli_handle_mb_event(struct lpfc_hba * phba)
+lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
{
- MAILBOX_t *mbox;
MAILBOX_t *pmbox;
LPFC_MBOXQ_t *pmb;
- struct lpfc_sli *psli;
- int i, rc;
- uint32_t process_next;
-
- psli = &phba->sli;
- /* We should only get here if we are in SLI2 mode */
- if (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE)) {
- return (1);
- }
+ int rc;
+ LIST_HEAD(cmplq);
phba->sli.slistat.mbox_event++;
+ /* Get all completed mailboxe buffers into the cmplq */
+ spin_lock_irq(&phba->hbalock);
+ list_splice_init(&phba->sli.mboxq_cmpl, &cmplq);
+ spin_unlock_irq(&phba->hbalock);
+
/* Get a Mailbox buffer to setup mailbox commands for callback */
- if ((pmb = phba->sli.mbox_active)) {
+ do {
+ list_remove_head(&cmplq, pmb, LPFC_MBOXQ_t, list);
+ if (pmb == NULL)
+ break;
+
pmbox = &pmb->mb;
- mbox = &phba->slim2p->mbx;
- /* First check out the status word */
- lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof (uint32_t));
-
- /* Sanity check to ensure the host owns the mailbox */
- if (pmbox->mbxOwner != OWN_HOST) {
- /* Lets try for a while */
- for (i = 0; i < 10240; i++) {
- /* First copy command data */
- lpfc_sli_pcimem_bcopy(mbox, pmbox,
- sizeof (uint32_t));
- if (pmbox->mbxOwner == OWN_HOST)
- goto mbout;
+ if (pmbox->mbxCommand != MBX_HEARTBEAT) {
+ if (pmb->vport) {
+ lpfc_debugfs_disc_trc(pmb->vport,
+ LPFC_DISC_TRC_MBOX_VPORT,
+ "MBOX cmpl vport: cmd:x%x mb:x%x x%x",
+ (uint32_t)pmbox->mbxCommand,
+ pmbox->un.varWords[0],
+ pmbox->un.varWords[1]);
}
- /* Stray Mailbox Interrupt, mbxCommand <cmd> mbxStatus
- <status> */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_MBOX | LOG_SLI,
- "%d:0304 Stray Mailbox Interrupt "
- "mbxCommand x%x mbxStatus x%x\n",
- phba->brd_no,
- pmbox->mbxCommand,
- pmbox->mbxStatus);
-
- spin_lock_irq(phba->host->host_lock);
- phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
- return (1);
+ else {
+ lpfc_debugfs_disc_trc(phba->pport,
+ LPFC_DISC_TRC_MBOX,
+ "MBOX cmpl: cmd:x%x mb:x%x x%x",
+ (uint32_t)pmbox->mbxCommand,
+ pmbox->un.varWords[0],
+ pmbox->un.varWords[1]);
+ }
}
- mbout:
- del_timer_sync(&phba->sli.mbox_tmo);
- phba->work_hba_events &= ~WORKER_MBOX_TMO;
-
/*
* It is a fatal error if unknown mbox command completion.
*/
@@ -633,51 +839,50 @@
MBX_SHUTDOWN) {
/* Unknow mailbox command compl */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_MBOX | LOG_SLI,
- "%d:0323 Unknown Mailbox command %x Cmpl\n",
- phba->brd_no,
- pmbox->mbxCommand);
- phba->hba_state = LPFC_HBA_ERROR;
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+ "%d (%d):0323 Unknown Mailbox command "
+ "%x Cmpl\n",
+ phba->brd_no,
+ pmb->vport ? pmb->vport->vpi : 0,
+ pmbox->mbxCommand);
+ phba->link_state = LPFC_HBA_ERROR;
phba->work_hs = HS_FFER3;
lpfc_handle_eratt(phba);
- return (0);
+ continue;
}
- phba->sli.mbox_active = NULL;
if (pmbox->mbxStatus) {
phba->sli.slistat.mbox_stat_err++;
if (pmbox->mbxStatus == MBXERR_NO_RESOURCES) {
/* Mbox cmd cmpl error - RETRYing */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_MBOX | LOG_SLI,
- "%d:0305 Mbox cmd cmpl error - "
- "RETRYing Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- pmbox->mbxCommand,
- pmbox->mbxStatus,
- pmbox->un.varWords[0],
- phba->hba_state);
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_MBOX | LOG_SLI,
+ "%d (%d):0305 Mbox cmd cmpl "
+ "error - RETRYing Data: x%x "
+ "x%x x%x x%x\n",
+ phba->brd_no,
+ pmb->vport ? pmb->vport->vpi :0,
+ pmbox->mbxCommand,
+ pmbox->mbxStatus,
+ pmbox->un.varWords[0],
+ pmb->vport->port_state);
pmbox->mbxStatus = 0;
pmbox->mbxOwner = OWN_HOST;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
if (rc == MBX_SUCCESS)
- return (0);
+ continue;
}
}
/* Mailbox cmd <cmd> Cmpl <cmpl> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_MBOX | LOG_SLI,
- "%d:0307 Mailbox cmd x%x Cmpl x%p "
+ lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+ "%d (%d):0307 Mailbox cmd x%x Cmpl x%p "
"Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x\n",
phba->brd_no,
+ pmb->vport ? pmb->vport->vpi : 0,
pmbox->mbxCommand,
pmb->mbox_cmpl,
*((uint32_t *) pmbox),
@@ -690,39 +895,35 @@
pmbox->un.varWords[6],
pmbox->un.varWords[7]);
- if (pmb->mbox_cmpl) {
- lpfc_sli_pcimem_bcopy(mbox, pmbox, MAILBOX_CMD_SIZE);
+ if (pmb->mbox_cmpl)
pmb->mbox_cmpl(phba,pmb);
- }
- }
-
-
- do {
- process_next = 0; /* by default don't loop */
- spin_lock_irq(phba->host->host_lock);
- phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-
- /* Process next mailbox command if there is one */
- if ((pmb = lpfc_mbox_get(phba))) {
- spin_unlock_irq(phba->host->host_lock);
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- pmb->mb.mbxStatus = MBX_NOT_FINISHED;
- pmb->mbox_cmpl(phba,pmb);
- process_next = 1;
- continue; /* loop back */
- }
- } else {
- spin_unlock_irq(phba->host->host_lock);
- /* Turn on IOCB processing */
- for (i = 0; i < phba->sli.num_rings; i++)
- lpfc_sli_turn_on_ring(phba, i);
- }
-
- } while (process_next);
-
- return (0);
+ } while (1);
+ return 0;
}
+
+static struct lpfc_dmabuf *
+lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
+{
+ struct hbq_dmabuf *hbq_entry, *new_hbq_entry;
+
+ hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
+ if (hbq_entry == NULL)
+ return NULL;
+ list_del(&hbq_entry->dbuf.list);
+ new_hbq_entry = kmalloc(sizeof(struct hbq_dmabuf), GFP_ATOMIC);
+ if (new_hbq_entry == NULL)
+ return &hbq_entry->dbuf;
+ new_hbq_entry->dbuf = hbq_entry->dbuf;
+ new_hbq_entry->tag = -1;
+ hbq_entry->dbuf.virt = lpfc_hbq_alloc(phba, 0, &hbq_entry->dbuf.phys);
+ if (hbq_entry->dbuf.virt == NULL) {
+ kfree(new_hbq_entry);
+ return &hbq_entry->dbuf;
+ }
+ lpfc_sli_free_hbq(phba, hbq_entry);
+ return &new_hbq_entry->dbuf;
+}
+
static int
lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *saveq)
@@ -735,7 +936,9 @@
match = 0;
irsp = &(saveq->iocb);
if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX)
- || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)) {
+ || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)
+ || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)
+ || (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX)) {
Rctl = FC_ELS_REQ;
Type = FC_ELS_DATA;
} else {
@@ -747,13 +950,24 @@
/* Firmware Workaround */
if ((Rctl == 0) && (pring->ringno == LPFC_ELS_RING) &&
- (irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX)) {
+ (irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX ||
+ irsp->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
Rctl = FC_ELS_REQ;
Type = FC_ELS_DATA;
w5p->hcsw.Rctl = Rctl;
w5p->hcsw.Type = Type;
}
}
+
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ if (irsp->ulpBdeCount != 0)
+ saveq->context2 = lpfc_sli_replace_hbqbuff(phba,
+ irsp->un.ulpWord[3]);
+ if (irsp->ulpBdeCount == 2)
+ saveq->context3 = lpfc_sli_replace_hbqbuff(phba,
+ irsp->un.ulpWord[15]);
+ }
+
/* unSolicited Responses */
if (pring->prt[0].profile) {
if (pring->prt[0].lpfc_sli_rcv_unsol_event)
@@ -781,23 +995,21 @@
/* Unexpected Rctl / Type received */
/* Ring <ringno> handler: unexpected
Rctl <Rctl> Type <Type> received */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_SLI,
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
"%d:0313 Ring %d handler: unexpected Rctl x%x "
- "Type x%x received \n",
+ "Type x%x received\n",
phba->brd_no,
pring->ringno,
Rctl,
Type);
}
- return(1);
+ return 1;
}
static struct lpfc_iocbq *
-lpfc_sli_iocbq_lookup(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring,
- struct lpfc_iocbq * prspiocb)
+lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *prspiocb)
{
struct lpfc_iocbq *cmd_iocb = NULL;
uint16_t iotag;
@@ -806,7 +1018,7 @@
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
- list_del(&cmd_iocb->list);
+ list_del_init(&cmd_iocb->list);
pring->txcmplq_cnt--;
return cmd_iocb;
}
@@ -821,16 +1033,18 @@
}
static int
-lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
+lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *saveq)
{
- struct lpfc_iocbq * cmdiocbp;
+ struct lpfc_iocbq *cmdiocbp;
int rc = 1;
unsigned long iflag;
/* Based on the iotag field, get the cmd IOCB from the txcmplq */
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+
if (cmdiocbp) {
if (cmdiocbp->iocb_cmpl) {
/*
@@ -846,17 +1060,8 @@
saveq->iocb.un.ulpWord[4] =
IOERR_SLI_ABORTED;
}
- spin_unlock_irqrestore(phba->host->host_lock,
- iflag);
- (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
- spin_lock_irqsave(phba->host->host_lock, iflag);
}
- else {
- spin_unlock_irqrestore(phba->host->host_lock,
- iflag);
- (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
- spin_lock_irqsave(phba->host->host_lock, iflag);
- }
+ (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
} else
lpfc_sli_release_iocbq(phba, cmdiocbp);
} else {
@@ -870,29 +1075,30 @@
* Ring <ringno> handler: unexpected completion IoTag
* <IoTag>
*/
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_SLI,
- "%d:0322 Ring %d handler: unexpected "
- "completion IoTag x%x Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- pring->ringno,
- saveq->iocb.ulpIoTag,
- saveq->iocb.ulpStatus,
- saveq->iocb.un.ulpWord[4],
- saveq->iocb.ulpCommand,
- saveq->iocb.ulpContext);
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+ "%d (%d):0322 Ring %d handler: "
+ "unexpected completion IoTag x%x "
+ "Data: x%x x%x x%x x%x\n",
+ phba->brd_no,
+ cmdiocbp->vport->vpi,
+ pring->ringno,
+ saveq->iocb.ulpIoTag,
+ saveq->iocb.ulpStatus,
+ saveq->iocb.un.ulpWord[4],
+ saveq->iocb.ulpCommand,
+ saveq->iocb.ulpContext);
}
}
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
return rc;
}
-static void lpfc_sli_rsp_pointers_error(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring)
+static void
+lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
- struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
+ struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+ &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+ &phba->slim2p->mbx.us.s2.port[pring->ringno];
/*
* Ring <ringno> handler: portRspPut <portRspPut> is bigger then
* rsp ring <portRspMax>
@@ -904,7 +1110,7 @@
le32_to_cpu(pgp->rspPutInx),
pring->numRiocb);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
/*
* All error attention handlers are posted to
@@ -912,16 +1118,18 @@
*/
phba->work_ha |= HA_ERATT;
phba->work_hs = HS_FFER3;
+
+ /* hbalock should already be held */
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
return;
}
-void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba)
+void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
{
- struct lpfc_sli * psli = &phba->sli;
- struct lpfc_sli_ring * pring = &psli->ring[LPFC_FCP_RING];
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING];
IOCB_t *irsp = NULL;
IOCB_t *entry = NULL;
struct lpfc_iocbq *cmdiocbq = NULL;
@@ -931,13 +1139,15 @@
uint32_t portRspPut, portRspMax;
int type;
uint32_t rsp_cmpl = 0;
- void __iomem *to_slim;
uint32_t ha_copy;
+ unsigned long iflags;
pring->stats.iocb_event++;
- /* The driver assumes SLI-2 mode */
- pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
+ pgp = (phba->sli_rev == 3) ?
+ &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+ &phba->slim2p->mbx.us.s2.port[pring->ringno];
+
/*
* The next available response entry should never exceed the maximum
@@ -952,15 +1162,13 @@
rmb();
while (pring->rspidx != portRspPut) {
-
- entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
-
+ entry = lpfc_resp_iocb(phba, pring);
if (++pring->rspidx >= portRspMax)
pring->rspidx = 0;
lpfc_sli_pcimem_bcopy((uint32_t *) entry,
(uint32_t *) &rspiocbq.iocb,
- sizeof (IOCB_t));
+ phba->iocb_rsp_size);
irsp = &rspiocbq.iocb;
type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK);
pring->stats.iocb_rsp++;
@@ -998,8 +1206,10 @@
break;
}
+ spin_lock_irqsave(&phba->hbalock, iflags);
cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring,
&rspiocbq);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) {
(cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
&rspiocbq);
@@ -1033,9 +1243,7 @@
* been updated, sync the pgp->rspPutInx and fetch the new port
* response put pointer.
*/
- to_slim = phba->MBslimaddr +
- (SLIMOFF + (pring->ringno * 2) + 1) * 4;
- writeb(pring->rspidx, to_slim);
+ writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
if (pring->rspidx == portRspPut)
portRspPut = le32_to_cpu(pgp->rspPutInx);
@@ -1045,13 +1253,16 @@
ha_copy >>= (LPFC_FCP_RING * 4);
if ((rsp_cmpl > 0) && (ha_copy & HA_R0RE_REQ)) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
pring->stats.iocb_rsp_full++;
status = ((CA_R0ATT | CA_R0RE_RSP) << (LPFC_FCP_RING * 4));
writel(status, phba->CAregaddr);
readl(phba->CAregaddr);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
}
if ((ha_copy & HA_R0CE_RSP) &&
(pring->flag & LPFC_CALL_RING_AVAILABLE)) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
pring->flag &= ~LPFC_CALL_RING_AVAILABLE;
pring->stats.iocb_cmd_empty++;
@@ -1062,6 +1273,7 @@
if ((pring->lpfc_sli_cmd_available))
(pring->lpfc_sli_cmd_available) (phba, pring);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
}
return;
@@ -1072,10 +1284,12 @@
* to check it explicitly.
*/
static int
-lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring, uint32_t mask)
+lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring, uint32_t mask)
{
- struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
+ struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+ &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+ &phba->slim2p->mbx.us.s2.port[pring->ringno];
IOCB_t *irsp = NULL;
IOCB_t *entry = NULL;
struct lpfc_iocbq *cmdiocbq = NULL;
@@ -1086,9 +1300,8 @@
lpfc_iocb_type type;
unsigned long iflag;
uint32_t rsp_cmpl = 0;
- void __iomem *to_slim;
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
pring->stats.iocb_event++;
/*
@@ -1099,7 +1312,7 @@
portRspPut = le32_to_cpu(pgp->rspPutInx);
if (unlikely(portRspPut >= portRspMax)) {
lpfc_sli_rsp_pointers_error(phba, pring);
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
return 1;
}
@@ -1110,14 +1323,15 @@
* structure. The copy involves a byte-swap since the
* network byte order and pci byte orders are different.
*/
- entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
+ entry = lpfc_resp_iocb(phba, pring);
+ phba->last_completion_time = jiffies;
if (++pring->rspidx >= portRspMax)
pring->rspidx = 0;
lpfc_sli_pcimem_bcopy((uint32_t *) entry,
(uint32_t *) &rspiocbq.iocb,
- sizeof (IOCB_t));
+ phba->iocb_rsp_size);
INIT_LIST_HEAD(&(rspiocbq.list));
irsp = &rspiocbq.iocb;
@@ -1126,16 +1340,30 @@
rsp_cmpl++;
if (unlikely(irsp->ulpStatus)) {
+ /*
+ * If resource errors reported from HBA, reduce
+ * queuedepths of the SCSI device.
+ */
+ if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+ (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) {
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ lpfc_adjust_queue_depth(phba);
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ }
+
/* Rsp ring <ringno> error: IOCB */
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
- "%d:0336 Rsp Ring %d error: IOCB Data: "
- "x%x x%x x%x x%x x%x x%x x%x x%x\n",
- phba->brd_no, pring->ringno,
- irsp->un.ulpWord[0], irsp->un.ulpWord[1],
- irsp->un.ulpWord[2], irsp->un.ulpWord[3],
- irsp->un.ulpWord[4], irsp->un.ulpWord[5],
- *(((uint32_t *) irsp) + 6),
- *(((uint32_t *) irsp) + 7));
+ "%d:0336 Rsp Ring %d error: IOCB Data: "
+ "x%x x%x x%x x%x x%x x%x x%x x%x\n",
+ phba->brd_no, pring->ringno,
+ irsp->un.ulpWord[0],
+ irsp->un.ulpWord[1],
+ irsp->un.ulpWord[2],
+ irsp->un.ulpWord[3],
+ irsp->un.ulpWord[4],
+ irsp->un.ulpWord[5],
+ *(((uint32_t *) irsp) + 6),
+ *(((uint32_t *) irsp) + 7));
}
switch (type) {
@@ -1149,7 +1377,8 @@
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"%d:0333 IOCB cmd 0x%x"
" processed. Skipping"
- " completion\n", phba->brd_no,
+ " completion\n",
+ phba->brd_no,
irsp->ulpCommand);
break;
}
@@ -1161,19 +1390,19 @@
(cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
&rspiocbq);
} else {
- spin_unlock_irqrestore(
- phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock,
+ iflag);
(cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
&rspiocbq);
- spin_lock_irqsave(phba->host->host_lock,
+ spin_lock_irqsave(&phba->hbalock,
iflag);
}
}
break;
case LPFC_UNSOL_IOCB:
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
lpfc_sli_process_unsol_iocb(phba, pring, &rspiocbq);
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
break;
default:
if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
@@ -1186,11 +1415,13 @@
} else {
/* Unknown IOCB command */
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0334 Unknown IOCB command "
- "Data: x%x, x%x x%x x%x x%x\n",
- phba->brd_no, type, irsp->ulpCommand,
- irsp->ulpStatus, irsp->ulpIoTag,
- irsp->ulpContext);
+ "%d:0334 Unknown IOCB command "
+ "Data: x%x, x%x x%x x%x x%x\n",
+ phba->brd_no, type,
+ irsp->ulpCommand,
+ irsp->ulpStatus,
+ irsp->ulpIoTag,
+ irsp->ulpContext);
}
break;
}
@@ -1201,9 +1432,7 @@
* been updated, sync the pgp->rspPutInx and fetch the new port
* response put pointer.
*/
- to_slim = phba->MBslimaddr +
- (SLIMOFF + (pring->ringno * 2) + 1) * 4;
- writel(pring->rspidx, to_slim);
+ writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
if (pring->rspidx == portRspPut)
portRspPut = le32_to_cpu(pgp->rspPutInx);
@@ -1228,31 +1457,31 @@
}
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
return rc;
}
-
int
-lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring, uint32_t mask)
+lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring, uint32_t mask)
{
+ struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+ &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+ &phba->slim2p->mbx.us.s2.port[pring->ringno];
IOCB_t *entry;
IOCB_t *irsp = NULL;
struct lpfc_iocbq *rspiocbp = NULL;
struct lpfc_iocbq *next_iocb;
struct lpfc_iocbq *cmdiocbp;
struct lpfc_iocbq *saveq;
- struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
uint8_t iocb_cmd_type;
lpfc_iocb_type type;
uint32_t status, free_saveq;
uint32_t portRspPut, portRspMax;
int rc = 1;
unsigned long iflag;
- void __iomem *to_slim;
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
pring->stats.iocb_event++;
/*
@@ -1266,16 +1495,14 @@
* Ring <ringno> handler: portRspPut <portRspPut> is bigger then
* rsp ring <portRspMax>
*/
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_SLI,
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"%d:0303 Ring %d handler: portRspPut %d "
"is bigger then rsp ring %d\n",
- phba->brd_no,
- pring->ringno, portRspPut, portRspMax);
+ phba->brd_no, pring->ringno, portRspPut,
+ portRspMax);
- phba->hba_state = LPFC_HBA_ERROR;
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ phba->link_state = LPFC_HBA_ERROR;
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
phba->work_hs = HS_FFER3;
lpfc_handle_eratt(phba);
@@ -1298,23 +1525,24 @@
* the ulpLe field is set, the entire Command has been
* received.
*/
- entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
- rspiocbp = lpfc_sli_get_iocbq(phba);
+ entry = lpfc_resp_iocb(phba, pring);
+
+ phba->last_completion_time = jiffies;
+ rspiocbp = __lpfc_sli_get_iocbq(phba);
if (rspiocbp == NULL) {
printk(KERN_ERR "%s: out of buffers! Failing "
"completion.\n", __FUNCTION__);
break;
}
- lpfc_sli_pcimem_bcopy(entry, &rspiocbp->iocb, sizeof (IOCB_t));
+ lpfc_sli_pcimem_bcopy(entry, &rspiocbp->iocb,
+ phba->iocb_rsp_size);
irsp = &rspiocbp->iocb;
if (++pring->rspidx >= portRspMax)
pring->rspidx = 0;
- to_slim = phba->MBslimaddr + (SLIMOFF + (pring->ringno * 2)
- + 1) * 4;
- writel(pring->rspidx, to_slim);
+ writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
if (list_empty(&(pring->iocb_continueq))) {
list_add(&rspiocbp->list, &(pring->iocb_continueq));
@@ -1338,23 +1566,44 @@
pring->stats.iocb_rsp++;
+ /*
+ * If resource errors reported from HBA, reduce
+ * queuedepths of the SCSI device.
+ */
+ if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+ (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) {
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ lpfc_adjust_queue_depth(phba);
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ }
+
if (irsp->ulpStatus) {
/* Rsp ring <ringno> error: IOCB */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_SLI,
- "%d:0328 Rsp Ring %d error: IOCB Data: "
- "x%x x%x x%x x%x x%x x%x x%x x%x\n",
- phba->brd_no,
- pring->ringno,
- irsp->un.ulpWord[0],
- irsp->un.ulpWord[1],
- irsp->un.ulpWord[2],
- irsp->un.ulpWord[3],
- irsp->un.ulpWord[4],
- irsp->un.ulpWord[5],
- *(((uint32_t *) irsp) + 6),
- *(((uint32_t *) irsp) + 7));
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+ "%d:0328 Rsp Ring %d error: "
+ "IOCB Data: "
+ "x%x x%x x%x x%x "
+ "x%x x%x x%x x%x "
+ "x%x x%x x%x x%x "
+ "x%x x%x x%x x%x\n",
+ phba->brd_no,
+ pring->ringno,
+ irsp->un.ulpWord[0],
+ irsp->un.ulpWord[1],
+ irsp->un.ulpWord[2],
+ irsp->un.ulpWord[3],
+ irsp->un.ulpWord[4],
+ irsp->un.ulpWord[5],
+ *(((uint32_t *) irsp) + 6),
+ *(((uint32_t *) irsp) + 7),
+ *(((uint32_t *) irsp) + 8),
+ *(((uint32_t *) irsp) + 9),
+ *(((uint32_t *) irsp) + 10),
+ *(((uint32_t *) irsp) + 11),
+ *(((uint32_t *) irsp) + 12),
+ *(((uint32_t *) irsp) + 13),
+ *(((uint32_t *) irsp) + 14),
+ *(((uint32_t *) irsp) + 15));
}
/*
@@ -1366,17 +1615,17 @@
iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
if (type == LPFC_SOL_IOCB) {
- spin_unlock_irqrestore(phba->host->host_lock,
+ spin_unlock_irqrestore(&phba->hbalock,
iflag);
rc = lpfc_sli_process_sol_iocb(phba, pring,
- saveq);
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ saveq);
+ spin_lock_irqsave(&phba->hbalock, iflag);
} else if (type == LPFC_UNSOL_IOCB) {
- spin_unlock_irqrestore(phba->host->host_lock,
+ spin_unlock_irqrestore(&phba->hbalock,
iflag);
rc = lpfc_sli_process_unsol_iocb(phba, pring,
- saveq);
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ saveq);
+ spin_lock_irqsave(&phba->hbalock, iflag);
} else if (type == LPFC_ABORT_IOCB) {
if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) &&
((cmdiocbp =
@@ -1386,15 +1635,15 @@
routine */
if (cmdiocbp->iocb_cmpl) {
spin_unlock_irqrestore(
- phba->host->host_lock,
+ &phba->hbalock,
iflag);
(cmdiocbp->iocb_cmpl) (phba,
cmdiocbp, saveq);
spin_lock_irqsave(
- phba->host->host_lock,
+ &phba->hbalock,
iflag);
} else
- lpfc_sli_release_iocbq(phba,
+ __lpfc_sli_release_iocbq(phba,
cmdiocbp);
}
} else if (type == LPFC_UNKNOWN_IOCB) {
@@ -1411,32 +1660,28 @@
phba->brd_no, adaptermsg);
} else {
/* Unknown IOCB command */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_SLI,
- "%d:0335 Unknown IOCB command "
- "Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- irsp->ulpCommand,
- irsp->ulpStatus,
- irsp->ulpIoTag,
- irsp->ulpContext);
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "%d:0335 Unknown IOCB "
+ "command Data: x%x "
+ "x%x x%x x%x\n",
+ phba->brd_no,
+ irsp->ulpCommand,
+ irsp->ulpStatus,
+ irsp->ulpIoTag,
+ irsp->ulpContext);
}
}
if (free_saveq) {
- if (!list_empty(&saveq->list)) {
- list_for_each_entry_safe(rspiocbp,
- next_iocb,
- &saveq->list,
- list) {
- list_del(&rspiocbp->list);
- lpfc_sli_release_iocbq(phba,
- rspiocbp);
- }
+ list_for_each_entry_safe(rspiocbp, next_iocb,
+ &saveq->list, list) {
+ list_del(&rspiocbp->list);
+ __lpfc_sli_release_iocbq(phba,
+ rspiocbp);
}
- lpfc_sli_release_iocbq(phba, saveq);
+ __lpfc_sli_release_iocbq(phba, saveq);
}
+ rspiocbp = NULL;
}
/*
@@ -1449,7 +1694,7 @@
}
} /* while (pring->rspidx != portRspPut) */
- if ((rspiocbp != 0) && (mask & HA_R0RE_REQ)) {
+ if ((rspiocbp != NULL) && (mask & HA_R0RE_REQ)) {
/* At least one response entry has been freed */
pring->stats.iocb_rsp_full++;
/* SET RxRE_RSP in Chip Att register */
@@ -1470,24 +1715,25 @@
}
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
return rc;
}
-int
+void
lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
LIST_HEAD(completions);
struct lpfc_iocbq *iocb, *next_iocb;
IOCB_t *cmd = NULL;
- int errcnt;
- errcnt = 0;
+ if (pring->ringno == LPFC_ELS_RING) {
+ lpfc_fabric_abort_hba(phba);
+ }
/* Error everything on txq and txcmplq
* First do the txq.
*/
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_splice_init(&pring->txq, &completions);
pring->txq_cnt = 0;
@@ -1495,26 +1741,25 @@
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
lpfc_sli_issue_abort_iotag(phba, pring, iocb);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
while (!list_empty(&completions)) {
iocb = list_get_first(&completions, struct lpfc_iocbq, list);
cmd = &iocb->iocb;
- list_del(&iocb->list);
+ list_del_init(&iocb->list);
- if (iocb->iocb_cmpl) {
+ if (!iocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, iocb);
+ else {
cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
(iocb->iocb_cmpl) (phba, iocb, iocb);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
+ }
}
-
- return errcnt;
}
int
-lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask)
+lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask)
{
uint32_t status;
int i = 0;
@@ -1541,7 +1786,8 @@
msleep(2500);
if (i == 15) {
- phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */
+ /* Do post */
+ phba->pport->port_state = LPFC_VPORT_UNKNOWN;
lpfc_sli_brdrestart(phba);
}
/* Read the HBA Host Status Register */
@@ -1550,7 +1796,7 @@
/* Check to see if any errors occurred during init */
if ((status & HS_FFERM) || (i >= 20)) {
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
retval = 1;
}
@@ -1559,7 +1805,7 @@
#define BARRIER_TEST_PATTERN (0xdeadbeef)
-void lpfc_reset_barrier(struct lpfc_hba * phba)
+void lpfc_reset_barrier(struct lpfc_hba *phba)
{
uint32_t __iomem *resp_buf;
uint32_t __iomem *mbox_buf;
@@ -1584,12 +1830,12 @@
hc_copy = readl(phba->HCregaddr);
writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- phba->fc_flag |= FC_IGNORE_ERATT;
+ phba->link_flag |= LS_IGNORE_ERATT;
if (readl(phba->HAregaddr) & HA_ERATT) {
/* Clear Chip error bit */
writel(HA_ERATT, phba->HAregaddr);
- phba->stopped = 1;
+ phba->pport->stopped = 1;
}
mbox = 0;
@@ -1606,7 +1852,7 @@
if (readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN)) {
if (phba->sli.sli_flag & LPFC_SLI2_ACTIVE ||
- phba->stopped)
+ phba->pport->stopped)
goto restore_hc;
else
goto clear_errat;
@@ -1623,17 +1869,17 @@
if (readl(phba->HAregaddr) & HA_ERATT) {
writel(HA_ERATT, phba->HAregaddr);
- phba->stopped = 1;
+ phba->pport->stopped = 1;
}
restore_hc:
- phba->fc_flag &= ~FC_IGNORE_ERATT;
+ phba->link_flag &= ~LS_IGNORE_ERATT;
writel(hc_copy, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
}
int
-lpfc_sli_brdkill(struct lpfc_hba * phba)
+lpfc_sli_brdkill(struct lpfc_hba *phba)
{
struct lpfc_sli *psli;
LPFC_MBOXQ_t *pmb;
@@ -1645,26 +1891,22 @@
psli = &phba->sli;
/* Kill HBA */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_SLI,
- "%d:0329 Kill HBA Data: x%x x%x\n",
- phba->brd_no,
- phba->hba_state,
- psli->sli_flag);
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "%d:0329 Kill HBA Data: x%x x%x\n",
+ phba->brd_no, phba->pport->port_state, psli->sli_flag);
if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
GFP_KERNEL)) == 0)
return 1;
/* Disable the error attention */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
status = readl(phba->HCregaddr);
status &= ~HC_ERINT_ENA;
writel(status, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- phba->fc_flag |= FC_IGNORE_ERATT;
- spin_unlock_irq(phba->host->host_lock);
+ phba->link_flag |= LS_IGNORE_ERATT;
+ spin_unlock_irq(&phba->hbalock);
lpfc_kill_board(phba, pmb);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -1673,9 +1915,9 @@
if (retval != MBX_SUCCESS) {
if (retval != MBX_BUSY)
mempool_free(pmb, phba->mbox_mem_pool);
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_IGNORE_ERATT;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
+ phba->link_flag &= ~LS_IGNORE_ERATT;
+ spin_unlock_irq(&phba->hbalock);
return 1;
}
@@ -1698,22 +1940,22 @@
del_timer_sync(&psli->mbox_tmo);
if (ha_copy & HA_ERATT) {
writel(HA_ERATT, phba->HAregaddr);
- phba->stopped = 1;
+ phba->pport->stopped = 1;
}
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- phba->fc_flag &= ~FC_IGNORE_ERATT;
- spin_unlock_irq(phba->host->host_lock);
+ phba->link_flag &= ~LS_IGNORE_ERATT;
+ spin_unlock_irq(&phba->hbalock);
psli->mbox_active = NULL;
lpfc_hba_down_post(phba);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
- return (ha_copy & HA_ERATT ? 0 : 1);
+ return ha_copy & HA_ERATT ? 0 : 1;
}
int
-lpfc_sli_brdreset(struct lpfc_hba * phba)
+lpfc_sli_brdreset(struct lpfc_hba *phba)
{
struct lpfc_sli *psli;
struct lpfc_sli_ring *pring;
@@ -1725,12 +1967,12 @@
/* Reset HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"%d:0325 Reset HBA Data: x%x x%x\n", phba->brd_no,
- phba->hba_state, psli->sli_flag);
+ phba->pport->port_state, psli->sli_flag);
/* perform board reset */
phba->fc_eventTag = 0;
- phba->fc_myDID = 0;
- phba->fc_prevDID = 0;
+ phba->pport->fc_myDID = 0;
+ phba->pport->fc_prevDID = 0;
/* Turn off parity checking and serr during the physical reset */
pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
@@ -1760,12 +2002,12 @@
pring->missbufcnt = 0;
}
- phba->hba_state = LPFC_WARM_START;
+ phba->link_state = LPFC_WARM_START;
return 0;
}
int
-lpfc_sli_brdrestart(struct lpfc_hba * phba)
+lpfc_sli_brdrestart(struct lpfc_hba *phba)
{
MAILBOX_t *mb;
struct lpfc_sli *psli;
@@ -1773,14 +2015,14 @@
volatile uint32_t word0;
void __iomem *to_slim;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
psli = &phba->sli;
/* Restart HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"%d:0337 Restart HBA Data: x%x x%x\n", phba->brd_no,
- phba->hba_state, psli->sli_flag);
+ phba->pport->port_state, psli->sli_flag);
word0 = 0;
mb = (MAILBOX_t *) &word0;
@@ -1794,7 +2036,7 @@
readl(to_slim); /* flush */
/* Only skip post after fc_ffinit is completed */
- if (phba->hba_state) {
+ if (phba->pport->port_state) {
skip_post = 1;
word0 = 1; /* This is really setting up word1 */
} else {
@@ -1806,10 +2048,10 @@
readl(to_slim); /* flush */
lpfc_sli_brdreset(phba);
- phba->stopped = 0;
- phba->hba_state = LPFC_INIT_START;
+ phba->pport->stopped = 0;
+ phba->link_state = LPFC_INIT_START;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
psli->stats_start = get_seconds();
@@ -1843,14 +2085,11 @@
if (i++ >= 20) {
/* Adapter failed to init, timeout, status reg
<status> */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0436 Adapter failed to init, "
"timeout, status reg x%x\n",
- phba->brd_no,
- status);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->brd_no, status);
+ phba->link_state = LPFC_HBA_ERROR;
return -ETIMEDOUT;
}
@@ -1859,14 +2098,12 @@
/* ERROR: During chipset initialization */
/* Adapter failed to init, chipset, status reg
<status> */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0437 Adapter failed to init, "
"chipset, status reg x%x\n",
phba->brd_no,
status);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
return -EIO;
}
@@ -1879,7 +2116,8 @@
}
if (i == 15) {
- phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */
+ /* Do post */
+ phba->pport->port_state = LPFC_VPORT_UNKNOWN;
lpfc_sli_brdrestart(phba);
}
/* Read the HBA Host Status Register */
@@ -1890,14 +2128,12 @@
if (status & HS_FFERM) {
/* ERROR: During chipset initialization */
/* Adapter failed to init, chipset, status reg <status> */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0438 Adapter failed to init, chipset, "
"status reg x%x\n",
phba->brd_no,
status);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
return -EIO;
}
@@ -1911,80 +2147,253 @@
return 0;
}
+static int
+lpfc_sli_hbq_count(void)
+{
+ return ARRAY_SIZE(lpfc_hbq_defs);
+}
+
+static int
+lpfc_sli_hbq_entry_count(void)
+{
+ int hbq_count = lpfc_sli_hbq_count();
+ int count = 0;
+ int i;
+
+ for (i = 0; i < hbq_count; ++i)
+ count += lpfc_hbq_defs[i]->entry_count;
+ return count;
+}
+
int
-lpfc_sli_hba_setup(struct lpfc_hba * phba)
+lpfc_sli_hbq_size(void)
+{
+ return lpfc_sli_hbq_entry_count() * sizeof(struct lpfc_hbq_entry);
+}
+
+static int
+lpfc_sli_hbq_setup(struct lpfc_hba *phba)
+{
+ int hbq_count = lpfc_sli_hbq_count();
+ LPFC_MBOXQ_t *pmb;
+ MAILBOX_t *pmbox;
+ uint32_t hbqno;
+ uint32_t hbq_entry_index;
+
+ /* Get a Mailbox buffer to setup mailbox
+ * commands for HBA initialization
+ */
+ pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+
+ if (!pmb)
+ return -ENOMEM;
+
+ pmbox = &pmb->mb;
+
+ /* Initialize the struct lpfc_sli_hbq structure for each hbq */
+ phba->link_state = LPFC_INIT_MBX_CMDS;
+
+ hbq_entry_index = 0;
+ for (hbqno = 0; hbqno < hbq_count; ++hbqno) {
+ phba->hbqs[hbqno].next_hbqPutIdx = 0;
+ phba->hbqs[hbqno].hbqPutIdx = 0;
+ phba->hbqs[hbqno].local_hbqGetIdx = 0;
+ phba->hbqs[hbqno].entry_count =
+ lpfc_hbq_defs[hbqno]->entry_count;
+ lpfc_config_hbq(phba, lpfc_hbq_defs[hbqno], hbq_entry_index,
+ pmb);
+ hbq_entry_index += phba->hbqs[hbqno].entry_count;
+
+ if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
+ /* Adapter failed to init, mbxCmd <cmd> CFG_RING,
+ mbxStatus <status>, ring <num> */
+
+ lpfc_printf_log(phba, KERN_ERR,
+ LOG_SLI | LOG_VPORT,
+ "%d:1805 Adapter failed to init. "
+ "Data: x%x x%x x%x\n",
+ phba->brd_no, pmbox->mbxCommand,
+ pmbox->mbxStatus, hbqno);
+
+ phba->link_state = LPFC_HBA_ERROR;
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return ENXIO;
+ }
+ }
+ phba->hbq_count = hbq_count;
+
+ mempool_free(pmb, phba->mbox_mem_pool);
+
+ /* Initially populate or replenish the HBQs */
+ for (hbqno = 0; hbqno < hbq_count; ++hbqno) {
+ if (lpfc_sli_hbqbuf_init_hbqs(phba, hbqno))
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int
+lpfc_do_config_port(struct lpfc_hba *phba, int sli_mode)
{
LPFC_MBOXQ_t *pmb;
uint32_t resetcount = 0, rc = 0, done = 0;
pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
return -ENOMEM;
}
+ phba->sli_rev = sli_mode;
while (resetcount < 2 && !done) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
- phba->hba_state = LPFC_STATE_UNKNOWN;
+ spin_unlock_irq(&phba->hbalock);
+ phba->pport->port_state = LPFC_VPORT_UNKNOWN;
lpfc_sli_brdrestart(phba);
msleep(2500);
rc = lpfc_sli_chipset_init(phba);
if (rc)
break;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
resetcount++;
- /* Call pre CONFIG_PORT mailbox command initialization. A value of 0
- * means the call was successful. Any other nonzero value is a failure,
- * but if ERESTART is returned, the driver may reset the HBA and try
- * again.
- */
+ /* Call pre CONFIG_PORT mailbox command initialization. A
+ * value of 0 means the call was successful. Any other
+ * nonzero value is a failure, but if ERESTART is returned,
+ * the driver may reset the HBA and try again.
+ */
rc = lpfc_config_port_prep(phba);
if (rc == -ERESTART) {
- phba->hba_state = 0;
+ phba->link_state = LPFC_LINK_UNKNOWN;
continue;
} else if (rc) {
break;
}
- phba->hba_state = LPFC_INIT_MBX_CMDS;
+ phba->link_state = LPFC_INIT_MBX_CMDS;
lpfc_config_port(phba, pmb);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
- if (rc == MBX_SUCCESS)
- done = 1;
- else {
+ if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0442 Adapter failed to init, mbxCmd x%x "
"CONFIG_PORT, mbxStatus x%x Data: x%x\n",
phba->brd_no, pmb->mb.mbxCommand,
pmb->mb.mbxStatus, 0);
+ spin_lock_irq(&phba->hbalock);
phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
+ spin_unlock_irq(&phba->hbalock);
+ rc = -ENXIO;
+ } else {
+ done = 1;
+ phba->max_vpi = (phba->max_vpi &&
+ pmb->mb.un.varCfgPort.gmv) != 0
+ ? pmb->mb.un.varCfgPort.max_vpi
+ : 0;
}
}
- if (!done)
+
+ if (!done) {
+ rc = -EINVAL;
+ goto do_prep_failed;
+ }
+
+ if ((pmb->mb.un.varCfgPort.sli_mode == 3) &&
+ (!pmb->mb.un.varCfgPort.cMA)) {
+ rc = -ENXIO;
+ goto do_prep_failed;
+ }
+ return rc;
+
+do_prep_failed:
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return rc;
+}
+
+int
+lpfc_sli_hba_setup(struct lpfc_hba *phba)
+{
+ uint32_t rc;
+ int mode = 3;
+
+ switch (lpfc_sli_mode) {
+ case 2:
+ if (phba->cfg_npiv_enable) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
+ "%d:1824 NPIV enabled: Override lpfc_sli_mode "
+ "parameter (%d) to auto (0).\n",
+ phba->brd_no, lpfc_sli_mode);
+ break;
+ }
+ mode = 2;
+ break;
+ case 0:
+ case 3:
+ break;
+ default:
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
+ "%d:1819 Unrecognized lpfc_sli_mode "
+ "parameter: %d.\n",
+ phba->brd_no, lpfc_sli_mode);
+
+ break;
+ }
+
+ rc = lpfc_do_config_port(phba, mode);
+ if (rc && lpfc_sli_mode == 3)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
+ "%d:1820 Unable to select SLI-3. "
+ "Not supported by adapter.\n",
+ phba->brd_no);
+ if (rc && mode != 2)
+ rc = lpfc_do_config_port(phba, 2);
+ if (rc)
goto lpfc_sli_hba_setup_error;
- rc = lpfc_sli_ring_map(phba, pmb);
+ if (phba->sli_rev == 3) {
+ phba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE;
+ phba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE;
+ phba->sli3_options |= LPFC_SLI3_ENABLED;
+ phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
+
+ } else {
+ phba->iocb_cmd_size = SLI2_IOCB_CMD_SIZE;
+ phba->iocb_rsp_size = SLI2_IOCB_RSP_SIZE;
+ phba->sli3_options = 0;
+ }
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "%d:0444 Firmware in SLI %x mode. Max_vpi %d\n",
+ phba->brd_no, phba->sli_rev, phba->max_vpi);
+ rc = lpfc_sli_ring_map(phba);
if (rc)
goto lpfc_sli_hba_setup_error;
+ /* Init HBQs */
+
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ rc = lpfc_sli_hbq_setup(phba);
+ if (rc)
+ goto lpfc_sli_hba_setup_error;
+ }
+
phba->sli.sli_flag |= LPFC_PROCESS_LA;
rc = lpfc_config_port_post(phba);
if (rc)
goto lpfc_sli_hba_setup_error;
- goto lpfc_sli_hba_setup_exit;
+ return rc;
+
lpfc_sli_hba_setup_error:
- phba->hba_state = LPFC_HBA_ERROR;
-lpfc_sli_hba_setup_exit:
- mempool_free(pmb, phba->mbox_mem_pool);
+ phba->link_state = LPFC_HBA_ERROR;
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "%d:0445 Firmware initialization failed\n",
+ phba->brd_no);
return rc;
}
@@ -2004,56 +2413,58 @@
void
lpfc_mbox_timeout(unsigned long ptr)
{
- struct lpfc_hba *phba;
+ struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
unsigned long iflag;
+ uint32_t tmo_posted;
- phba = (struct lpfc_hba *)ptr;
- spin_lock_irqsave(phba->host->host_lock, iflag);
- if (!(phba->work_hba_events & WORKER_MBOX_TMO)) {
- phba->work_hba_events |= WORKER_MBOX_TMO;
+ spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
+ tmo_posted = phba->pport->work_port_events & WORKER_MBOX_TMO;
+ if (!tmo_posted)
+ phba->pport->work_port_events |= WORKER_MBOX_TMO;
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
+
+ if (!tmo_posted) {
+ spin_lock_irqsave(&phba->hbalock, iflag);
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
}
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
}
void
lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
{
- LPFC_MBOXQ_t *pmbox;
- MAILBOX_t *mb;
+ LPFC_MBOXQ_t *pmbox = phba->sli.mbox_active;
+ MAILBOX_t *mb = &pmbox->mb;
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
- spin_lock_irq(phba->host->host_lock);
- if (!(phba->work_hba_events & WORKER_MBOX_TMO)) {
- spin_unlock_irq(phba->host->host_lock);
+ if (!(phba->pport->work_port_events & WORKER_MBOX_TMO)) {
return;
}
- pmbox = phba->sli.mbox_active;
- mb = &pmbox->mb;
-
/* Mbox cmd <mbxCommand> timeout */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_MBOX | LOG_SLI,
- "%d:0310 Mailbox command x%x timeout Data: x%x x%x x%p\n",
- phba->brd_no,
- mb->mbxCommand,
- phba->hba_state,
- phba->sli.sli_flag,
- phba->sli.mbox_active);
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+ "%d:0310 Mailbox command x%x timeout Data: x%x x%x "
+ "x%p\n",
+ phba->brd_no,
+ mb->mbxCommand,
+ phba->pport->port_state,
+ phba->sli.sli_flag,
+ phba->sli.mbox_active);
/* Setting state unknown so lpfc_sli_abort_iocb_ring
* would get IOCB_ERROR from lpfc_sli_issue_iocb, allowing
* it to fail all oustanding SCSI IO.
*/
- phba->hba_state = LPFC_STATE_UNKNOWN;
- phba->work_hba_events &= ~WORKER_MBOX_TMO;
- phba->fc_flag |= FC_ESTABLISH_LINK;
+ spin_lock_irq(&phba->pport->work_port_lock);
+ phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
+ spin_unlock_irq(&phba->pport->work_port_lock);
+ spin_lock_irq(&phba->hbalock);
+ phba->link_state = LPFC_LINK_UNKNOWN;
+ phba->pport->fc_flag |= FC_ESTABLISH_LINK;
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
pring = &psli->ring[psli->fcp_ring];
lpfc_sli_abort_iocb_ring(phba, pring);
@@ -2075,10 +2486,10 @@
}
int
-lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
+lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
{
MAILBOX_t *mb;
- struct lpfc_sli *psli;
+ struct lpfc_sli *psli = &phba->sli;
uint32_t status, evtctr;
uint32_t ha_copy;
int i;
@@ -2086,31 +2497,44 @@
volatile uint32_t word0, ldata;
void __iomem *to_slim;
+ if (pmbox->mbox_cmpl && pmbox->mbox_cmpl != lpfc_sli_def_mbox_cmpl &&
+ pmbox->mbox_cmpl != lpfc_sli_wake_mbox_wait) {
+ if(!pmbox->vport) {
+ lpfc_printf_log(phba, KERN_ERR,
+ LOG_MBOX | LOG_VPORT,
+ "%d:1806 Mbox x%x failed. No vport\n",
+ phba->brd_no,
+ pmbox->mb.mbxCommand);
+ dump_stack();
+ return MBXERR_ERROR;
+ }
+ }
+
+
/* If the PCI channel is in offline state, do not post mbox. */
if (unlikely(pci_channel_offline(phba->pcidev)))
return MBX_NOT_FINISHED;
+ spin_lock_irqsave(&phba->hbalock, drvr_flag);
psli = &phba->sli;
- spin_lock_irqsave(phba->host->host_lock, drvr_flag);
-
mb = &pmbox->mb;
status = MBX_SUCCESS;
- if (phba->hba_state == LPFC_HBA_ERROR) {
- spin_unlock_irqrestore(phba->host->host_lock, drvr_flag);
+ if (phba->link_state == LPFC_HBA_ERROR) {
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
/* Mbox command <mbxCommand> cannot issue */
- LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
- return (MBX_NOT_FINISHED);
+ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag)
+ return MBX_NOT_FINISHED;
}
if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT &&
!(readl(phba->HCregaddr) & HC_MBINT_ENA)) {
- spin_unlock_irqrestore(phba->host->host_lock, drvr_flag);
- LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
- return (MBX_NOT_FINISHED);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
+ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag)
+ return MBX_NOT_FINISHED;
}
if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
@@ -2120,20 +2544,18 @@
*/
if (flag & MBX_POLL) {
- spin_unlock_irqrestore(phba->host->host_lock,
- drvr_flag);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
/* Mbox command <mbxCommand> cannot issue */
- LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
- return (MBX_NOT_FINISHED);
+ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+ return MBX_NOT_FINISHED;
}
if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) {
- spin_unlock_irqrestore(phba->host->host_lock,
- drvr_flag);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
/* Mbox command <mbxCommand> cannot issue */
- LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
- return (MBX_NOT_FINISHED);
+ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+ return MBX_NOT_FINISHED;
}
/* Handle STOP IOCB processing flag. This is only meaningful
@@ -2157,21 +2579,33 @@
lpfc_mbox_put(phba, pmbox);
/* Mbox cmd issue - BUSY */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_MBOX | LOG_SLI,
- "%d:0308 Mbox cmd issue - BUSY Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- mb->mbxCommand,
- phba->hba_state,
- psli->sli_flag,
- flag);
+ lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+ "%d (%d):0308 Mbox cmd issue - BUSY Data: "
+ "x%x x%x x%x x%x\n",
+ phba->brd_no,
+ pmbox->vport ? pmbox->vport->vpi : 0xffffff,
+ mb->mbxCommand, phba->pport->port_state,
+ psli->sli_flag, flag);
psli->slistat.mbox_busy++;
- spin_unlock_irqrestore(phba->host->host_lock,
- drvr_flag);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
- return (MBX_BUSY);
+ if (pmbox->vport) {
+ lpfc_debugfs_disc_trc(pmbox->vport,
+ LPFC_DISC_TRC_MBOX_VPORT,
+ "MBOX Bsy vport: cmd:x%x mb:x%x x%x",
+ (uint32_t)mb->mbxCommand,
+ mb->un.varWords[0], mb->un.varWords[1]);
+ }
+ else {
+ lpfc_debugfs_disc_trc(phba->pport,
+ LPFC_DISC_TRC_MBOX,
+ "MBOX Bsy: cmd:x%x mb:x%x x%x",
+ (uint32_t)mb->mbxCommand,
+ mb->un.varWords[0], mb->un.varWords[1]);
+ }
+
+ return MBX_BUSY;
}
/* Handle STOP IOCB processing flag. This is only meaningful
@@ -2198,11 +2632,10 @@
if (!(psli->sli_flag & LPFC_SLI2_ACTIVE) &&
(mb->mbxCommand != MBX_KILL_BOARD)) {
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- spin_unlock_irqrestore(phba->host->host_lock,
- drvr_flag);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
/* Mbox command <mbxCommand> cannot issue */
- LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag);
- return (MBX_NOT_FINISHED);
+ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+ return MBX_NOT_FINISHED;
}
/* timeout active mbox command */
mod_timer(&psli->mbox_tmo, (jiffies +
@@ -2210,15 +2643,29 @@
}
/* Mailbox cmd <cmd> issue */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_MBOX | LOG_SLI,
- "%d:0309 Mailbox cmd x%x issue Data: x%x x%x x%x\n",
- phba->brd_no,
- mb->mbxCommand,
- phba->hba_state,
- psli->sli_flag,
- flag);
+ lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+ "%d (%d):0309 Mailbox cmd x%x issue Data: x%x x%x "
+ "x%x\n",
+ phba->brd_no, pmbox->vport ? pmbox->vport->vpi : 0,
+ mb->mbxCommand, phba->pport->port_state,
+ psli->sli_flag, flag);
+
+ if (mb->mbxCommand != MBX_HEARTBEAT) {
+ if (pmbox->vport) {
+ lpfc_debugfs_disc_trc(pmbox->vport,
+ LPFC_DISC_TRC_MBOX_VPORT,
+ "MBOX Send vport: cmd:x%x mb:x%x x%x",
+ (uint32_t)mb->mbxCommand,
+ mb->un.varWords[0], mb->un.varWords[1]);
+ }
+ else {
+ lpfc_debugfs_disc_trc(phba->pport,
+ LPFC_DISC_TRC_MBOX,
+ "MBOX Send: cmd:x%x mb:x%x x%x",
+ (uint32_t)mb->mbxCommand,
+ mb->un.varWords[0], mb->un.varWords[1]);
+ }
+ }
psli->slistat.mbox_cmd++;
evtctr = psli->slistat.mbox_event;
@@ -2233,7 +2680,7 @@
if (mb->mbxCommand == MBX_CONFIG_PORT) {
/* copy command data into host mbox for cmpl */
lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx,
- MAILBOX_CMD_SIZE);
+ MAILBOX_CMD_SIZE);
}
/* First copy mbox command data to HBA SLIM, skip past first
@@ -2285,12 +2732,12 @@
/* Wait for command to complete */
while (((word0 & OWN_CHIP) == OWN_CHIP) ||
(!(ha_copy & HA_MBATT) &&
- (phba->hba_state > LPFC_WARM_START))) {
+ (phba->link_state > LPFC_WARM_START))) {
if (i-- <= 0) {
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- spin_unlock_irqrestore(phba->host->host_lock,
+ spin_unlock_irqrestore(&phba->hbalock,
drvr_flag);
- return (MBX_NOT_FINISHED);
+ return MBX_NOT_FINISHED;
}
/* Check if we took a mbox interrupt while we were
@@ -2299,12 +2746,12 @@
&& (evtctr != psli->slistat.mbox_event))
break;
- spin_unlock_irqrestore(phba->host->host_lock,
+ spin_unlock_irqrestore(&phba->hbalock,
drvr_flag);
msleep(1);
- spin_lock_irqsave(phba->host->host_lock, drvr_flag);
+ spin_lock_irqsave(&phba->hbalock, drvr_flag);
if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
/* First copy command data */
@@ -2335,7 +2782,7 @@
if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
/* copy results back to user */
lpfc_sli_pcimem_bcopy(&phba->slim2p->mbx, mb,
- MAILBOX_CMD_SIZE);
+ MAILBOX_CMD_SIZE);
} else {
/* First copy command data */
lpfc_memcpy_from_slim(mb, phba->MBslimaddr,
@@ -2355,23 +2802,25 @@
status = mb->mbxStatus;
}
- spin_unlock_irqrestore(phba->host->host_lock, drvr_flag);
- return (status);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
+ return status;
}
-static int
-lpfc_sli_ringtx_put(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
- struct lpfc_iocbq * piocb)
+/*
+ * Caller needs to hold lock.
+ */
+static void
+__lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocb)
{
/* Insert the caller's iocb in the txq tail for later processing. */
list_add_tail(&piocb->list, &pring->txq);
pring->txq_cnt++;
- return (0);
}
static struct lpfc_iocbq *
lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- struct lpfc_iocbq ** piocb)
+ struct lpfc_iocbq **piocb)
{
struct lpfc_iocbq * nextiocb;
@@ -2384,13 +2833,29 @@
return nextiocb;
}
+/*
+ * Lockless version of lpfc_sli_issue_iocb.
+ */
int
-lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+__lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb, uint32_t flag)
{
struct lpfc_iocbq *nextiocb;
IOCB_t *iocb;
+ if (piocb->iocb_cmpl && (!piocb->vport) &&
+ (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
+ (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
+ lpfc_printf_log(phba, KERN_ERR,
+ LOG_SLI | LOG_VPORT,
+ "%d:1807 IOCB x%x failed. No vport\n",
+ phba->brd_no,
+ piocb->iocb.ulpCommand);
+ dump_stack();
+ return IOCB_ERROR;
+ }
+
+
/* If the PCI channel is in offline state, do not post iocbs. */
if (unlikely(pci_channel_offline(phba->pcidev)))
return IOCB_ERROR;
@@ -2398,7 +2863,7 @@
/*
* We should never get an IOCB if we are in a < LINK_DOWN state
*/
- if (unlikely(phba->hba_state < LPFC_LINK_DOWN))
+ if (unlikely(phba->link_state < LPFC_LINK_DOWN))
return IOCB_ERROR;
/*
@@ -2408,7 +2873,7 @@
if (unlikely(pring->flag & LPFC_STOP_IOCB_MBX))
goto iocb_busy;
- if (unlikely(phba->hba_state == LPFC_LINK_DOWN)) {
+ if (unlikely(phba->link_state == LPFC_LINK_DOWN)) {
/*
* Only CREATE_XRI, CLOSE_XRI, and QUE_RING_BUF
* can be issued if the link is not up.
@@ -2436,8 +2901,9 @@
* attention events.
*/
} else if (unlikely(pring->ringno == phba->sli.fcp_ring &&
- !(phba->sli.sli_flag & LPFC_PROCESS_LA)))
+ !(phba->sli.sli_flag & LPFC_PROCESS_LA))) {
goto iocb_busy;
+ }
while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) &&
(nextiocb = lpfc_sli_next_iocb(phba, pring, &piocb)))
@@ -2459,13 +2925,28 @@
out_busy:
if (!(flag & SLI_IOCB_RET_IOCB)) {
- lpfc_sli_ringtx_put(phba, pring, piocb);
+ __lpfc_sli_ringtx_put(phba, pring, piocb);
return IOCB_SUCCESS;
}
return IOCB_BUSY;
}
+
+int
+lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocb, uint32_t flag)
+{
+ unsigned long iflags;
+ int rc;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ rc = __lpfc_sli_issue_iocb(phba, pring, piocb, flag);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+ return rc;
+}
+
static int
lpfc_extra_ring_setup( struct lpfc_hba *phba)
{
@@ -2504,7 +2985,7 @@
int
lpfc_sli_setup(struct lpfc_hba *phba)
{
- int i, totiocb = 0;
+ int i, totiocbsize = 0;
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
@@ -2529,6 +3010,12 @@
pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES;
pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES;
pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES;
+ pring->sizeCiocb = (phba->sli_rev == 3) ?
+ SLI3_IOCB_CMD_SIZE :
+ SLI2_IOCB_CMD_SIZE;
+ pring->sizeRiocb = (phba->sli_rev == 3) ?
+ SLI3_IOCB_RSP_SIZE :
+ SLI2_IOCB_RSP_SIZE;
pring->iotag_ctr = 0;
pring->iotag_max =
(phba->cfg_hba_queue_depth * 2);
@@ -2539,12 +3026,25 @@
/* numCiocb and numRiocb are used in config_port */
pring->numCiocb = SLI2_IOCB_CMD_R1_ENTRIES;
pring->numRiocb = SLI2_IOCB_RSP_R1_ENTRIES;
+ pring->sizeCiocb = (phba->sli_rev == 3) ?
+ SLI3_IOCB_CMD_SIZE :
+ SLI2_IOCB_CMD_SIZE;
+ pring->sizeRiocb = (phba->sli_rev == 3) ?
+ SLI3_IOCB_RSP_SIZE :
+ SLI2_IOCB_RSP_SIZE;
+ pring->iotag_max = phba->cfg_hba_queue_depth;
pring->num_mask = 0;
break;
case LPFC_ELS_RING: /* ring 2 - ELS / CT */
/* numCiocb and numRiocb are used in config_port */
pring->numCiocb = SLI2_IOCB_CMD_R2_ENTRIES;
pring->numRiocb = SLI2_IOCB_RSP_R2_ENTRIES;
+ pring->sizeCiocb = (phba->sli_rev == 3) ?
+ SLI3_IOCB_CMD_SIZE :
+ SLI2_IOCB_CMD_SIZE;
+ pring->sizeRiocb = (phba->sli_rev == 3) ?
+ SLI3_IOCB_RSP_SIZE :
+ SLI2_IOCB_RSP_SIZE;
pring->fast_iotag = 0;
pring->iotag_ctr = 0;
pring->iotag_max = 4096;
@@ -2575,14 +3075,16 @@
lpfc_ct_unsol_event;
break;
}
- totiocb += (pring->numCiocb + pring->numRiocb);
+ totiocbsize += (pring->numCiocb * pring->sizeCiocb) +
+ (pring->numRiocb * pring->sizeRiocb);
}
- if (totiocb > MAX_SLI2_IOCB) {
+ if (totiocbsize > MAX_SLIM_IOCB_SIZE) {
/* Too many cmd / rsp ring entries in SLI2 SLIM */
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0462 Too many cmd / rsp ring entries in "
- "SLI2 SLIM Data: x%x x%x\n",
- phba->brd_no, totiocb, MAX_SLI2_IOCB);
+ "SLI2 SLIM Data: x%x x%lx\n",
+ phba->brd_no, totiocbsize,
+ (unsigned long) MAX_SLIM_IOCB_SIZE);
}
if (phba->cfg_multi_ring_support == 2)
lpfc_extra_ring_setup(phba);
@@ -2591,15 +3093,16 @@
}
int
-lpfc_sli_queue_setup(struct lpfc_hba * phba)
+lpfc_sli_queue_setup(struct lpfc_hba *phba)
{
struct lpfc_sli *psli;
struct lpfc_sli_ring *pring;
int i;
psli = &phba->sli;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
INIT_LIST_HEAD(&psli->mboxq);
+ INIT_LIST_HEAD(&psli->mboxq_cmpl);
/* Initialize list headers for txq and txcmplq as double linked lists */
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
@@ -2612,15 +3115,73 @@
INIT_LIST_HEAD(&pring->iocb_continueq);
INIT_LIST_HEAD(&pring->postbufq);
}
- spin_unlock_irq(phba->host->host_lock);
- return (1);
+ spin_unlock_irq(&phba->hbalock);
+ return 1;
}
int
-lpfc_sli_hba_down(struct lpfc_hba * phba)
+lpfc_sli_host_down(struct lpfc_vport *vport)
{
LIST_HEAD(completions);
- struct lpfc_sli *psli;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring;
+ struct lpfc_iocbq *iocb, *next_iocb;
+ int i;
+ unsigned long flags = 0;
+ uint16_t prev_pring_flag;
+
+ lpfc_cleanup_discovery_resources(vport);
+
+ spin_lock_irqsave(&phba->hbalock, flags);
+ for (i = 0; i < psli->num_rings; i++) {
+ pring = &psli->ring[i];
+ prev_pring_flag = pring->flag;
+ if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */
+ pring->flag |= LPFC_DEFERRED_RING_EVENT;
+ /*
+ * Error everything on the txq since these iocbs have not been
+ * given to the FW yet.
+ */
+ list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+ if (iocb->vport != vport)
+ continue;
+ list_move_tail(&iocb->list, &completions);
+ pring->txq_cnt--;
+ }
+
+ /* Next issue ABTS for everything on the txcmplq */
+ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq,
+ list) {
+ if (iocb->vport != vport)
+ continue;
+ lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+ }
+
+ pring->flag = prev_pring_flag;
+ }
+
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+
+ while (!list_empty(&completions)) {
+ list_remove_head(&completions, iocb, struct lpfc_iocbq, list);
+
+ if (!iocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, iocb);
+ else {
+ iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
+ iocb->iocb.un.ulpWord[4] = IOERR_SLI_DOWN;
+ (iocb->iocb_cmpl) (phba, iocb, iocb);
+ }
+ }
+ return 1;
+}
+
+int
+lpfc_sli_hba_down(struct lpfc_hba *phba)
+{
+ LIST_HEAD(completions);
+ struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
LPFC_MBOXQ_t *pmb;
struct lpfc_iocbq *iocb;
@@ -2628,13 +3189,15 @@
int i;
unsigned long flags = 0;
- psli = &phba->sli;
lpfc_hba_down_prep(phba);
- spin_lock_irqsave(phba->host->host_lock, flags);
+ lpfc_fabric_abort_hba(phba);
+
+ spin_lock_irqsave(&phba->hbalock, flags);
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
- pring->flag |= LPFC_DEFERRED_RING_EVENT;
+ if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */
+ pring->flag |= LPFC_DEFERRED_RING_EVENT;
/*
* Error everything on the txq since these iocbs have not been
@@ -2644,51 +3207,50 @@
pring->txq_cnt = 0;
}
- spin_unlock_irqrestore(phba->host->host_lock, flags);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
while (!list_empty(&completions)) {
- iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ list_remove_head(&completions, iocb, struct lpfc_iocbq, list);
cmd = &iocb->iocb;
- list_del(&iocb->list);
- if (iocb->iocb_cmpl) {
+ if (!iocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, iocb);
+ else {
cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
cmd->un.ulpWord[4] = IOERR_SLI_DOWN;
(iocb->iocb_cmpl) (phba, iocb, iocb);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
+ }
}
/* Return any active mbox cmds */
del_timer_sync(&psli->mbox_tmo);
- spin_lock_irqsave(phba->host->host_lock, flags);
- phba->work_hba_events &= ~WORKER_MBOX_TMO;
+ spin_lock_irqsave(&phba->hbalock, flags);
+
+ spin_lock(&phba->pport->work_port_lock);
+ phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
+ spin_unlock(&phba->pport->work_port_lock);
+
if (psli->mbox_active) {
- pmb = psli->mbox_active;
- pmb->mb.mbxStatus = MBX_NOT_FINISHED;
- if (pmb->mbox_cmpl) {
- spin_unlock_irqrestore(phba->host->host_lock, flags);
- pmb->mbox_cmpl(phba,pmb);
- spin_lock_irqsave(phba->host->host_lock, flags);
- }
- }
- psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- psli->mbox_active = NULL;
-
- /* Return any pending mbox cmds */
- while ((pmb = lpfc_mbox_get(phba)) != NULL) {
- pmb->mb.mbxStatus = MBX_NOT_FINISHED;
- if (pmb->mbox_cmpl) {
- spin_unlock_irqrestore(phba->host->host_lock, flags);
- pmb->mbox_cmpl(phba,pmb);
- spin_lock_irqsave(phba->host->host_lock, flags);
- }
+ list_add_tail(&psli->mbox_active->list, &completions);
+ psli->mbox_active = NULL;
+ psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
}
+ /* Return any pending or completed mbox cmds */
+ list_splice_init(&phba->sli.mboxq, &completions);
+ list_splice_init(&phba->sli.mboxq_cmpl, &completions);
INIT_LIST_HEAD(&psli->mboxq);
+ INIT_LIST_HEAD(&psli->mboxq_cmpl);
- spin_unlock_irqrestore(phba->host->host_lock, flags);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ while (!list_empty(&completions)) {
+ list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list);
+ pmb->mb.mbxStatus = MBX_NOT_FINISHED;
+ if (pmb->mbox_cmpl) {
+ pmb->mbox_cmpl(phba,pmb);
+ }
+ }
return 1;
}
@@ -2710,14 +3272,15 @@
}
int
-lpfc_sli_ringpostbuf_put(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
- struct lpfc_dmabuf * mp)
+lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_dmabuf *mp)
{
/* Stick struct lpfc_dmabuf at end of postbufq so driver can look it up
later */
+ spin_lock_irq(&phba->hbalock);
list_add_tail(&mp->list, &pring->postbufq);
-
pring->postbufq_cnt++;
+ spin_unlock_irq(&phba->hbalock);
return 0;
}
@@ -2730,14 +3293,17 @@
struct list_head *slp = &pring->postbufq;
/* Search postbufq, from the begining, looking for a match on phys */
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
if (mp->phys == phys) {
list_del_init(&mp->list);
pring->postbufq_cnt--;
+ spin_unlock_irq(&phba->hbalock);
return mp;
}
}
+ spin_unlock_irq(&phba->hbalock);
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0410 Cannot find virtual addr for mapped buf on "
"ring %d Data x%llx x%p x%p x%x\n",
@@ -2747,92 +3313,110 @@
}
static void
-lpfc_sli_abort_els_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
- IOCB_t *irsp;
+ IOCB_t *irsp = &rspiocb->iocb;
uint16_t abort_iotag, abort_context;
- struct lpfc_iocbq *abort_iocb, *rsp_ab_iocb;
+ struct lpfc_iocbq *abort_iocb;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
abort_iocb = NULL;
- irsp = &rspiocb->iocb;
-
- spin_lock_irq(phba->host->host_lock);
if (irsp->ulpStatus) {
abort_context = cmdiocb->iocb.un.acxri.abortContextTag;
abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag;
+ spin_lock_irq(&phba->hbalock);
if (abort_iotag != 0 && abort_iotag <= phba->sli.last_iotag)
abort_iocb = phba->sli.iocbq_lookup[abort_iotag];
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0327 Cannot abort els iocb %p"
- " with tag %x context %x\n",
- phba->brd_no, abort_iocb,
- abort_iotag, abort_context);
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI,
+ "%d:0327 Cannot abort els iocb %p "
+ "with tag %x context %x, abort status %x, "
+ "abort code %x\n",
+ phba->brd_no, abort_iocb, abort_iotag,
+ abort_context, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
/*
* make sure we have the right iocbq before taking it
* off the txcmplq and try to call completion routine.
*/
- if (abort_iocb &&
- abort_iocb->iocb.ulpContext == abort_context &&
- abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) {
- list_del(&abort_iocb->list);
+ if (!abort_iocb ||
+ abort_iocb->iocb.ulpContext != abort_context ||
+ (abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) == 0)
+ spin_unlock_irq(&phba->hbalock);
+ else {
+ list_del_init(&abort_iocb->list);
pring->txcmplq_cnt--;
+ spin_unlock_irq(&phba->hbalock);
- rsp_ab_iocb = lpfc_sli_get_iocbq(phba);
- if (rsp_ab_iocb == NULL)
- lpfc_sli_release_iocbq(phba, abort_iocb);
- else {
- abort_iocb->iocb_flag &=
- ~LPFC_DRIVER_ABORTED;
- rsp_ab_iocb->iocb.ulpStatus =
- IOSTAT_LOCAL_REJECT;
- rsp_ab_iocb->iocb.un.ulpWord[4] =
- IOERR_SLI_ABORTED;
- spin_unlock_irq(phba->host->host_lock);
- (abort_iocb->iocb_cmpl)
- (phba, abort_iocb, rsp_ab_iocb);
- spin_lock_irq(phba->host->host_lock);
- lpfc_sli_release_iocbq(phba, rsp_ab_iocb);
- }
+ abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
+ abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
+ abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb);
}
}
lpfc_sli_release_iocbq(phba, cmdiocb);
- spin_unlock_irq(phba->host->host_lock);
+ return;
+}
+
+static void
+lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ IOCB_t *irsp = &rspiocb->iocb;
+
+ /* ELS cmd tag <ulpIoTag> completes */
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (X):0133 Ignoring ELS cmd tag x%x completion Data: "
+ "x%x x%x x%x\n",
+ phba->brd_no, irsp->ulpIoTag, irsp->ulpStatus,
+ irsp->un.ulpWord[4], irsp->ulpTimeout);
+ if (cmdiocb->iocb.ulpCommand == CMD_GEN_REQUEST64_CR)
+ lpfc_ct_free_iocb(phba, cmdiocb);
+ else
+ lpfc_els_free_iocb(phba, cmdiocb);
return;
}
int
-lpfc_sli_issue_abort_iotag(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring,
- struct lpfc_iocbq * cmdiocb)
+lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *cmdiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
struct lpfc_iocbq *abtsiocbp;
IOCB_t *icmd = NULL;
IOCB_t *iabt = NULL;
int retval = IOCB_ERROR;
- /* There are certain command types we don't want
- * to abort.
+ /*
+ * There are certain command types we don't want to abort. And we
+ * don't want to abort commands that are already in the process of
+ * being aborted.
*/
icmd = &cmdiocb->iocb;
- if ((icmd->ulpCommand == CMD_ABORT_XRI_CN) ||
- (icmd->ulpCommand == CMD_CLOSE_XRI_CN))
+ if (icmd->ulpCommand == CMD_ABORT_XRI_CN ||
+ icmd->ulpCommand == CMD_CLOSE_XRI_CN ||
+ (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0)
return 0;
- /* If we're unloading, interrupts are disabled so we
- * need to cleanup the iocb here.
+ /* If we're unloading, don't abort iocb on the ELS ring, but change the
+ * callback so that nothing happens when it finishes.
*/
- if (phba->fc_flag & FC_UNLOADING)
+ if ((vport->load_flag & FC_UNLOADING) &&
+ (pring->ringno == LPFC_ELS_RING)) {
+ if (cmdiocb->iocb_flag & LPFC_IO_FABRIC)
+ cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl;
+ else
+ cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl;
goto abort_iotag_exit;
+ }
/* issue ABTS for this IOCB based on iotag */
- abtsiocbp = lpfc_sli_get_iocbq(phba);
+ abtsiocbp = __lpfc_sli_get_iocbq(phba);
if (abtsiocbp == NULL)
return 0;
@@ -2848,7 +3432,7 @@
iabt->ulpLe = 1;
iabt->ulpClass = icmd->ulpClass;
- if (phba->hba_state >= LPFC_LINK_UP)
+ if (phba->link_state >= LPFC_LINK_UP)
iabt->ulpCommand = CMD_ABORT_XRI_CN;
else
iabt->ulpCommand = CMD_CLOSE_XRI_CN;
@@ -2856,32 +3440,20 @@
abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl;
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d:0339 Abort xri x%x, original iotag x%x, abort "
- "cmd iotag x%x\n",
- phba->brd_no, iabt->un.acxri.abortContextTag,
+ "%d (%d):0339 Abort xri x%x, original iotag x%x, "
+ "abort cmd iotag x%x\n",
+ phba->brd_no, vport->vpi,
+ iabt->un.acxri.abortContextTag,
iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
- retval = lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
+ retval = __lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
abort_iotag_exit:
-
- /* If we could not issue an abort dequeue the iocb and handle
- * the completion here.
+ /*
+ * Caller to this routine should check for IOCB_ERROR
+ * and handle it properly. This routine no longer removes
+ * iocb off txcmplq and call compl in case of IOCB_ERROR.
*/
- if (retval == IOCB_ERROR) {
- list_del(&cmdiocb->list);
- pring->txcmplq_cnt--;
-
- if (cmdiocb->iocb_cmpl) {
- icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
- icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
- spin_unlock_irq(phba->host->host_lock);
- (cmdiocb->iocb_cmpl) (phba, cmdiocb, cmdiocb);
- spin_lock_irq(phba->host->host_lock);
- } else
- lpfc_sli_release_iocbq(phba, cmdiocb);
- }
-
- return 1;
+ return retval;
}
static int
@@ -2930,7 +3502,7 @@
int
lpfc_sli_sum_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd ctx_cmd)
+ uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd ctx_cmd)
{
struct lpfc_iocbq *iocbq;
int sum, i;
@@ -2947,14 +3519,10 @@
}
void
-lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
- unsigned long iflags;
-
- spin_lock_irqsave(phba->host->host_lock, iflags);
lpfc_sli_release_iocbq(phba, cmdiocb);
- spin_unlock_irqrestore(phba->host->host_lock, iflags);
return;
}
@@ -2972,8 +3540,8 @@
for (i = 1; i <= phba->sli.last_iotag; i++) {
iocbq = phba->sli.iocbq_lookup[i];
- if (lpfc_sli_validate_fcp_iocb (iocbq, tgt_id, lun_id,
- 0, abort_cmd) != 0)
+ if (lpfc_sli_validate_fcp_iocb(iocbq, tgt_id, lun_id, 0,
+ abort_cmd) != 0)
continue;
/* issue ABTS for this IOCB based on iotag */
@@ -2989,8 +3557,9 @@
abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag;
abtsiocb->iocb.ulpLe = 1;
abtsiocb->iocb.ulpClass = cmd->ulpClass;
+ abtsiocb->vport = phba->pport;
- if (phba->hba_state >= LPFC_LINK_UP)
+ if (lpfc_is_link_up(phba))
abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN;
else
abtsiocb->iocb.ulpCommand = CMD_CLOSE_XRI_CN;
@@ -3016,16 +3585,16 @@
wait_queue_head_t *pdone_q;
unsigned long iflags;
- spin_lock_irqsave(phba->host->host_lock, iflags);
+ spin_lock_irqsave(&phba->hbalock, iflags);
cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
if (cmdiocbq->context2 && rspiocbq)
memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
&rspiocbq->iocb, sizeof(IOCB_t));
pdone_q = cmdiocbq->context_un.wait_queue;
- spin_unlock_irqrestore(phba->host->host_lock, iflags);
if (pdone_q)
wake_up(pdone_q);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
return;
}
@@ -3035,11 +3604,12 @@
* lpfc_sli_issue_call since the wake routine sets a unique value and by
* definition this is a wait function.
*/
+
int
-lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring,
- struct lpfc_iocbq * piocb,
- struct lpfc_iocbq * prspiocbq,
+lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocb,
+ struct lpfc_iocbq *prspiocbq,
uint32_t timeout)
{
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
@@ -3071,11 +3641,9 @@
retval = lpfc_sli_issue_iocb(phba, pring, piocb, 0);
if (retval == IOCB_SUCCESS) {
timeout_req = timeout * HZ;
- spin_unlock_irq(phba->host->host_lock);
timeleft = wait_event_timeout(done_q,
piocb->iocb_flag & LPFC_IO_WAKE,
timeout_req);
- spin_lock_irq(phba->host->host_lock);
if (piocb->iocb_flag & LPFC_IO_WAKE) {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -3117,16 +3685,16 @@
}
int
-lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
+lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
uint32_t timeout)
{
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
int retval;
+ unsigned long flag;
/* The caller must leave context1 empty. */
- if (pmboxq->context1 != 0) {
- return (MBX_NOT_FINISHED);
- }
+ if (pmboxq->context1 != 0)
+ return MBX_NOT_FINISHED;
/* setup wake call as IOCB callback */
pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait;
@@ -3141,6 +3709,7 @@
pmboxq->mbox_flag & LPFC_MBX_WAKE,
timeout * HZ);
+ spin_lock_irqsave(&phba->hbalock, flag);
pmboxq->context1 = NULL;
/*
* if LPFC_MBX_WAKE flag is set the mailbox is completed
@@ -3148,8 +3717,11 @@
*/
if (pmboxq->mbox_flag & LPFC_MBX_WAKE)
retval = MBX_SUCCESS;
- else
+ else {
retval = MBX_TIMEOUT;
+ pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ }
+ spin_unlock_irqrestore(&phba->hbalock, flag);
}
return retval;
@@ -3158,14 +3730,27 @@
int
lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
{
+ struct lpfc_vport *vport = phba->pport;
int i = 0;
+ uint32_t ha_copy;
- while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !phba->stopped) {
+ while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !vport->stopped) {
if (i++ > LPFC_MBOX_TMO * 1000)
return 1;
- if (lpfc_sli_handle_mb_event(phba) == 0)
- i = 0;
+ /*
+ * Call lpfc_sli_handle_mb_event only if a mailbox cmd
+ * did finish. This way we won't get the misleading
+ * "Stray Mailbox Interrupt" message.
+ */
+ spin_lock_irq(&phba->hbalock);
+ ha_copy = phba->work_ha;
+ phba->work_ha &= ~HA_MBATT;
+ spin_unlock_irq(&phba->hbalock);
+
+ if (ha_copy & HA_MBATT)
+ if (lpfc_sli_handle_mb_event(phba) == 0)
+ i = 0;
msleep(1);
}
@@ -3176,13 +3761,20 @@
irqreturn_t
lpfc_intr_handler(int irq, void *dev_id)
{
- struct lpfc_hba *phba;
+ struct lpfc_hba *phba;
uint32_t ha_copy;
uint32_t work_ha_copy;
unsigned long status;
int i;
uint32_t control;
+ MAILBOX_t *mbox, *pmbox;
+ struct lpfc_vport *vport;
+ struct lpfc_nodelist *ndlp;
+ struct lpfc_dmabuf *mp;
+ LPFC_MBOXQ_t *pmb;
+ int rc;
+
/*
* Get the driver's phba structure from the dev_id and
* assume the HBA is not interrupting.
@@ -3204,7 +3796,7 @@
*/
/* Ignore all interrupts during initialization. */
- if (unlikely(phba->hba_state < LPFC_LINK_DOWN))
+ if (unlikely(phba->link_state < LPFC_LINK_DOWN))
return IRQ_NONE;
/*
@@ -3212,16 +3804,16 @@
* Clear Attention Sources, except Error Attention (to
* preserve status) and Link Attention
*/
- spin_lock(phba->host->host_lock);
+ spin_lock(&phba->hbalock);
ha_copy = readl(phba->HAregaddr);
/* If somebody is waiting to handle an eratt don't process it
* here. The brdkill function will do this.
*/
- if (phba->fc_flag & FC_IGNORE_ERATT)
+ if (phba->link_flag & LS_IGNORE_ERATT)
ha_copy &= ~HA_ERATT;
writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
- spin_unlock(phba->host->host_lock);
+ spin_unlock(&phba->hbalock);
if (unlikely(!ha_copy))
return IRQ_NONE;
@@ -3235,36 +3827,41 @@
* Turn off Link Attention interrupts
* until CLEAR_LA done
*/
- spin_lock(phba->host->host_lock);
+ spin_lock(&phba->hbalock);
phba->sli.sli_flag &= ~LPFC_PROCESS_LA;
control = readl(phba->HCregaddr);
control &= ~HC_LAINT_ENA;
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- spin_unlock(phba->host->host_lock);
+ spin_unlock(&phba->hbalock);
}
else
work_ha_copy &= ~HA_LATT;
}
if (work_ha_copy & ~(HA_ERATT|HA_MBATT|HA_LATT)) {
- for (i = 0; i < phba->sli.num_rings; i++) {
- if (work_ha_copy & (HA_RXATT << (4*i))) {
- /*
- * Turn off Slow Rings interrupts
- */
- spin_lock(phba->host->host_lock);
- control = readl(phba->HCregaddr);
- control &= ~(HC_R0INT_ENA << i);
+ /*
+ * Turn off Slow Rings interrupts, LPFC_ELS_RING is
+ * the only slow ring.
+ */
+ status = (work_ha_copy &
+ (HA_RXMASK << (4*LPFC_ELS_RING)));
+ status >>= (4*LPFC_ELS_RING);
+ if (status & HA_RXMASK) {
+ spin_lock(&phba->hbalock);
+ control = readl(phba->HCregaddr);
+ if (control & (HC_R0INT_ENA << LPFC_ELS_RING)) {
+ control &=
+ ~(HC_R0INT_ENA << LPFC_ELS_RING);
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- spin_unlock(phba->host->host_lock);
}
+ spin_unlock(&phba->hbalock);
}
}
if (work_ha_copy & HA_ERATT) {
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
/*
* There was a link/board error. Read the
* status register to retrieve the error event
@@ -3279,14 +3876,108 @@
/* Clear Chip error bit */
writel(HA_ERATT, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
- phba->stopped = 1;
+ phba->pport->stopped = 1;
}
- spin_lock(phba->host->host_lock);
+ if ((work_ha_copy & HA_MBATT) &&
+ (phba->sli.mbox_active)) {
+ pmb = phba->sli.mbox_active;
+ pmbox = &pmb->mb;
+ mbox = &phba->slim2p->mbx;
+ vport = pmb->vport;
+
+ /* First check out the status word */
+ lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof(uint32_t));
+ if (pmbox->mbxOwner != OWN_HOST) {
+ /*
+ * Stray Mailbox Interrupt, mbxCommand <cmd>
+ * mbxStatus <status>
+ */
+ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX |
+ LOG_SLI,
+ "%d (%d):0304 Stray Mailbox "
+ "Interrupt mbxCommand x%x "
+ "mbxStatus x%x\n",
+ phba->brd_no,
+ (vport
+ ? vport->vpi : 0),
+ pmbox->mbxCommand,
+ pmbox->mbxStatus);
+ }
+ phba->last_completion_time = jiffies;
+ del_timer_sync(&phba->sli.mbox_tmo);
+
+ phba->sli.mbox_active = NULL;
+ if (pmb->mbox_cmpl) {
+ lpfc_sli_pcimem_bcopy(mbox, pmbox,
+ MAILBOX_CMD_SIZE);
+ }
+ if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
+ pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
+
+ lpfc_debugfs_disc_trc(vport,
+ LPFC_DISC_TRC_MBOX_VPORT,
+ "MBOX dflt rpi: : status:x%x rpi:x%x",
+ (uint32_t)pmbox->mbxStatus,
+ pmbox->un.varWords[0], 0);
+
+ if ( !pmbox->mbxStatus) {
+ mp = (struct lpfc_dmabuf *)
+ (pmb->context1);
+ ndlp = (struct lpfc_nodelist *)
+ pmb->context2;
+
+ /* Reg_LOGIN of dflt RPI was successful.
+ * new lets get rid of the RPI using the
+ * same mbox buffer.
+ */
+ lpfc_unreg_login(phba, vport->vpi,
+ pmbox->un.varWords[0], pmb);
+ pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
+ pmb->context1 = mp;
+ pmb->context2 = ndlp;
+ pmb->vport = vport;
+ spin_lock(&phba->hbalock);
+ phba->sli.sli_flag &=
+ ~LPFC_SLI_MBOX_ACTIVE;
+ spin_unlock(&phba->hbalock);
+ goto send_current_mbox;
+ }
+ }
+ spin_lock(&phba->pport->work_port_lock);
+ phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
+ spin_unlock(&phba->pport->work_port_lock);
+ lpfc_mbox_cmpl_put(phba, pmb);
+ }
+ if ((work_ha_copy & HA_MBATT) &&
+ (phba->sli.mbox_active == NULL)) {
+send_next_mbox:
+ spin_lock(&phba->hbalock);
+ phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+ pmb = lpfc_mbox_get(phba);
+ spin_unlock(&phba->hbalock);
+send_current_mbox:
+ /* Process next mailbox command if there is one */
+ if (pmb != NULL) {
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ pmb->mb.mbxStatus = MBX_NOT_FINISHED;
+ lpfc_mbox_cmpl_put(phba, pmb);
+ goto send_next_mbox;
+ }
+ } else {
+ /* Turn on IOCB processing */
+ for (i = 0; i < phba->sli.num_rings; i++)
+ lpfc_sli_turn_on_ring(phba, i);
+ }
+
+ }
+
+ spin_lock(&phba->hbalock);
phba->work_ha |= work_ha_copy;
if (phba->work_wait)
- wake_up(phba->work_wait);
- spin_unlock(phba->host->host_lock);
+ lpfc_worker_wake_up(phba);
+ spin_unlock(&phba->hbalock);
}
ha_copy &= ~(phba->work_ha_mask);
@@ -3298,7 +3989,7 @@
*/
status = (ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING)));
status >>= (4*LPFC_FCP_RING);
- if (status & HA_RXATT)
+ if (status & HA_RXMASK)
lpfc_sli_handle_fast_ring_event(phba,
&phba->sli.ring[LPFC_FCP_RING],
status);
@@ -3311,7 +4002,7 @@
*/
status = (ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING)));
status >>= (4*LPFC_EXTRA_RING);
- if (status & HA_RXATT) {
+ if (status & HA_RXMASK) {
lpfc_sli_handle_fast_ring_event(phba,
&phba->sli.ring[LPFC_EXTRA_RING],
status);
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 41c38d3..76058505 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -20,6 +20,7 @@
/* forward declaration for LPFC_IOCB_t's use */
struct lpfc_hba;
+struct lpfc_vport;
/* Define the context types that SLI handles for abort and sums. */
typedef enum _lpfc_ctx_cmd {
@@ -43,10 +44,12 @@
#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */
#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */
#define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */
+#define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */
uint8_t abort_count;
uint8_t rsvd2;
uint32_t drvrTimeout; /* driver timeout in seconds */
+ struct lpfc_vport *vport;/* virtual port pointer */
void *context1; /* caller context information */
void *context2; /* caller context information */
void *context3; /* caller context information */
@@ -56,6 +59,8 @@
struct lpfcMboxq *mbox;
} context_un;
+ void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
+ struct lpfc_iocbq *);
void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *);
@@ -68,12 +73,14 @@
#define IOCB_ERROR 2
#define IOCB_TIMEDOUT 3
-#define LPFC_MBX_WAKE 1
+#define LPFC_MBX_WAKE 1
+#define LPFC_MBX_IMED_UNREG 2
typedef struct lpfcMboxq {
/* MBOXQs are used in single linked lists */
struct list_head list; /* ptr to next mailbox command */
MAILBOX_t mb; /* Mailbox cmd */
+ struct lpfc_vport *vport;/* virutal port pointer */
void *context1; /* caller context information */
void *context2; /* caller context information */
@@ -135,6 +142,8 @@
uint8_t ringno; /* ring number */
uint16_t numCiocb; /* number of command iocb's per ring */
uint16_t numRiocb; /* number of rsp iocb's per ring */
+ uint16_t sizeCiocb; /* Size of command iocb's in this ring */
+ uint16_t sizeRiocb; /* Size of response iocb's in this ring */
uint32_t fast_iotag; /* max fastlookup based iotag */
uint32_t iotag_ctr; /* keeps track of the next iotag to use */
@@ -165,6 +174,34 @@
struct lpfc_sli_ring *);
};
+/* Structure used for configuring rings to a specific profile or rctl / type */
+struct lpfc_hbq_init {
+ uint32_t rn; /* Receive buffer notification */
+ uint32_t entry_count; /* max # of entries in HBQ */
+ uint32_t headerLen; /* 0 if not profile 4 or 5 */
+ uint32_t logEntry; /* Set to 1 if this HBQ used for LogEntry */
+ uint32_t profile; /* Selection profile 0=all, 7=logentry */
+ uint32_t ring_mask; /* Binds HBQ to a ring e.g. Ring0=b0001,
+ * ring2=b0100 */
+ uint32_t hbq_index; /* index of this hbq in ring .HBQs[] */
+
+ uint32_t seqlenoff;
+ uint32_t maxlen;
+ uint32_t seqlenbcnt;
+ uint32_t cmdcodeoff;
+ uint32_t cmdmatch[8];
+ uint32_t mask_count; /* number of mask entries in prt array */
+ struct hbq_mask hbqMasks[6];
+
+ /* Non-config rings fields to keep track of buffer allocations */
+ uint32_t buffer_count; /* number of buffers allocated */
+ uint32_t init_count; /* number to allocate when initialized */
+ uint32_t add_count; /* number to allocate when starved */
+} ;
+
+#define LPFC_MAX_HBQ 16
+
+
/* Structure used to hold SLI statistical counters and info */
struct lpfc_sli_stat {
uint64_t mbox_stat_err; /* Mbox cmds completed status error */
@@ -197,6 +234,7 @@
#define LPFC_SLI_MBOX_ACTIVE 0x100 /* HBA mailbox is currently active */
#define LPFC_SLI2_ACTIVE 0x200 /* SLI2 overlay in firmware is active */
#define LPFC_PROCESS_LA 0x400 /* Able to process link attention */
+#define LPFC_BLOCK_MGMT_IO 0x800 /* Don't allow mgmt mbx or iocb cmds */
struct lpfc_sli_ring ring[LPFC_MAX_RING];
int fcp_ring; /* ring used for FCP initiator commands */
@@ -209,6 +247,7 @@
uint16_t mboxq_cnt; /* current length of queue */
uint16_t mboxq_max; /* max length */
LPFC_MBOXQ_t *mbox_active; /* active mboxq information */
+ struct list_head mboxq_cmpl;
struct timer_list mbox_tmo; /* Hold clk to timeout active mbox
cmd */
@@ -221,12 +260,6 @@
struct lpfc_lnk_stat lnk_stat_offsets;
};
-/* Given a pointer to the start of the ring, and the slot number of
- * the desired iocb entry, calc a pointer to that entry.
- * (assume iocb entry size is 32 bytes, or 8 words)
- */
-#define IOCB_ENTRY(ring,slot) ((IOCB_t *)(((char *)(ring)) + ((slot) * 32)))
-
#define LPFC_MBOX_TMO 30 /* Sec tmo for outstanding mbox
command */
#define LPFC_MBOX_TMO_FLASH_CMD 300 /* Sec tmo for outstanding FLASH write
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 92a9107..a5bc79e 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.1.12"
+#define LPFC_DRIVER_VERSION "8.2.1"
#define LPFC_DRIVER_NAME "lpfc"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
new file mode 100644
index 0000000..85797db
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -0,0 +1,523 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for *
+ * Fibre Channel Host Bus Adapters. *
+ * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * Portions Copyright (C) 2004-2005 Christoph Hellwig *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *******************************************************************/
+
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+#include "lpfc_version.h"
+#include "lpfc_vport.h"
+
+inline void lpfc_vport_set_state(struct lpfc_vport *vport,
+ enum fc_vport_state new_state)
+{
+ struct fc_vport *fc_vport = vport->fc_vport;
+
+ if (fc_vport) {
+ /*
+ * When the transport defines fc_vport_set state we will replace
+ * this code with the following line
+ */
+ /* fc_vport_set_state(fc_vport, new_state); */
+ if (new_state != FC_VPORT_INITIALIZING)
+ fc_vport->vport_last_state = fc_vport->vport_state;
+ fc_vport->vport_state = new_state;
+ }
+
+ /* for all the error states we will set the invternal state to FAILED */
+ switch (new_state) {
+ case FC_VPORT_NO_FABRIC_SUPP:
+ case FC_VPORT_NO_FABRIC_RSCS:
+ case FC_VPORT_FABRIC_LOGOUT:
+ case FC_VPORT_FABRIC_REJ_WWN:
+ case FC_VPORT_FAILED:
+ vport->port_state = LPFC_VPORT_FAILED;
+ break;
+ case FC_VPORT_LINKDOWN:
+ vport->port_state = LPFC_VPORT_UNKNOWN;
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+}
+
+static int
+lpfc_alloc_vpi(struct lpfc_hba *phba)
+{
+ int vpi;
+
+ spin_lock_irq(&phba->hbalock);
+ /* Start at bit 1 because vpi zero is reserved for the physical port */
+ vpi = find_next_zero_bit(phba->vpi_bmask, (phba->max_vpi + 1), 1);
+ if (vpi > phba->max_vpi)
+ vpi = 0;
+ else
+ set_bit(vpi, phba->vpi_bmask);
+ spin_unlock_irq(&phba->hbalock);
+ return vpi;
+}
+
+static void
+lpfc_free_vpi(struct lpfc_hba *phba, int vpi)
+{
+ spin_lock_irq(&phba->hbalock);
+ clear_bit(vpi, phba->vpi_bmask);
+ spin_unlock_irq(&phba->hbalock);
+}
+
+static int
+lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
+{
+ LPFC_MBOXQ_t *pmb;
+ MAILBOX_t *mb;
+ struct lpfc_dmabuf *mp;
+ int rc;
+
+ pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmb) {
+ return -ENOMEM;
+ }
+ mb = &pmb->mb;
+
+ lpfc_read_sparam(phba, pmb, vport->vpi);
+ /*
+ * Grab buffer pointer and clear context1 so we can use
+ * lpfc_sli_issue_box_wait
+ */
+ mp = (struct lpfc_dmabuf *) pmb->context1;
+ pmb->context1 = NULL;
+
+ pmb->vport = vport;
+ rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2);
+ if (rc != MBX_SUCCESS) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
+ "%d (%d):1818 VPort failed init, mbxCmd x%x "
+ "READ_SPARM mbxStatus x%x, rc = x%x\n",
+ phba->brd_no, vport->vpi,
+ mb->mbxCommand, mb->mbxStatus, rc);
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ if (rc != MBX_TIMEOUT)
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return -EIO;
+ }
+
+ memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
+ memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
+ sizeof (struct lpfc_name));
+ memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
+ sizeof (struct lpfc_name));
+
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ mempool_free(pmb, phba->mbox_mem_pool);
+
+ return 0;
+}
+
+static int
+lpfc_valid_wwn_format(struct lpfc_hba *phba, struct lpfc_name *wwn,
+ const char *name_type)
+{
+ /* ensure that IEEE format 1 addresses
+ * contain zeros in bits 59-48
+ */
+ if (!((wwn->u.wwn[0] >> 4) == 1 &&
+ ((wwn->u.wwn[0] & 0xf) != 0 || (wwn->u.wwn[1] & 0xf) != 0)))
+ return 1;
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1822 Invalid %s: %02x:%02x:%02x:%02x:"
+ "%02x:%02x:%02x:%02x\n",
+ phba->brd_no, name_type,
+ wwn->u.wwn[0], wwn->u.wwn[1],
+ wwn->u.wwn[2], wwn->u.wwn[3],
+ wwn->u.wwn[4], wwn->u.wwn[5],
+ wwn->u.wwn[6], wwn->u.wwn[7]);
+ return 0;
+}
+
+static int
+lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport)
+{
+ struct lpfc_vport *vport;
+
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ if (vport == new_vport)
+ continue;
+ /* If they match, return not unique */
+ if (memcmp(&vport->fc_sparam.portName,
+ &new_vport->fc_sparam.portName,
+ sizeof(struct lpfc_name)) == 0)
+ return 0;
+ }
+ return 1;
+}
+
+int
+lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
+{
+ struct lpfc_nodelist *ndlp;
+ struct lpfc_vport *pport =
+ (struct lpfc_vport *) fc_vport->shost->hostdata;
+ struct lpfc_hba *phba = pport->phba;
+ struct lpfc_vport *vport = NULL;
+ int instance;
+ int vpi;
+ int rc = VPORT_ERROR;
+
+ if ((phba->sli_rev < 3) ||
+ !(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1808 Create VPORT failed: "
+ "NPIV is not enabled: SLImode:%d\n",
+ phba->brd_no, phba->sli_rev);
+ rc = VPORT_INVAL;
+ goto error_out;
+ }
+
+ vpi = lpfc_alloc_vpi(phba);
+ if (vpi == 0) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1809 Create VPORT failed: "
+ "Max VPORTs (%d) exceeded\n",
+ phba->brd_no, phba->max_vpi);
+ rc = VPORT_NORESOURCES;
+ goto error_out;
+ }
+
+
+ /* Assign an unused board number */
+ if ((instance = lpfc_get_instance()) < 0) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1810 Create VPORT failed: Cannot get "
+ "instance number\n", phba->brd_no);
+ lpfc_free_vpi(phba, vpi);
+ rc = VPORT_NORESOURCES;
+ goto error_out;
+ }
+
+ vport = lpfc_create_port(phba, instance, fc_vport);
+ if (!vport) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1811 Create VPORT failed: vpi x%x\n",
+ phba->brd_no, vpi);
+ lpfc_free_vpi(phba, vpi);
+ rc = VPORT_NORESOURCES;
+ goto error_out;
+ }
+
+ vport->vpi = vpi;
+ lpfc_debugfs_initialize(vport);
+
+ if (lpfc_vport_sparm(phba, vport)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1813 Create VPORT failed: vpi:%d "
+ "Cannot get sparam\n",
+ phba->brd_no, vpi);
+ lpfc_free_vpi(phba, vpi);
+ destroy_port(vport);
+ rc = VPORT_NORESOURCES;
+ goto error_out;
+ }
+
+ memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8);
+ memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8);
+
+ if (fc_vport->node_name != 0)
+ u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn);
+ if (fc_vport->port_name != 0)
+ u64_to_wwn(fc_vport->port_name, vport->fc_portname.u.wwn);
+
+ memcpy(&vport->fc_sparam.portName, vport->fc_portname.u.wwn, 8);
+ memcpy(&vport->fc_sparam.nodeName, vport->fc_nodename.u.wwn, 8);
+
+ if (!lpfc_valid_wwn_format(phba, &vport->fc_sparam.nodeName, "WWNN") ||
+ !lpfc_valid_wwn_format(phba, &vport->fc_sparam.portName, "WWPN")) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1821 Create VPORT failed: vpi:%d "
+ "Invalid WWN format\n",
+ phba->brd_no, vpi);
+ lpfc_free_vpi(phba, vpi);
+ destroy_port(vport);
+ rc = VPORT_INVAL;
+ goto error_out;
+ }
+
+ if (!lpfc_unique_wwpn(phba, vport)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1823 Create VPORT failed: vpi:%d "
+ "Duplicate WWN on HBA\n",
+ phba->brd_no, vpi);
+ lpfc_free_vpi(phba, vpi);
+ destroy_port(vport);
+ rc = VPORT_INVAL;
+ goto error_out;
+ }
+
+ *(struct lpfc_vport **)fc_vport->dd_data = vport;
+ vport->fc_vport = fc_vport;
+
+ if ((phba->link_state < LPFC_LINK_UP) ||
+ (phba->fc_topology == TOPOLOGY_LOOP)) {
+ lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
+ rc = VPORT_OK;
+ goto out;
+ }
+
+ if (disable) {
+ rc = VPORT_OK;
+ goto out;
+ }
+
+ /* Use the Physical nodes Fabric NDLP to determine if the link is
+ * up and ready to FDISC.
+ */
+ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+ if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
+ if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) {
+ lpfc_set_disctmo(vport);
+ lpfc_initial_fdisc(vport);
+ } else {
+ lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0262 No NPIV Fabric "
+ "support\n",
+ phba->brd_no, vport->vpi);
+ }
+ } else {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ }
+ rc = VPORT_OK;
+
+out:
+ lpfc_host_attrib_init(lpfc_shost_from_vport(vport));
+error_out:
+ return rc;
+}
+
+int
+disable_vport(struct fc_vport *fc_vport)
+{
+ struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL;
+ long timeout;
+
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ if (ndlp && phba->link_state >= LPFC_LINK_UP) {
+ vport->unreg_vpi_cmpl = VPORT_INVAL;
+ timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
+ if (!lpfc_issue_els_npiv_logo(vport, ndlp))
+ while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout)
+ timeout = schedule_timeout(timeout);
+ }
+
+ lpfc_sli_host_down(vport);
+
+ /* Mark all nodes for discovery so we can remove them by
+ * calling lpfc_cleanup_rpis(vport, 1)
+ */
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+ continue;
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+ NLP_EVT_DEVICE_RECOVERY);
+ }
+ lpfc_cleanup_rpis(vport, 1);
+
+ lpfc_stop_vport_timers(vport);
+ lpfc_unreg_all_rpis(vport);
+ lpfc_unreg_default_rpis(vport);
+ /*
+ * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the
+ * scsi_host_put() to release the vport.
+ */
+ lpfc_mbx_unreg_vpi(vport);
+
+ lpfc_vport_set_state(vport, FC_VPORT_DISABLED);
+ return VPORT_OK;
+}
+
+int
+enable_vport(struct fc_vport *fc_vport)
+{
+ struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp = NULL;
+
+ if ((phba->link_state < LPFC_LINK_UP) ||
+ (phba->fc_topology == TOPOLOGY_LOOP)) {
+ lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
+ return VPORT_OK;
+ }
+
+ vport->load_flag |= FC_LOADING;
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+
+ /* Use the Physical nodes Fabric NDLP to determine if the link is
+ * up and ready to FDISC.
+ */
+ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+ if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
+ if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) {
+ lpfc_set_disctmo(vport);
+ lpfc_initial_fdisc(vport);
+ } else {
+ lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0264 No NPIV Fabric "
+ "support\n",
+ phba->brd_no, vport->vpi);
+ }
+ } else {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ }
+
+ return VPORT_OK;
+}
+
+int
+lpfc_vport_disable(struct fc_vport *fc_vport, bool disable)
+{
+ if (disable)
+ return disable_vport(fc_vport);
+ else
+ return enable_vport(fc_vport);
+}
+
+
+int
+lpfc_vport_delete(struct fc_vport *fc_vport)
+{
+ struct lpfc_nodelist *ndlp = NULL;
+ struct lpfc_nodelist *next_ndlp;
+ struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost;
+ struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
+ struct lpfc_hba *phba = vport->phba;
+ long timeout;
+ int rc = VPORT_ERROR;
+
+ /*
+ * This is a bit of a mess. We want to ensure the shost doesn't get
+ * torn down until we're done with the embedded lpfc_vport structure.
+ *
+ * Beyond holding a reference for this function, we also need a
+ * reference for outstanding I/O requests we schedule during delete
+ * processing. But once we scsi_remove_host() we can no longer obtain
+ * a reference through scsi_host_get().
+ *
+ * So we take two references here. We release one reference at the
+ * bottom of the function -- after delinking the vport. And we
+ * release the other at the completion of the unreg_vpi that get's
+ * initiated after we've disposed of all other resources associated
+ * with the port.
+ */
+ if (!scsi_host_get(shost) || !scsi_host_get(shost))
+ return VPORT_INVAL;
+
+ if (vport->port_type == LPFC_PHYSICAL_PORT) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1812 vport_delete failed: Cannot delete "
+ "physical host\n", phba->brd_no);
+ goto out;
+ }
+
+ vport->load_flag |= FC_UNLOADING;
+
+ kfree(vport->vname);
+ lpfc_debugfs_terminate(vport);
+ fc_remove_host(lpfc_shost_from_vport(vport));
+ scsi_remove_host(lpfc_shost_from_vport(vport));
+
+ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+ if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
+ phba->link_state >= LPFC_LINK_UP) {
+
+ /* First look for the Fabric ndlp */
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ if (!ndlp) {
+ /* Cannot find existing Fabric ndlp, allocate one */
+ ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+ if (!ndlp)
+ goto skip_logo;
+ lpfc_nlp_init(vport, ndlp, Fabric_DID);
+ } else {
+ lpfc_dequeue_node(vport, ndlp);
+ }
+ vport->unreg_vpi_cmpl = VPORT_INVAL;
+ timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
+ if (!lpfc_issue_els_npiv_logo(vport, ndlp))
+ while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout)
+ timeout = schedule_timeout(timeout);
+ }
+
+skip_logo:
+ lpfc_sli_host_down(vport);
+
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+ NLP_EVT_DEVICE_RECOVERY);
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+ NLP_EVT_DEVICE_RM);
+ }
+
+ lpfc_stop_vport_timers(vport);
+ lpfc_unreg_all_rpis(vport);
+ lpfc_unreg_default_rpis(vport);
+ /*
+ * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the
+ * scsi_host_put() to release the vport.
+ */
+ lpfc_mbx_unreg_vpi(vport);
+
+ lpfc_free_vpi(phba, vport->vpi);
+ vport->work_port_events = 0;
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&vport->listentry);
+ spin_unlock_irq(&phba->hbalock);
+
+ rc = VPORT_OK;
+out:
+ scsi_host_put(shost);
+ return rc;
+}
+
+
+EXPORT_SYMBOL(lpfc_vport_create);
+EXPORT_SYMBOL(lpfc_vport_delete);
diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h
new file mode 100644
index 0000000..f223550
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_vport.h
@@ -0,0 +1,113 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for *
+ * Fibre Channel Host Bus Adapters. *
+ * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * Portions Copyright (C) 2004-2005 Christoph Hellwig *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *******************************************************************/
+
+#ifndef _H_LPFC_VPORT
+#define _H_LPFC_VPORT
+
+/* API version values (each will be an individual bit) */
+#define VPORT_API_VERSION_1 0x01
+
+/* Values returned via lpfc_vport_getinfo() */
+struct vport_info {
+
+ uint32_t api_versions;
+ uint8_t linktype;
+#define VPORT_TYPE_PHYSICAL 0
+#define VPORT_TYPE_VIRTUAL 1
+
+ uint8_t state;
+#define VPORT_STATE_OFFLINE 0
+#define VPORT_STATE_ACTIVE 1
+#define VPORT_STATE_FAILED 2
+
+ uint8_t fail_reason;
+ uint8_t prev_fail_reason;
+#define VPORT_FAIL_UNKNOWN 0
+#define VPORT_FAIL_LINKDOWN 1
+#define VPORT_FAIL_FAB_UNSUPPORTED 2
+#define VPORT_FAIL_FAB_NORESOURCES 3
+#define VPORT_FAIL_FAB_LOGOUT 4
+#define VPORT_FAIL_ADAP_NORESOURCES 5
+
+ uint8_t node_name[8]; /* WWNN */
+ uint8_t port_name[8]; /* WWPN */
+
+ struct Scsi_Host *shost;
+
+/* Following values are valid only on physical links */
+ uint32_t vports_max;
+ uint32_t vports_inuse;
+ uint32_t rpi_max;
+ uint32_t rpi_inuse;
+#define VPORT_CNT_INVALID 0xFFFFFFFF
+};
+
+/* data used in link creation */
+struct vport_data {
+ uint32_t api_version;
+
+ uint32_t options;
+#define VPORT_OPT_AUTORETRY 0x01
+
+ uint8_t node_name[8]; /* WWNN */
+ uint8_t port_name[8]; /* WWPN */
+
+/*
+ * Upon successful creation, vport_shost will point to the new Scsi_Host
+ * structure for the new virtual link.
+ */
+ struct Scsi_Host *vport_shost;
+};
+
+/* API function return codes */
+#define VPORT_OK 0
+#define VPORT_ERROR -1
+#define VPORT_INVAL -2
+#define VPORT_NOMEM -3
+#define VPORT_NORESOURCES -4
+
+int lpfc_vport_create(struct fc_vport *, bool);
+int lpfc_vport_delete(struct fc_vport *);
+int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *);
+int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint);
+
+/*
+ * queuecommand VPORT-specific return codes. Specified in the host byte code.
+ * Returned when the virtual link has failed or is not active.
+ */
+#define DID_VPORT_ERROR 0x0f
+
+#define VPORT_INFO 0x1
+#define VPORT_CREATE 0x2
+#define VPORT_DELETE 0x4
+
+struct vport_cmd_tag {
+ uint32_t cmd;
+ struct vport_data cdata;
+ struct vport_info cinfo;
+ void *vport;
+ int vport_num;
+};
+
+void lpfc_vport_set_state(struct lpfc_vport *vport,
+ enum fc_vport_state new_state);
+
+#endif /* H_LPFC_VPORT */
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 5806ede..b12ad7c7 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -77,7 +77,7 @@
for (i = 0; i < cmd->cmd_len; ++i)
printk(" %.2x", cmd->cmnd[i]);
printk("\n" KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n",
- cmd->use_sg, cmd->request_bufflen, cmd->request_buffer);
+ scsi_sg_count(cmd), scsi_bufflen(cmd), scsi_sglist(cmd));
}
#endif
@@ -173,8 +173,7 @@
writeb(CMD_SELECT, ®s->command);
state->phase = selecting;
- if (cmd->use_sg > 0 || cmd->request_bufflen != 0)
- set_dma_cmds(state, cmd);
+ set_dma_cmds(state, cmd);
}
static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id)
@@ -262,7 +261,7 @@
writeb(CMD_NOP, ®s->command);
/* set DMA controller going if any data to transfer */
if ((stat & (STAT_MSG|STAT_CD)) == 0
- && (cmd->use_sg > 0 || cmd->request_bufflen != 0)) {
+ && (scsi_sg_count(cmd) > 0 || scsi_bufflen(cmd))) {
nb = cmd->SCp.this_residual;
if (nb > 0xfff0)
nb = 0xfff0;
@@ -310,14 +309,7 @@
printk(KERN_DEBUG "intr %x before data xfer complete\n", intr);
}
writel(RUN << 16, &dma->control); /* stop dma */
- if (cmd->use_sg != 0) {
- pci_unmap_sg(state->pdev,
- (struct scatterlist *)cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- } else {
- pci_unmap_single(state->pdev, state->dma_addr,
- cmd->request_bufflen, cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
/* should check dma status */
writeb(CMD_I_COMPLETE, ®s->command);
state->phase = completing;
@@ -365,47 +357,35 @@
*/
static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd)
{
- int i, dma_cmd, total;
+ int i, dma_cmd, total, nseg;
struct scatterlist *scl;
struct dbdma_cmd *dcmds;
dma_addr_t dma_addr;
u32 dma_len;
+ nseg = scsi_dma_map(cmd);
+ BUG_ON(nseg < 0);
+ if (!nseg)
+ return;
+
dma_cmd = cmd->sc_data_direction == DMA_TO_DEVICE ?
OUTPUT_MORE : INPUT_MORE;
dcmds = state->dma_cmds;
- if (cmd->use_sg > 0) {
- int nseg;
+ total = 0;
- total = 0;
- scl = (struct scatterlist *) cmd->request_buffer;
- nseg = pci_map_sg(state->pdev, scl, cmd->use_sg,
- cmd->sc_data_direction);
- for (i = 0; i < nseg; ++i) {
- dma_addr = sg_dma_address(scl);
- dma_len = sg_dma_len(scl);
- if (dma_len > 0xffff)
- panic("mac53c94: scatterlist element >= 64k");
- total += dma_len;
- st_le16(&dcmds->req_count, dma_len);
- st_le16(&dcmds->command, dma_cmd);
- st_le32(&dcmds->phy_addr, dma_addr);
- dcmds->xfer_status = 0;
- ++scl;
- ++dcmds;
- }
- } else {
- total = cmd->request_bufflen;
- if (total > 0xffff)
- panic("mac53c94: transfer size >= 64k");
- dma_addr = pci_map_single(state->pdev, cmd->request_buffer,
- total, cmd->sc_data_direction);
- state->dma_addr = dma_addr;
- st_le16(&dcmds->req_count, total);
+ scsi_for_each_sg(cmd, scl, nseg, i) {
+ dma_addr = sg_dma_address(scl);
+ dma_len = sg_dma_len(scl);
+ if (dma_len > 0xffff)
+ panic("mac53c94: scatterlist element >= 64k");
+ total += dma_len;
+ st_le16(&dcmds->req_count, dma_len);
+ st_le16(&dcmds->command, dma_cmd);
st_le32(&dcmds->phy_addr, dma_addr);
dcmds->xfer_status = 0;
++dcmds;
}
+
dma_cmd += OUTPUT_LAST - OUTPUT_MORE;
st_le16(&dcmds[-1].command, dma_cmd);
st_le16(&dcmds->command, DBDMA_STOP);
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 3cce75d..3907f67 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -523,10 +523,8 @@
/*
* filter the internal and ioctl commands
*/
- if((cmd->cmnd[0] == MEGA_INTERNAL_CMD)) {
- return cmd->request_buffer;
- }
-
+ if((cmd->cmnd[0] == MEGA_INTERNAL_CMD))
+ return (scb_t *)cmd->host_scribble;
/*
* We know what channels our logical drives are on - mega_find_card()
@@ -657,22 +655,14 @@
case MODE_SENSE: {
char *buf;
+ struct scatterlist *sg;
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ sg = scsi_sglist(cmd);
+ buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- sg = (struct scatterlist *)cmd->request_buffer;
- buf = kmap_atomic(sg->page, KM_IRQ0) +
- sg->offset;
- } else
- buf = cmd->request_buffer;
memset(buf, 0, cmd->cmnd[4]);
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
- sg = (struct scatterlist *)cmd->request_buffer;
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
- }
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
@@ -1551,23 +1541,15 @@
islogical = adapter->logdrv_chan[cmd->device->channel];
if( cmd->cmnd[0] == INQUIRY && !islogical ) {
- if( cmd->use_sg ) {
- sgl = (struct scatterlist *)
- cmd->request_buffer;
-
- if( sgl->page ) {
- c = *(unsigned char *)
+ sgl = scsi_sglist(cmd);
+ if( sgl->page ) {
+ c = *(unsigned char *)
page_address((&sgl[0])->page) +
(&sgl[0])->offset;
- }
- else {
- printk(KERN_WARNING
- "megaraid: invalid sg.\n");
- c = 0;
- }
- }
- else {
- c = *(u8 *)cmd->request_buffer;
+ } else {
+ printk(KERN_WARNING
+ "megaraid: invalid sg.\n");
+ c = 0;
}
if(IS_RAID_CH(adapter, cmd->device->channel) &&
@@ -1704,30 +1686,14 @@
static void
mega_free_scb(adapter_t *adapter, scb_t *scb)
{
- unsigned long length;
-
switch( scb->dma_type ) {
case MEGA_DMA_TYPE_NONE:
break;
- case MEGA_BULK_DATA:
- if (scb->cmd->use_sg == 0)
- length = scb->cmd->request_bufflen;
- else {
- struct scatterlist *sgl =
- (struct scatterlist *)scb->cmd->request_buffer;
- length = sgl->length;
- }
- pci_unmap_page(adapter->dev, scb->dma_h_bulkdata,
- length, scb->dma_direction);
- break;
-
case MEGA_SGLIST:
- pci_unmap_sg(adapter->dev, scb->cmd->request_buffer,
- scb->cmd->use_sg, scb->dma_direction);
+ scsi_dma_unmap(scb->cmd);
break;
-
default:
break;
}
@@ -1767,80 +1733,33 @@
static int
mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len)
{
- struct scatterlist *sgl;
- struct page *page;
- unsigned long offset;
- unsigned int length;
+ struct scatterlist *sg;
Scsi_Cmnd *cmd;
int sgcnt;
int idx;
cmd = scb->cmd;
- /* Scatter-gather not used */
- if( cmd->use_sg == 0 || (cmd->use_sg == 1 &&
- !adapter->has_64bit_addr)) {
-
- if (cmd->use_sg == 0) {
- page = virt_to_page(cmd->request_buffer);
- offset = offset_in_page(cmd->request_buffer);
- length = cmd->request_bufflen;
- } else {
- sgl = (struct scatterlist *)cmd->request_buffer;
- page = sgl->page;
- offset = sgl->offset;
- length = sgl->length;
- }
-
- scb->dma_h_bulkdata = pci_map_page(adapter->dev,
- page, offset,
- length,
- scb->dma_direction);
- scb->dma_type = MEGA_BULK_DATA;
-
- /*
- * We need to handle special 64-bit commands that need a
- * minimum of 1 SG
- */
- if( adapter->has_64bit_addr ) {
- scb->sgl64[0].address = scb->dma_h_bulkdata;
- scb->sgl64[0].length = length;
- *buf = (u32)scb->sgl_dma_addr;
- *len = (u32)length;
- return 1;
- }
- else {
- *buf = (u32)scb->dma_h_bulkdata;
- *len = (u32)length;
- }
- return 0;
- }
-
- sgl = (struct scatterlist *)cmd->request_buffer;
-
/*
* Copy Scatter-Gather list info into controller structure.
*
* The number of sg elements returned must not exceed our limit
*/
- sgcnt = pci_map_sg(adapter->dev, sgl, cmd->use_sg,
- scb->dma_direction);
+ sgcnt = scsi_dma_map(cmd);
scb->dma_type = MEGA_SGLIST;
- BUG_ON(sgcnt > adapter->sglen);
+ BUG_ON(sgcnt > adapter->sglen || sgcnt < 0);
*len = 0;
- for( idx = 0; idx < sgcnt; idx++, sgl++ ) {
-
- if( adapter->has_64bit_addr ) {
- scb->sgl64[idx].address = sg_dma_address(sgl);
- *len += scb->sgl64[idx].length = sg_dma_len(sgl);
- }
- else {
- scb->sgl[idx].address = sg_dma_address(sgl);
- *len += scb->sgl[idx].length = sg_dma_len(sgl);
+ scsi_for_each_sg(cmd, sg, sgcnt, idx) {
+ if (adapter->has_64bit_addr) {
+ scb->sgl64[idx].address = sg_dma_address(sg);
+ *len += scb->sgl64[idx].length = sg_dma_len(sg);
+ } else {
+ scb->sgl[idx].address = sg_dma_address(sg);
+ *len += scb->sgl[idx].length = sg_dma_len(sg);
}
}
@@ -3571,7 +3490,7 @@
/*
* The user passthru structure
*/
- upthru = (mega_passthru __user *)MBOX(uioc)->xferaddr;
+ upthru = (mega_passthru __user *)(unsigned long)MBOX(uioc)->xferaddr;
/*
* Copy in the user passthru here.
@@ -3623,7 +3542,7 @@
/*
* Get the user data
*/
- if( copy_from_user(data, (char __user *)uxferaddr,
+ if( copy_from_user(data, (char __user *)(unsigned long) uxferaddr,
pthru->dataxferlen) ) {
rval = (-EFAULT);
goto freemem_and_return;
@@ -3649,7 +3568,7 @@
* Is data going up-stream
*/
if( pthru->dataxferlen && (uioc.flags & UIOC_RD) ) {
- if( copy_to_user((char __user *)uxferaddr, data,
+ if( copy_to_user((char __user *)(unsigned long) uxferaddr, data,
pthru->dataxferlen) ) {
rval = (-EFAULT);
}
@@ -3702,7 +3621,7 @@
/*
* Get the user data
*/
- if( copy_from_user(data, (char __user *)uxferaddr,
+ if( copy_from_user(data, (char __user *)(unsigned long) uxferaddr,
uioc.xferlen) ) {
pci_free_consistent(pdev,
@@ -3742,7 +3661,7 @@
* Is data going up-stream
*/
if( uioc.xferlen && (uioc.flags & UIOC_RD) ) {
- if( copy_to_user((char __user *)uxferaddr, data,
+ if( copy_to_user((char __user *)(unsigned long) uxferaddr, data,
uioc.xferlen) ) {
rval = (-EFAULT);
@@ -4494,7 +4413,7 @@
scmd->device = sdev;
scmd->device->host = adapter->host;
- scmd->request_buffer = (void *)scb;
+ scmd->host_scribble = (void *)scb;
scmd->cmnd[0] = MEGA_INTERNAL_CMD;
scb->state |= SCB_ACTIVE;
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
index 26e1e6c..fef9ac9 100644
--- a/drivers/scsi/megaraid/mega_common.h
+++ b/drivers/scsi/megaraid/mega_common.h
@@ -21,6 +21,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 04d0b69..c46685a 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -1378,8 +1378,6 @@
{
struct scatterlist *sgl;
mbox_ccb_t *ccb;
- struct page *page;
- unsigned long offset;
struct scsi_cmnd *scp;
int sgcnt;
int i;
@@ -1388,48 +1386,16 @@
scp = scb->scp;
ccb = (mbox_ccb_t *)scb->ccb;
+ sgcnt = scsi_dma_map(scp);
+ BUG_ON(sgcnt < 0 || sgcnt > adapter->sglen);
+
// no mapping required if no data to be transferred
- if (!scp->request_buffer || !scp->request_bufflen)
+ if (!sgcnt)
return 0;
- if (!scp->use_sg) { /* scatter-gather list not used */
-
- page = virt_to_page(scp->request_buffer);
-
- offset = ((unsigned long)scp->request_buffer & ~PAGE_MASK);
-
- ccb->buf_dma_h = pci_map_page(adapter->pdev, page, offset,
- scp->request_bufflen,
- scb->dma_direction);
- scb->dma_type = MRAID_DMA_WBUF;
-
- /*
- * We need to handle special 64-bit commands that need a
- * minimum of 1 SG
- */
- sgcnt = 1;
- ccb->sgl64[0].address = ccb->buf_dma_h;
- ccb->sgl64[0].length = scp->request_bufflen;
-
- return sgcnt;
- }
-
- sgl = (struct scatterlist *)scp->request_buffer;
-
- // The number of sg elements returned must not exceed our limit
- sgcnt = pci_map_sg(adapter->pdev, sgl, scp->use_sg,
- scb->dma_direction);
-
- if (sgcnt > adapter->sglen) {
- con_log(CL_ANN, (KERN_CRIT
- "megaraid critical: too many sg elements:%d\n",
- sgcnt));
- BUG();
- }
-
scb->dma_type = MRAID_DMA_WSG;
- for (i = 0; i < sgcnt; i++, sgl++) {
+ scsi_for_each_sg(scp, sgl, sgcnt, i) {
ccb->sgl64[i].address = sg_dma_address(sgl);
ccb->sgl64[i].length = sg_dma_len(sgl);
}
@@ -1489,19 +1455,11 @@
adapter->outstanding_cmds++;
- if (scb->dma_direction == PCI_DMA_TODEVICE) {
- if (!scb->scp->use_sg) { // sg list not used
- pci_dma_sync_single_for_device(adapter->pdev,
- ccb->buf_dma_h,
- scb->scp->request_bufflen,
- PCI_DMA_TODEVICE);
- }
- else {
- pci_dma_sync_sg_for_device(adapter->pdev,
- scb->scp->request_buffer,
- scb->scp->use_sg, PCI_DMA_TODEVICE);
- }
- }
+ if (scb->dma_direction == PCI_DMA_TODEVICE)
+ pci_dma_sync_sg_for_device(adapter->pdev,
+ scsi_sglist(scb->scp),
+ scsi_sg_count(scb->scp),
+ PCI_DMA_TODEVICE);
mbox->busy = 1; // Set busy
mbox->poll = 0;
@@ -1624,29 +1582,26 @@
return scb;
case MODE_SENSE:
- if (scp->use_sg) {
- struct scatterlist *sgl;
- caddr_t vaddr;
+ {
+ struct scatterlist *sgl;
+ caddr_t vaddr;
- sgl = (struct scatterlist *)scp->request_buffer;
- if (sgl->page) {
- vaddr = (caddr_t)
- (page_address((&sgl[0])->page)
- + (&sgl[0])->offset);
+ sgl = scsi_sglist(scp);
+ if (sgl->page) {
+ vaddr = (caddr_t)
+ (page_address((&sgl[0])->page)
+ + (&sgl[0])->offset);
- memset(vaddr, 0, scp->cmnd[4]);
- }
- else {
- con_log(CL_ANN, (KERN_WARNING
- "megaraid mailbox: invalid sg:%d\n",
- __LINE__));
- }
+ memset(vaddr, 0, scp->cmnd[4]);
}
else {
- memset(scp->request_buffer, 0, scp->cmnd[4]);
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid mailbox: invalid sg:%d\n",
+ __LINE__));
}
- scp->result = (DID_OK << 16);
- return NULL;
+ }
+ scp->result = (DID_OK << 16);
+ return NULL;
case INQUIRY:
/*
@@ -1716,7 +1671,7 @@
mbox->cmd = MBOXCMD_PASSTHRU64;
scb->dma_direction = scp->sc_data_direction;
- pthru->dataxferlen = scp->request_bufflen;
+ pthru->dataxferlen = scsi_bufflen(scp);
pthru->dataxferaddr = ccb->sgl_dma_h;
pthru->numsge = megaraid_mbox_mksgl(adapter,
scb);
@@ -2050,8 +2005,8 @@
memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
- if (scp->request_bufflen) {
- pthru->dataxferlen = scp->request_bufflen;
+ if (scsi_bufflen(scp)) {
+ pthru->dataxferlen = scsi_bufflen(scp);
pthru->dataxferaddr = ccb->sgl_dma_h;
pthru->numsge = megaraid_mbox_mksgl(adapter, scb);
}
@@ -2099,8 +2054,8 @@
memcpy(epthru->cdb, scp->cmnd, scp->cmd_len);
- if (scp->request_bufflen) {
- epthru->dataxferlen = scp->request_bufflen;
+ if (scsi_bufflen(scp)) {
+ epthru->dataxferlen = scsi_bufflen(scp);
epthru->dataxferaddr = ccb->sgl_dma_h;
epthru->numsge = megaraid_mbox_mksgl(adapter, scb);
}
@@ -2266,37 +2221,13 @@
ccb = (mbox_ccb_t *)scb->ccb;
- switch (scb->dma_type) {
-
- case MRAID_DMA_WBUF:
- if (scb->dma_direction == PCI_DMA_FROMDEVICE) {
- pci_dma_sync_single_for_cpu(adapter->pdev,
- ccb->buf_dma_h,
- scb->scp->request_bufflen,
+ if (scb->dma_direction == PCI_DMA_FROMDEVICE)
+ pci_dma_sync_sg_for_cpu(adapter->pdev,
+ scsi_sglist(scb->scp),
+ scsi_sg_count(scb->scp),
PCI_DMA_FROMDEVICE);
- }
- pci_unmap_page(adapter->pdev, ccb->buf_dma_h,
- scb->scp->request_bufflen, scb->dma_direction);
-
- break;
-
- case MRAID_DMA_WSG:
- if (scb->dma_direction == PCI_DMA_FROMDEVICE) {
- pci_dma_sync_sg_for_cpu(adapter->pdev,
- scb->scp->request_buffer,
- scb->scp->use_sg, PCI_DMA_FROMDEVICE);
- }
-
- pci_unmap_sg(adapter->pdev, scb->scp->request_buffer,
- scb->scp->use_sg, scb->dma_direction);
-
- break;
-
- default:
- break;
- }
-
+ scsi_dma_unmap(scb->scp);
return;
}
@@ -2399,24 +2330,16 @@
if (scp->cmnd[0] == INQUIRY && status == 0 && islogical == 0
&& IS_RAID_CH(raid_dev, scb->dev_channel)) {
- if (scp->use_sg) {
- sgl = (struct scatterlist *)
- scp->request_buffer;
-
- if (sgl->page) {
- c = *(unsigned char *)
+ sgl = scsi_sglist(scp);
+ if (sgl->page) {
+ c = *(unsigned char *)
(page_address((&sgl[0])->page) +
- (&sgl[0])->offset);
- }
- else {
- con_log(CL_ANN, (KERN_WARNING
- "megaraid mailbox: invalid sg:%d\n",
- __LINE__));
- c = 0;
- }
- }
- else {
- c = *(uint8_t *)scp->request_buffer;
+ (&sgl[0])->offset);
+ } else {
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid mailbox: invalid sg:%d\n",
+ __LINE__));
+ c = 0;
}
if ((c & 0x1F ) == TYPE_DISK) {
@@ -3957,7 +3880,7 @@
megaraid_sysfs_free_resources(adapter);
}
- sema_init(&raid_dev->sysfs_sem, 1);
+ mutex_init(&raid_dev->sysfs_mtx);
init_waitqueue_head(&raid_dev->sysfs_wait_q);
@@ -4058,7 +3981,7 @@
/*
* Allow only one read at a time to go through the sysfs attributes
*/
- down(&raid_dev->sysfs_sem);
+ mutex_lock(&raid_dev->sysfs_mtx);
uioc = raid_dev->sysfs_uioc;
mbox64 = raid_dev->sysfs_mbox64;
@@ -4134,7 +4057,7 @@
del_timer_sync(timerp);
- up(&raid_dev->sysfs_sem);
+ mutex_unlock(&raid_dev->sysfs_mtx);
return rval;
}
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
index 9de803c..626459d 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.h
+++ b/drivers/scsi/megaraid/megaraid_mbox.h
@@ -168,7 +168,7 @@
* @hw_error : set if FW not responding
* @fast_load : If set, skip physical device scanning
* @channel_class : channel class, RAID or SCSI
- * @sysfs_sem : semaphore to serialize access to sysfs res.
+ * @sysfs_mtx : mutex to serialize access to sysfs res.
* @sysfs_uioc : management packet to issue FW calls from sysfs
* @sysfs_mbox64 : mailbox packet to issue FW calls from sysfs
* @sysfs_buffer : data buffer for FW commands issued from sysfs
@@ -208,7 +208,7 @@
int hw_error;
int fast_load;
uint8_t channel_class;
- struct semaphore sysfs_sem;
+ struct mutex sysfs_mtx;
uioc_t *sysfs_uioc;
mbox64_t *sysfs_mbox64;
caddr_t sysfs_buffer;
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index e2cf12e..b7f2e61 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -433,34 +433,15 @@
int sge_count;
struct scatterlist *os_sgl;
- /*
- * Return 0 if there is no data transfer
- */
- if (!scp->request_buffer || !scp->request_bufflen)
- return 0;
+ sge_count = scsi_dma_map(scp);
+ BUG_ON(sge_count < 0);
- if (!scp->use_sg) {
- mfi_sgl->sge32[0].phys_addr = pci_map_single(instance->pdev,
- scp->
- request_buffer,
- scp->
- request_bufflen,
- scp->
- sc_data_direction);
- mfi_sgl->sge32[0].length = scp->request_bufflen;
-
- return 1;
+ if (sge_count) {
+ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+ mfi_sgl->sge32[i].length = sg_dma_len(os_sgl);
+ mfi_sgl->sge32[i].phys_addr = sg_dma_address(os_sgl);
+ }
}
-
- os_sgl = (struct scatterlist *)scp->request_buffer;
- sge_count = pci_map_sg(instance->pdev, os_sgl, scp->use_sg,
- scp->sc_data_direction);
-
- for (i = 0; i < sge_count; i++, os_sgl++) {
- mfi_sgl->sge32[i].length = sg_dma_len(os_sgl);
- mfi_sgl->sge32[i].phys_addr = sg_dma_address(os_sgl);
- }
-
return sge_count;
}
@@ -481,35 +462,15 @@
int sge_count;
struct scatterlist *os_sgl;
- /*
- * Return 0 if there is no data transfer
- */
- if (!scp->request_buffer || !scp->request_bufflen)
- return 0;
+ sge_count = scsi_dma_map(scp);
+ BUG_ON(sge_count < 0);
- if (!scp->use_sg) {
- mfi_sgl->sge64[0].phys_addr = pci_map_single(instance->pdev,
- scp->
- request_buffer,
- scp->
- request_bufflen,
- scp->
- sc_data_direction);
-
- mfi_sgl->sge64[0].length = scp->request_bufflen;
-
- return 1;
+ if (sge_count) {
+ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+ mfi_sgl->sge64[i].length = sg_dma_len(os_sgl);
+ mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl);
+ }
}
-
- os_sgl = (struct scatterlist *)scp->request_buffer;
- sge_count = pci_map_sg(instance->pdev, os_sgl, scp->use_sg,
- scp->sc_data_direction);
-
- for (i = 0; i < sge_count; i++, os_sgl++) {
- mfi_sgl->sge64[i].length = sg_dma_len(os_sgl);
- mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl);
- }
-
return sge_count;
}
@@ -593,7 +554,7 @@
pthru->cdb_len = scp->cmd_len;
pthru->timeout = 0;
pthru->flags = flags;
- pthru->data_xfer_len = scp->request_bufflen;
+ pthru->data_xfer_len = scsi_bufflen(scp);
memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
@@ -1195,45 +1156,6 @@
}
/**
- * megasas_unmap_sgbuf - Unmap SG buffers
- * @instance: Adapter soft state
- * @cmd: Completed command
- */
-static void
-megasas_unmap_sgbuf(struct megasas_instance *instance, struct megasas_cmd *cmd)
-{
- dma_addr_t buf_h;
- u8 opcode;
-
- if (cmd->scmd->use_sg) {
- pci_unmap_sg(instance->pdev, cmd->scmd->request_buffer,
- cmd->scmd->use_sg, cmd->scmd->sc_data_direction);
- return;
- }
-
- if (!cmd->scmd->request_bufflen)
- return;
-
- opcode = cmd->frame->hdr.cmd;
-
- if ((opcode == MFI_CMD_LD_READ) || (opcode == MFI_CMD_LD_WRITE)) {
- if (IS_DMA64)
- buf_h = cmd->frame->io.sgl.sge64[0].phys_addr;
- else
- buf_h = cmd->frame->io.sgl.sge32[0].phys_addr;
- } else {
- if (IS_DMA64)
- buf_h = cmd->frame->pthru.sgl.sge64[0].phys_addr;
- else
- buf_h = cmd->frame->pthru.sgl.sge32[0].phys_addr;
- }
-
- pci_unmap_single(instance->pdev, buf_h, cmd->scmd->request_bufflen,
- cmd->scmd->sc_data_direction);
- return;
-}
-
-/**
* megasas_complete_cmd - Completes a command
* @instance: Adapter soft state
* @cmd: Command to be completed
@@ -1281,7 +1203,7 @@
atomic_dec(&instance->fw_outstanding);
- megasas_unmap_sgbuf(instance, cmd);
+ scsi_dma_unmap(cmd->scmd);
cmd->scmd->scsi_done(cmd->scmd);
megasas_return_cmd(instance, cmd);
@@ -1329,7 +1251,7 @@
atomic_dec(&instance->fw_outstanding);
- megasas_unmap_sgbuf(instance, cmd);
+ scsi_dma_unmap(cmd->scmd);
cmd->scmd->scsi_done(cmd->scmd);
megasas_return_cmd(instance, cmd);
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index e64d1a1..651d09b 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -421,7 +421,7 @@
for (i = 0; i < cmd->cmd_len; ++i)
printk(" %x", cmd->cmnd[i]);
printk(" use_sg=%d buffer=%p bufflen=%u\n",
- cmd->use_sg, cmd->request_buffer, cmd->request_bufflen);
+ scsi_sg_count(cmd), scsi_sglist(cmd), scsi_bufflen(cmd));
}
#endif
if (ms->dma_started)
@@ -602,13 +602,16 @@
cmd->result += (cmd->SCp.Message << 8);
if (DEBUG_TARGET(cmd)) {
printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n",
- cmd->result, ms->data_ptr, cmd->request_bufflen);
+ cmd->result, ms->data_ptr, scsi_bufflen(cmd));
+#if 0
+ /* needs to use sg? */
if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3)
&& cmd->request_buffer != 0) {
unsigned char *b = cmd->request_buffer;
printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n",
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
}
+#endif
}
cmd->SCp.this_residual -= ms->data_ptr;
mesh_completed(ms, cmd);
@@ -1265,15 +1268,18 @@
dcmds = ms->dma_cmds;
dtot = 0;
if (cmd) {
- cmd->SCp.this_residual = cmd->request_bufflen;
- if (cmd->use_sg > 0) {
- int nseg;
+ int nseg;
+
+ cmd->SCp.this_residual = scsi_bufflen(cmd);
+
+ nseg = scsi_dma_map(cmd);
+ BUG_ON(nseg < 0);
+
+ if (nseg) {
total = 0;
- scl = (struct scatterlist *) cmd->request_buffer;
off = ms->data_ptr;
- nseg = pci_map_sg(ms->pdev, scl, cmd->use_sg,
- cmd->sc_data_direction);
- for (i = 0; i <nseg; ++i, ++scl) {
+
+ scsi_for_each_sg(cmd, scl, nseg, i) {
u32 dma_addr = sg_dma_address(scl);
u32 dma_len = sg_dma_len(scl);
@@ -1292,16 +1298,6 @@
dtot += dma_len - off;
off = 0;
}
- } else if (ms->data_ptr < cmd->request_bufflen) {
- dtot = cmd->request_bufflen - ms->data_ptr;
- if (dtot > 0xffff)
- panic("mesh: transfer size >= 64k");
- st_le16(&dcmds->req_count, dtot);
- /* XXX Use pci DMA API here ... */
- st_le32(&dcmds->phy_addr,
- virt_to_phys(cmd->request_buffer) + ms->data_ptr);
- dcmds->xfer_status = 0;
- ++dcmds;
}
}
if (dtot == 0) {
@@ -1356,18 +1352,14 @@
dumplog(ms, ms->conn_tgt);
dumpslog(ms);
#endif /* MESH_DBG */
- } else if (cmd && cmd->request_bufflen != 0 &&
- ms->data_ptr > cmd->request_bufflen) {
+ } else if (cmd && scsi_bufflen(cmd) &&
+ ms->data_ptr > scsi_bufflen(cmd)) {
printk(KERN_DEBUG "mesh: target %d overrun, "
"data_ptr=%x total=%x goes_out=%d\n",
- ms->conn_tgt, ms->data_ptr, cmd->request_bufflen,
+ ms->conn_tgt, ms->data_ptr, scsi_bufflen(cmd),
ms->tgts[ms->conn_tgt].data_goes_out);
}
- if (cmd->use_sg != 0) {
- struct scatterlist *sg;
- sg = (struct scatterlist *)cmd->request_buffer;
- pci_unmap_sg(ms->pdev, sg, cmd->use_sg, cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
ms->dma_started = 0;
}
diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
deleted file mode 100644
index 575fe6f..0000000
--- a/drivers/scsi/mvme16x.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux.
- *
- * Based on work by Alan Hourihane
- */
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/blkdev.h>
-
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/mvme16xhw.h>
-#include <asm/irq.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "53c7xx.h"
-#include "mvme16x.h"
-
-#include<linux/stat.h>
-
-
-int mvme16x_scsi_detect(struct scsi_host_template *tpnt)
-{
- static unsigned char called = 0;
- int clock;
- long long options;
-
- if (!MACH_IS_MVME16x)
- return 0;
- if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) {
- printk ("SCSI detection disabled, SCSI chip not present\n");
- return 0;
- }
- if (called)
- return 0;
-
- tpnt->proc_name = "MVME16x";
-
- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
-
- clock = 66000000; /* 66MHz SCSI Clock */
-
- ncr53c7xx_init(tpnt, 0, 710, (unsigned long)0xfff47000,
- 0, MVME16x_IRQ_SCSI, DMA_NONE,
- options, clock);
- called = 1;
- return 1;
-}
-
-static int mvme16x_scsi_release(struct Scsi_Host *shost)
-{
- if (shost->irq)
- free_irq(shost->irq, NULL);
- if (shost->dma_channel != 0xff)
- free_dma(shost->dma_channel);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
- scsi_unregister(shost);
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .name = "MVME16x NCR53c710 SCSI",
- .detect = mvme16x_scsi_detect,
- .release = mvme16x_scsi_release,
- .queuecommand = NCR53c7xx_queue_command,
- .abort = NCR53c7xx_abort,
- .reset = NCR53c7xx_reset,
- .can_queue = 24,
- .this_id = 7,
- .sg_tablesize = 63,
- .cmd_per_lun = 3,
- .use_clustering = DISABLE_CLUSTERING
-};
-
-
-#include "scsi_module.c"
diff --git a/drivers/scsi/mvme16x.h b/drivers/scsi/mvme16x.h
deleted file mode 100644
index 73e33b3..0000000
--- a/drivers/scsi/mvme16x.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef MVME16x_SCSI_H
-#define MVME16x_SCSI_H
-
-#include <linux/types.h>
-
-int mvme16x_scsi_detect(struct scsi_host_template *);
-const char *NCR53c7x0_info(void);
-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int NCR53c7xx_abort(Scsi_Cmnd *);
-int NCR53c7x0_release (struct Scsi_Host *);
-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
-void NCR53c7x0_intr(int irq, void *dev_id);
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 3
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 24
-#endif
-
-#include <scsi/scsicam.h>
-
-#endif /* MVME16x_SCSI_H */
diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c
new file mode 100644
index 0000000..d6ef22a
--- /dev/null
+++ b/drivers/scsi/mvme16x_scsi.c
@@ -0,0 +1,158 @@
+/*
+ * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux.
+ *
+ * Based on work by Alan Hourihane
+ *
+ * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org>
+ */
+
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/mvme16xhw.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+
+MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>");
+MODULE_DESCRIPTION("MVME16x NCR53C710 driver");
+MODULE_LICENSE("GPL");
+
+static struct scsi_host_template mvme16x_scsi_driver_template = {
+ .name = "MVME16x NCR53c710 SCSI",
+ .proc_name = "MVME16x",
+ .this_id = 7,
+ .module = THIS_MODULE,
+};
+
+static struct platform_device *mvme16x_scsi_device;
+
+static __devinit int
+mvme16x_probe(struct device *dev)
+{
+ struct Scsi_Host * host = NULL;
+ struct NCR_700_Host_Parameters *hostdata;
+
+ if (!MACH_IS_MVME16x)
+ goto out;
+
+ if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) {
+ printk(KERN_INFO "mvme16x-scsi: detection disabled, "
+ "SCSI chip not present\n");
+ goto out;
+ }
+
+ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (hostdata == NULL) {
+ printk(KERN_ERR "mvme16x-scsi: "
+ "Failed to allocate host data\n");
+ goto out;
+ }
+ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
+
+ /* Fill in the required pieces of hostdata */
+ hostdata->base = (void __iomem *)0xfff47000UL;
+ hostdata->clock = 50; /* XXX - depends on the CPU clock! */
+ hostdata->chip710 = 1;
+ hostdata->dmode_extra = DMODE_FC2;
+ hostdata->dcntl_extra = EA_710;
+ hostdata->ctest7_extra = CTEST7_TT1;
+
+ /* and register the chip */
+ host = NCR_700_detect(&mvme16x_scsi_driver_template, hostdata, dev);
+ if (!host) {
+ printk(KERN_ERR "mvme16x-scsi: No host detected; "
+ "board configuration problem?\n");
+ goto out_free;
+ }
+ host->this_id = 7;
+ host->base = 0xfff47000UL;
+ host->irq = MVME16x_IRQ_SCSI;
+ if (request_irq(host->irq, NCR_700_intr, 0, "mvme16x-scsi", host)) {
+ printk(KERN_ERR "mvme16x-scsi: request_irq failed\n");
+ goto out_put_host;
+ }
+
+ /* Enable scsi chip ints */
+ {
+ volatile unsigned long v;
+
+ /* Enable scsi interrupts at level 4 in PCCchip2 */
+ v = in_be32(0xfff4202c);
+ v = (v & ~0xff) | 0x10 | 4;
+ out_be32(0xfff4202c, v);
+ }
+
+ scsi_scan_host(host);
+
+ return 0;
+
+ out_put_host:
+ scsi_host_put(host);
+ out_free:
+ kfree(hostdata);
+ out:
+ return -ENODEV;
+}
+
+static __devexit int
+mvme16x_device_remove(struct device *dev)
+{
+ struct Scsi_Host *host = dev_to_shost(dev);
+ struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
+
+ /* Disable scsi chip ints */
+ {
+ volatile unsigned long v;
+
+ v = in_be32(0xfff4202c);
+ v &= ~0x10;
+ out_be32(0xfff4202c, v);
+ }
+ scsi_remove_host(host);
+ NCR_700_release(host);
+ kfree(hostdata);
+ free_irq(host->irq, host);
+
+ return 0;
+}
+
+static struct device_driver mvme16x_scsi_driver = {
+ .name = "mvme16x-scsi",
+ .bus = &platform_bus_type,
+ .probe = mvme16x_probe,
+ .remove = __devexit_p(mvme16x_device_remove),
+};
+
+static int __init mvme16x_scsi_init(void)
+{
+ int err;
+
+ err = driver_register(&mvme16x_scsi_driver);
+ if (err)
+ return err;
+
+ mvme16x_scsi_device = platform_device_register_simple("mvme16x-scsi",
+ -1, NULL, 0);
+ if (IS_ERR(mvme16x_scsi_device)) {
+ driver_unregister(&mvme16x_scsi_driver);
+ return PTR_ERR(mvme16x_scsi_device);
+ }
+
+ return 0;
+}
+
+static void __exit mvme16x_scsi_exit(void)
+{
+ platform_device_unregister(mvme16x_scsi_device);
+ driver_unregister(&mvme16x_scsi_driver);
+}
+
+module_init(mvme16x_scsi_init);
+module_exit(mvme16x_scsi_exit);
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index bbf521c..030ba49 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -529,43 +529,20 @@
{
switch(cmd->__data_mapped) {
case 2:
- dma_unmap_sg(dev, cmd->request_buffer, cmd->use_sg,
- cmd->sc_data_direction);
- break;
- case 1:
- dma_unmap_single(dev, cmd->__data_mapping,
- cmd->request_bufflen,
- cmd->sc_data_direction);
+ scsi_dma_unmap(cmd);
break;
}
cmd->__data_mapped = 0;
}
-static u_long __map_scsi_single_data(struct device *dev, struct scsi_cmnd *cmd)
-{
- dma_addr_t mapping;
-
- if (cmd->request_bufflen == 0)
- return 0;
-
- mapping = dma_map_single(dev, cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- cmd->__data_mapped = 1;
- cmd->__data_mapping = mapping;
-
- return mapping;
-}
-
static int __map_scsi_sg_data(struct device *dev, struct scsi_cmnd *cmd)
{
int use_sg;
- if (cmd->use_sg == 0)
+ use_sg = scsi_dma_map(cmd);
+ if (!use_sg)
return 0;
- use_sg = dma_map_sg(dev, cmd->request_buffer, cmd->use_sg,
- cmd->sc_data_direction);
cmd->__data_mapped = 2;
cmd->__data_mapping = use_sg;
@@ -573,7 +550,6 @@
}
#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->dev, cmd)
-#define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->dev, cmd)
#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->dev, cmd)
/*==========================================================
@@ -7667,39 +7643,16 @@
** sizes to the data segment array.
*/
-static int ncr_scatter_no_sglist(struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd)
-{
- struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - 1];
- int segment;
-
- cp->data_len = cmd->request_bufflen;
-
- if (cmd->request_bufflen) {
- dma_addr_t baddr = map_scsi_single_data(np, cmd);
- if (baddr) {
- ncr_build_sge(np, data, baddr, cmd->request_bufflen);
- segment = 1;
- } else {
- segment = -2;
- }
- } else {
- segment = 0;
- }
-
- return segment;
-}
-
static int ncr_scatter(struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd)
{
int segment = 0;
- int use_sg = (int) cmd->use_sg;
+ int use_sg = scsi_sg_count(cmd);
cp->data_len = 0;
- if (!use_sg)
- segment = ncr_scatter_no_sglist(np, cp, cmd);
- else if ((use_sg = map_scsi_sg_data(np, cmd)) > 0) {
- struct scatterlist *scatter = (struct scatterlist *)cmd->request_buffer;
+ use_sg = map_scsi_sg_data(np, cmd);
+ if (use_sg > 0) {
+ struct scatterlist *sg;
struct scr_tblmove *data;
if (use_sg > MAX_SCATTER) {
@@ -7709,16 +7662,15 @@
data = &cp->phys.data[MAX_SCATTER - use_sg];
- for (segment = 0; segment < use_sg; segment++) {
- dma_addr_t baddr = sg_dma_address(&scatter[segment]);
- unsigned int len = sg_dma_len(&scatter[segment]);
+ scsi_for_each_sg(cmd, sg, use_sg, segment) {
+ dma_addr_t baddr = sg_dma_address(sg);
+ unsigned int len = sg_dma_len(sg);
ncr_build_sge(np, &data[segment], baddr, len);
cp->data_len += len;
}
- } else {
+ } else
segment = -2;
- }
return segment;
}
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 3e9765f..7fed353 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -49,10 +49,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
-# include <linux/blk.h>
-#endif
-
#include "nsp32.h"
@@ -199,17 +195,9 @@
static void __exit exit_nsp32 (void);
/* struct struct scsi_host_template */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
static int nsp32_proc_info (struct Scsi_Host *, char *, char **, off_t, int, int);
-#else
-static int nsp32_proc_info (char *, char **, off_t, int, int, int);
-#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
static int nsp32_detect (struct pci_dev *pdev);
-#else
-static int nsp32_detect (struct scsi_host_template *);
-#endif
static int nsp32_queuecommand(struct scsi_cmnd *,
void (*done)(struct scsi_cmnd *));
static const char *nsp32_info (struct Scsi_Host *);
@@ -296,15 +284,7 @@
.eh_abort_handler = nsp32_eh_abort,
.eh_bus_reset_handler = nsp32_eh_bus_reset,
.eh_host_reset_handler = nsp32_eh_host_reset,
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74))
- .detect = nsp32_detect,
- .release = nsp32_release,
-#endif
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
- .use_new_eh_code = 1,
-#else
/* .highmem_io = 1, */
-#endif
};
#include "nsp32_io.h"
@@ -739,7 +719,7 @@
command = 0;
command |= (TRANSFER_GO | ALL_COUNTER_CLR);
if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
- if (SCpnt->request_bufflen > 0) {
+ if (scsi_bufflen(SCpnt) > 0) {
command |= BM_START;
}
} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
@@ -888,31 +868,28 @@
static int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
- struct scatterlist *sgl;
+ struct scatterlist *sg;
nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt;
int num, i;
u32_le l;
- if (SCpnt->request_bufflen == 0) {
- return TRUE;
- }
-
if (sgt == NULL) {
nsp32_dbg(NSP32_DEBUG_SGLIST, "SGT == null");
return FALSE;
}
- if (SCpnt->use_sg) {
- sgl = (struct scatterlist *)SCpnt->request_buffer;
- num = pci_map_sg(data->Pci, sgl, SCpnt->use_sg,
- SCpnt->sc_data_direction);
- for (i = 0; i < num; i++) {
+ num = scsi_dma_map(SCpnt);
+ if (!num)
+ return TRUE;
+ else if (num < 0)
+ return FALSE;
+ else {
+ scsi_for_each_sg(SCpnt, sg, num, i) {
/*
* Build nsp32_sglist, substitute sg dma addresses.
*/
- sgt[i].addr = cpu_to_le32(sg_dma_address(sgl));
- sgt[i].len = cpu_to_le32(sg_dma_len(sgl));
- sgl++;
+ sgt[i].addr = cpu_to_le32(sg_dma_address(sg));
+ sgt[i].len = cpu_to_le32(sg_dma_len(sg));
if (le32_to_cpu(sgt[i].len) > 0x10000) {
nsp32_msg(KERN_ERR,
@@ -929,23 +906,6 @@
/* set end mark */
l = le32_to_cpu(sgt[num-1].len);
sgt[num-1].len = cpu_to_le32(l | SGTEND);
-
- } else {
- SCpnt->SCp.have_data_in = pci_map_single(data->Pci,
- SCpnt->request_buffer, SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
-
- sgt[0].addr = cpu_to_le32(SCpnt->SCp.have_data_in);
- sgt[0].len = cpu_to_le32(SCpnt->request_bufflen | SGTEND); /* set end mark */
-
- if (SCpnt->request_bufflen > 0x10000) {
- nsp32_msg(KERN_ERR,
- "can't transfer over 64KB at a time, size=0x%lx", SCpnt->request_bufflen);
- return FALSE;
- }
- nsp32_dbg(NSP32_DEBUG_SGLIST, "single : addr 0x%lx len=0x%lx",
- le32_to_cpu(sgt[0].addr),
- le32_to_cpu(sgt[0].len ));
}
return TRUE;
@@ -962,7 +922,7 @@
"enter. target: 0x%x LUN: 0x%x cmnd: 0x%x cmndlen: 0x%x "
"use_sg: 0x%x reqbuf: 0x%lx reqlen: 0x%x",
SCpnt->device->id, SCpnt->device->lun, SCpnt->cmnd[0], SCpnt->cmd_len,
- SCpnt->use_sg, SCpnt->request_buffer, SCpnt->request_bufflen);
+ scsi_sg_count(SCpnt), scsi_sglist(SCpnt), scsi_bufflen(SCpnt));
if (data->CurrentSC != NULL) {
nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request");
@@ -994,10 +954,10 @@
data->CurrentSC = SCpnt;
SCpnt->SCp.Status = CHECK_CONDITION;
SCpnt->SCp.Message = 0;
- SCpnt->resid = SCpnt->request_bufflen;
+ scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
- SCpnt->SCp.ptr = (char *) SCpnt->request_buffer;
- SCpnt->SCp.this_residual = SCpnt->request_bufflen;
+ SCpnt->SCp.ptr = (char *)scsi_sglist(SCpnt);
+ SCpnt->SCp.this_residual = scsi_bufflen(SCpnt);
SCpnt->SCp.buffer = NULL;
SCpnt->SCp.buffers_residual = 0;
@@ -1210,13 +1170,9 @@
unsigned long flags;
int ret;
int handled = 0;
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
struct Scsi_Host *host = data->Host;
+
spin_lock_irqsave(host->host_lock, flags);
-#else
- spin_lock_irqsave(&io_request_lock, flags);
-#endif
/*
* IRQ check, then enable IRQ mask
@@ -1312,7 +1268,7 @@
}
if ((auto_stat & DATA_IN_PHASE) &&
- (SCpnt->resid > 0) &&
+ (scsi_get_resid(SCpnt) > 0) &&
((nsp32_read2(base, FIFO_REST_CNT) & FIFO_REST_MASK) != 0)) {
printk( "auto+fifo\n");
//nsp32_pio_read(SCpnt);
@@ -1333,7 +1289,7 @@
nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx",
nsp32_read4(base, SAVED_SACK_CNT));
- SCpnt->resid = 0; /* all data transfered! */
+ scsi_set_resid(SCpnt, 0); /* all data transfered! */
}
/*
@@ -1480,11 +1436,7 @@
nsp32_write2(base, IRQ_CONTROL, 0);
out2:
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
spin_unlock_irqrestore(host->host_lock, flags);
-#else
- spin_unlock_irqrestore(&io_request_lock, flags);
-#endif
nsp32_dbg(NSP32_DEBUG_INTR, "exit");
@@ -1499,28 +1451,15 @@
nsp32_dbg(NSP32_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\
} \
} while(0)
-static int nsp32_proc_info(
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- struct Scsi_Host *host,
-#endif
- char *buffer,
- char **start,
- off_t offset,
- int length,
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- int hostno,
-#endif
- int inout)
+
+static int nsp32_proc_info(struct Scsi_Host *host, char *buffer, char **start,
+ off_t offset, int length, int inout)
{
char *pos = buffer;
int thislength;
unsigned long flags;
nsp32_hw_data *data;
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
int hostno;
-#else
- struct Scsi_Host *host;
-#endif
unsigned int base;
unsigned char mode_reg;
int id, speed;
@@ -1531,15 +1470,7 @@
return -EINVAL;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
hostno = host->host_no;
-#else
- /* search this HBA host */
- host = scsi_host_hn_get(hostno);
- if (host == NULL) {
- return -ESRCH;
- }
-#endif
data = (nsp32_hw_data *)host->hostdata;
base = host->io_port;
@@ -1626,25 +1557,8 @@
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
unsigned int base = SCpnt->device->host->io_port;
- /*
- * unmap pci
- */
- if (SCpnt->request_bufflen == 0) {
- goto skip;
- }
+ scsi_dma_unmap(SCpnt);
- if (SCpnt->use_sg) {
- pci_unmap_sg(data->Pci,
- (struct scatterlist *)SCpnt->request_buffer,
- SCpnt->use_sg, SCpnt->sc_data_direction);
- } else {
- pci_unmap_single(data->Pci,
- (u32)SCpnt->SCp.have_data_in,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- }
-
- skip:
/*
* clear TRANSFERCONTROL_BM_START
*/
@@ -1800,7 +1714,7 @@
SCpnt->SCp.Message = 0;
nsp32_dbg(NSP32_DEBUG_BUSFREE,
"normal end stat=0x%x resid=0x%x\n",
- SCpnt->SCp.Status, SCpnt->resid);
+ SCpnt->SCp.Status, scsi_get_resid(SCpnt));
SCpnt->result = (DID_OK << 16) |
(SCpnt->SCp.Message << 8) |
(SCpnt->SCp.Status << 0);
@@ -1844,7 +1758,7 @@
unsigned int restlen, sentlen;
u32_le len, addr;
- nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", SCpnt->resid);
+ nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", scsi_get_resid(SCpnt));
/* adjust saved SACK count with 4 byte start address boundary */
s_sacklen -= le32_to_cpu(sgt[old_entry].addr) & 3;
@@ -1888,12 +1802,12 @@
return;
last:
- if (SCpnt->resid < sentlen) {
+ if (scsi_get_resid(SCpnt) < sentlen) {
nsp32_msg(KERN_ERR, "resid underflow");
}
- SCpnt->resid -= sentlen;
- nsp32_dbg(NSP32_DEBUG_SGLIST, "new resid=0x%x", SCpnt->resid);
+ scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) - sentlen);
+ nsp32_dbg(NSP32_DEBUG_SGLIST, "new resid=0x%x", scsi_get_resid(SCpnt));
/* update hostdata and lun */
@@ -2022,7 +1936,7 @@
transfer = 0;
transfer |= (TRANSFER_GO | ALL_COUNTER_CLR);
if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
- if (SCpnt->request_bufflen > 0) {
+ if (scsi_bufflen(SCpnt) > 0) {
transfer |= BM_START;
}
} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
@@ -2674,17 +2588,7 @@
* 0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly)
* 0xc00-0xfff: CardBus status registers
*/
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
-#define DETECT_OK 0
-#define DETECT_NG 1
-#define PCIDEV pdev
static int nsp32_detect(struct pci_dev *pdev)
-#else
-#define DETECT_OK 1
-#define DETECT_NG 0
-#define PCIDEV (data->Pci)
-static int nsp32_detect(struct scsi_host_template *sht)
-#endif
{
struct Scsi_Host *host; /* registered host structure */
struct resource *res;
@@ -2697,11 +2601,7 @@
/*
* register this HBA as SCSI device
*/
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
host = scsi_host_alloc(&nsp32_template, sizeof(nsp32_hw_data));
-#else
- host = scsi_register(sht, sizeof(nsp32_hw_data));
-#endif
if (host == NULL) {
nsp32_msg (KERN_ERR, "failed to scsi register");
goto err;
@@ -2719,9 +2619,6 @@
host->unique_id = data->BaseAddress;
host->n_io_port = data->NumAddress;
host->base = (unsigned long)data->MmioAddress;
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,63))
- scsi_set_pci_device(host, PCIDEV);
-#endif
data->Host = host;
spin_lock_init(&(data->Lock));
@@ -2776,7 +2673,7 @@
/*
* setup DMA
*/
- if (pci_set_dma_mask(PCIDEV, DMA_32BIT_MASK) != 0) {
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
nsp32_msg (KERN_ERR, "failed to set PCI DMA mask");
goto scsi_unregister;
}
@@ -2784,7 +2681,7 @@
/*
* allocate autoparam DMA resource.
*/
- data->autoparam = pci_alloc_consistent(PCIDEV, sizeof(nsp32_autoparam), &(data->auto_paddr));
+ data->autoparam = pci_alloc_consistent(pdev, sizeof(nsp32_autoparam), &(data->auto_paddr));
if (data->autoparam == NULL) {
nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
goto scsi_unregister;
@@ -2793,7 +2690,7 @@
/*
* allocate scatter-gather DMA resource.
*/
- data->sg_list = pci_alloc_consistent(PCIDEV, NSP32_SG_TABLE_SIZE,
+ data->sg_list = pci_alloc_consistent(pdev, NSP32_SG_TABLE_SIZE,
&(data->sg_paddr));
if (data->sg_list == NULL) {
nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
@@ -2883,16 +2780,14 @@
goto free_irq;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- ret = scsi_add_host(host, &PCIDEV->dev);
+ ret = scsi_add_host(host, &pdev->dev);
if (ret) {
nsp32_msg(KERN_ERR, "failed to add scsi host");
goto free_region;
}
scsi_scan_host(host);
-#endif
- pci_set_drvdata(PCIDEV, host);
- return DETECT_OK;
+ pci_set_drvdata(pdev, host);
+ return 0;
free_region:
release_region(host->io_port, host->n_io_port);
@@ -2901,22 +2796,19 @@
free_irq(host->irq, data);
free_sg_list:
- pci_free_consistent(PCIDEV, NSP32_SG_TABLE_SIZE,
+ pci_free_consistent(pdev, NSP32_SG_TABLE_SIZE,
data->sg_list, data->sg_paddr);
free_autoparam:
- pci_free_consistent(PCIDEV, sizeof(nsp32_autoparam),
+ pci_free_consistent(pdev, sizeof(nsp32_autoparam),
data->autoparam, data->auto_paddr);
scsi_unregister:
scsi_host_put(host);
err:
- return DETECT_NG;
+ return 1;
}
-#undef DETECT_OK
-#undef DETECT_NG
-#undef PCIDEV
static int nsp32_release(struct Scsi_Host *host)
{
@@ -3516,11 +3408,7 @@
pci_set_master(pdev);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
ret = nsp32_detect(pdev);
-#else
- ret = scsi_register_host(&nsp32_template);
-#endif
nsp32_msg(KERN_INFO, "irq: %i mmio: %p+0x%lx slot: %s model: %s",
pdev->irq,
@@ -3535,25 +3423,17 @@
static void __devexit nsp32_remove(struct pci_dev *pdev)
{
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
struct Scsi_Host *host = pci_get_drvdata(pdev);
-#endif
nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
scsi_remove_host(host);
nsp32_release(host);
scsi_host_put(host);
-#else
- scsi_unregister_host(&nsp32_template);
-#endif
}
-
-
static struct pci_driver nsp32_driver = {
.name = "nsp32",
.id_table = nsp32_pci_table,
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index ffe75c4..2695b71 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -370,8 +370,6 @@
DEB(unsigned char seq_reg;)
unsigned char status, int_reg;
unsigned char pio_status;
- struct scatterlist *sglist;
- unsigned int sgcount;
int port_base = dev->io_port;
struct sym53c500_data *data =
(struct sym53c500_data *)dev->hostdata;
@@ -434,20 +432,19 @@
switch (status & 0x07) { /* scsi phase */
case 0x00: /* DATA-OUT */
if (int_reg & 0x10) { /* Target requesting info transfer */
+ struct scatterlist *sg;
+ int i;
+
curSC->SCp.phase = data_out;
VDEB(printk("SYM53C500: Data-Out phase\n"));
outb(FLUSH_FIFO, port_base + CMD_REG);
- LOAD_DMA_COUNT(port_base, curSC->request_bufflen); /* Max transfer size */
+ LOAD_DMA_COUNT(port_base, scsi_bufflen(curSC)); /* Max transfer size */
outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG);
- if (!curSC->use_sg) /* Don't use scatter-gather */
- SYM53C500_pio_write(fast_pio, port_base, curSC->request_buffer, curSC->request_bufflen);
- else { /* use scatter-gather */
- sgcount = curSC->use_sg;
- sglist = curSC->request_buffer;
- while (sgcount--) {
- SYM53C500_pio_write(fast_pio, port_base, page_address(sglist->page) + sglist->offset, sglist->length);
- sglist++;
- }
+
+ scsi_for_each_sg(curSC, sg, scsi_sg_count(curSC), i) {
+ SYM53C500_pio_write(fast_pio, port_base,
+ page_address(sg->page) + sg->offset,
+ sg->length);
}
REG0(port_base);
}
@@ -455,20 +452,19 @@
case 0x01: /* DATA-IN */
if (int_reg & 0x10) { /* Target requesting info transfer */
+ struct scatterlist *sg;
+ int i;
+
curSC->SCp.phase = data_in;
VDEB(printk("SYM53C500: Data-In phase\n"));
outb(FLUSH_FIFO, port_base + CMD_REG);
- LOAD_DMA_COUNT(port_base, curSC->request_bufflen); /* Max transfer size */
+ LOAD_DMA_COUNT(port_base, scsi_bufflen(curSC)); /* Max transfer size */
outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG);
- if (!curSC->use_sg) /* Don't use scatter-gather */
- SYM53C500_pio_read(fast_pio, port_base, curSC->request_buffer, curSC->request_bufflen);
- else { /* Use scatter-gather */
- sgcount = curSC->use_sg;
- sglist = curSC->request_buffer;
- while (sgcount--) {
- SYM53C500_pio_read(fast_pio, port_base, page_address(sglist->page) + sglist->offset, sglist->length);
- sglist++;
- }
+
+ scsi_for_each_sg(curSC, sg, scsi_sg_count(curSC), i) {
+ SYM53C500_pio_read(fast_pio, port_base,
+ page_address(sg->page) + sg->offset,
+ sg->length);
}
REG0(port_base);
}
@@ -578,7 +574,7 @@
DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n",
SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->device->id,
- SCpnt->device->lun, SCpnt->request_bufflen));
+ SCpnt->device->lun, scsi_bufflen(SCpnt)));
VDEB(for (i = 0; i < SCpnt->cmd_len; i++)
printk("cmd[%d]=%02x ", i, SCpnt->cmnd[i]));
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 584ba4d..2f1fa1e 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -129,11 +129,11 @@
if ((length > 10) && (strncmp(buffer, "recon_tmo=", 10) == 0)) {
x = simple_strtoul(buffer + 10, NULL, 0);
dev->recon_tmo = x;
- printk("ppa: recon_tmo set to %ld\n", x);
+ printk(KERN_INFO "ppa: recon_tmo set to %ld\n", x);
return length;
}
- printk("ppa /proc: invalid variable\n");
- return (-EINVAL);
+ printk(KERN_WARNING "ppa /proc: invalid variable\n");
+ return -EINVAL;
}
static int ppa_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout)
@@ -216,7 +216,7 @@
/* Counter expired - Time out occurred */
ppa_fail(dev, DID_TIME_OUT);
- printk("ppa timeout in ppa_wait\n");
+ printk(KERN_WARNING "ppa timeout in ppa_wait\n");
return 0; /* command timed out */
}
@@ -248,7 +248,7 @@
return;
udelay(5);
}
- printk("ppa: ECP sync failed as data still present in FIFO.\n");
+ printk(KERN_WARNING "ppa: ECP sync failed as data still present in FIFO.\n");
}
}
@@ -328,7 +328,7 @@
break;
default:
- printk("PPA: bug in ppa_out()\n");
+ printk(KERN_ERR "PPA: bug in ppa_out()\n");
r = 0;
}
return r;
@@ -381,7 +381,7 @@
break;
default:
- printk("PPA: bug in ppa_ins()\n");
+ printk(KERN_ERR "PPA: bug in ppa_ins()\n");
r = 0;
break;
}
@@ -633,7 +633,7 @@
struct scsi_cmnd *cmd = dev->cur_cmd;
if (!cmd) {
- printk("PPA: bug in ppa_interrupt\n");
+ printk(KERN_ERR "PPA: bug in ppa_interrupt\n");
return;
}
if (ppa_engine(dev, cmd)) {
@@ -646,31 +646,31 @@
case DID_OK:
break;
case DID_NO_CONNECT:
- printk("ppa: no device at SCSI ID %i\n", cmd->device->target);
+ printk(KERN_DEBUG "ppa: no device at SCSI ID %i\n", cmd->device->target);
break;
case DID_BUS_BUSY:
- printk("ppa: BUS BUSY - EPP timeout detected\n");
+ printk(KERN_DEBUG "ppa: BUS BUSY - EPP timeout detected\n");
break;
case DID_TIME_OUT:
- printk("ppa: unknown timeout\n");
+ printk(KERN_DEBUG "ppa: unknown timeout\n");
break;
case DID_ABORT:
- printk("ppa: told to abort\n");
+ printk(KERN_DEBUG "ppa: told to abort\n");
break;
case DID_PARITY:
- printk("ppa: parity error (???)\n");
+ printk(KERN_DEBUG "ppa: parity error (???)\n");
break;
case DID_ERROR:
- printk("ppa: internal driver error\n");
+ printk(KERN_DEBUG "ppa: internal driver error\n");
break;
case DID_RESET:
- printk("ppa: told to reset device\n");
+ printk(KERN_DEBUG "ppa: told to reset device\n");
break;
case DID_BAD_INTR:
- printk("ppa: bad interrupt (???)\n");
+ printk(KERN_WARNING "ppa: bad interrupt (???)\n");
break;
default:
- printk("ppa: bad return code (%02x)\n",
+ printk(KERN_WARNING "ppa: bad return code (%02x)\n",
(cmd->result >> 16) & 0xff);
}
#endif
@@ -724,8 +724,7 @@
if (retv) {
if (time_after(jiffies, dev->jstart + (1 * HZ))) {
- printk
- ("ppa: Parallel port cable is unplugged!!\n");
+ printk(KERN_ERR "ppa: Parallel port cable is unplugged.\n");
ppa_fail(dev, DID_BUS_BUSY);
return 0;
} else {
@@ -755,11 +754,9 @@
case 4: /* Phase 4 - Setup scatter/gather buffers */
if (cmd->use_sg) {
/* if many buffers are available, start filling the first */
- cmd->SCp.buffer =
- (struct scatterlist *) cmd->request_buffer;
+ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr =
- page_address(cmd->SCp.buffer->page) +
+ cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
cmd->SCp.buffer->offset;
} else {
/* else fill the only available buffer */
@@ -800,7 +797,7 @@
break;
default:
- printk("ppa: Invalid scsi phase\n");
+ printk(KERN_ERR "ppa: Invalid scsi phase\n");
}
return 0;
}
@@ -811,7 +808,7 @@
ppa_struct *dev = ppa_dev(cmd->device->host);
if (dev->cur_cmd) {
- printk("PPA: bug in ppa_queuecommand\n");
+ printk(KERN_ERR "PPA: bug in ppa_queuecommand\n");
return 0;
}
dev->failed = 0;
@@ -899,7 +896,7 @@
/* This routine looks for a device and then attempts to use EPP
to send a command. If all goes as planned then EPP is available. */
- static char cmd[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static u8 cmd[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
int loop, old_mode, status, k, ppb = dev->base;
unsigned char l;
@@ -909,14 +906,14 @@
if ((ppb & 0x0007) == 0x0000)
dev->mode = PPA_EPP_32;
- second_pass:
+second_pass:
ppa_connect(dev, CONNECT_EPP_MAYBE);
/* Select SCSI device */
if (!ppa_select(dev, loop)) {
ppa_disconnect(dev);
continue;
}
- printk("ppa: Found device at ID %i, Attempting to use %s\n",
+ printk(KERN_INFO "ppa: Found device at ID %i, Attempting to use %s\n",
loop, PPA_MODE_STRING[dev->mode]);
/* Send SCSI command */
@@ -965,7 +962,7 @@
return -EIO;
}
ppa_disconnect(dev);
- printk("ppa: Communication established with ID %i using %s\n",
+ printk(KERN_INFO "ppa: Communication established with ID %i using %s\n",
loop, PPA_MODE_STRING[dev->mode]);
ppa_connect(dev, CONNECT_EPP_MAYBE);
ppa_reset_pulse(ppb);
@@ -1140,7 +1137,7 @@
static int __init ppa_driver_init(void)
{
- printk("ppa: Version %s\n", PPA_VERSION);
+ printk(KERN_INFO "ppa: Version %s\n", PPA_VERSION);
return parport_register_driver(&ppa_driver);
}
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
index 411663a..71ddb5d 100644
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -1,4 +1,4 @@
qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
- qla_dbg.o qla_sup.o qla_attr.o
+ qla_dbg.o qla_sup.o qla_attr.o qla_mid.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 942db9d..3eb2208 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -6,8 +6,11 @@
*/
#include "qla_def.h"
+#include <linux/kthread.h>
#include <linux/vmalloc.h>
+int qla24xx_vport_disable(struct fc_vport *, bool);
+
/* SYSFS attributes --------------------------------------------------------- */
static ssize_t
@@ -963,6 +966,122 @@
fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
}
+static int
+qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
+{
+ int ret = 0;
+ scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *vha;
+
+ ret = qla24xx_vport_create_req_sanity_check(fc_vport);
+ if (ret) {
+ DEBUG15(printk("qla24xx_vport_create_req_sanity_check failed, "
+ "status %x\n", ret));
+ return (ret);
+ }
+
+ vha = qla24xx_create_vhost(fc_vport);
+ if (vha == NULL) {
+ DEBUG15(printk ("qla24xx_create_vhost failed, vha = %p\n",
+ vha));
+ return FC_VPORT_FAILED;
+ }
+ if (disable) {
+ atomic_set(&vha->vp_state, VP_OFFLINE);
+ fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
+ } else
+ atomic_set(&vha->vp_state, VP_FAILED);
+
+ /* ready to create vport */
+ qla_printk(KERN_INFO, vha, "VP entry id %d assigned.\n", vha->vp_idx);
+
+ /* initialized vport states */
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ vha->vp_err_state= VP_ERR_PORTDWN;
+ vha->vp_prev_err_state= VP_ERR_UNKWN;
+ /* Check if physical ha port is Up */
+ if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
+ atomic_read(&ha->loop_state) == LOOP_DEAD) {
+ /* Don't retry or attempt login of this virtual port */
+ DEBUG15(printk ("scsi(%ld): pport loop_state is not UP.\n",
+ vha->host_no));
+ atomic_set(&vha->loop_state, LOOP_DEAD);
+ if (!disable)
+ fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
+ }
+
+ if (scsi_add_host(vha->host, &fc_vport->dev)) {
+ DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n",
+ vha->host_no, vha->vp_idx));
+ goto vport_create_failed_2;
+ }
+
+ /* initialize attributes */
+ fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name);
+ fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name);
+ fc_host_supported_classes(vha->host) =
+ fc_host_supported_classes(ha->host);
+ fc_host_supported_speeds(vha->host) =
+ fc_host_supported_speeds(ha->host);
+
+ qla24xx_vport_disable(fc_vport, disable);
+
+ return 0;
+vport_create_failed_2:
+ qla24xx_disable_vp(vha);
+ qla24xx_deallocate_vp_id(vha);
+ kfree(vha->port_name);
+ kfree(vha->node_name);
+ scsi_host_put(vha->host);
+ return FC_VPORT_FAILED;
+}
+
+int
+qla24xx_vport_delete(struct fc_vport *fc_vport)
+{
+ scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *vha = fc_vport->dd_data;
+
+ qla24xx_disable_vp(vha);
+ qla24xx_deallocate_vp_id(vha);
+
+ down(&ha->vport_sem);
+ ha->cur_vport_count--;
+ clear_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
+ up(&ha->vport_sem);
+
+ kfree(vha->node_name);
+ kfree(vha->port_name);
+
+ if (vha->timer_active) {
+ qla2x00_vp_stop_timer(vha);
+ DEBUG15(printk ("scsi(%ld): timer for the vport[%d] = %p "
+ "has stopped\n",
+ vha->host_no, vha->vp_idx, vha));
+ }
+
+ fc_remove_host(vha->host);
+
+ scsi_remove_host(vha->host);
+
+ scsi_host_put(vha->host);
+
+ return 0;
+}
+
+int
+qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)
+{
+ scsi_qla_host_t *vha = fc_vport->dd_data;
+
+ if (disable)
+ qla24xx_disable_vp(vha);
+ else
+ qla24xx_enable_vp(vha);
+
+ return 0;
+}
+
struct fc_function_template qla2xxx_transport_functions = {
.show_host_node_name = 1,
@@ -1000,6 +1119,49 @@
.issue_fc_host_lip = qla2x00_issue_lip,
.get_fc_host_stats = qla2x00_get_fc_host_stats,
+
+ .vport_create = qla24xx_vport_create,
+ .vport_disable = qla24xx_vport_disable,
+ .vport_delete = qla24xx_vport_delete,
+};
+
+struct fc_function_template qla2xxx_transport_vport_functions = {
+
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+
+ .get_host_port_id = qla2x00_get_host_port_id,
+ .show_host_port_id = 1,
+ .get_host_speed = qla2x00_get_host_speed,
+ .show_host_speed = 1,
+ .get_host_port_type = qla2x00_get_host_port_type,
+ .show_host_port_type = 1,
+ .get_host_symbolic_name = qla2x00_get_host_symbolic_name,
+ .show_host_symbolic_name = 1,
+ .set_host_system_hostname = qla2x00_set_host_system_hostname,
+ .show_host_system_hostname = 1,
+ .get_host_fabric_name = qla2x00_get_host_fabric_name,
+ .show_host_fabric_name = 1,
+ .get_host_port_state = qla2x00_get_host_port_state,
+ .show_host_port_state = 1,
+
+ .dd_fcrport_size = sizeof(struct fc_port *),
+ .show_rport_supported_classes = 1,
+
+ .get_starget_node_name = qla2x00_get_starget_node_name,
+ .show_starget_node_name = 1,
+ .get_starget_port_name = qla2x00_get_starget_port_name,
+ .show_starget_port_name = 1,
+ .get_starget_port_id = qla2x00_get_starget_port_id,
+ .show_starget_port_id = 1,
+
+ .get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo,
+ .set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
+ .show_rport_dev_loss_tmo = 1,
+
+ .issue_fc_host_lip = qla2x00_issue_lip,
+ .get_fc_host_stats = qla2x00_get_fc_host_stats,
};
void
@@ -1008,4 +1170,6 @@
fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name);
fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name);
fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
+ fc_host_max_npiv_vports(ha->host) = MAX_NUM_VPORT_FABRIC;
+ fc_host_npiv_vports_inuse(ha->host) = ha->cur_vport_count;
}
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index f6ed696..996c47a 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -1411,9 +1411,9 @@
printk("0x%02x ", cmd->cmnd[i]);
}
printk("\n seg_cnt=%d, allowed=%d, retries=%d\n",
- cmd->use_sg, cmd->allowed, cmd->retries);
+ scsi_sg_count(cmd), cmd->allowed, cmd->retries);
printk(" request buffer=0x%p, request buffer len=0x%x\n",
- cmd->request_buffer, cmd->request_bufflen);
+ scsi_sglist(cmd), scsi_bufflen(cmd));
printk(" tag=%d, transfersize=0x%x\n",
cmd->tag, cmd->transfersize);
printk(" serial_number=%lx, SP=%p\n", cmd->serial_number, sp);
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 5b12278..49dffeb 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -21,6 +21,7 @@
/* #define QL_DEBUG_LEVEL_12 */ /* Output IP trace msgs */
/* #define QL_DEBUG_LEVEL_13 */ /* Output fdmi function trace msgs */
/* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */
+/* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */
/*
* Local Macro Definitions.
*/
@@ -30,7 +31,8 @@
defined(QL_DEBUG_LEVEL_7) || defined(QL_DEBUG_LEVEL_8) || \
defined(QL_DEBUG_LEVEL_9) || defined(QL_DEBUG_LEVEL_10) || \
defined(QL_DEBUG_LEVEL_11) || defined(QL_DEBUG_LEVEL_12) || \
- defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14)
+ defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14) || \
+ defined(QL_DEBUG_LEVEL_15)
#define QL_DEBUG_ROUTINES
#endif
@@ -125,6 +127,12 @@
#define DEBUG14(x) do {} while (0)
#endif
+#if defined(QL_DEBUG_LEVEL_15)
+#define DEBUG15(x) do {x;} while (0)
+#else
+#define DEBUG15(x) do {} while (0)
+#endif
+
/*
* Firmware Dump structure definition
*/
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index e8948b6..a1ca590 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1551,6 +1551,9 @@
unsigned long last_queue_full;
unsigned long last_ramp_up;
+
+ struct list_head vp_fcport;
+ uint16_t vp_idx;
} fc_port_t;
/*
@@ -1999,6 +2002,36 @@
};
#define GID_LIST_SIZE (sizeof(struct gid_list_info) * MAX_FIBRE_DEVICES)
+/* NPIV */
+typedef struct vport_info {
+ uint8_t port_name[WWN_SIZE];
+ uint8_t node_name[WWN_SIZE];
+ int vp_id;
+ uint16_t loop_id;
+ unsigned long host_no;
+ uint8_t port_id[3];
+ int loop_state;
+} vport_info_t;
+
+typedef struct vport_params {
+ uint8_t port_name[WWN_SIZE];
+ uint8_t node_name[WWN_SIZE];
+ uint32_t options;
+#define VP_OPTS_RETRY_ENABLE BIT_0
+#define VP_OPTS_VP_DISABLE BIT_1
+} vport_params_t;
+
+/* NPIV - return codes of VP create and modify */
+#define VP_RET_CODE_OK 0
+#define VP_RET_CODE_FATAL 1
+#define VP_RET_CODE_WRONG_ID 2
+#define VP_RET_CODE_WWPN 3
+#define VP_RET_CODE_RESOURCES 4
+#define VP_RET_CODE_NO_MEM 5
+#define VP_RET_CODE_NOT_FOUND 6
+
+#define to_qla_parent(x) (((x)->parent) ? (x)->parent : (x))
+
/*
* ISP operations
*/
@@ -2073,6 +2106,16 @@
uint16_t msix_entry;
};
+#define WATCH_INTERVAL 1 /* number of seconds */
+
+/* NPIV */
+#define MAX_MULTI_ID_LOOP 126
+#define MAX_MULTI_ID_FABRIC 64
+#define MAX_NUM_VPORT_LOOP (MAX_MULTI_ID_LOOP - 1)
+#define MAX_NUM_VPORT_FABRIC (MAX_MULTI_ID_FABRIC - 1)
+#define MAX_NUM_VHBA_LOOP (MAX_MULTI_ID_LOOP - 1)
+#define MAX_NUM_VHBA_FABRIC (MAX_MULTI_ID_FABRIC - 1)
+
/*
* Linux Host Adapter structure
*/
@@ -2108,6 +2151,8 @@
uint32_t msix_enabled :1;
uint32_t disable_serdes :1;
uint32_t gpsc_supported :1;
+ uint32_t vsan_enabled :1;
+ uint32_t npiv_supported :1;
} flags;
atomic_t loop_state;
@@ -2147,6 +2192,7 @@
#define BEACON_BLINK_NEEDED 25
#define REGISTER_FDMI_NEEDED 26
#define FCPORT_UPDATE_NEEDED 27
+#define VP_DPC_NEEDED 28 /* wake up for VP dpc handling */
uint32_t device_flags;
#define DFLG_LOCAL_DEVICES BIT_0
@@ -2237,6 +2283,11 @@
/* ISP configuration data. */
uint16_t loop_id; /* Host adapter loop id */
+ uint16_t switch_cap;
+#define FLOGI_SEQ_DEL BIT_8
+#define FLOGI_MID_SUPPORT BIT_10
+#define FLOGI_VSAN_SUPPORT BIT_12
+#define FLOGI_SP_SUPPORT BIT_13
uint16_t fb_rev;
port_id_t d_id; /* Host adapter port id */
@@ -2344,6 +2395,7 @@
#define MBX_UPDATE_FLASH_ACTIVE 3
struct semaphore mbx_cmd_sem; /* Serialialize mbx access */
+ struct semaphore vport_sem; /* Virtual port synchronization */
struct semaphore mbx_intr_sem; /* Used for completion notification */
uint32_t mbx_flags;
@@ -2428,6 +2480,37 @@
struct fc_host_statistics fc_host_stat;
struct qla_msix_entry msix_entries[QLA_MSIX_ENTRIES];
+
+ struct list_head vp_list; /* list of VP */
+ struct fc_vport *fc_vport; /* holds fc_vport * for each vport */
+ uint8_t vp_idx_map[16];
+ uint16_t num_vhosts; /* number of vports created */
+ uint16_t num_vsans; /* number of vsan created */
+ uint16_t vp_idx; /* vport ID */
+
+ struct scsi_qla_host *parent; /* holds pport */
+ unsigned long vp_flags;
+ struct list_head vp_fcports; /* list of fcports */
+#define VP_IDX_ACQUIRED 0 /* bit no 0 */
+#define VP_CREATE_NEEDED 1
+#define VP_BIND_NEEDED 2
+#define VP_DELETE_NEEDED 3
+#define VP_SCR_NEEDED 4 /* State Change Request registration */
+ atomic_t vp_state;
+#define VP_OFFLINE 0
+#define VP_ACTIVE 1
+#define VP_FAILED 2
+// #define VP_DISABLE 3
+ uint16_t vp_err_state;
+ uint16_t vp_prev_err_state;
+#define VP_ERR_UNKWN 0
+#define VP_ERR_PORTDWN 1
+#define VP_ERR_FAB_UNSUPPORTED 2
+#define VP_ERR_FAB_NORESOURCES 3
+#define VP_ERR_FAB_LOGOUT 4
+#define VP_ERR_ADAP_NORESOURCES 5
+ int max_npiv_vports; /* 63 or 125 per topoloty */
+ int cur_vport_count;
} scsi_qla_host_t;
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index a0a722c..63a11fe 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -69,6 +69,16 @@
uint8_t reserved_3[24];
};
+struct vp_database_24xx {
+ uint16_t vp_status;
+ uint8_t options;
+ uint8_t id;
+ uint8_t port_name[WWN_SIZE];
+ uint8_t node_name[WWN_SIZE];
+ uint16_t port_id_low;
+ uint16_t port_id_high;
+};
+
struct nvram_24xx {
/* NVRAM header. */
uint8_t id[4];
@@ -962,6 +972,25 @@
struct mid_db_entry_24xx entries[MAX_MID_VPS];
};
+ /*
+ * Virtual Fabric ID type definition.
+ */
+typedef struct vf_id {
+ uint16_t id : 12;
+ uint16_t priority : 4;
+} vf_id_t;
+
+/*
+ * Virtual Fabric HopCt type definition.
+ */
+typedef struct vf_hopct {
+ uint16_t reserved : 8;
+ uint16_t hopct : 8;
+} vf_hopct_t;
+
+/*
+ * Virtual Port Control IOCB
+ */
#define VP_CTRL_IOCB_TYPE 0x30 /* Vitual Port Control entry. */
struct vp_ctrl_entry_24xx {
uint8_t entry_type; /* Entry type. */
@@ -974,6 +1003,7 @@
uint16_t vp_idx_failed;
uint16_t comp_status; /* Completion status. */
+#define CS_VCE_IOCB_ERROR 0x01 /* Error processing IOCB */
#define CS_VCE_ACQ_ID_ERROR 0x02 /* Error while acquireing ID. */
#define CS_VCE_BUSY 0x05 /* Firmware not ready to accept cmd. */
@@ -982,24 +1012,34 @@
#define VCE_COMMAND_DISABLE_VPS 0x08 /* Disable VPs. */
#define VCE_COMMAND_DISABLE_VPS_REINIT 0x09 /* Disable VPs and reinit link. */
#define VCE_COMMAND_DISABLE_VPS_LOGO 0x0a /* Disable VPs and LOGO ports. */
+#define VCE_COMMAND_DISABLE_VPS_LOGO_ALL 0x0b /* Disable VPs and LOGO ports. */
uint16_t vp_count;
uint8_t vp_idx_map[16];
-
- uint8_t reserved_4[32];
+ uint16_t flags;
+ struct vf_id id;
+ uint16_t reserved_4;
+ struct vf_hopct hopct;
+ uint8_t reserved_5[8];
};
+/*
+ * Modify Virtual Port Configuration IOCB
+ */
#define VP_CONFIG_IOCB_TYPE 0x31 /* Vitual Port Config entry. */
struct vp_config_entry_24xx {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
- uint8_t sys_define; /* System defined. */
+ uint8_t handle_count;
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System handle. */
- uint16_t reserved_1;
+ uint16_t flags;
+#define CS_VF_BIND_VPORTS_TO_VF BIT_0
+#define CS_VF_SET_QOS_OF_VPORTS BIT_1
+#define CS_VF_SET_HOPS_OF_VPORTS BIT_2
uint16_t comp_status; /* Completion status. */
#define CS_VCT_STS_ERROR 0x01 /* Specified VPs were not disabled. */
@@ -1009,27 +1049,29 @@
#define CS_VCT_BUSY 0x05 /* Firmware not ready to accept cmd. */
uint8_t command;
-#define VCT_COMMAND_MOD_VPS 0x00 /* Enable VPs. */
-#define VCT_COMMAND_MOD_ENABLE_VPS 0x08 /* Disable VPs. */
+#define VCT_COMMAND_MOD_VPS 0x00 /* Modify VP configurations. */
+#define VCT_COMMAND_MOD_ENABLE_VPS 0x01 /* Modify configuration & enable VPs. */
uint8_t vp_count;
- uint8_t vp_idx1;
- uint8_t vp_idx2;
+ uint8_t vp_index1;
+ uint8_t vp_index2;
uint8_t options_idx1;
uint8_t hard_address_idx1;
- uint16_t reserved_2;
+ uint16_t reserved_vp1;
uint8_t port_name_idx1[WWN_SIZE];
uint8_t node_name_idx1[WWN_SIZE];
uint8_t options_idx2;
uint8_t hard_address_idx2;
- uint16_t reserved_3;
+ uint16_t reserved_vp2;
uint8_t port_name_idx2[WWN_SIZE];
uint8_t node_name_idx2[WWN_SIZE];
-
- uint8_t reserved_4[8];
+ struct vf_id id;
+ uint16_t reserved_4;
+ struct vf_hopct hopct;
+ uint8_t reserved_5;
};
#define VP_RPT_ID_IOCB_TYPE 0x32 /* Report ID Acquisition entry. */
@@ -1054,5 +1096,30 @@
uint8_t reserved_4[32];
};
+#define VF_EVFP_IOCB_TYPE 0x26 /* Exchange Virtual Fabric Parameters entry. */
+struct vf_evfp_entry_24xx {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint16_t comp_status; /* Completion status. */
+ uint16_t timeout; /* timeout */
+ uint16_t adim_tagging_mode;
+
+ uint16_t vfport_id;
+ uint32_t exch_addr;
+
+ uint16_t nport_handle; /* N_PORT handle. */
+ uint16_t control_flags;
+ uint32_t io_parameter_0;
+ uint32_t io_parameter_1;
+ uint32_t tx_address[2]; /* Data segment 0 address. */
+ uint32_t tx_len; /* Data segment 0 length. */
+ uint32_t rx_address[2]; /* Data segment 1 address. */
+ uint32_t rx_len; /* Data segment 1 length. */
+};
+
/* END MID Support ***********************************************************/
#endif
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 74544ae..b44eff2 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -62,6 +62,38 @@
extern int ql2xallocfwdump;
extern int ql2xextended_error_logging;
extern int ql2xqfullrampup;
+extern int num_hosts;
+
+/*
+ * Global Functions in qla_mid.c source file.
+ */
+extern struct scsi_host_template qla2x00_driver_template;
+extern struct scsi_host_template qla24xx_driver_template;
+extern struct scsi_transport_template *qla2xxx_transport_vport_template;
+extern uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+extern void qla2x00_timer(scsi_qla_host_t *);
+extern void qla2x00_start_timer(scsi_qla_host_t *, void *, unsigned long);
+extern void qla2x00_stop_timer(scsi_qla_host_t *);
+extern uint32_t qla24xx_allocate_vp_id(scsi_qla_host_t *);
+extern void qla24xx_deallocate_vp_id(scsi_qla_host_t *);
+extern int qla24xx_disable_vp (scsi_qla_host_t *);
+extern int qla24xx_enable_vp (scsi_qla_host_t *);
+extern void qla2x00_mem_free(scsi_qla_host_t *);
+extern int qla24xx_control_vp(scsi_qla_host_t *, int );
+extern int qla24xx_modify_vp_config(scsi_qla_host_t *);
+extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t, uint16_t);
+extern void qla2x00_vp_stop_timer(scsi_qla_host_t *);
+extern int qla24xx_configure_vhba (scsi_qla_host_t *);
+extern int qla24xx_get_vp_entry(scsi_qla_host_t *, uint16_t, int);
+extern int qla24xx_get_vp_database(scsi_qla_host_t *, uint16_t);
+extern int qla2x00_do_dpc_vp(scsi_qla_host_t *);
+extern void qla24xx_report_id_acquisition(scsi_qla_host_t *,
+ struct vp_rpt_id_entry_24xx *);
+extern scsi_qla_host_t * qla24xx_find_vhost_by_name(scsi_qla_host_t *,
+ uint8_t *);
+extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *);
+extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
+extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *);
extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
@@ -77,6 +109,10 @@
extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *);
extern void qla2xxx_wake_dpc(scsi_qla_host_t *);
+extern void qla2x00_alert_all_vps(scsi_qla_host_t *, uint16_t *);
+extern void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
+extern void qla2x00_vp_abort_isp(scsi_qla_host_t *);
+extern int qla24xx_vport_delete(struct fc_vport *);
/*
* Global Function Prototypes in qla_iocb.c source file.
@@ -128,7 +164,7 @@
extern int
qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *,
- uint8_t *, uint16_t *);
+ uint8_t *, uint16_t *, uint16_t *);
extern int
qla2x00_get_retry_cnt(scsi_qla_host_t *, uint8_t *, uint8_t *, uint16_t *);
@@ -303,6 +339,7 @@
extern struct class_device_attribute *qla2x00_host_attrs[];
struct fc_function_template;
extern struct fc_function_template qla2xxx_transport_functions;
+extern struct fc_function_template qla2xxx_transport_vport_functions;
extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
extern void qla2x00_init_host_attr(scsi_qla_host_t *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index ec5b2dd..a086b3f 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -88,6 +88,7 @@
ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+ ct_pkt->vp_index = ha->vp_idx;
return (ct_pkt);
}
@@ -1186,6 +1187,7 @@
ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+ ct_pkt->vp_index = ha->vp_idx;
return ct_pkt;
}
@@ -1746,6 +1748,7 @@
ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+ ct_pkt->vp_index = ha->vp_idx;
return ct_pkt;
}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index cf94f86..cc6ebb6 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -899,6 +899,10 @@
&ha->fw_subminor_version,
&ha->fw_attributes, &ha->fw_memory_size);
qla2x00_resize_request_q(ha);
+ ha->flags.npiv_supported = 0;
+ if (IS_QLA24XX(ha) &&
+ (ha->fw_attributes & BIT_2))
+ ha->flags.npiv_supported = 1;
if (ql2xallocfwdump)
qla2x00_alloc_fw_dump(ha);
@@ -1101,6 +1105,8 @@
int rval;
unsigned long flags = 0;
int cnt;
+ struct mid_init_cb_24xx *mid_init_cb =
+ (struct mid_init_cb_24xx *) ha->init_cb;
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1132,6 +1138,10 @@
ha->isp_ops.update_fw_options(ha);
DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
+
+ mid_init_cb->count = MAX_NUM_VPORT_FABRIC;
+ ha->max_npiv_vports = MAX_NUM_VPORT_FABRIC;
+
rval = qla2x00_init_firmware(ha, ha->init_cb_size);
if (rval) {
DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
@@ -1263,6 +1273,7 @@
int rval;
uint16_t loop_id;
uint16_t topo;
+ uint16_t sw_cap;
uint8_t al_pa;
uint8_t area;
uint8_t domain;
@@ -1270,7 +1281,7 @@
/* Get host addresses. */
rval = qla2x00_get_adapter_id(ha,
- &loop_id, &al_pa, &area, &domain, &topo);
+ &loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
if (rval != QLA_SUCCESS) {
if (LOOP_TRANSITION(ha) || atomic_read(&ha->loop_down_timer) ||
(rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
@@ -1295,6 +1306,7 @@
/* initialize */
ha->min_external_loopid = SNS_FIRST_LOOP_ID;
ha->operating_mode = LOOP;
+ ha->switch_cap = 0;
switch (topo) {
case 0:
@@ -1307,6 +1319,7 @@
case 1:
DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
ha->host_no));
+ ha->switch_cap = sw_cap;
ha->current_topology = ISP_CFG_FL;
strcpy(connect_type, "(FL_Port)");
break;
@@ -1322,6 +1335,7 @@
case 3:
DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
ha->host_no));
+ ha->switch_cap = sw_cap;
ha->operating_mode = P2P;
ha->current_topology = ISP_CFG_F;
strcpy(connect_type, "(F_Port)");
@@ -1743,7 +1757,6 @@
spin_unlock_irqrestore(&fcport->rport_lock, flags);
if (rport)
fc_remote_port_delete(rport);
-
}
/**
@@ -1765,6 +1778,7 @@
/* Setup fcport template structure. */
memset(fcport, 0, sizeof (fc_port_t));
fcport->ha = ha;
+ fcport->vp_idx = ha->vp_idx;
fcport->port_type = FCT_UNKNOWN;
fcport->loop_id = FC_NO_LOOP_ID;
atomic_set(&fcport->state, FCS_UNCONFIGURED);
@@ -1911,6 +1925,7 @@
char *id_iter;
uint16_t loop_id;
uint8_t domain, area, al_pa;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
found_devs = 0;
new_fcport = NULL;
@@ -1942,7 +1957,10 @@
/*
* Mark local devices that were present with FCF_DEVICE_LOST for now.
*/
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != ha->vp_idx)
+ continue;
+
if (atomic_read(&fcport->state) == FCS_ONLINE &&
fcport->port_type != FCT_BROADCAST &&
(fcport->flags & FCF_FABRIC_DEVICE) == 0) {
@@ -1988,6 +2006,7 @@
new_fcport->d_id.b.area = area;
new_fcport->d_id.b.al_pa = al_pa;
new_fcport->loop_id = loop_id;
+ new_fcport->vp_idx = ha->vp_idx;
rval2 = qla2x00_get_port_database(ha, new_fcport, 0);
if (rval2 != QLA_SUCCESS) {
DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
@@ -2003,7 +2022,10 @@
/* Check for matching device in port list. */
found = 0;
fcport = NULL;
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != ha->vp_idx)
+ continue;
+
if (memcmp(new_fcport->port_name, fcport->port_name,
WWN_SIZE))
continue;
@@ -2023,7 +2045,13 @@
if (!found) {
/* New device, add to fcports list. */
new_fcport->flags &= ~FCF_PERSISTENT_BOUND;
- list_add_tail(&new_fcport->list, &ha->fcports);
+ if (ha->parent) {
+ new_fcport->ha = ha;
+ new_fcport->vp_idx = ha->vp_idx;
+ list_add_tail(&new_fcport->vp_fcport,
+ &ha->vp_fcports);
+ }
+ list_add_tail(&new_fcport->list, &pha->fcports);
/* Allocate a new replacement fcport. */
fcport = new_fcport;
@@ -2199,11 +2227,13 @@
void
qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
{
+ scsi_qla_host_t *pha = to_qla_parent(ha);
+
fcport->ha = ha;
fcport->login_retry = 0;
- fcport->port_login_retry_count = ha->port_down_retry_count *
+ fcport->port_login_retry_count = pha->port_down_retry_count *
PORT_RETRY_TIME;
- atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
+ atomic_set(&fcport->port_down_timer, pha->port_down_retry_count *
PORT_RETRY_TIME);
fcport->flags &= ~FCF_LOGIN_NEEDED;
@@ -2234,6 +2264,7 @@
uint16_t mb[MAILBOX_REGISTER_COUNT];
uint16_t loop_id;
LIST_HEAD(new_fcports);
+ scsi_qla_host_t *pha = to_qla_parent(ha);
/* If FL port exists, then SNS is present */
if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
@@ -2307,7 +2338,10 @@
* Logout all previous fabric devices marked lost, except
* tape devices.
*/
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx !=ha->vp_idx)
+ continue;
+
if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
break;
@@ -2332,13 +2366,16 @@
}
/* Starting free loop ID. */
- next_loopid = ha->min_external_loopid;
+ next_loopid = pha->min_external_loopid;
/*
* Scan through our port list and login entries that need to be
* logged in.
*/
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != ha->vp_idx)
+ continue;
+
if (atomic_read(&ha->loop_down_timer) ||
test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
break;
@@ -2380,11 +2417,18 @@
break;
}
- /* Remove device from the new list and add it to DB */
- list_move_tail(&fcport->list, &ha->fcports);
-
/* Login and update database */
qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
+
+ if (ha->parent) {
+ fcport->ha = ha;
+ fcport->vp_idx = ha->vp_idx;
+ list_add_tail(&fcport->vp_fcport,
+ &ha->vp_fcports);
+ list_move_tail(&fcport->list,
+ &ha->parent->fcports);
+ } else
+ list_move_tail(&fcport->list, &ha->fcports);
}
} while (0);
@@ -2428,6 +2472,11 @@
int swl_idx;
int first_dev, last_dev;
port_id_t wrap, nxt_d_id;
+ int vp_index;
+ int empty_vp_index;
+ int found_vp;
+ scsi_qla_host_t *vha;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
rval = QLA_SUCCESS;
@@ -2461,13 +2510,13 @@
return (QLA_MEMORY_ALLOC_FAILED);
}
new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
-
+ new_fcport->vp_idx = ha->vp_idx;
/* Set start port ID scan at adapter ID. */
first_dev = 1;
last_dev = 0;
/* Starting free loop ID. */
- loop_id = ha->min_external_loopid;
+ loop_id = pha->min_external_loopid;
for (; loop_id <= ha->last_loop_id; loop_id++) {
if (qla2x00_is_reserved_id(ha, loop_id))
continue;
@@ -2521,10 +2570,42 @@
break;
}
- /* Bypass if host adapter. */
- if (new_fcport->d_id.b24 == ha->d_id.b24)
+ /* Bypass if same physical adapter. */
+ if (new_fcport->d_id.b24 == pha->d_id.b24)
continue;
+ /* Bypass virtual ports of the same host. */
+ if (pha->num_vhosts) {
+ vp_index = find_next_bit(
+ (unsigned long *)pha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, 1);
+
+ for (;vp_index <= MAX_MULTI_ID_FABRIC;
+ vp_index = find_next_bit(
+ (unsigned long *)pha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, vp_index + 1)) {
+ empty_vp_index = 1;
+ found_vp = 0;
+ list_for_each_entry(vha, &pha->vp_list,
+ vp_list) {
+ if (vp_index == vha->vp_idx) {
+ empty_vp_index = 0;
+ found_vp = 1;
+ break;
+ }
+ }
+
+ if (empty_vp_index)
+ continue;
+
+ if (found_vp &&
+ new_fcport->d_id.b24 == vha->d_id.b24)
+ break;
+ }
+ if (vp_index <= MAX_MULTI_ID_FABRIC)
+ continue;
+ }
+
/* Bypass if same domain and area of adapter. */
if (((new_fcport->d_id.b24 & 0xffff00) ==
(ha->d_id.b24 & 0xffff00)) && ha->current_topology ==
@@ -2537,7 +2618,9 @@
/* Locate matching device in database. */
found = 0;
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (new_fcport->vp_idx != fcport->vp_idx)
+ continue;
if (memcmp(new_fcport->port_name, fcport->port_name,
WWN_SIZE))
continue;
@@ -2605,6 +2688,7 @@
}
new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
new_fcport->d_id.b24 = nxt_d_id.b24;
+ new_fcport->vp_idx = ha->vp_idx;
}
kfree(swl);
@@ -2637,6 +2721,7 @@
int found;
fc_port_t *fcport;
uint16_t first_loop_id;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
rval = QLA_SUCCESS;
@@ -2663,7 +2748,7 @@
/* Check for loop ID being already in use. */
found = 0;
fcport = NULL;
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
if (fcport->loop_id == dev->loop_id && fcport != dev) {
/* ID possibly in use */
found++;
@@ -2710,6 +2795,7 @@
uint8_t rscn_out_iter;
uint8_t format;
port_id_t d_id;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
rval = QLA_RSCNS_HANDLED;
@@ -2776,7 +2862,10 @@
rval = QLA_SUCCESS;
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != ha->vp_idx)
+ continue;
+
if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
(fcport->d_id.b24 & mask) != d_id.b24 ||
fcport->port_type == FCT_BROADCAST)
@@ -3940,3 +4029,40 @@
ret = qla2x00_stop_firmware(ha);
}
}
+
+int
+qla24xx_configure_vhba(scsi_qla_host_t *ha)
+{
+ int rval = QLA_SUCCESS;
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+ if (!ha->parent)
+ return -EINVAL;
+
+ rval = qla2x00_fw_ready(ha);
+ if (rval == QLA_SUCCESS) {
+ clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+ qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
+ }
+
+ ha->flags.management_server_logged_in = 0;
+
+ /* Login to SNS first */
+ qla24xx_login_fabric(ha, NPH_SNS, 0xff, 0xff, 0xfc,
+ mb, BIT_1);
+ if (mb[0] != MBS_COMMAND_COMPLETE) {
+ DEBUG15(qla_printk(KERN_INFO, ha,
+ "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
+ "mb[2]=%x mb[6]=%x mb[7]=%x\n", NPH_SNS,
+ mb[0], mb[1], mb[2], mb[6], mb[7]));
+ return (QLA_FUNCTION_FAILED);
+ }
+
+ atomic_set(&ha->loop_down_timer, 0);
+ atomic_set(&ha->loop_state, LOOP_UP);
+ set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+ set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+ rval = qla2x00_loop_resync(ha);
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c5b3c61..c71863f 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -155,6 +155,8 @@
uint32_t *cur_dsd;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
+ struct scatterlist *sg;
+ int i;
cmd = sp->cmd;
@@ -163,7 +165,7 @@
__constant_cpu_to_le32(COMMAND_TYPE);
/* No data transfer */
- if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
+ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
cmd_pkt->byte_count = __constant_cpu_to_le32(0);
return;
}
@@ -177,35 +179,23 @@
cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
/* Load data segments */
- if (cmd->use_sg != 0) {
- struct scatterlist *cur_seg;
- struct scatterlist *end_seg;
+ scsi_for_each_sg(cmd, sg, tot_dsds, i) {
+ cont_entry_t *cont_pkt;
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- end_seg = cur_seg + tot_dsds;
- while (cur_seg < end_seg) {
- cont_entry_t *cont_pkt;
-
- /* Allocate additional continuation packets? */
- if (avail_dsds == 0) {
- /*
- * Seven DSDs are available in the Continuation
- * Type 0 IOCB.
- */
- cont_pkt = qla2x00_prep_cont_type0_iocb(ha);
- cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address;
- avail_dsds = 7;
- }
-
- *cur_dsd++ = cpu_to_le32(sg_dma_address(cur_seg));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
- avail_dsds--;
-
- cur_seg++;
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Seven DSDs are available in the Continuation
+ * Type 0 IOCB.
+ */
+ cont_pkt = qla2x00_prep_cont_type0_iocb(ha);
+ cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address;
+ avail_dsds = 7;
}
- } else {
- *cur_dsd++ = cpu_to_le32(sp->dma_handle);
- *cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
+
+ *cur_dsd++ = cpu_to_le32(sg_dma_address(sg));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
}
}
@@ -224,6 +214,8 @@
uint32_t *cur_dsd;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
+ struct scatterlist *sg;
+ int i;
cmd = sp->cmd;
@@ -232,7 +224,7 @@
__constant_cpu_to_le32(COMMAND_A64_TYPE);
/* No data transfer */
- if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
+ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
cmd_pkt->byte_count = __constant_cpu_to_le32(0);
return;
}
@@ -246,39 +238,26 @@
cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
/* Load data segments */
- if (cmd->use_sg != 0) {
- struct scatterlist *cur_seg;
- struct scatterlist *end_seg;
+ scsi_for_each_sg(cmd, sg, tot_dsds, i) {
+ dma_addr_t sle_dma;
+ cont_a64_entry_t *cont_pkt;
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- end_seg = cur_seg + tot_dsds;
- while (cur_seg < end_seg) {
- dma_addr_t sle_dma;
- cont_a64_entry_t *cont_pkt;
-
- /* Allocate additional continuation packets? */
- if (avail_dsds == 0) {
- /*
- * Five DSDs are available in the Continuation
- * Type 1 IOCB.
- */
- cont_pkt = qla2x00_prep_cont_type1_iocb(ha);
- cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
- avail_dsds = 5;
- }
-
- sle_dma = sg_dma_address(cur_seg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
- avail_dsds--;
-
- cur_seg++;
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Five DSDs are available in the Continuation
+ * Type 1 IOCB.
+ */
+ cont_pkt = qla2x00_prep_cont_type1_iocb(ha);
+ cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
+ avail_dsds = 5;
}
- } else {
- *cur_dsd++ = cpu_to_le32(LSD(sp->dma_handle));
- *cur_dsd++ = cpu_to_le32(MSD(sp->dma_handle));
- *cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
+
+ sle_dma = sg_dma_address(sg);
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
}
}
@@ -291,7 +270,7 @@
int
qla2x00_start_scsi(srb_t *sp)
{
- int ret;
+ int ret, nseg;
unsigned long flags;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
@@ -299,7 +278,6 @@
uint32_t index;
uint32_t handle;
cmd_entry_t *cmd_pkt;
- struct scatterlist *sg;
uint16_t cnt;
uint16_t req_cnt;
uint16_t tot_dsds;
@@ -337,23 +315,15 @@
goto queuing_error;
/* Map the sg table so we have an accurate count of sg entries needed */
- if (cmd->use_sg) {
- sg = (struct scatterlist *) cmd->request_buffer;
- tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
- if (tot_dsds == 0)
+ if (scsi_sg_count(cmd)) {
+ nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
+ scsi_sg_count(cmd), cmd->sc_data_direction);
+ if (unlikely(!nseg))
goto queuing_error;
- } else if (cmd->request_bufflen) {
- dma_addr_t req_dma;
+ } else
+ nseg = 0;
- req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
- cmd->request_bufflen, cmd->sc_data_direction);
- if (dma_mapping_error(req_dma))
- goto queuing_error;
-
- sp->dma_handle = req_dma;
- tot_dsds = 1;
- }
+ tot_dsds = nseg;
/* Calculate the number of request entries needed. */
req_cnt = ha->isp_ops.calc_req_entries(tot_dsds);
@@ -391,7 +361,7 @@
/* Load SCSI command packet. */
memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len);
- cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen);
+ cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
/* Build IOCB segments */
ha->isp_ops.build_iocbs(sp, cmd_pkt, tot_dsds);
@@ -423,14 +393,9 @@
return (QLA_SUCCESS);
queuing_error:
- if (cmd->use_sg && tot_dsds) {
- sg = (struct scatterlist *) cmd->request_buffer;
- pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
- } else if (tot_dsds) {
- pci_unmap_single(ha->pdev, sp->dma_handle,
- cmd->request_bufflen, cmd->sc_data_direction);
- }
+ if (tot_dsds)
+ scsi_dma_unmap(cmd);
+
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return (QLA_FUNCTION_FAILED);
@@ -453,9 +418,10 @@
{
mrk_entry_t *mrk;
struct mrk_entry_24xx *mrk24;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
mrk24 = NULL;
- mrk = (mrk_entry_t *)qla2x00_req_pkt(ha);
+ mrk = (mrk_entry_t *)qla2x00_req_pkt(pha);
if (mrk == NULL) {
DEBUG2_3(printk("%s(%ld): failed to allocate Marker IOCB.\n",
__func__, ha->host_no));
@@ -472,6 +438,7 @@
mrk24->lun[1] = LSB(lun);
mrk24->lun[2] = MSB(lun);
host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
+ mrk24->vp_index = ha->vp_idx;
} else {
SET_TARGET_ID(ha, mrk->target, loop_id);
mrk->lun = cpu_to_le16(lun);
@@ -479,7 +446,7 @@
}
wmb();
- qla2x00_isp_cmd(ha);
+ qla2x00_isp_cmd(pha);
return (QLA_SUCCESS);
}
@@ -642,6 +609,8 @@
uint32_t *cur_dsd;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
+ struct scatterlist *sg;
+ int i;
cmd = sp->cmd;
@@ -650,7 +619,7 @@
__constant_cpu_to_le32(COMMAND_TYPE_7);
/* No data transfer */
- if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
+ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
cmd_pkt->byte_count = __constant_cpu_to_le32(0);
return;
}
@@ -670,39 +639,27 @@
cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
/* Load data segments */
- if (cmd->use_sg != 0) {
- struct scatterlist *cur_seg;
- struct scatterlist *end_seg;
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- end_seg = cur_seg + tot_dsds;
- while (cur_seg < end_seg) {
- dma_addr_t sle_dma;
- cont_a64_entry_t *cont_pkt;
+ scsi_for_each_sg(cmd, sg, tot_dsds, i) {
+ dma_addr_t sle_dma;
+ cont_a64_entry_t *cont_pkt;
- /* Allocate additional continuation packets? */
- if (avail_dsds == 0) {
- /*
- * Five DSDs are available in the Continuation
- * Type 1 IOCB.
- */
- cont_pkt = qla2x00_prep_cont_type1_iocb(ha);
- cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
- avail_dsds = 5;
- }
-
- sle_dma = sg_dma_address(cur_seg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
- avail_dsds--;
-
- cur_seg++;
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Five DSDs are available in the Continuation
+ * Type 1 IOCB.
+ */
+ cont_pkt = qla2x00_prep_cont_type1_iocb(ha);
+ cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
+ avail_dsds = 5;
}
- } else {
- *cur_dsd++ = cpu_to_le32(LSD(sp->dma_handle));
- *cur_dsd++ = cpu_to_le32(MSD(sp->dma_handle));
- *cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
+
+ sle_dma = sg_dma_address(sg);
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
}
}
@@ -716,7 +673,7 @@
int
qla24xx_start_scsi(srb_t *sp)
{
- int ret;
+ int ret, nseg;
unsigned long flags;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
@@ -724,7 +681,6 @@
uint32_t index;
uint32_t handle;
struct cmd_type_7 *cmd_pkt;
- struct scatterlist *sg;
uint16_t cnt;
uint16_t req_cnt;
uint16_t tot_dsds;
@@ -762,23 +718,15 @@
goto queuing_error;
/* Map the sg table so we have an accurate count of sg entries needed */
- if (cmd->use_sg) {
- sg = (struct scatterlist *) cmd->request_buffer;
- tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
- if (tot_dsds == 0)
+ if (scsi_sg_count(cmd)) {
+ nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
+ scsi_sg_count(cmd), cmd->sc_data_direction);
+ if (unlikely(!nseg))
goto queuing_error;
- } else if (cmd->request_bufflen) {
- dma_addr_t req_dma;
+ } else
+ nseg = 0;
- req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
- cmd->request_bufflen, cmd->sc_data_direction);
- if (dma_mapping_error(req_dma))
- goto queuing_error;
-
- sp->dma_handle = req_dma;
- tot_dsds = 1;
- }
+ tot_dsds = nseg;
req_cnt = qla24xx_calc_iocbs(tot_dsds);
if (ha->req_q_cnt < (req_cnt + 2)) {
@@ -813,6 +761,7 @@
cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
+ cmd_pkt->vp_index = sp->fcport->vp_idx;
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
@@ -821,7 +770,7 @@
memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));
- cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen);
+ cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
/* Build IOCB segments */
qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds);
@@ -853,14 +802,9 @@
return QLA_SUCCESS;
queuing_error:
- if (cmd->use_sg && tot_dsds) {
- sg = (struct scatterlist *) cmd->request_buffer;
- pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
- } else if (tot_dsds) {
- pci_unmap_single(ha->pdev, sp->dma_handle,
- cmd->request_bufflen, cmd->sc_data_direction);
- }
+ if (tot_dsds)
+ scsi_dma_unmap(cmd);
+
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_FUNCTION_FAILED;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index ca46346..0ba4c8d 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -9,7 +9,6 @@
#include <scsi/scsi_tcq.h>
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
-static void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t);
static void qla2x00_status_entry(scsi_qla_host_t *, void *);
static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *);
@@ -244,7 +243,7 @@
* @ha: SCSI driver HA context
* @mb: Mailbox registers (0 - 3)
*/
-static void
+void
qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
{
#define LS_UNKNOWN 2
@@ -386,6 +385,11 @@
qla2x00_mark_all_devices_lost(ha, 1);
}
+ if (ha->parent) {
+ atomic_set(&ha->vp_state, VP_FAILED);
+ fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+ }
+
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
ha->flags.management_server_logged_in = 0;
@@ -422,6 +426,11 @@
qla2x00_mark_all_devices_lost(ha, 1);
}
+ if (ha->parent) {
+ atomic_set(&ha->vp_state, VP_FAILED);
+ fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+ }
+
ha->flags.management_server_logged_in = 0;
ha->link_data_rate = PORT_SPEED_UNKNOWN;
if (ql2xfdmienable)
@@ -440,6 +449,11 @@
qla2x00_mark_all_devices_lost(ha, 1);
}
+ if (ha->parent) {
+ atomic_set(&ha->vp_state, VP_FAILED);
+ fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+ }
+
set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
ha->operating_mode = LOOP;
@@ -465,6 +479,11 @@
qla2x00_mark_all_devices_lost(ha, 1);
}
+ if (ha->parent) {
+ atomic_set(&ha->vp_state, VP_FAILED);
+ fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+ }
+
if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) {
set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
}
@@ -491,6 +510,11 @@
qla2x00_mark_all_devices_lost(ha, 1);
}
+ if (ha->parent) {
+ atomic_set(&ha->vp_state, VP_FAILED);
+ fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+ }
+
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
break;
@@ -530,6 +554,10 @@
break;
case MBA_RSCN_UPDATE: /* State Change Registration */
+ /* Check if the Vport has issued a SCR */
+ if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags))
+ break;
+
DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
ha->host_no));
DEBUG(printk(KERN_INFO
@@ -589,6 +617,9 @@
ha->host_no, mb[1], mb[2]));
break;
}
+
+ if (!ha->parent && ha->num_vhosts)
+ qla2x00_alert_all_vps(ha, mb);
}
static void
@@ -889,19 +920,19 @@
}
if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
resid = resid_len;
- cp->resid = resid;
+ scsi_set_resid(cp, resid);
CMD_RESID_LEN(cp) = resid;
if (!lscsi_status &&
- ((unsigned)(cp->request_bufflen - resid) <
+ ((unsigned)(scsi_bufflen(cp) - resid) <
cp->underflow)) {
qla_printk(KERN_INFO, ha,
- "scsi(%ld:%d:%d:%d): Mid-layer underflow "
- "detected (%x of %x bytes)...returning "
- "error status.\n", ha->host_no,
- cp->device->channel, cp->device->id,
- cp->device->lun, resid,
- cp->request_bufflen);
+ "scsi(%ld:%d:%d:%d): Mid-layer underflow "
+ "detected (%x of %x bytes)...returning "
+ "error status.\n", ha->host_no,
+ cp->device->channel, cp->device->id,
+ cp->device->lun, resid,
+ scsi_bufflen(cp));
cp->result = DID_ERROR << 16;
break;
@@ -963,7 +994,7 @@
resid = fw_resid_len;
if (scsi_status & SS_RESIDUAL_UNDER) {
- cp->resid = resid;
+ scsi_set_resid(cp, resid);
CMD_RESID_LEN(cp) = resid;
} else {
DEBUG2(printk(KERN_INFO
@@ -1042,26 +1073,26 @@
*/
if (!(scsi_status & SS_RESIDUAL_UNDER)) {
DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
- "frame(s) detected (%x of %x bytes)..."
- "retrying command.\n", ha->host_no,
- cp->device->channel, cp->device->id,
- cp->device->lun, resid,
- cp->request_bufflen));
+ "frame(s) detected (%x of %x bytes)..."
+ "retrying command.\n", ha->host_no,
+ cp->device->channel, cp->device->id,
+ cp->device->lun, resid,
+ scsi_bufflen(cp)));
cp->result = DID_BUS_BUSY << 16;
break;
}
/* Handle mid-layer underflow */
- if ((unsigned)(cp->request_bufflen - resid) <
+ if ((unsigned)(scsi_bufflen(cp) - resid) <
cp->underflow) {
qla_printk(KERN_INFO, ha,
- "scsi(%ld:%d:%d:%d): Mid-layer underflow "
- "detected (%x of %x bytes)...returning "
- "error status.\n", ha->host_no,
- cp->device->channel, cp->device->id,
- cp->device->lun, resid,
- cp->request_bufflen);
+ "scsi(%ld:%d:%d:%d): Mid-layer underflow "
+ "detected (%x of %x bytes)...returning "
+ "error status.\n", ha->host_no,
+ cp->device->channel, cp->device->id,
+ cp->device->lun, resid,
+ scsi_bufflen(cp));
cp->result = DID_ERROR << 16;
break;
@@ -1084,7 +1115,7 @@
DEBUG2(printk(KERN_INFO
"PID=0x%lx req=0x%x xtra=0x%x -- returning DID_ERROR "
"status!\n",
- cp->serial_number, cp->request_bufflen, resid_len));
+ cp->serial_number, scsi_bufflen(cp), resid_len));
cp->result = DID_ERROR << 16;
break;
@@ -1393,6 +1424,10 @@
case MS_IOCB_TYPE:
qla24xx_ms_entry(ha, (struct ct_entry_24xx *)pkt);
break;
+ case VP_RPT_ID_IOCB_TYPE:
+ qla24xx_report_id_acquisition(ha,
+ (struct vp_rpt_id_entry_24xx *)pkt);
+ break;
default:
/* Type Not Supported. */
DEBUG4(printk(KERN_WARNING
@@ -1633,7 +1668,7 @@
uint16_t entry;
uint16_t index;
const char *name;
- irqreturn_t (*handler)(int, void *);
+ irq_handler_t handler;
};
static struct qla_init_msix_entry imsix_entries[QLA_MSIX_ENTRIES] = {
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 71e32a2..2cd0cff 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -42,25 +42,29 @@
* Kernel context.
*/
static int
-qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
+qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
{
int rval;
unsigned long flags = 0;
- device_reg_t __iomem *reg = ha->iobase;
+ device_reg_t __iomem *reg;
struct timer_list tmp_intr_timer;
uint8_t abort_active;
- uint8_t io_lock_on = ha->flags.init_done;
+ uint8_t io_lock_on;
uint16_t command;
uint16_t *iptr;
uint16_t __iomem *optr;
uint32_t cnt;
uint32_t mboxes;
unsigned long wait_time;
+ scsi_qla_host_t *ha = to_qla_parent(pvha);
+
+ reg = ha->iobase;
+ io_lock_on = ha->flags.init_done;
rval = QLA_SUCCESS;
abort_active = test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, pvha->host_no));
/*
* Wait for active mailbox commands to finish by waiting at most tov
@@ -889,7 +893,7 @@
*/
int
qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
- uint8_t *area, uint8_t *domain, uint16_t *top)
+ uint8_t *area, uint8_t *domain, uint16_t *top, uint16_t *sw_cap)
{
int rval;
mbx_cmd_t mc;
@@ -899,8 +903,9 @@
ha->host_no));
mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
+ mcp->mb[9] = ha->vp_idx;
mcp->out_mb = MBX_0;
- mcp->in_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
mcp->tov = 30;
mcp->flags = 0;
rval = qla2x00_mailbox_command(ha, mcp);
@@ -913,6 +918,7 @@
*area = MSB(mcp->mb[2]);
*domain = LSB(mcp->mb[3]);
*top = mcp->mb[6];
+ *sw_cap = mcp->mb[7];
if (rval != QLA_SUCCESS) {
/*EMPTY*/
@@ -1009,7 +1015,11 @@
DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
ha->host_no));
- mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
+ if (ha->flags.npiv_supported)
+ mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE;
+ else
+ mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
+
mcp->mb[2] = MSW(ha->init_cb_dma);
mcp->mb[3] = LSW(ha->init_cb_dma);
mcp->mb[4] = 0;
@@ -1081,7 +1091,8 @@
mcp->mb[3] = LSW(pd_dma);
mcp->mb[6] = MSW(MSD(pd_dma));
mcp->mb[7] = LSW(MSD(pd_dma));
- mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+ mcp->mb[9] = ha->vp_idx;
+ mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
mcp->in_mb = MBX_0;
if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
mcp->mb[1] = fcport->loop_id;
@@ -1259,7 +1270,8 @@
ha->host_no));
mcp->mb[0] = MBC_GET_PORT_NAME;
- mcp->out_mb = MBX_1|MBX_0;
+ mcp->mb[9] = ha->vp_idx;
+ mcp->out_mb = MBX_9|MBX_1|MBX_0;
if (HAS_EXTENDED_IDS(ha)) {
mcp->mb[1] = loop_id;
mcp->mb[10] = opt;
@@ -1447,6 +1459,7 @@
lg->port_id[0] = al_pa;
lg->port_id[1] = area;
lg->port_id[2] = domain;
+ lg->vp_index = cpu_to_le16(ha->vp_idx);
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB "
@@ -1701,6 +1714,7 @@
lg->port_id[0] = al_pa;
lg->port_id[1] = area;
lg->port_id[2] = domain;
+ lg->vp_index = cpu_to_le16(ha->vp_idx);
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB "
@@ -1863,7 +1877,8 @@
mcp->mb[6] = MSW(MSD(id_list_dma));
mcp->mb[7] = LSW(MSD(id_list_dma));
mcp->mb[8] = 0;
- mcp->out_mb |= MBX_8|MBX_7|MBX_6|MBX_3|MBX_2;
+ mcp->mb[9] = ha->vp_idx;
+ mcp->out_mb |= MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2;
} else {
mcp->mb[1] = MSW(id_list_dma);
mcp->mb[2] = LSW(id_list_dma);
@@ -2212,6 +2227,7 @@
abt->port_id[0] = fcport->d_id.b.al_pa;
abt->port_id[1] = fcport->d_id.b.area;
abt->port_id[2] = fcport->d_id.b.domain;
+ abt->vp_index = fcport->vp_idx;
rval = qla2x00_issue_iocb(ha, abt, abt_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue IOCB (%x).\n",
@@ -2249,7 +2265,7 @@
int rval;
struct tsk_mgmt_cmd *tsk;
dma_addr_t tsk_dma;
- scsi_qla_host_t *ha;
+ scsi_qla_host_t *ha, *pha;
if (fcport == NULL)
return 0;
@@ -2257,7 +2273,8 @@
DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no));
ha = fcport->ha;
- tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma);
+ pha = to_qla_parent(ha);
+ tsk = dma_pool_alloc(pha->s_dma_pool, GFP_KERNEL, &tsk_dma);
if (tsk == NULL) {
DEBUG2_3(printk("%s(%ld): failed to allocate Task Management "
"IOCB.\n", __func__, ha->host_no));
@@ -2273,6 +2290,8 @@
tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa;
tsk->p.tsk.port_id[1] = fcport->d_id.b.area;
tsk->p.tsk.port_id[2] = fcport->d_id.b.domain;
+ tsk->p.tsk.vp_index = fcport->vp_idx;
+
rval = qla2x00_issue_iocb(ha, tsk, tsk_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Target Reset IOCB "
@@ -2303,7 +2322,7 @@
}
atarget_done:
- dma_pool_free(ha->s_dma_pool, tsk, tsk_dma);
+ dma_pool_free(pha->s_dma_pool, tsk, tsk_dma);
return rval;
}
@@ -2610,3 +2629,354 @@
return rval;
}
+
+/*
+ * qla24xx_get_vp_database
+ * Get the VP's database for all configured ports.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * size = size of initialization control block.
+ *
+ * Returns:
+ * qla2x00 local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+int
+qla24xx_get_vp_database(scsi_qla_host_t *ha, uint16_t size)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ DEBUG11(printk("scsi(%ld):%s - entered.\n",
+ ha->host_no, __func__));
+
+ mcp->mb[0] = MBC_MID_GET_VP_DATABASE;
+ mcp->mb[2] = MSW(ha->init_cb_dma);
+ mcp->mb[3] = LSW(ha->init_cb_dma);
+ mcp->mb[4] = 0;
+ mcp->mb[5] = 0;
+ mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
+ mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
+ mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+ mcp->in_mb = MBX_1|MBX_0;
+ mcp->buf_size = size;
+ mcp->flags = MBX_DMA_OUT;
+ mcp->tov = MBX_TOV_SECONDS;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ DEBUG2_3_11(printk("%s(%ld): failed=%x "
+ "mb0=%x.\n",
+ __func__, ha->host_no, rval, mcp->mb[0]));
+ } else {
+ /*EMPTY*/
+ DEBUG11(printk("%s(%ld): done.\n",
+ __func__, ha->host_no));
+ }
+
+ return rval;
+}
+
+int
+qla24xx_get_vp_entry(scsi_qla_host_t *ha, uint16_t size, int vp_id)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ mcp->mb[0] = MBC_MID_GET_VP_ENTRY;
+ mcp->mb[2] = MSW(ha->init_cb_dma);
+ mcp->mb[3] = LSW(ha->init_cb_dma);
+ mcp->mb[4] = 0;
+ mcp->mb[5] = 0;
+ mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
+ mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
+ mcp->mb[9] = vp_id;
+ mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+ mcp->in_mb = MBX_0;
+ mcp->buf_size = size;
+ mcp->flags = MBX_DMA_OUT;
+ mcp->tov = 30;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ DEBUG2_3_11(printk("qla24xx_get_vp_entry(%ld): failed=%x "
+ "mb0=%x.\n",
+ ha->host_no, rval, mcp->mb[0]));
+ } else {
+ /*EMPTY*/
+ DEBUG11(printk("qla24xx_get_vp_entry(%ld): done.\n",
+ ha->host_no));
+ }
+
+ return rval;
+}
+
+void
+qla24xx_report_id_acquisition(scsi_qla_host_t *ha,
+ struct vp_rpt_id_entry_24xx *rptid_entry)
+{
+ uint8_t vp_idx;
+ scsi_qla_host_t *vha;
+
+ if (rptid_entry->entry_status != 0)
+ return;
+ if (rptid_entry->entry_status != __constant_cpu_to_le16(CS_COMPLETE))
+ return;
+
+ if (rptid_entry->format == 0) {
+ DEBUG15(printk("%s:format 0 : scsi(%ld) number of VPs setup %d,"
+ " number of VPs acquired %d\n", __func__, ha->host_no,
+ MSB(rptid_entry->vp_count), LSB(rptid_entry->vp_count)));
+ DEBUG15(printk("%s primary port id %02x%02x%02x\n", __func__,
+ rptid_entry->port_id[2], rptid_entry->port_id[1],
+ rptid_entry->port_id[0]));
+ } else if (rptid_entry->format == 1) {
+ vp_idx = LSB(rptid_entry->vp_idx);
+ DEBUG15(printk("%s:format 1: scsi(%ld): VP[%d] enabled "
+ "- status %d - "
+ "with port id %02x%02x%02x\n",__func__,ha->host_no,
+ vp_idx, MSB(rptid_entry->vp_idx),
+ rptid_entry->port_id[2], rptid_entry->port_id[1],
+ rptid_entry->port_id[0]));
+ if (vp_idx == 0)
+ return;
+
+ if (MSB(rptid_entry->vp_idx) == 1)
+ return;
+
+ list_for_each_entry(vha, &ha->vp_list, vp_list)
+ if (vp_idx == vha->vp_idx)
+ break;
+
+ if (!vha)
+ return;
+
+ vha->d_id.b.domain = rptid_entry->port_id[2];
+ vha->d_id.b.area = rptid_entry->port_id[1];
+ vha->d_id.b.al_pa = rptid_entry->port_id[0];
+
+ /*
+ * Cannot configure here as we are still sitting on the
+ * response queue. Handle it in dpc context.
+ */
+ set_bit(VP_IDX_ACQUIRED, &vha->vp_flags);
+ set_bit(VP_DPC_NEEDED, &ha->dpc_flags);
+
+ wake_up_process(ha->dpc_thread);
+ }
+}
+
+/*
+ * qla24xx_modify_vp_config
+ * Change VP configuration for vha
+ *
+ * Input:
+ * vha = adapter block pointer.
+ *
+ * Returns:
+ * qla2xxx local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+int
+qla24xx_modify_vp_config(scsi_qla_host_t *vha)
+{
+ int rval;
+ struct vp_config_entry_24xx *vpmod;
+ dma_addr_t vpmod_dma;
+ scsi_qla_host_t *pha;
+
+ /* This can be called by the parent */
+ pha = to_qla_parent(vha);
+
+ vpmod = dma_pool_alloc(pha->s_dma_pool, GFP_KERNEL, &vpmod_dma);
+ if (!vpmod) {
+ DEBUG2_3(printk("%s(%ld): failed to allocate Modify VP "
+ "IOCB.\n", __func__, pha->host_no));
+ return QLA_MEMORY_ALLOC_FAILED;
+ }
+
+ memset(vpmod, 0, sizeof(struct vp_config_entry_24xx));
+ vpmod->entry_type = VP_CONFIG_IOCB_TYPE;
+ vpmod->entry_count = 1;
+ vpmod->command = VCT_COMMAND_MOD_ENABLE_VPS;
+ vpmod->vp_count = 1;
+ vpmod->vp_index1 = vha->vp_idx;
+ vpmod->options_idx1 = BIT_3|BIT_4|BIT_5;
+ memcpy(vpmod->node_name_idx1, vha->node_name, WWN_SIZE);
+ memcpy(vpmod->port_name_idx1, vha->port_name, WWN_SIZE);
+ vpmod->entry_count = 1;
+
+ rval = qla2x00_issue_iocb(pha, vpmod, vpmod_dma, 0);
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed to issue VP config IOCB"
+ "(%x).\n", __func__, pha->host_no, rval));
+ } else if (vpmod->comp_status != 0) {
+ DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+ "-- error status (%x).\n", __func__, pha->host_no,
+ vpmod->comp_status));
+ rval = QLA_FUNCTION_FAILED;
+ } else if (vpmod->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
+ DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+ "-- completion status (%x).\n", __func__, pha->host_no,
+ le16_to_cpu(vpmod->comp_status)));
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ /* EMPTY */
+ DEBUG11(printk("%s(%ld): done.\n", __func__, pha->host_no));
+ fc_vport_set_state(vha->fc_vport, FC_VPORT_INITIALIZING);
+ }
+ dma_pool_free(pha->s_dma_pool, vpmod, vpmod_dma);
+
+ return rval;
+}
+
+/*
+ * qla24xx_control_vp
+ * Enable a virtual port for given host
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * vhba = virtual adapter (unused)
+ * index = index number for enabled VP
+ *
+ * Returns:
+ * qla2xxx local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+int
+qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
+{
+ int rval;
+ int map, pos;
+ struct vp_ctrl_entry_24xx *vce;
+ dma_addr_t vce_dma;
+ scsi_qla_host_t *ha = vha->parent;
+ int vp_index = vha->vp_idx;
+
+ DEBUG11(printk("%s(%ld): entered. Enabling index %d\n", __func__,
+ ha->host_no, vp_index));
+
+ if (vp_index == 0 || vp_index >= MAX_MULTI_ID_LOOP)
+ return QLA_PARAMETER_ERROR;
+
+ vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma);
+ if (!vce) {
+ DEBUG2_3(printk("%s(%ld): "
+ "failed to allocate VP Control IOCB.\n", __func__,
+ ha->host_no));
+ return QLA_MEMORY_ALLOC_FAILED;
+ }
+ memset(vce, 0, sizeof(struct vp_ctrl_entry_24xx));
+
+ vce->entry_type = VP_CTRL_IOCB_TYPE;
+ vce->entry_count = 1;
+ vce->command = cpu_to_le16(cmd);
+ vce->vp_count = __constant_cpu_to_le16(1);
+
+ /* index map in firmware starts with 1; decrement index
+ * this is ok as we never use index 0
+ */
+ map = (vp_index - 1) / 8;
+ pos = (vp_index - 1) & 7;
+ down(&ha->vport_sem);
+ vce->vp_idx_map[map] |= 1 << pos;
+ up(&ha->vport_sem);
+
+ rval = qla2x00_issue_iocb(ha, vce, vce_dma, 0);
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed to issue VP control IOCB"
+ "(%x).\n", __func__, ha->host_no, rval));
+ printk("%s(%ld): failed to issue VP control IOCB"
+ "(%x).\n", __func__, ha->host_no, rval);
+ } else if (vce->entry_status != 0) {
+ DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+ "-- error status (%x).\n", __func__, ha->host_no,
+ vce->entry_status));
+ printk("%s(%ld): failed to complete IOCB "
+ "-- error status (%x).\n", __func__, ha->host_no,
+ vce->entry_status);
+ rval = QLA_FUNCTION_FAILED;
+ } else if (vce->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
+ DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+ "-- completion status (%x).\n", __func__, ha->host_no,
+ le16_to_cpu(vce->comp_status)));
+ printk("%s(%ld): failed to complete IOCB "
+ "-- completion status (%x).\n", __func__, ha->host_no,
+ le16_to_cpu(vce->comp_status));
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ DEBUG2(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ }
+
+ dma_pool_free(ha->s_dma_pool, vce, vce_dma);
+
+ return rval;
+}
+
+/*
+ * qla2x00_send_change_request
+ * Receive or disable RSCN request from fabric controller
+ *
+ * Input:
+ * ha = adapter block pointer
+ * format = registration format:
+ * 0 - Reserved
+ * 1 - Fabric detected registration
+ * 2 - N_port detected registration
+ * 3 - Full registration
+ * FF - clear registration
+ * vp_idx = Virtual port index
+ *
+ * Returns:
+ * qla2x00 local function return status code.
+ *
+ * Context:
+ * Kernel Context
+ */
+
+int
+qla2x00_send_change_request(scsi_qla_host_t *ha, uint16_t format,
+ uint16_t vp_idx)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ /*
+ * This command is implicitly executed by firmware during login for the
+ * physical hosts
+ */
+ if (vp_idx == 0)
+ return QLA_FUNCTION_FAILED;
+
+ mcp->mb[0] = MBC_SEND_CHANGE_REQUEST;
+ mcp->mb[1] = format;
+ mcp->mb[9] = vp_idx;
+ mcp->out_mb = MBX_9|MBX_1|MBX_0;
+ mcp->in_mb = MBX_0|MBX_1;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval == QLA_SUCCESS) {
+ if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
+ rval = BIT_1;
+ }
+ } else
+ rval = BIT_1;
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
new file mode 100644
index 0000000..54dc415
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -0,0 +1,497 @@
+/*
+ * QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2005 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * 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.
+ *
+ */
+#include "qla_def.h"
+
+#include <linux/version.h>
+#include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include <linux/list.h>
+
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsicam.h>
+#include <linux/delay.h>
+
+void qla2x00_vp_stop_timer(scsi_qla_host_t *);
+
+void
+qla2x00_vp_stop_timer(scsi_qla_host_t *vha)
+{
+ if (vha->parent && vha->timer_active) {
+ del_timer_sync(&vha->timer);
+ vha->timer_active = 0;
+ }
+}
+
+uint32_t
+qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
+{
+ uint32_t vp_id;
+ scsi_qla_host_t *ha = vha->parent;
+
+ /* Find an empty slot and assign an vp_id */
+ down(&ha->vport_sem);
+ vp_id = find_first_zero_bit((unsigned long *)ha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC);
+ if (vp_id > MAX_MULTI_ID_FABRIC) {
+ DEBUG15(printk ("vp_id %d is bigger than MAX_MULTI_ID_FABRID\n",
+ vp_id));
+ up(&ha->vport_sem);
+ return vp_id;
+ }
+
+ set_bit(vp_id, (unsigned long *)ha->vp_idx_map);
+ ha->num_vhosts++;
+ vha->vp_idx = vp_id;
+ list_add_tail(&vha->vp_list, &ha->vp_list);
+ up(&ha->vport_sem);
+ return vp_id;
+}
+
+void
+qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
+{
+ uint16_t vp_id;
+ scsi_qla_host_t *ha = vha->parent;
+
+ down(&ha->vport_sem);
+ vp_id = vha->vp_idx;
+ ha->num_vhosts--;
+ clear_bit(vp_id, (unsigned long *)ha->vp_idx_map);
+ list_del(&vha->vp_list);
+ up(&ha->vport_sem);
+}
+
+scsi_qla_host_t *
+qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name)
+{
+ scsi_qla_host_t *vha;
+
+ /* Locate matching device in database. */
+ list_for_each_entry(vha, &ha->vp_list, vp_list) {
+ if (!memcmp(port_name, vha->port_name, WWN_SIZE))
+ return vha;
+ }
+ return NULL;
+}
+
+/*
+ * qla2x00_mark_vp_devices_dead
+ * Updates fcport state when device goes offline.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * fcport = port structure pointer.
+ *
+ * Return:
+ * None.
+ *
+ * Context:
+ */
+void
+qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
+{
+ fc_port_t *fcport;
+ scsi_qla_host_t *pha = to_qla_parent(vha);
+
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != vha->vp_idx)
+ continue;
+
+ DEBUG15(printk("scsi(%ld): Marking port dead, "
+ "loop_id=0x%04x :%x\n",
+ vha->host_no, fcport->loop_id, fcport->vp_idx));
+
+ atomic_set(&fcport->state, FCS_DEVICE_DEAD);
+ qla2x00_mark_device_lost(vha, fcport, 0, 0);
+ }
+}
+
+int
+qla24xx_disable_vp(scsi_qla_host_t *vha)
+{
+ int ret;
+
+ ret = qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL);
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+
+ /* Delete all vp's fcports from parent's list */
+ qla2x00_mark_vp_devices_dead(vha);
+ atomic_set(&vha->vp_state, VP_FAILED);
+ vha->flags.management_server_logged_in = 0;
+ if (ret == QLA_SUCCESS) {
+ fc_vport_set_state(vha->fc_vport, FC_VPORT_DISABLED);
+ } else {
+ fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
+ return -1;
+ }
+ return 0;
+}
+
+int
+qla24xx_enable_vp(scsi_qla_host_t *vha)
+{
+ int ret;
+ scsi_qla_host_t *ha = vha->parent;
+
+ /* Check if physical ha port is Up */
+ if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
+ atomic_read(&ha->loop_state) == LOOP_DEAD ) {
+ vha->vp_err_state = VP_ERR_PORTDWN;
+ fc_vport_set_state(vha->fc_vport, FC_VPORT_LINKDOWN);
+ goto enable_failed;
+ }
+
+ /* Initialize the new vport unless it is a persistent port */
+ down(&ha->vport_sem);
+ ret = qla24xx_modify_vp_config(vha);
+ up(&ha->vport_sem);
+
+ if (ret != QLA_SUCCESS) {
+ fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
+ goto enable_failed;
+ }
+
+ DEBUG15(qla_printk(KERN_INFO, ha,
+ "Virtual port with id: %d - Enabled\n", vha->vp_idx));
+ return 0;
+
+enable_failed:
+ DEBUG15(qla_printk(KERN_INFO, ha,
+ "Virtual port with id: %d - Disabled\n", vha->vp_idx));
+ return 1;
+}
+
+/**
+ * qla24xx_modify_vport() - Modifies the virtual fabric port's configuration
+ * @ha: HA context
+ * @vp: pointer to buffer of virtual port parameters.
+ * @ret_code: return error code:
+ *
+ * Returns the virtual port id, or MAX_VSAN_ID, if couldn't create.
+ */
+uint32_t
+qla24xx_modify_vhba(scsi_qla_host_t *ha, vport_params_t *vp, uint32_t *vp_id)
+{
+ scsi_qla_host_t *vha;
+
+ vha = qla24xx_find_vhost_by_name(ha, vp->port_name);
+ if (!vha) {
+ *vp_id = MAX_NUM_VPORT_LOOP;
+ return VP_RET_CODE_WWPN;
+ }
+
+ if (qla24xx_enable_vp(vha)) {
+ scsi_host_put(vha->host);
+ qla2x00_mem_free(vha);
+ *vp_id = MAX_NUM_VPORT_LOOP;
+ return VP_RET_CODE_RESOURCES;
+ }
+
+ *vp_id = vha->vp_idx;
+ return VP_RET_CODE_OK;
+}
+
+void
+qla24xx_configure_vp(scsi_qla_host_t *vha)
+{
+ struct fc_vport *fc_vport;
+ int ret;
+
+ fc_vport = vha->fc_vport;
+
+ DEBUG15(printk("scsi(%ld): %s: change request #3 for this host.\n",
+ vha->host_no, __func__));
+ ret = qla2x00_send_change_request(vha, 0x3, vha->vp_idx);
+ if (ret != QLA_SUCCESS) {
+ DEBUG15(qla_printk(KERN_ERR, vha, "Failed to enable receiving"
+ " of RSCN requests: 0x%x\n", ret));
+ return;
+ } else {
+ /* Corresponds to SCR enabled */
+ clear_bit(VP_SCR_NEEDED, &vha->vp_flags);
+ }
+
+ vha->flags.online = 1;
+ if (qla24xx_configure_vhba(vha))
+ return;
+
+ atomic_set(&vha->vp_state, VP_ACTIVE);
+ fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
+}
+
+void
+qla2x00_alert_all_vps(scsi_qla_host_t *ha, uint16_t *mb)
+{
+ int i, vp_idx_matched;
+ scsi_qla_host_t *vha;
+
+ if (ha->parent)
+ return;
+
+ i = find_next_bit((unsigned long *)ha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, 1);
+ for (;i <= MAX_MULTI_ID_FABRIC;
+ i = find_next_bit((unsigned long *)ha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, i + 1)) {
+ vp_idx_matched = 0;
+
+ list_for_each_entry(vha, &ha->vp_list, vp_list) {
+ if (i == vha->vp_idx) {
+ vp_idx_matched = 1;
+ break;
+ }
+ }
+
+ if (vp_idx_matched) {
+ switch (mb[0]) {
+ case MBA_LIP_OCCURRED:
+ case MBA_LOOP_UP:
+ case MBA_LOOP_DOWN:
+ case MBA_LIP_RESET:
+ case MBA_POINT_TO_POINT:
+ case MBA_CHG_IN_CONNECTION:
+ case MBA_PORT_UPDATE:
+ case MBA_RSCN_UPDATE:
+ DEBUG15(printk("scsi(%ld)%s: Async_event for"
+ " VP[%d], mb = 0x%x, vha=%p\n",
+ vha->host_no, __func__,i, *mb, vha));
+ qla2x00_async_event(vha, mb);
+ break;
+ }
+ }
+ }
+}
+
+void
+qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
+{
+ /*
+ * Physical port will do most of the abort and recovery work. We can
+ * just treat it as a loop down
+ */
+ if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ qla2x00_mark_all_devices_lost(vha, 0);
+ } else {
+ if (!atomic_read(&vha->loop_down_timer))
+ atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+ }
+
+ DEBUG15(printk("scsi(%ld): Scheduling enable of Vport %d...\n",
+ vha->host_no, vha->vp_idx));
+ qla24xx_enable_vp(vha);
+}
+
+int
+qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
+{
+ if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
+ /* VP acquired. complete port configuration */
+ qla24xx_configure_vp(vha);
+ return 0;
+ }
+
+ if (test_and_clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
+ qla2x00_vp_abort_isp(vha);
+
+ if (test_and_clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) &&
+ (!(test_and_set_bit(RESET_ACTIVE, &vha->dpc_flags)))) {
+ clear_bit(RESET_ACTIVE, &vha->dpc_flags);
+ }
+
+ if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
+ if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) {
+ qla2x00_loop_resync(vha);
+ clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags);
+ }
+ }
+
+ return 0;
+}
+
+void
+qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha)
+{
+ int ret;
+ int i, vp_idx_matched;
+ scsi_qla_host_t *vha;
+
+ if (ha->parent)
+ return;
+ if (list_empty(&ha->vp_list))
+ return;
+
+ clear_bit(VP_DPC_NEEDED, &ha->dpc_flags);
+
+ i = find_next_bit((unsigned long *)ha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, 1);
+ for (;i <= MAX_MULTI_ID_FABRIC;
+ i = find_next_bit((unsigned long *)ha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, i + 1)) {
+ vp_idx_matched = 0;
+
+ list_for_each_entry(vha, &ha->vp_list, vp_list) {
+ if (i == vha->vp_idx) {
+ vp_idx_matched = 1;
+ break;
+ }
+ }
+
+ if (vp_idx_matched)
+ ret = qla2x00_do_dpc_vp(vha);
+ }
+}
+
+int
+qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
+{
+ scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *vha;
+ uint8_t port_name[WWN_SIZE];
+
+ if (fc_vport->roles != FC_PORT_ROLE_FCP_INITIATOR)
+ return VPCERR_UNSUPPORTED;
+
+ /* Check up the F/W and H/W support NPIV */
+ if (!ha->flags.npiv_supported)
+ return VPCERR_UNSUPPORTED;
+
+ /* Check up whether npiv supported switch presented */
+ if (!(ha->switch_cap & FLOGI_MID_SUPPORT))
+ return VPCERR_NO_FABRIC_SUPP;
+
+ /* Check up unique WWPN */
+ u64_to_wwn(fc_vport->port_name, port_name);
+ vha = qla24xx_find_vhost_by_name(ha, port_name);
+ if (vha)
+ return VPCERR_BAD_WWN;
+
+ /* Check up max-npiv-supports */
+ if (ha->num_vhosts > ha->max_npiv_vports) {
+ DEBUG15(printk("scsi(%ld): num_vhosts %d is bigger than "
+ "max_npv_vports %d.\n", ha->host_no,
+ (uint16_t) ha->num_vhosts, (int) ha->max_npiv_vports));
+ return VPCERR_UNSUPPORTED;
+ }
+ return 0;
+}
+
+scsi_qla_host_t *
+qla24xx_create_vhost(struct fc_vport *fc_vport)
+{
+ scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *vha;
+ struct Scsi_Host *host;
+
+ host = scsi_host_alloc(&qla24xx_driver_template,
+ sizeof(scsi_qla_host_t));
+ if (!host) {
+ printk(KERN_WARNING
+ "qla2xxx: scsi_host_alloc() failed for vport\n");
+ return(NULL);
+ }
+
+ vha = (scsi_qla_host_t *)host->hostdata;
+
+ /* clone the parent hba */
+ memcpy(vha, ha, sizeof (scsi_qla_host_t));
+
+ fc_vport->dd_data = vha;
+
+ vha->node_name = kmalloc(WWN_SIZE * sizeof(char), GFP_KERNEL);
+ if (!vha->node_name)
+ goto create_vhost_failed_1;
+
+ vha->port_name = kmalloc(WWN_SIZE * sizeof(char), GFP_KERNEL);
+ if (!vha->port_name)
+ goto create_vhost_failed_2;
+
+ /* New host info */
+ u64_to_wwn(fc_vport->node_name, vha->node_name);
+ u64_to_wwn(fc_vport->port_name, vha->port_name);
+
+ vha->host = host;
+ vha->host_no = host->host_no;
+ vha->parent = ha;
+ vha->fc_vport = fc_vport;
+ vha->device_flags = 0;
+ vha->instance = num_hosts;
+ vha->vp_idx = qla24xx_allocate_vp_id(vha);
+ if (vha->vp_idx > ha->max_npiv_vports) {
+ DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n",
+ vha->host_no));
+ goto create_vhost_failed_3;
+ }
+ vha->mgmt_svr_loop_id = 10 + vha->vp_idx;
+
+ init_MUTEX(&vha->mbx_cmd_sem);
+ init_MUTEX_LOCKED(&vha->mbx_intr_sem);
+
+ INIT_LIST_HEAD(&vha->list);
+ INIT_LIST_HEAD(&vha->fcports);
+ INIT_LIST_HEAD(&vha->vp_fcports);
+
+ vha->dpc_flags = 0L;
+ set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
+ set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
+
+ /*
+ * To fix the issue of processing a parent's RSCN for the vport before
+ * its SCR is complete.
+ */
+ set_bit(VP_SCR_NEEDED, &vha->vp_flags);
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+
+ qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL);
+
+ host->can_queue = vha->request_q_length + 128;
+ host->this_id = 255;
+ host->cmd_per_lun = 3;
+ host->max_cmd_len = MAX_CMDSZ;
+ host->max_channel = MAX_BUSES - 1;
+ host->max_lun = MAX_LUNS;
+ host->unique_id = vha->instance;
+ host->max_id = MAX_TARGETS_2200;
+ host->transportt = qla2xxx_transport_vport_template;
+
+ DEBUG15(printk("DEBUG: detect vport hba %ld at address = %p\n",
+ vha->host_no, vha));
+
+ vha->flags.init_done = 1;
+ num_hosts++;
+
+ down(&ha->vport_sem);
+ set_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
+ ha->cur_vport_count++;
+ up(&ha->vport_sem);
+
+ return vha;
+
+create_vhost_failed_3:
+ kfree(vha->port_name);
+
+create_vhost_failed_2:
+ kfree(vha->node_name);
+
+create_vhost_failed_1:
+ return NULL;
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index b98136a..b5a77b0 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -29,8 +29,7 @@
/*
* Ioctl related information.
*/
-static int num_hosts;
-
+int num_hosts;
int ql2xlogintimeout = 20;
module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xlogintimeout,
@@ -112,7 +111,7 @@
static int qla2x00_change_queue_depth(struct scsi_device *, int);
static int qla2x00_change_queue_type(struct scsi_device *, int);
-static struct scsi_host_template qla2x00_driver_template = {
+struct scsi_host_template qla2x00_driver_template = {
.module = THIS_MODULE,
.name = QLA2XXX_DRIVER_NAME,
.queuecommand = qla2x00_queuecommand,
@@ -143,7 +142,7 @@
.shost_attrs = qla2x00_host_attrs,
};
-static struct scsi_host_template qla24xx_driver_template = {
+struct scsi_host_template qla24xx_driver_template = {
.module = THIS_MODULE,
.name = QLA2XXX_DRIVER_NAME,
.queuecommand = qla24xx_queuecommand,
@@ -171,21 +170,21 @@
};
static struct scsi_transport_template *qla2xxx_transport_template = NULL;
+struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
/* TODO Convert to inlines
*
* Timer routines
*/
-#define WATCH_INTERVAL 1 /* number of seconds */
-static void qla2x00_timer(scsi_qla_host_t *);
+void qla2x00_timer(scsi_qla_host_t *);
-static __inline__ void qla2x00_start_timer(scsi_qla_host_t *,
+__inline__ void qla2x00_start_timer(scsi_qla_host_t *,
void *, unsigned long);
static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);
-static __inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
+__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
-static inline void
+__inline__ void
qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
{
init_timer(&ha->timer);
@@ -202,7 +201,7 @@
mod_timer(&ha->timer, jiffies + interval * HZ);
}
-static __inline__ void
+__inline__ void
qla2x00_stop_timer(scsi_qla_host_t *ha)
{
del_timer_sync(&ha->timer);
@@ -213,8 +212,8 @@
static void qla2x00_rst_aen(scsi_qla_host_t *);
-static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
-static void qla2x00_mem_free(scsi_qla_host_t *ha);
+uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+void qla2x00_mem_free(scsi_qla_host_t *ha);
static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
@@ -438,6 +437,7 @@
struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
srb_t *sp;
int rval;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
rval = fc_remote_port_chkready(rport);
if (rval) {
@@ -453,7 +453,7 @@
if (atomic_read(&fcport->state) != FCS_ONLINE) {
if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
- atomic_read(&ha->loop_state) == LOOP_DEAD) {
+ atomic_read(&pha->loop_state) == LOOP_DEAD) {
cmd->result = DID_NO_CONNECT << 16;
goto qc24_fail_command;
}
@@ -462,7 +462,7 @@
spin_unlock_irq(ha->host->host_lock);
- sp = qla2x00_get_new_sp(ha, fcport, cmd, done);
+ sp = qla2x00_get_new_sp(pha, fcport, cmd, done);
if (!sp)
goto qc24_host_busy_lock;
@@ -475,8 +475,8 @@
return 0;
qc24_host_busy_free_sp:
- qla2x00_sp_free_dma(ha, sp);
- mempool_free(sp, ha->srb_mempool);
+ qla2x00_sp_free_dma(pha, sp);
+ mempool_free(sp, pha->srb_mempool);
qc24_host_busy_lock:
spin_lock_irq(ha->host->host_lock);
@@ -548,16 +548,17 @@
{
int return_status;
unsigned long wait_online;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);
- while (((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) ||
- test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
- test_bit(ISP_ABORT_RETRY, &ha->dpc_flags) ||
- ha->dpc_active) && time_before(jiffies, wait_online)) {
+ while (((test_bit(ISP_ABORT_NEEDED, &pha->dpc_flags)) ||
+ test_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags) ||
+ test_bit(ISP_ABORT_RETRY, &pha->dpc_flags) ||
+ pha->dpc_active) && time_before(jiffies, wait_online)) {
msleep(1000);
}
- if (ha->flags.online)
+ if (pha->flags.online)
return_status = QLA_SUCCESS;
else
return_status = QLA_FUNCTION_FAILED;
@@ -588,14 +589,15 @@
{
int return_status = QLA_SUCCESS;
unsigned long loop_timeout ;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
/* wait for 5 min at the max for loop to be ready */
loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ);
- while ((!atomic_read(&ha->loop_down_timer) &&
- atomic_read(&ha->loop_state) == LOOP_DOWN) ||
- atomic_read(&ha->loop_state) != LOOP_READY) {
- if (atomic_read(&ha->loop_state) == LOOP_DEAD) {
+ while ((!atomic_read(&pha->loop_down_timer) &&
+ atomic_read(&pha->loop_state) == LOOP_DOWN) ||
+ atomic_read(&pha->loop_state) != LOOP_READY) {
+ if (atomic_read(&pha->loop_state) == LOOP_DEAD) {
return_status = QLA_FUNCTION_FAILED;
break;
}
@@ -650,6 +652,7 @@
unsigned long serial;
unsigned long flags;
int wait = 0;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
qla2x00_block_error_handler(cmd);
@@ -663,9 +666,9 @@
serial = cmd->serial_number;
/* Check active list for command command. */
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&pha->hardware_lock, flags);
for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
- sp = ha->outstanding_cmds[i];
+ sp = pha->outstanding_cmds[i];
if (sp == NULL)
continue;
@@ -677,7 +680,7 @@
__func__, ha->host_no, sp, serial));
DEBUG3(qla2x00_print_scsi_cmd(cmd));
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
if (ha->isp_ops.abort_command(ha, sp)) {
DEBUG2(printk("%s(%ld): abort_command "
"mbx failed.\n", __func__, ha->host_no));
@@ -686,11 +689,11 @@
"mbx success.\n", __func__, ha->host_no));
wait = 1;
}
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&pha->hardware_lock, flags);
break;
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
/* Wait for the command to be returned. */
if (wait) {
@@ -731,6 +734,7 @@
srb_t *sp;
struct scsi_cmnd *cmd;
unsigned long flags;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
status = 0;
@@ -739,19 +743,20 @@
* array
*/
for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
- spin_lock_irqsave(&ha->hardware_lock, flags);
- sp = ha->outstanding_cmds[cnt];
+ spin_lock_irqsave(&pha->hardware_lock, flags);
+ sp = pha->outstanding_cmds[cnt];
if (sp) {
cmd = sp->cmd;
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (cmd->device->id == t) {
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
+ if (cmd->device->id == t &&
+ ha->vp_idx == sp->ha->vp_idx) {
if (!qla2x00_eh_wait_on_command(ha, cmd)) {
status = 1;
break;
}
}
} else {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
}
}
return (status);
@@ -782,14 +787,12 @@
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- int ret;
+ int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
qla2x00_block_error_handler(cmd);
- ret = FAILED;
-
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
@@ -912,15 +915,14 @@
qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *pha = to_qla_parent(ha);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- int ret;
+ int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
qla2x00_block_error_handler(cmd);
- ret = FAILED;
-
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
@@ -944,7 +946,7 @@
goto eh_bus_reset_done;
/* Flush outstanding commands. */
- if (!qla2x00_eh_wait_for_pending_commands(ha))
+ if (!qla2x00_eh_wait_for_pending_commands(pha))
ret = FAILED;
eh_bus_reset_done:
@@ -974,14 +976,13 @@
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- int ret;
+ int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
qla2x00_block_error_handler(cmd);
- ret = FAILED;
-
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
@@ -1004,21 +1005,24 @@
* while dpc is stuck for the mailbox to complete.
*/
qla2x00_wait_for_loop_ready(ha);
- set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
- if (qla2x00_abort_isp(ha)) {
- clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+ set_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
+ if (qla2x00_abort_isp(pha)) {
+ clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
/* failed. schedule dpc to try */
- set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+ set_bit(ISP_ABORT_NEEDED, &pha->dpc_flags);
if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
goto eh_host_reset_lock;
}
- clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+ clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
/* Waiting for our command in done_queue to be returned to OS.*/
- if (qla2x00_eh_wait_for_pending_commands(ha))
+ if (qla2x00_eh_wait_for_pending_commands(pha))
ret = SUCCESS;
+ if (ha->parent)
+ qla2x00_vp_abort_isp(ha);
+
eh_host_reset_lock:
qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
(ret == FAILED) ? "failed" : "succeded");
@@ -1435,6 +1439,7 @@
ha->host = host;
ha->host_no = host->host_no;
sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no);
+ ha->parent = NULL;
/* Set ISP-type information. */
qla2x00_set_isp_flags(ha);
@@ -1452,7 +1457,7 @@
ha->prev_topology = 0;
ha->init_cb_size = sizeof(init_cb_t);
- ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
+ ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx;
ha->link_data_rate = PORT_SPEED_UNKNOWN;
ha->optrom_size = OPTROM_SIZE_2300;
@@ -1524,8 +1529,8 @@
ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
- ha->init_cb_size = sizeof(struct init_cb_24xx);
- ha->mgmt_svr_loop_id = 10;
+ ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
+ ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
ha->isp_ops.pci_config = qla24xx_pci_config;
ha->isp_ops.reset_chip = qla24xx_reset_chip;
ha->isp_ops.chip_diag = qla24xx_chip_diag;
@@ -1563,10 +1568,14 @@
ha->instance = num_hosts;
init_MUTEX(&ha->mbx_cmd_sem);
+ init_MUTEX(&ha->vport_sem);
init_MUTEX_LOCKED(&ha->mbx_intr_sem);
INIT_LIST_HEAD(&ha->list);
INIT_LIST_HEAD(&ha->fcports);
+ INIT_LIST_HEAD(&ha->vp_list);
+
+ set_bit(0, (unsigned long *) ha->vp_idx_map);
qla2x00_config_dma_addressing(ha);
if (qla2x00_mem_alloc(ha)) {
@@ -1789,7 +1798,8 @@
void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
int do_login, int defer)
{
- if (atomic_read(&fcport->state) == FCS_ONLINE)
+ if (atomic_read(&fcport->state) == FCS_ONLINE &&
+ ha->vp_idx == fcport->vp_idx)
qla2x00_schedule_rport_del(ha, fcport, defer);
/*
@@ -1840,19 +1850,23 @@
qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
{
fc_port_t *fcport;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
- list_for_each_entry(fcport, &ha->fcports, list) {
- if (fcport->port_type != FCT_TARGET)
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx)
continue;
-
/*
* No point in marking the device as lost, if the device is
* already DEAD.
*/
if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
continue;
- if (atomic_read(&fcport->state) == FCS_ONLINE)
- qla2x00_schedule_rport_del(ha, fcport, defer);
+ if (atomic_read(&fcport->state) == FCS_ONLINE) {
+ if (defer)
+ qla2x00_schedule_rport_del(ha, fcport, defer);
+ else if (ha->vp_idx == fcport->vp_idx)
+ qla2x00_schedule_rport_del(ha, fcport, defer);
+ }
atomic_set(&fcport->state, FCS_DEVICE_LOST);
}
@@ -1868,7 +1882,7 @@
* 0 = success.
* 1 = failure.
*/
-static uint8_t
+uint8_t
qla2x00_mem_alloc(scsi_qla_host_t *ha)
{
char name[16];
@@ -1920,6 +1934,20 @@
continue;
}
+ /* get consistent memory allocated for init control block */
+ ha->init_cb = dma_alloc_coherent(&ha->pdev->dev,
+ ha->init_cb_size, &ha->init_cb_dma, GFP_KERNEL);
+ if (ha->init_cb == NULL) {
+ qla_printk(KERN_WARNING, ha,
+ "Memory Allocation failed - init_cb\n");
+
+ qla2x00_mem_free(ha);
+ msleep(100);
+
+ continue;
+ }
+ memset(ha->init_cb, 0, ha->init_cb_size);
+
snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
ha->host_no);
ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
@@ -1934,20 +1962,6 @@
continue;
}
- /* get consistent memory allocated for init control block */
- ha->init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
- &ha->init_cb_dma);
- if (ha->init_cb == NULL) {
- qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - init_cb\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
- memset(ha->init_cb, 0, ha->init_cb_size);
-
if (qla2x00_allocate_sp_pool(ha)) {
qla_printk(KERN_WARNING, ha,
"Memory Allocation failed - "
@@ -2052,7 +2066,7 @@
* Input:
* ha = adapter block pointer.
*/
-static void
+void
qla2x00_mem_free(scsi_qla_host_t *ha)
{
struct list_head *fcpl, *fcptemp;
@@ -2088,12 +2102,13 @@
if (ha->ms_iocb)
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
- if (ha->init_cb)
- dma_pool_free(ha->s_dma_pool, ha->init_cb, ha->init_cb_dma);
-
if (ha->s_dma_pool)
dma_pool_destroy(ha->s_dma_pool);
+ if (ha->init_cb)
+ dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
+ ha->init_cb, ha->init_cb_dma);
+
if (ha->gid_list)
dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
ha->gid_list_dma);
@@ -2199,6 +2214,7 @@
static int
qla2x00_do_dpc(void *data)
{
+ int rval;
scsi_qla_host_t *ha;
fc_port_t *fcport;
uint8_t status;
@@ -2347,7 +2363,7 @@
if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE,
&ha->dpc_flags))) {
- qla2x00_loop_resync(ha);
+ rval = qla2x00_loop_resync(ha);
clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags);
}
@@ -2374,6 +2390,8 @@
if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags))
ha->isp_ops.beacon_blink(ha);
+ qla2x00_do_dpc_all_vps(ha);
+
ha->dpc_active = 0;
} /* End of while(1) */
@@ -2426,13 +2444,7 @@
struct scsi_cmnd *cmd = sp->cmd;
if (sp->flags & SRB_DMA_VALID) {
- if (cmd->use_sg) {
- dma_unmap_sg(&ha->pdev->dev, cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- } else if (cmd->request_bufflen) {
- dma_unmap_single(&ha->pdev->dev, sp->dma_handle,
- cmd->request_bufflen, cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
sp->flags &= ~SRB_DMA_VALID;
}
CMD_SP(cmd) = NULL;
@@ -2458,7 +2470,7 @@
*
* Context: Interrupt
***************************************************************************/
-static void
+void
qla2x00_timer(scsi_qla_host_t *ha)
{
unsigned long cpu_flags = 0;
@@ -2467,6 +2479,7 @@
int index;
srb_t *sp;
int t;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
/*
* Ports - Port down timer.
@@ -2512,23 +2525,29 @@
atomic_set(&ha->loop_state, LOOP_DEAD);
/* Schedule an ISP abort to return any tape commands. */
- spin_lock_irqsave(&ha->hardware_lock, cpu_flags);
- for (index = 1; index < MAX_OUTSTANDING_COMMANDS;
- index++) {
- fc_port_t *sfcp;
+ /* NPIV - scan physical port only */
+ if (!ha->parent) {
+ spin_lock_irqsave(&ha->hardware_lock,
+ cpu_flags);
+ for (index = 1;
+ index < MAX_OUTSTANDING_COMMANDS;
+ index++) {
+ fc_port_t *sfcp;
- sp = ha->outstanding_cmds[index];
- if (!sp)
- continue;
- sfcp = sp->fcport;
- if (!(sfcp->flags & FCF_TAPE_PRESENT))
- continue;
+ sp = ha->outstanding_cmds[index];
+ if (!sp)
+ continue;
+ sfcp = sp->fcport;
+ if (!(sfcp->flags & FCF_TAPE_PRESENT))
+ continue;
- set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
- break;
+ set_bit(ISP_ABORT_NEEDED,
+ &ha->dpc_flags);
+ break;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock,
+ cpu_flags);
}
- spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags);
-
set_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags);
start_dpc++;
}
@@ -2572,8 +2591,9 @@
test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) ||
test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) ||
+ test_bit(VP_DPC_NEEDED, &ha->dpc_flags) ||
test_bit(RELOGIN_NEEDED, &ha->dpc_flags)))
- qla2xxx_wake_dpc(ha);
+ qla2xxx_wake_dpc(pha);
qla2x00_restart_timer(ha, WATCH_INTERVAL);
}
@@ -2717,14 +2737,24 @@
qla2xxx_transport_template =
fc_attach_transport(&qla2xxx_transport_functions);
- if (!qla2xxx_transport_template)
+ if (!qla2xxx_transport_template) {
+ kmem_cache_destroy(srb_cachep);
return -ENODEV;
+ }
+ qla2xxx_transport_vport_template =
+ fc_attach_transport(&qla2xxx_transport_vport_functions);
+ if (!qla2xxx_transport_vport_template) {
+ kmem_cache_destroy(srb_cachep);
+ fc_release_transport(qla2xxx_transport_template);
+ return -ENODEV;
+ }
printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n");
ret = pci_register_driver(&qla2xxx_pci_driver);
if (ret) {
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
+ fc_release_transport(qla2xxx_transport_vport_template);
}
return ret;
}
@@ -2739,6 +2769,7 @@
qla2x00_release_firmware();
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
+ fc_release_transport(qla2xxx_transport_vport_template);
}
module_init(qla2x00_module_init);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index c375a4e..fd2f10a 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.01.07-k7"
+#define QLA2XXX_VERSION "8.02.00-k1"
#define QLA_DRIVER_MAJOR_VER 8
-#define QLA_DRIVER_MINOR_VER 1
-#define QLA_DRIVER_PATCH_VER 7
+#define QLA_DRIVER_MINOR_VER 2
+#define QLA_DRIVER_PATCH_VER 0
#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
index 6437d024..fcc184c 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.c
+++ b/drivers/scsi/qla4xxx/ql4_dbg.c
@@ -6,176 +6,9 @@
*/
#include "ql4_def.h"
-#include <scsi/scsi_dbg.h>
-
-#if 0
-
-static void qla4xxx_print_srb_info(struct srb * srb)
-{
- printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags);
- printk("%s: cmd = 0x%p, saved_dma_handle = 0x%lx\n",
- __func__, srb->cmd, (unsigned long) srb->dma_handle);
- printk("%s: fw_ddb_index = %d, lun = %d\n",
- __func__, srb->fw_ddb_index, srb->cmd->device->lun);
- printk("%s: iocb_tov = %d\n",
- __func__, srb->iocb_tov);
- printk("%s: cc_stat = 0x%x, r_start = 0x%lx, u_start = 0x%lx\n\n",
- __func__, srb->cc_stat, srb->r_start, srb->u_start);
-}
-
-void qla4xxx_print_scsi_cmd(struct scsi_cmnd *cmd)
-{
- printk("SCSI Command = 0x%p, Handle=0x%p\n", cmd, cmd->host_scribble);
- printk(" b=%d, t=%02xh, l=%02xh, cmd_len = %02xh\n",
- cmd->device->channel, cmd->device->id, cmd->device->lun,
- cmd->cmd_len);
- scsi_print_command(cmd);
- printk(" seg_cnt = %d\n", cmd->use_sg);
- printk(" request buffer = 0x%p, request buffer len = 0x%x\n",
- cmd->request_buffer, cmd->request_bufflen);
- if (cmd->use_sg) {
- struct scatterlist *sg;
- sg = (struct scatterlist *)cmd->request_buffer;
- printk(" SG buffer: \n");
- qla4xxx_dump_buffer((caddr_t) sg,
- (cmd->use_sg * sizeof(*sg)));
- }
- printk(" tag = %d, transfersize = 0x%x \n", cmd->tag,
- cmd->transfersize);
- printk(" Pid = %d, SP = 0x%p\n", (int)cmd->pid, cmd->SCp.ptr);
- printk(" underflow size = 0x%x, direction=0x%x\n", cmd->underflow,
- cmd->sc_data_direction);
- printk(" Current time (jiffies) = 0x%lx, "
- "timeout expires = 0x%lx\n", jiffies, cmd->eh_timeout.expires);
- qla4xxx_print_srb_info((struct srb *) cmd->SCp.ptr);
-}
-
-void __dump_registers(struct scsi_qla_host *ha)
-{
- uint8_t i;
- for (i = 0; i < MBOX_REG_COUNT; i++) {
- printk(KERN_INFO "0x%02X mailbox[%d] = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, mailbox[i]), i,
- readw(&ha->reg->mailbox[i]));
- }
- printk(KERN_INFO "0x%02X flash_address = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, flash_address),
- readw(&ha->reg->flash_address));
- printk(KERN_INFO "0x%02X flash_data = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, flash_data),
- readw(&ha->reg->flash_data));
- printk(KERN_INFO "0x%02X ctrl_status = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, ctrl_status),
- readw(&ha->reg->ctrl_status));
- if (is_qla4010(ha)) {
- printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram),
- readw(&ha->reg->u1.isp4010.nvram));
- }
-
- else if (is_qla4022(ha) | is_qla4032(ha)) {
- printk(KERN_INFO "0x%02X intr_mask = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u1.isp4022.intr_mask),
- readw(&ha->reg->u1.isp4022.intr_mask));
- printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram),
- readw(&ha->reg->u1.isp4022.nvram));
- printk(KERN_INFO "0x%02X semaphore = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u1.isp4022.semaphore),
- readw(&ha->reg->u1.isp4022.semaphore));
- }
- printk(KERN_INFO "0x%02X req_q_in = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, req_q_in),
- readw(&ha->reg->req_q_in));
- printk(KERN_INFO "0x%02X rsp_q_out = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, rsp_q_out),
- readw(&ha->reg->rsp_q_out));
- if (is_qla4010(ha)) {
- printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4010.ext_hw_conf),
- readw(&ha->reg->u2.isp4010.ext_hw_conf));
- printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4010.port_ctrl),
- readw(&ha->reg->u2.isp4010.port_ctrl));
- printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4010.port_status),
- readw(&ha->reg->u2.isp4010.port_status));
- printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4010.req_q_out),
- readw(&ha->reg->u2.isp4010.req_q_out));
- printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out),
- readw(&ha->reg->u2.isp4010.gp_out));
- printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in),
- readw(&ha->reg->u2.isp4010.gp_in));
- printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4010.port_err_status),
- readw(&ha->reg->u2.isp4010.port_err_status));
- }
-
- else if (is_qla4022(ha) | is_qla4032(ha)) {
- printk(KERN_INFO "Page 0 Registers:\n");
- printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4022.p0.ext_hw_conf),
- readw(&ha->reg->u2.isp4022.p0.ext_hw_conf));
- printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4022.p0.port_ctrl),
- readw(&ha->reg->u2.isp4022.p0.port_ctrl));
- printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4022.p0.port_status),
- readw(&ha->reg->u2.isp4022.p0.port_status));
- printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4022.p0.gp_out),
- readw(&ha->reg->u2.isp4022.p0.gp_out));
- printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in),
- readw(&ha->reg->u2.isp4022.p0.gp_in));
- printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4022.p0.port_err_status),
- readw(&ha->reg->u2.isp4022.p0.port_err_status));
- printk(KERN_INFO "Page 1 Registers:\n");
- writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
- &ha->reg->ctrl_status);
- printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4022.p1.req_q_out),
- readw(&ha->reg->u2.isp4022.p1.req_q_out));
- writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
- &ha->reg->ctrl_status);
- }
-}
-
-void qla4xxx_dump_mbox_registers(struct scsi_qla_host *ha)
-{
- unsigned long flags = 0;
- int i = 0;
- spin_lock_irqsave(&ha->hardware_lock, flags);
- for (i = 1; i < MBOX_REG_COUNT; i++)
- printk(KERN_INFO " Mailbox[%d] = %08x\n", i,
- readw(&ha->reg->mailbox[i]));
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-void qla4xxx_dump_registers(struct scsi_qla_host *ha)
-{
- unsigned long flags = 0;
- spin_lock_irqsave(&ha->hardware_lock, flags);
- __dump_registers(ha);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
void qla4xxx_dump_buffer(void *b, uint32_t size)
{
@@ -198,4 +31,3 @@
printk(KERN_DEBUG "\n");
}
-#endif /* 0 */
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 6f4cf2d..accaf690 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -122,8 +122,7 @@
#define ISCSI_IPADDR_SIZE 4 /* IP address size */
#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alais name size */
-#define ISCSI_NAME_SIZE 255 /* ISCSI Name size -
- * usually a string */
+#define ISCSI_NAME_SIZE 0xE0 /* ISCSI Name size */
#define LSDW(x) ((u32)((u64)(x)))
#define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16))
@@ -187,9 +186,21 @@
u_long u_start; /* Time when we handed the cmd to F/W */
};
- /*
- * Device Database (DDB) structure
- */
+/*
+ * Asynchronous Event Queue structure
+ */
+struct aen {
+ uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
+};
+
+struct ql4_aen_log {
+ int count;
+ struct aen entry[MAX_AEN_ENTRIES];
+};
+
+/*
+ * Device Database (DDB) structure
+ */
struct ddb_entry {
struct list_head list; /* ddb list */
struct scsi_qla_host *ha;
@@ -254,13 +265,6 @@
#define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */
#define DF_FO_MASKED 3
-/*
- * Asynchronous Event Queue structure
- */
-struct aen {
- uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
-};
-
#include "ql4_fw.h"
#include "ql4_nvram.h"
@@ -270,31 +274,31 @@
*/
struct scsi_qla_host {
/* Linux adapter configuration data */
- struct Scsi_Host *host; /* pointer to host data */
- uint32_t tot_ddbs;
unsigned long flags;
-#define AF_ONLINE 0 /* 0x00000001 */
-#define AF_INIT_DONE 1 /* 0x00000002 */
-#define AF_MBOX_COMMAND 2 /* 0x00000004 */
-#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */
-#define AF_INTERRUPTS_ON 6 /* 0x00000040 Not Used */
-#define AF_GET_CRASH_RECORD 7 /* 0x00000080 */
-#define AF_LINK_UP 8 /* 0x00000100 */
-#define AF_IRQ_ATTACHED 10 /* 0x00000400 */
-#define AF_ISNS_CMD_IN_PROCESS 12 /* 0x00001000 */
-#define AF_ISNS_CMD_DONE 13 /* 0x00002000 */
+#define AF_ONLINE 0 /* 0x00000001 */
+#define AF_INIT_DONE 1 /* 0x00000002 */
+#define AF_MBOX_COMMAND 2 /* 0x00000004 */
+#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */
+#define AF_INTERRUPTS_ON 6 /* 0x00000040 */
+#define AF_GET_CRASH_RECORD 7 /* 0x00000080 */
+#define AF_LINK_UP 8 /* 0x00000100 */
+#define AF_IRQ_ATTACHED 10 /* 0x00000400 */
+#define AF_DISABLE_ACB_COMPLETE 11 /* 0x00000800 */
unsigned long dpc_flags;
-#define DPC_RESET_HA 1 /* 0x00000002 */
-#define DPC_RETRY_RESET_HA 2 /* 0x00000004 */
-#define DPC_RELOGIN_DEVICE 3 /* 0x00000008 */
-#define DPC_RESET_HA_DESTROY_DDB_LIST 4 /* 0x00000010 */
-#define DPC_RESET_HA_INTR 5 /* 0x00000020 */
-#define DPC_ISNS_RESTART 7 /* 0x00000080 */
-#define DPC_AEN 9 /* 0x00000200 */
-#define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */
+#define DPC_RESET_HA 1 /* 0x00000002 */
+#define DPC_RETRY_RESET_HA 2 /* 0x00000004 */
+#define DPC_RELOGIN_DEVICE 3 /* 0x00000008 */
+#define DPC_RESET_HA_DESTROY_DDB_LIST 4 /* 0x00000010 */
+#define DPC_RESET_HA_INTR 5 /* 0x00000020 */
+#define DPC_ISNS_RESTART 7 /* 0x00000080 */
+#define DPC_AEN 9 /* 0x00000200 */
+#define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */
+
+ struct Scsi_Host *host; /* pointer to host data */
+ uint32_t tot_ddbs;
uint16_t iocb_cnt;
uint16_t iocb_hiwat;
@@ -344,6 +348,7 @@
uint32_t firmware_version[2];
uint32_t patch_number;
uint32_t build_number;
+ uint32_t board_id;
/* --- From Init_FW --- */
/* init_cb_t *init_cb; */
@@ -363,7 +368,6 @@
/* --- From GetFwState --- */
uint32_t firmware_state;
- uint32_t board_id;
uint32_t addl_fw_state;
/* Linux kernel thread */
@@ -414,6 +418,8 @@
uint16_t aen_out;
struct aen aen_q[MAX_AEN_ENTRIES];
+ struct ql4_aen_log aen_log;/* tracks all aens */
+
/* This mutex protects several threads to do mailbox commands
* concurrently.
*/
@@ -585,10 +591,4 @@
#define FLUSH_DDB_CHANGED_AENS 1
#define RELOGIN_DDB_CHANGED_AENS 2
-#include "ql4_version.h"
-#include "ql4_glbl.h"
-#include "ql4_dbg.h"
-#include "ql4_inline.h"
-
-
#endif /*_QLA4XXX_H */
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 4eea8c5..9bb3d1d 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -20,143 +20,23 @@
*************************************************************************/
struct port_ctrl_stat_regs {
- __le32 ext_hw_conf; /* 80 x50 R/W */
- __le32 intChipConfiguration; /* 84 x54 */
- __le32 port_ctrl; /* 88 x58 */
- __le32 port_status; /* 92 x5c */
- __le32 HostPrimMACHi; /* 96 x60 */
- __le32 HostPrimMACLow; /* 100 x64 */
- __le32 HostSecMACHi; /* 104 x68 */
- __le32 HostSecMACLow; /* 108 x6c */
- __le32 EPPrimMACHi; /* 112 x70 */
- __le32 EPPrimMACLow; /* 116 x74 */
- __le32 EPSecMACHi; /* 120 x78 */
- __le32 EPSecMACLow; /* 124 x7c */
- __le32 HostPrimIPHi; /* 128 x80 */
- __le32 HostPrimIPMidHi; /* 132 x84 */
- __le32 HostPrimIPMidLow; /* 136 x88 */
- __le32 HostPrimIPLow; /* 140 x8c */
- __le32 HostSecIPHi; /* 144 x90 */
- __le32 HostSecIPMidHi; /* 148 x94 */
- __le32 HostSecIPMidLow; /* 152 x98 */
- __le32 HostSecIPLow; /* 156 x9c */
- __le32 EPPrimIPHi; /* 160 xa0 */
- __le32 EPPrimIPMidHi; /* 164 xa4 */
- __le32 EPPrimIPMidLow; /* 168 xa8 */
- __le32 EPPrimIPLow; /* 172 xac */
- __le32 EPSecIPHi; /* 176 xb0 */
- __le32 EPSecIPMidHi; /* 180 xb4 */
- __le32 EPSecIPMidLow; /* 184 xb8 */
- __le32 EPSecIPLow; /* 188 xbc */
- __le32 IPReassemblyTimeout; /* 192 xc0 */
- __le32 EthMaxFramePayload; /* 196 xc4 */
- __le32 TCPMaxWindowSize; /* 200 xc8 */
- __le32 TCPCurrentTimestampHi; /* 204 xcc */
- __le32 TCPCurrentTimestampLow; /* 208 xd0 */
- __le32 LocalRAMAddress; /* 212 xd4 */
- __le32 LocalRAMData; /* 216 xd8 */
- __le32 PCSReserved1; /* 220 xdc */
- __le32 gp_out; /* 224 xe0 */
- __le32 gp_in; /* 228 xe4 */
- __le32 ProbeMuxAddr; /* 232 xe8 */
- __le32 ProbeMuxData; /* 236 xec */
- __le32 ERMQueueBaseAddr0; /* 240 xf0 */
- __le32 ERMQueueBaseAddr1; /* 244 xf4 */
- __le32 MACConfiguration; /* 248 xf8 */
- __le32 port_err_status; /* 252 xfc COR */
+ __le32 ext_hw_conf; /* 0x50 R/W */
+ __le32 rsrvd0; /* 0x54 */
+ __le32 port_ctrl; /* 0x58 */
+ __le32 port_status; /* 0x5c */
+ __le32 rsrvd1[32]; /* 0x60-0xdf */
+ __le32 gp_out; /* 0xe0 */
+ __le32 gp_in; /* 0xe4 */
+ __le32 rsrvd2[5]; /* 0xe8-0xfb */
+ __le32 port_err_status; /* 0xfc */
};
struct host_mem_cfg_regs {
- __le32 NetRequestQueueOut; /* 80 x50 */
- __le32 NetRequestQueueOutAddrHi; /* 84 x54 */
- __le32 NetRequestQueueOutAddrLow; /* 88 x58 */
- __le32 NetRequestQueueBaseAddrHi; /* 92 x5c */
- __le32 NetRequestQueueBaseAddrLow; /* 96 x60 */
- __le32 NetRequestQueueLength; /* 100 x64 */
- __le32 NetResponseQueueIn; /* 104 x68 */
- __le32 NetResponseQueueInAddrHi; /* 108 x6c */
- __le32 NetResponseQueueInAddrLow; /* 112 x70 */
- __le32 NetResponseQueueBaseAddrHi; /* 116 x74 */
- __le32 NetResponseQueueBaseAddrLow; /* 120 x78 */
- __le32 NetResponseQueueLength; /* 124 x7c */
- __le32 req_q_out; /* 128 x80 */
- __le32 RequestQueueOutAddrHi; /* 132 x84 */
- __le32 RequestQueueOutAddrLow; /* 136 x88 */
- __le32 RequestQueueBaseAddrHi; /* 140 x8c */
- __le32 RequestQueueBaseAddrLow; /* 144 x90 */
- __le32 RequestQueueLength; /* 148 x94 */
- __le32 ResponseQueueIn; /* 152 x98 */
- __le32 ResponseQueueInAddrHi; /* 156 x9c */
- __le32 ResponseQueueInAddrLow; /* 160 xa0 */
- __le32 ResponseQueueBaseAddrHi; /* 164 xa4 */
- __le32 ResponseQueueBaseAddrLow; /* 168 xa8 */
- __le32 ResponseQueueLength; /* 172 xac */
- __le32 NetRxLargeBufferQueueOut; /* 176 xb0 */
- __le32 NetRxLargeBufferQueueBaseAddrHi; /* 180 xb4 */
- __le32 NetRxLargeBufferQueueBaseAddrLow; /* 184 xb8 */
- __le32 NetRxLargeBufferQueueLength; /* 188 xbc */
- __le32 NetRxLargeBufferLength; /* 192 xc0 */
- __le32 NetRxSmallBufferQueueOut; /* 196 xc4 */
- __le32 NetRxSmallBufferQueueBaseAddrHi; /* 200 xc8 */
- __le32 NetRxSmallBufferQueueBaseAddrLow; /* 204 xcc */
- __le32 NetRxSmallBufferQueueLength; /* 208 xd0 */
- __le32 NetRxSmallBufferLength; /* 212 xd4 */
- __le32 HMCReserved0[10]; /* 216 xd8 */
+ __le32 rsrvd0[12]; /* 0x50-0x79 */
+ __le32 req_q_out; /* 0x80 */
+ __le32 rsrvd1[31]; /* 0x84-0xFF */
};
-struct local_ram_cfg_regs {
- __le32 BufletSize; /* 80 x50 */
- __le32 BufletMaxCount; /* 84 x54 */
- __le32 BufletCurrCount; /* 88 x58 */
- __le32 BufletPauseThresholdCount; /* 92 x5c */
- __le32 BufletTCPWinThresholdHi; /* 96 x60 */
- __le32 BufletTCPWinThresholdLow; /* 100 x64 */
- __le32 IPHashTableBaseAddr; /* 104 x68 */
- __le32 IPHashTableSize; /* 108 x6c */
- __le32 TCPHashTableBaseAddr; /* 112 x70 */
- __le32 TCPHashTableSize; /* 116 x74 */
- __le32 NCBAreaBaseAddr; /* 120 x78 */
- __le32 NCBMaxCount; /* 124 x7c */
- __le32 NCBCurrCount; /* 128 x80 */
- __le32 DRBAreaBaseAddr; /* 132 x84 */
- __le32 DRBMaxCount; /* 136 x88 */
- __le32 DRBCurrCount; /* 140 x8c */
- __le32 LRCReserved[28]; /* 144 x90 */
-};
-
-struct prot_stat_regs {
- __le32 MACTxFrameCount; /* 80 x50 R */
- __le32 MACTxByteCount; /* 84 x54 R */
- __le32 MACRxFrameCount; /* 88 x58 R */
- __le32 MACRxByteCount; /* 92 x5c R */
- __le32 MACCRCErrCount; /* 96 x60 R */
- __le32 MACEncErrCount; /* 100 x64 R */
- __le32 MACRxLengthErrCount; /* 104 x68 R */
- __le32 IPTxPacketCount; /* 108 x6c R */
- __le32 IPTxByteCount; /* 112 x70 R */
- __le32 IPTxFragmentCount; /* 116 x74 R */
- __le32 IPRxPacketCount; /* 120 x78 R */
- __le32 IPRxByteCount; /* 124 x7c R */
- __le32 IPRxFragmentCount; /* 128 x80 R */
- __le32 IPDatagramReassemblyCount; /* 132 x84 R */
- __le32 IPV6RxPacketCount; /* 136 x88 R */
- __le32 IPErrPacketCount; /* 140 x8c R */
- __le32 IPReassemblyErrCount; /* 144 x90 R */
- __le32 TCPTxSegmentCount; /* 148 x94 R */
- __le32 TCPTxByteCount; /* 152 x98 R */
- __le32 TCPRxSegmentCount; /* 156 x9c R */
- __le32 TCPRxByteCount; /* 160 xa0 R */
- __le32 TCPTimerExpCount; /* 164 xa4 R */
- __le32 TCPRxAckCount; /* 168 xa8 R */
- __le32 TCPTxAckCount; /* 172 xac R */
- __le32 TCPRxErrOOOCount; /* 176 xb0 R */
- __le32 PSReserved0; /* 180 xb4 */
- __le32 TCPRxWindowProbeUpdateCount; /* 184 xb8 R */
- __le32 ECCErrCorrectionCount; /* 188 xbc R */
- __le32 PSReserved1[16]; /* 192 xc0 */
-};
-
-
/* remote register set (access via PCI memory read/write) */
struct isp_reg {
#define MBOX_REG_COUNT 8
@@ -207,11 +87,7 @@
union {
struct port_ctrl_stat_regs p0;
struct host_mem_cfg_regs p1;
- struct local_ram_cfg_regs p2;
- struct prot_stat_regs p3;
- __le32 r_union[44];
};
-
} __attribute__ ((packed)) isp4022;
} u2;
}; /* 256 x100 */
@@ -296,6 +172,7 @@
/* ISP Semaphore definitions */
/* ISP General Purpose Output definitions */
+#define GPOR_TOPCAT_RESET 0x00000004
/* shadow registers (DMA'd from HA to system memory. read only) */
struct shadow_regs {
@@ -337,6 +214,7 @@
/* Mailbox command definitions */
#define MBOX_CMD_ABOUT_FW 0x0009
+#define MBOX_CMD_PING 0x000B
#define MBOX_CMD_LUN_RESET 0x0016
#define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E
#define MBOX_CMD_GET_FW_STATUS 0x001F
@@ -364,6 +242,17 @@
#define MBOX_CMD_GET_FW_STATE 0x0069
#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK_DEFAULTS 0x006A
#define MBOX_CMD_RESTORE_FACTORY_DEFAULTS 0x0087
+#define MBOX_CMD_SET_ACB 0x0088
+#define MBOX_CMD_GET_ACB 0x0089
+#define MBOX_CMD_DISABLE_ACB 0x008A
+#define MBOX_CMD_GET_IPV6_NEIGHBOR_CACHE 0x008B
+#define MBOX_CMD_GET_IPV6_DEST_CACHE 0x008C
+#define MBOX_CMD_GET_IPV6_DEF_ROUTER_LIST 0x008D
+#define MBOX_CMD_GET_IPV6_LCL_PREFIX_LIST 0x008E
+#define MBOX_CMD_SET_IPV6_NEIGHBOR_CACHE 0x0090
+#define MBOX_CMD_GET_IP_ADDR_STATE 0x0091
+#define MBOX_CMD_SEND_IPV6_ROUTER_SOL 0x0092
+#define MBOX_CMD_GET_DB_ENTRY_CURRENT_IP_ADDR 0x0093
/* Mailbox 1 */
#define FW_STATE_READY 0x0000
@@ -409,6 +298,16 @@
#define MBOX_ASTS_DHCP_LEASE_EXPIRED 0x801D
#define MBOX_ASTS_DHCP_LEASE_ACQUIRED 0x801F
#define MBOX_ASTS_ISNS_UNSOLICITED_PDU_RECEIVED 0x8021
+#define MBOX_ASTS_DUPLICATE_IP 0x8025
+#define MBOX_ASTS_ARP_COMPLETE 0x8026
+#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027
+#define MBOX_ASTS_RESPONSE_QUEUE_FULL 0x8028
+#define MBOX_ASTS_IP_ADDR_STATE_CHANGED 0x8029
+#define MBOX_ASTS_IPV6_PREFIX_EXPIRED 0x802B
+#define MBOX_ASTS_IPV6_ND_PREFIX_IGNORED 0x802C
+#define MBOX_ASTS_IPV6_LCL_PREFIX_IGNORED 0x802D
+#define MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD 0x802E
+
#define ISNS_EVENT_DATA_RECEIVED 0x0000
#define ISNS_EVENT_CONNECTION_OPENED 0x0001
#define ISNS_EVENT_CONNECTION_FAILED 0x0002
@@ -418,137 +317,166 @@
/*************************************************************************/
/* Host Adapter Initialization Control Block (from host) */
-struct init_fw_ctrl_blk {
- uint8_t Version; /* 00 */
- uint8_t Control; /* 01 */
+struct addr_ctrl_blk {
+ uint8_t version; /* 00 */
+ uint8_t control; /* 01 */
- uint16_t FwOptions; /* 02-03 */
+ uint16_t fw_options; /* 02-03 */
#define FWOPT_HEARTBEAT_ENABLE 0x1000
#define FWOPT_SESSION_MODE 0x0040
#define FWOPT_INITIATOR_MODE 0x0020
#define FWOPT_TARGET_MODE 0x0010
- uint16_t ExecThrottle; /* 04-05 */
- uint8_t RetryCount; /* 06 */
- uint8_t RetryDelay; /* 07 */
- uint16_t MaxEthFrPayloadSize; /* 08-09 */
- uint16_t AddFwOptions; /* 0A-0B */
+ uint16_t exec_throttle; /* 04-05 */
+ uint8_t zio_count; /* 06 */
+ uint8_t res0; /* 07 */
+ uint16_t eth_mtu_size; /* 08-09 */
+ uint16_t add_fw_options; /* 0A-0B */
- uint8_t HeartbeatInterval; /* 0C */
- uint8_t InstanceNumber; /* 0D */
- uint16_t RES2; /* 0E-0F */
- uint16_t ReqQConsumerIndex; /* 10-11 */
- uint16_t ComplQProducerIndex; /* 12-13 */
- uint16_t ReqQLen; /* 14-15 */
- uint16_t ComplQLen; /* 16-17 */
- uint32_t ReqQAddrLo; /* 18-1B */
- uint32_t ReqQAddrHi; /* 1C-1F */
- uint32_t ComplQAddrLo; /* 20-23 */
- uint32_t ComplQAddrHi; /* 24-27 */
- uint32_t ShadowRegBufAddrLo; /* 28-2B */
- uint32_t ShadowRegBufAddrHi; /* 2C-2F */
+ uint8_t hb_interval; /* 0C */
+ uint8_t inst_num; /* 0D */
+ uint16_t res1; /* 0E-0F */
+ uint16_t rqq_consumer_idx; /* 10-11 */
+ uint16_t compq_producer_idx; /* 12-13 */
+ uint16_t rqq_len; /* 14-15 */
+ uint16_t compq_len; /* 16-17 */
+ uint32_t rqq_addr_lo; /* 18-1B */
+ uint32_t rqq_addr_hi; /* 1C-1F */
+ uint32_t compq_addr_lo; /* 20-23 */
+ uint32_t compq_addr_hi; /* 24-27 */
+ uint32_t shdwreg_addr_lo; /* 28-2B */
+ uint32_t shdwreg_addr_hi; /* 2C-2F */
- uint16_t iSCSIOptions; /* 30-31 */
+ uint16_t iscsi_opts; /* 30-31 */
+ uint16_t ipv4_tcp_opts; /* 32-33 */
+ uint16_t ipv4_ip_opts; /* 34-35 */
- uint16_t TCPOptions; /* 32-33 */
+ uint16_t iscsi_max_pdu_size; /* 36-37 */
+ uint8_t ipv4_tos; /* 38 */
+ uint8_t ipv4_ttl; /* 39 */
+ uint8_t acb_version; /* 3A */
+ uint8_t res2; /* 3B */
+ uint16_t def_timeout; /* 3C-3D */
+ uint16_t iscsi_fburst_len; /* 3E-3F */
+ uint16_t iscsi_def_time2wait; /* 40-41 */
+ uint16_t iscsi_def_time2retain; /* 42-43 */
+ uint16_t iscsi_max_outstnd_r2t; /* 44-45 */
+ uint16_t conn_ka_timeout; /* 46-47 */
+ uint16_t ipv4_port; /* 48-49 */
+ uint16_t iscsi_max_burst_len; /* 4A-4B */
+ uint32_t res5; /* 4C-4F */
+ uint8_t ipv4_addr[4]; /* 50-53 */
+ uint16_t ipv4_vlan_tag; /* 54-55 */
+ uint8_t ipv4_addr_state; /* 56 */
+ uint8_t ipv4_cacheid; /* 57 */
+ uint8_t res6[8]; /* 58-5F */
+ uint8_t ipv4_subnet[4]; /* 60-63 */
+ uint8_t res7[12]; /* 64-6F */
+ uint8_t ipv4_gw_addr[4]; /* 70-73 */
+ uint8_t res8[0xc]; /* 74-7F */
+ uint8_t pri_dns_srvr_ip[4];/* 80-83 */
+ uint8_t sec_dns_srvr_ip[4];/* 84-87 */
+ uint16_t min_eph_port; /* 88-89 */
+ uint16_t max_eph_port; /* 8A-8B */
+ uint8_t res9[4]; /* 8C-8F */
+ uint8_t iscsi_alias[32];/* 90-AF */
+ uint8_t res9_1[0x16]; /* B0-C5 */
+ uint16_t tgt_portal_grp;/* C6-C7 */
+ uint8_t abort_timer; /* C8 */
+ uint8_t ipv4_tcp_wsf; /* C9 */
+ uint8_t res10[6]; /* CA-CF */
+ uint8_t ipv4_sec_ip_addr[4]; /* D0-D3 */
+ uint8_t ipv4_dhcp_vid_len; /* D4 */
+ uint8_t ipv4_dhcp_vid[11]; /* D5-DF */
+ uint8_t res11[20]; /* E0-F3 */
+ uint8_t ipv4_dhcp_alt_cid_len; /* F4 */
+ uint8_t ipv4_dhcp_alt_cid[11]; /* F5-FF */
+ uint8_t iscsi_name[224]; /* 100-1DF */
+ uint8_t res12[32]; /* 1E0-1FF */
+ uint32_t cookie; /* 200-203 */
+ uint16_t ipv6_port; /* 204-205 */
+ uint16_t ipv6_opts; /* 206-207 */
+ uint16_t ipv6_addtl_opts; /* 208-209 */
+ uint16_t ipv6_tcp_opts; /* 20A-20B */
+ uint8_t ipv6_tcp_wsf; /* 20C */
+ uint16_t ipv6_flow_lbl; /* 20D-20F */
+ uint8_t ipv6_gw_addr[16]; /* 210-21F */
+ uint16_t ipv6_vlan_tag; /* 220-221 */
+ uint8_t ipv6_lnk_lcl_addr_state;/* 222 */
+ uint8_t ipv6_addr0_state; /* 223 */
+ uint8_t ipv6_addr1_state; /* 224 */
+ uint8_t ipv6_gw_state; /* 225 */
+ uint8_t ipv6_traffic_class; /* 226 */
+ uint8_t ipv6_hop_limit; /* 227 */
+ uint8_t ipv6_if_id[8]; /* 228-22F */
+ uint8_t ipv6_addr0[16]; /* 230-23F */
+ uint8_t ipv6_addr1[16]; /* 240-24F */
+ uint32_t ipv6_nd_reach_time; /* 250-253 */
+ uint32_t ipv6_nd_rexmit_timer; /* 254-257 */
+ uint32_t ipv6_nd_stale_timeout; /* 258-25B */
+ uint8_t ipv6_dup_addr_detect_count; /* 25C */
+ uint8_t ipv6_cache_id; /* 25D */
+ uint8_t res13[18]; /* 25E-26F */
+ uint32_t ipv6_gw_advrt_mtu; /* 270-273 */
+ uint8_t res14[140]; /* 274-2FF */
+};
- uint16_t IPOptions; /* 34-35 */
-
- uint16_t MaxPDUSize; /* 36-37 */
- uint16_t RcvMarkerInt; /* 38-39 */
- uint16_t SndMarkerInt; /* 3A-3B */
- uint16_t InitMarkerlessInt; /* 3C-3D */
- uint16_t FirstBurstSize; /* 3E-3F */
- uint16_t DefaultTime2Wait; /* 40-41 */
- uint16_t DefaultTime2Retain; /* 42-43 */
- uint16_t MaxOutStndngR2T; /* 44-45 */
- uint16_t KeepAliveTimeout; /* 46-47 */
- uint16_t PortNumber; /* 48-49 */
- uint16_t MaxBurstSize; /* 4A-4B */
- uint32_t RES4; /* 4C-4F */
- uint8_t IPAddr[4]; /* 50-53 */
- uint8_t RES5[12]; /* 54-5F */
- uint8_t SubnetMask[4]; /* 60-63 */
- uint8_t RES6[12]; /* 64-6F */
- uint8_t GatewayIPAddr[4]; /* 70-73 */
- uint8_t RES7[12]; /* 74-7F */
- uint8_t PriDNSIPAddr[4]; /* 80-83 */
- uint8_t SecDNSIPAddr[4]; /* 84-87 */
- uint8_t RES8[8]; /* 88-8F */
- uint8_t Alias[32]; /* 90-AF */
- uint8_t TargAddr[8]; /* B0-B7 *//* /FIXME: Remove?? */
- uint8_t CHAPNameSecretsTable[8]; /* B8-BF */
- uint8_t EthernetMACAddr[6]; /* C0-C5 */
- uint16_t TargetPortalGroup; /* C6-C7 */
- uint8_t SendScale; /* C8 */
- uint8_t RecvScale; /* C9 */
- uint8_t TypeOfService; /* CA */
- uint8_t Time2Live; /* CB */
- uint16_t VLANPriority; /* CC-CD */
- uint16_t Reserved8; /* CE-CF */
- uint8_t SecIPAddr[4]; /* D0-D3 */
- uint8_t Reserved9[12]; /* D4-DF */
- uint8_t iSNSIPAddr[4]; /* E0-E3 */
- uint16_t iSNSServerPortNumber; /* E4-E5 */
- uint8_t Reserved10[10]; /* E6-EF */
- uint8_t SLPDAIPAddr[4]; /* F0-F3 */
- uint8_t Reserved11[12]; /* F4-FF */
- uint8_t iSCSINameString[256]; /* 100-1FF */
+struct init_fw_ctrl_blk {
+ struct addr_ctrl_blk pri;
+ struct addr_ctrl_blk sec;
};
/*************************************************************************/
struct dev_db_entry {
- uint8_t options; /* 00 */
+ uint16_t options; /* 00-01 */
#define DDB_OPT_DISC_SESSION 0x10
#define DDB_OPT_TARGET 0x02 /* device is a target */
- uint8_t control; /* 01 */
-
- uint16_t exeThrottle; /* 02-03 */
- uint16_t exeCount; /* 04-05 */
- uint8_t retryCount; /* 06 */
- uint8_t retryDelay; /* 07 */
- uint16_t iSCSIOptions; /* 08-09 */
-
- uint16_t TCPOptions; /* 0A-0B */
-
- uint16_t IPOptions; /* 0C-0D */
-
- uint16_t maxPDUSize; /* 0E-0F */
- uint16_t rcvMarkerInt; /* 10-11 */
- uint16_t sndMarkerInt; /* 12-13 */
- uint16_t iSCSIMaxSndDataSegLen; /* 14-15 */
- uint16_t firstBurstSize; /* 16-17 */
- uint16_t minTime2Wait; /* 18-19 : RA :default_time2wait */
- uint16_t maxTime2Retain; /* 1A-1B */
- uint16_t maxOutstndngR2T; /* 1C-1D */
- uint16_t keepAliveTimeout; /* 1E-1F */
- uint8_t ISID[6]; /* 20-25 big-endian, must be converted
+ uint16_t exec_throttle; /* 02-03 */
+ uint16_t exec_count; /* 04-05 */
+ uint16_t res0; /* 06-07 */
+ uint16_t iscsi_options; /* 08-09 */
+ uint16_t tcp_options; /* 0A-0B */
+ uint16_t ip_options; /* 0C-0D */
+ uint16_t iscsi_max_rcv_data_seg_len; /* 0E-0F */
+ uint32_t res1; /* 10-13 */
+ uint16_t iscsi_max_snd_data_seg_len; /* 14-15 */
+ uint16_t iscsi_first_burst_len; /* 16-17 */
+ uint16_t iscsi_def_time2wait; /* 18-19 */
+ uint16_t iscsi_def_time2retain; /* 1A-1B */
+ uint16_t iscsi_max_outsnd_r2t; /* 1C-1D */
+ uint16_t ka_timeout; /* 1E-1F */
+ uint8_t isid[6]; /* 20-25 big-endian, must be converted
* to little-endian */
- uint16_t TSID; /* 26-27 */
- uint16_t portNumber; /* 28-29 */
- uint16_t maxBurstSize; /* 2A-2B */
- uint16_t taskMngmntTimeout; /* 2C-2D */
- uint16_t reserved1; /* 2E-2F */
- uint8_t ipAddr[0x10]; /* 30-3F */
- uint8_t iSCSIAlias[0x20]; /* 40-5F */
- uint8_t targetAddr[0x20]; /* 60-7F */
- uint8_t userID[0x20]; /* 80-9F */
- uint8_t password[0x20]; /* A0-BF */
- uint8_t iscsiName[0x100]; /* C0-1BF : xxzzy Make this a
+ uint16_t tsid; /* 26-27 */
+ uint16_t port; /* 28-29 */
+ uint16_t iscsi_max_burst_len; /* 2A-2B */
+ uint16_t def_timeout; /* 2C-2D */
+ uint16_t res2; /* 2E-2F */
+ uint8_t ip_addr[0x10]; /* 30-3F */
+ uint8_t iscsi_alias[0x20]; /* 40-5F */
+ uint8_t tgt_addr[0x20]; /* 60-7F */
+ uint16_t mss; /* 80-81 */
+ uint16_t res3; /* 82-83 */
+ uint16_t lcl_port; /* 84-85 */
+ uint8_t ipv4_tos; /* 86 */
+ uint16_t ipv6_flow_lbl; /* 87-89 */
+ uint8_t res4[0x36]; /* 8A-BF */
+ uint8_t iscsi_name[0xE0]; /* C0-19F : xxzzy Make this a
* pointer to a string so we
* don't have to reserve soooo
* much RAM */
- uint16_t ddbLink; /* 1C0-1C1 */
- uint16_t CHAPTableIndex; /* 1C2-1C3 */
- uint16_t TargetPortalGroup; /* 1C4-1C5 */
- uint16_t reserved2[2]; /* 1C6-1C7 */
- uint32_t statSN; /* 1C8-1CB */
- uint32_t expStatSN; /* 1CC-1CF */
- uint16_t reserved3[0x2C]; /* 1D0-1FB */
- uint16_t ddbValidCookie; /* 1FC-1FD */
- uint16_t ddbValidSize; /* 1FE-1FF */
+ uint8_t ipv6_addr[0x10];/* 1A0-1AF */
+ uint8_t res5[0x10]; /* 1B0-1BF */
+ uint16_t ddb_link; /* 1C0-1C1 */
+ uint16_t chap_tbl_idx; /* 1C2-1C3 */
+ uint16_t tgt_portal_grp; /* 1C4-1C5 */
+ uint8_t tcp_xmt_wsf; /* 1C6 */
+ uint8_t tcp_rcv_wsf; /* 1C7 */
+ uint32_t stat_sn; /* 1C8-1CB */
+ uint32_t exp_stat_sn; /* 1CC-1CF */
+ uint8_t res6[0x30]; /* 1D0-1FF */
};
/*************************************************************************/
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 5b00cb0..a3608e0 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -8,6 +8,9 @@
#ifndef __QLA4x_GBL_H
#define __QLA4x_GBL_H
+struct iscsi_cls_conn;
+
+void qla4xxx_hw_reset(struct scsi_qla_host *ha);
int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a);
int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port);
int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb);
@@ -58,11 +61,13 @@
void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
uint32_t intr_status);
int qla4xxx_init_rings(struct scsi_qla_host * ha);
-struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index);
+struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
+ uint32_t index);
void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha,
uint32_t fw_ddb_index, uint32_t state);
+void qla4xxx_dump_buffer(void *b, uint32_t size);
extern int ql4xextended_error_logging;
extern int ql4xdiscoverywait;
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 6365df2..1e29f51 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -6,6 +6,9 @@
*/
#include "ql4_def.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
uint32_t fw_ddb_index);
@@ -300,12 +303,12 @@
if (!qla4xxx_fw_ready(ha))
return status;
- set_bit(AF_ONLINE, &ha->flags);
return qla4xxx_get_firmware_status(ha);
}
static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
- uint32_t fw_ddb_index)
+ uint32_t fw_ddb_index,
+ uint32_t *new_tgt)
{
struct dev_db_entry *fw_ddb_entry = NULL;
dma_addr_t fw_ddb_entry_dma;
@@ -313,6 +316,7 @@
int found = 0;
uint32_t device_state;
+ *new_tgt = 0;
/* Make sure the dma buffer is valid */
fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
sizeof(*fw_ddb_entry),
@@ -337,7 +341,7 @@
DEBUG2(printk("scsi%ld: %s: Looking for ddb[%d]\n", ha->host_no,
__func__, fw_ddb_index));
list_for_each_entry(ddb_entry, &ha->ddb_list, list) {
- if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsiName,
+ if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsi_name,
ISCSI_NAME_SIZE) == 0) {
found++;
break;
@@ -348,6 +352,7 @@
DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating "
"new ddb\n", ha->host_no, __func__,
fw_ddb_index));
+ *new_tgt = 1;
ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
}
@@ -409,26 +414,26 @@
}
status = QLA_SUCCESS;
- ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->TSID);
+ ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->tsid);
ddb_entry->task_mgmt_timeout =
- le16_to_cpu(fw_ddb_entry->taskMngmntTimeout);
+ le16_to_cpu(fw_ddb_entry->def_timeout);
ddb_entry->CmdSn = 0;
- ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exeThrottle);
+ ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exec_throttle);
ddb_entry->default_relogin_timeout =
- le16_to_cpu(fw_ddb_entry->taskMngmntTimeout);
- ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->minTime2Wait);
+ le16_to_cpu(fw_ddb_entry->def_timeout);
+ ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
/* Update index in case it changed */
ddb_entry->fw_ddb_index = fw_ddb_index;
ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;
- ddb_entry->port = le16_to_cpu(fw_ddb_entry->portNumber);
- ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->TargetPortalGroup);
- memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsiName[0],
+ ddb_entry->port = le16_to_cpu(fw_ddb_entry->port);
+ ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
+ memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsi_name[0],
min(sizeof(ddb_entry->iscsi_name),
- sizeof(fw_ddb_entry->iscsiName)));
- memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ipAddr[0],
- min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ipAddr)));
+ sizeof(fw_ddb_entry->iscsi_name)));
+ memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0],
+ min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr)));
DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n",
ha->host_no, __func__, fw_ddb_index,
@@ -495,6 +500,7 @@
uint32_t ddb_state;
uint32_t conn_err, err_code;
struct ddb_entry *ddb_entry;
+ uint32_t new_tgt;
dev_info(&ha->pdev->dev, "Initializing DDBs ...\n");
for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES;
@@ -526,8 +532,19 @@
"completed "
"or access denied failure\n",
ha->host_no, __func__));
- } else
+ } else {
qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0);
+ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index,
+ NULL, 0, NULL, &next_fw_ddb_index,
+ &ddb_state, &conn_err, NULL, NULL)
+ == QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s:"
+ "get_ddb_entry %d failed\n",
+ ha->host_no,
+ __func__, fw_ddb_index));
+ return QLA_ERROR;
+ }
+ }
}
if (ddb_state != DDB_DS_SESSION_ACTIVE)
@@ -540,7 +557,7 @@
ha->host_no, __func__, fw_ddb_index));
/* Add DDB to internal our ddb list. */
- ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index);
+ ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt);
if (ddb_entry == NULL) {
DEBUG2(printk("scsi%ld: %s: Unable to allocate memory "
"for device at fw_ddb_index %d\n",
@@ -865,21 +882,20 @@
static void qla4x00_pci_config(struct scsi_qla_host *ha)
{
- uint16_t w, mwi;
+ uint16_t w;
+ int status;
dev_info(&ha->pdev->dev, "Configuring PCI space...\n");
pci_set_master(ha->pdev);
- mwi = 0;
- if (pci_set_mwi(ha->pdev))
- mwi = PCI_COMMAND_INVALIDATE;
+ status = pci_set_mwi(ha->pdev);
/*
* We want to respect framework's setting of PCI configuration space
* command register and also want to make sure that all bits of
* interest to us are properly set in command register.
*/
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
- w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
w &= ~PCI_COMMAND_INTX_DISABLE;
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
}
@@ -911,6 +927,9 @@
writel(set_rmask(NVR_WRITE_ENABLE),
&ha->reg->u1.isp4022.nvram);
+ writel(2, &ha->reg->mailbox[6]);
+ readl(&ha->reg->mailbox[6]);
+
writel(set_rmask(CSR_BOOT_ENABLE), &ha->reg->ctrl_status);
readl(&ha->reg->ctrl_status);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -958,25 +977,25 @@
return status;
}
-int ql4xxx_lock_drvr_wait(struct scsi_qla_host *ha)
+int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a)
{
-#define QL4_LOCK_DRVR_WAIT 30
+#define QL4_LOCK_DRVR_WAIT 60
#define QL4_LOCK_DRVR_SLEEP 1
int drvr_wait = QL4_LOCK_DRVR_WAIT;
while (drvr_wait) {
- if (ql4xxx_lock_drvr(ha) == 0) {
+ if (ql4xxx_lock_drvr(a) == 0) {
ssleep(QL4_LOCK_DRVR_SLEEP);
if (drvr_wait) {
DEBUG2(printk("scsi%ld: %s: Waiting for "
- "Global Init Semaphore(%d)...n",
- ha->host_no,
+ "Global Init Semaphore(%d)...\n",
+ a->host_no,
__func__, drvr_wait));
}
drvr_wait -= QL4_LOCK_DRVR_SLEEP;
} else {
DEBUG2(printk("scsi%ld: %s: Global Init Semaphore "
- "acquired.n", ha->host_no, __func__));
+ "acquired\n", a->host_no, __func__));
return QLA_SUCCESS;
}
}
@@ -1125,17 +1144,17 @@
/* Initialize the Host adapter request/response queues and firmware */
if (qla4xxx_start_firmware(ha) == QLA_ERROR)
- return status;
+ goto exit_init_hba;
if (qla4xxx_validate_mac_address(ha) == QLA_ERROR)
- return status;
+ goto exit_init_hba;
if (qla4xxx_init_local_data(ha) == QLA_ERROR)
- return status;
+ goto exit_init_hba;
status = qla4xxx_init_firmware(ha);
if (status == QLA_ERROR)
- return status;
+ goto exit_init_hba;
/*
* FW is waiting to get an IP address from DHCP server: Skip building
@@ -1143,12 +1162,12 @@
* followed by 0x8014 aen" to trigger the tgt discovery process.
*/
if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)
- return status;
+ goto exit_init_online;
/* Skip device discovery if ip and subnet is zero */
if (memcmp(ha->ip_address, ip_address, IP_ADDR_LEN) == 0 ||
memcmp(ha->subnet_mask, ip_address, IP_ADDR_LEN) == 0)
- return status;
+ goto exit_init_online;
if (renew_ddb_list == PRESERVE_DDB_LIST) {
/*
@@ -1177,9 +1196,10 @@
ha->host_no));
}
- exit_init_hba:
+exit_init_online:
+ set_bit(AF_ONLINE, &ha->flags);
+exit_init_hba:
return status;
-
}
/**
@@ -1193,9 +1213,10 @@
uint32_t fw_ddb_index)
{
struct ddb_entry * ddb_entry;
+ uint32_t new_tgt;
/* First allocate a device structure */
- ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index);
+ ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt);
if (ddb_entry == NULL) {
DEBUG2(printk(KERN_WARNING
"scsi%ld: Unable to allocate memory to add "
@@ -1203,6 +1224,18 @@
return;
}
+ if (!new_tgt && (ddb_entry->fw_ddb_index != fw_ddb_index)) {
+ /* Target has been bound to a new fw_ddb_index */
+ qla4xxx_free_ddb(ha, ddb_entry);
+ ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
+ if (ddb_entry == NULL) {
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: Unable to allocate memory"
+ " to add fw_ddb_index %d\n",
+ ha->host_no, fw_ddb_index));
+ return;
+ }
+ }
if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
QLA_ERROR) {
ha->fw_ddb_index_map[fw_ddb_index] =
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index a216a17..5006ecb 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -6,6 +6,10 @@
*/
#include "ql4_def.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
+
#include <scsi/scsi_tcq.h>
@@ -141,11 +145,13 @@
uint16_t avail_dsds;
struct data_seg_a64 *cur_dsd;
struct scsi_cmnd *cmd;
+ struct scatterlist *sg;
+ int i;
cmd = srb->cmd;
ha = srb->ha;
- if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
+ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
/* No data being transferred */
cmd_entry->ttlByteCnt = __constant_cpu_to_le32(0);
return;
@@ -154,40 +160,27 @@
avail_dsds = COMMAND_SEG;
cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]);
- /* Load data segments */
- if (cmd->use_sg) {
- struct scatterlist *cur_seg;
- struct scatterlist *end_seg;
+ scsi_for_each_sg(cmd, sg, tot_dsds, i) {
+ dma_addr_t sle_dma;
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- end_seg = cur_seg + tot_dsds;
- while (cur_seg < end_seg) {
- dma_addr_t sle_dma;
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ struct continuation_t1_entry *cont_entry;
- /* Allocate additional continuation packets? */
- if (avail_dsds == 0) {
- struct continuation_t1_entry *cont_entry;
-
- cont_entry = qla4xxx_alloc_cont_entry(ha);
- cur_dsd =
- (struct data_seg_a64 *)
- &cont_entry->dataseg[0];
- avail_dsds = CONTINUE_SEG;
- }
-
- sle_dma = sg_dma_address(cur_seg);
- cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma));
- cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma));
- cur_dsd->count = cpu_to_le32(sg_dma_len(cur_seg));
- avail_dsds--;
-
- cur_dsd++;
- cur_seg++;
+ cont_entry = qla4xxx_alloc_cont_entry(ha);
+ cur_dsd =
+ (struct data_seg_a64 *)
+ &cont_entry->dataseg[0];
+ avail_dsds = CONTINUE_SEG;
}
- } else {
- cur_dsd->base.addrLow = cpu_to_le32(LSDW(srb->dma_handle));
- cur_dsd->base.addrHigh = cpu_to_le32(MSDW(srb->dma_handle));
- cur_dsd->count = cpu_to_le32(cmd->request_bufflen);
+
+ sle_dma = sg_dma_address(sg);
+ cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma));
+ cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma));
+ cur_dsd->count = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
+
+ cur_dsd++;
}
}
@@ -204,8 +197,8 @@
struct scsi_cmnd *cmd = srb->cmd;
struct ddb_entry *ddb_entry;
struct command_t3_entry *cmd_entry;
- struct scatterlist *sg = NULL;
+ int nseg;
uint16_t tot_dsds;
uint16_t req_cnt;
@@ -233,24 +226,11 @@
index = (uint32_t)cmd->request->tag;
/* Calculate the number of request entries needed. */
- if (cmd->use_sg) {
- sg = (struct scatterlist *)cmd->request_buffer;
- tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
- if (tot_dsds == 0)
- goto queuing_error;
- } else if (cmd->request_bufflen) {
- dma_addr_t req_dma;
+ nseg = scsi_dma_map(cmd);
+ if (nseg < 0)
+ goto queuing_error;
+ tot_dsds = nseg;
- req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- if (dma_mapping_error(req_dma))
- goto queuing_error;
-
- srb->dma_handle = req_dma;
- tot_dsds = 1;
- }
req_cnt = qla4xxx_calc_request_entries(tot_dsds);
if (ha->req_q_count < (req_cnt + 2)) {
@@ -279,7 +259,7 @@
int_to_scsilun(cmd->device->lun, &cmd_entry->lun);
cmd_entry->cmdSeqNum = cpu_to_le32(ddb_entry->CmdSn);
- cmd_entry->ttlByteCnt = cpu_to_le32(cmd->request_bufflen);
+ cmd_entry->ttlByteCnt = cpu_to_le32(scsi_bufflen(cmd));
memcpy(cmd_entry->cdb, cmd->cmnd, cmd->cmd_len);
cmd_entry->dataSegCnt = cpu_to_le16(tot_dsds);
cmd_entry->hdr.entryCount = req_cnt;
@@ -289,13 +269,13 @@
* transferred, as the data direction bit is sometimed filled
* in when there is no data to be transferred */
cmd_entry->control_flags = CF_NO_DATA;
- if (cmd->request_bufflen) {
+ if (scsi_bufflen(cmd)) {
if (cmd->sc_data_direction == DMA_TO_DEVICE)
cmd_entry->control_flags = CF_WRITE;
else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
cmd_entry->control_flags = CF_READ;
- ha->bytes_xfered += cmd->request_bufflen;
+ ha->bytes_xfered += scsi_bufflen(cmd);
if (ha->bytes_xfered & ~0xFFFFF){
ha->total_mbytes_xferred += ha->bytes_xfered >> 20;
ha->bytes_xfered &= 0xFFFFF;
@@ -359,14 +339,9 @@
return QLA_SUCCESS;
queuing_error:
+ if (tot_dsds)
+ scsi_dma_unmap(cmd);
- if (cmd->use_sg && tot_dsds) {
- sg = (struct scatterlist *) cmd->request_buffer;
- pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
- } else if (tot_dsds)
- pci_unmap_single(ha->pdev, srb->dma_handle,
- cmd->request_bufflen, cmd->sc_data_direction);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_ERROR;
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 35b9e36..4a154be 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -6,6 +6,9 @@
*/
#include "ql4_def.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
/**
* qla2x00_process_completed_request() - Process a Fast Post response.
@@ -90,9 +93,29 @@
break;
}
- if (sts_entry->iscsiFlags &
- (ISCSI_FLAG_RESIDUAL_OVER|ISCSI_FLAG_RESIDUAL_UNDER))
- cmd->resid = residual;
+ if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {
+ cmd->result = DID_ERROR << 16;
+ break;
+ }
+
+ if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER) {
+ scsi_set_resid(cmd, residual);
+ if (!scsi_status && ((scsi_bufflen(cmd) - residual) <
+ cmd->underflow)) {
+
+ cmd->result = DID_ERROR << 16;
+
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
+ "Mid-layer Data underrun0, "
+ "xferlen = 0x%x, "
+ "residual = 0x%x\n", ha->host_no,
+ cmd->device->channel,
+ cmd->device->id,
+ cmd->device->lun, __func__,
+ scsi_bufflen(cmd), residual));
+ break;
+ }
+ }
cmd->result = DID_OK << 16 | scsi_status;
@@ -161,7 +184,8 @@
case SCS_DATA_UNDERRUN:
case SCS_DATA_OVERRUN:
- if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {
+ if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) ||
+ (sts_entry->completionStatus == SCS_DATA_OVERRUN)) {
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun, "
"residual = 0x%x\n", ha->host_no,
cmd->device->channel, cmd->device->id,
@@ -171,21 +195,7 @@
break;
}
- if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
- /*
- * Firmware detected a SCSI transport underrun
- * condition
- */
- cmd->resid = residual;
- DEBUG2(printk("scsi%ld:%d:%d:%d: %s: UNDERRUN status "
- "detected, xferlen = 0x%x, residual = "
- "0x%x\n",
- ha->host_no, cmd->device->channel,
- cmd->device->id,
- cmd->device->lun, __func__,
- cmd->request_bufflen,
- residual));
- }
+ scsi_set_resid(cmd, residual);
/*
* If there is scsi_status, it takes precedense over
@@ -227,7 +237,7 @@
if ((sts_entry->iscsiFlags &
ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
cmd->result = DID_BUS_BUSY << 16;
- } else if ((cmd->request_bufflen - residual) <
+ } else if ((scsi_bufflen(cmd) - residual) <
cmd->underflow) {
/*
* Handle mid-layer underflow???
@@ -242,13 +252,13 @@
* will return DID_ERROR.
*/
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
- "Mid-layer Data underrun, "
- "xferlen = 0x%x, "
- "residual = 0x%x\n", ha->host_no,
- cmd->device->channel,
- cmd->device->id,
- cmd->device->lun, __func__,
- cmd->request_bufflen, residual));
+ "Mid-layer Data underrun1, "
+ "xferlen = 0x%x, "
+ "residual = 0x%x\n", ha->host_no,
+ cmd->device->channel,
+ cmd->device->id,
+ cmd->device->lun, __func__,
+ scsi_bufflen(cmd), residual));
cmd->result = DID_ERROR << 16;
} else {
@@ -417,6 +427,7 @@
uint32_t mbox_status)
{
int i;
+ uint32_t mbox_stat2, mbox_stat3;
if ((mbox_status == MBOX_STS_BUSY) ||
(mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) ||
@@ -437,6 +448,12 @@
} else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {
/* Immediately process the AENs that don't require much work.
* Only queue the database_changed AENs */
+ if (ha->aen_log.count < MAX_AEN_ENTRIES) {
+ for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
+ ha->aen_log.entry[ha->aen_log.count].mbox_sts[i] =
+ readl(&ha->reg->mailbox[i]);
+ ha->aen_log.count++;
+ }
switch (mbox_status) {
case MBOX_ASTS_SYSTEM_ERROR:
/* Log Mailbox registers */
@@ -493,6 +510,16 @@
mbox_status));
break;
+ case MBOX_ASTS_IP_ADDR_STATE_CHANGED:
+ mbox_stat2 = readl(&ha->reg->mailbox[2]);
+ mbox_stat3 = readl(&ha->reg->mailbox[3]);
+
+ if ((mbox_stat3 == 5) && (mbox_stat2 == 3))
+ set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
+ else if ((mbox_stat3 == 2) && (mbox_stat2 == 5))
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ break;
+
case MBOX_ASTS_MAC_ADDRESS_CHANGED:
case MBOX_ASTS_DNS:
/* No action */
@@ -518,11 +545,6 @@
/* Queue AEN information and process it in the DPC
* routine */
if (ha->aen_q_count > 0) {
- /* advance pointer */
- if (ha->aen_in == (MAX_AEN_ENTRIES - 1))
- ha->aen_in = 0;
- else
- ha->aen_in++;
/* decrement available counter */
ha->aen_q_count--;
@@ -542,6 +564,10 @@
ha->aen_q[ha->aen_in].mbox_sts[2],
ha->aen_q[ha->aen_in].mbox_sts[3],
ha->aen_q[ha->aen_in]. mbox_sts[4]));
+ /* advance pointer */
+ ha->aen_in++;
+ if (ha->aen_in == MAX_AEN_ENTRIES)
+ ha->aen_in = 0;
/* The DPC routine will process the aen */
set_bit(DPC_AEN, &ha->dpc_flags);
@@ -724,25 +750,24 @@
spin_lock_irqsave(&ha->hardware_lock, flags);
while (ha->aen_out != ha->aen_in) {
- /* Advance pointers for next entry */
- if (ha->aen_out == (MAX_AEN_ENTRIES - 1))
- ha->aen_out = 0;
- else
- ha->aen_out++;
-
- ha->aen_q_count++;
aen = &ha->aen_q[ha->aen_out];
-
/* copy aen information to local structure */
for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
mbox_sts[i] = aen->mbox_sts[i];
+ ha->aen_q_count++;
+ ha->aen_out++;
+
+ if (ha->aen_out == MAX_AEN_ENTRIES)
+ ha->aen_out = 0;
+
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- DEBUG(printk("scsi%ld: AEN[%d] %04x, index [%d] state=%04x "
- "mod=%x conerr=%08x \n", ha->host_no, ha->aen_out,
- mbox_sts[0], mbox_sts[2], mbox_sts[3],
- mbox_sts[1], mbox_sts[4]));
+ DEBUG2(printk("qla4xxx(%ld): AEN[%d]=0x%08x, mbx1=0x%08x mbx2=0x%08x"
+ " mbx3=0x%08x mbx4=0x%08x\n", ha->host_no,
+ (ha->aen_out ? (ha->aen_out-1): (MAX_AEN_ENTRIES-1)),
+ mbox_sts[0], mbox_sts[1], mbox_sts[2],
+ mbox_sts[3], mbox_sts[4]));
switch (mbox_sts[0]) {
case MBOX_ASTS_DATABASE_CHANGED:
@@ -792,6 +817,5 @@
spin_lock_irqsave(&ha->hardware_lock, flags);
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
}
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index f116ff9..35cd73c 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -6,6 +6,9 @@
*/
#include "ql4_def.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
/**
@@ -169,84 +172,6 @@
return status;
}
-
-#if 0
-
-/**
- * qla4xxx_issue_iocb - issue mailbox iocb command
- * @ha: adapter state pointer.
- * @buffer: buffer pointer.
- * @phys_addr: physical address of buffer.
- * @size: size of buffer.
- *
- * Issues iocbs via mailbox commands.
- * TARGET_QUEUE_LOCK must be released.
- * ADAPTER_STATE_LOCK must be released.
- **/
-int
-qla4xxx_issue_iocb(struct scsi_qla_host * ha, void *buffer,
- dma_addr_t phys_addr, size_t size)
-{
- uint32_t mbox_cmd[MBOX_REG_COUNT];
- uint32_t mbox_sts[MBOX_REG_COUNT];
- int status;
-
- memset(&mbox_cmd, 0, sizeof(mbox_cmd));
- memset(&mbox_sts, 0, sizeof(mbox_sts));
- mbox_cmd[0] = MBOX_CMD_EXECUTE_IOCB_A64;
- mbox_cmd[1] = 0;
- mbox_cmd[2] = LSDW(phys_addr);
- mbox_cmd[3] = MSDW(phys_addr);
- status = qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
- return status;
-}
-
-int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
- uint16_t fw_ddb_index,
- uint16_t connection_id,
- uint16_t option)
-{
- uint32_t mbox_cmd[MBOX_REG_COUNT];
- uint32_t mbox_sts[MBOX_REG_COUNT];
-
- memset(&mbox_cmd, 0, sizeof(mbox_cmd));
- memset(&mbox_sts, 0, sizeof(mbox_sts));
- mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT;
- mbox_cmd[1] = fw_ddb_index;
- mbox_cmd[2] = connection_id;
- mbox_cmd[3] = LOGOUT_OPTION_RELOGIN;
- if (qla4xxx_mailbox_command(ha, 4, 2, &mbox_cmd[0], &mbox_sts[0]) !=
- QLA_SUCCESS) {
- DEBUG2(printk("scsi%ld: %s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT "
- "option %04x failed sts %04X %04X",
- ha->host_no, __func__,
- option, mbox_sts[0], mbox_sts[1]));
- if (mbox_sts[0] == 0x4005)
- DEBUG2(printk("%s reason %04X\n", __func__,
- mbox_sts[1]));
- }
- return QLA_SUCCESS;
-}
-
-int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
- uint16_t fw_ddb_index)
-{
- uint32_t mbox_cmd[MBOX_REG_COUNT];
- uint32_t mbox_sts[MBOX_REG_COUNT];
-
- memset(&mbox_cmd, 0, sizeof(mbox_cmd));
- memset(&mbox_sts, 0, sizeof(mbox_sts));
- mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY;
- mbox_cmd[1] = fw_ddb_index;
- if (qla4xxx_mailbox_command(ha, 2, 5, &mbox_cmd[0], &mbox_sts[0]) !=
- QLA_SUCCESS)
- return QLA_ERROR;
-
- return QLA_SUCCESS;
-}
-
-#endif /* 0 */
-
/**
* qla4xxx_initialize_fw_cb - initializes firmware control block.
* @ha: Pointer to host adapter structure.
@@ -272,10 +197,13 @@
/* Get Initialize Firmware Control Block. */
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
mbox_cmd[2] = LSDW(init_fw_cb_dma);
mbox_cmd[3] = MSDW(init_fw_cb_dma);
- if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+ mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk);
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
dma_free_coherent(&ha->pdev->dev,
sizeof(struct init_fw_ctrl_blk),
@@ -287,51 +215,56 @@
qla4xxx_init_rings(ha);
/* Fill in the request and response queue information. */
- init_fw_cb->ReqQConsumerIndex = cpu_to_le16(ha->request_out);
- init_fw_cb->ComplQProducerIndex = cpu_to_le16(ha->response_in);
- init_fw_cb->ReqQLen = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH);
- init_fw_cb->ComplQLen = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH);
- init_fw_cb->ReqQAddrLo = cpu_to_le32(LSDW(ha->request_dma));
- init_fw_cb->ReqQAddrHi = cpu_to_le32(MSDW(ha->request_dma));
- init_fw_cb->ComplQAddrLo = cpu_to_le32(LSDW(ha->response_dma));
- init_fw_cb->ComplQAddrHi = cpu_to_le32(MSDW(ha->response_dma));
- init_fw_cb->ShadowRegBufAddrLo =
+ init_fw_cb->pri.rqq_consumer_idx = cpu_to_le16(ha->request_out);
+ init_fw_cb->pri.compq_producer_idx = cpu_to_le16(ha->response_in);
+ init_fw_cb->pri.rqq_len = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH);
+ init_fw_cb->pri.compq_len = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH);
+ init_fw_cb->pri.rqq_addr_lo = cpu_to_le32(LSDW(ha->request_dma));
+ init_fw_cb->pri.rqq_addr_hi = cpu_to_le32(MSDW(ha->request_dma));
+ init_fw_cb->pri.compq_addr_lo = cpu_to_le32(LSDW(ha->response_dma));
+ init_fw_cb->pri.compq_addr_hi = cpu_to_le32(MSDW(ha->response_dma));
+ init_fw_cb->pri.shdwreg_addr_lo =
cpu_to_le32(LSDW(ha->shadow_regs_dma));
- init_fw_cb->ShadowRegBufAddrHi =
+ init_fw_cb->pri.shdwreg_addr_hi =
cpu_to_le32(MSDW(ha->shadow_regs_dma));
/* Set up required options. */
- init_fw_cb->FwOptions |=
+ init_fw_cb->pri.fw_options |=
__constant_cpu_to_le16(FWOPT_SESSION_MODE |
FWOPT_INITIATOR_MODE);
- init_fw_cb->FwOptions &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
+ init_fw_cb->pri.fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
/* Save some info in adapter structure. */
- ha->firmware_options = le16_to_cpu(init_fw_cb->FwOptions);
- ha->tcp_options = le16_to_cpu(init_fw_cb->TCPOptions);
- ha->heartbeat_interval = init_fw_cb->HeartbeatInterval;
- memcpy(ha->ip_address, init_fw_cb->IPAddr,
- min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr)));
- memcpy(ha->subnet_mask, init_fw_cb->SubnetMask,
- min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask)));
- memcpy(ha->gateway, init_fw_cb->GatewayIPAddr,
- min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr)));
- memcpy(ha->name_string, init_fw_cb->iSCSINameString,
+ ha->firmware_options = le16_to_cpu(init_fw_cb->pri.fw_options);
+ ha->tcp_options = le16_to_cpu(init_fw_cb->pri.ipv4_tcp_opts);
+ ha->heartbeat_interval = init_fw_cb->pri.hb_interval;
+ memcpy(ha->ip_address, init_fw_cb->pri.ipv4_addr,
+ min(sizeof(ha->ip_address), sizeof(init_fw_cb->pri.ipv4_addr)));
+ memcpy(ha->subnet_mask, init_fw_cb->pri.ipv4_subnet,
+ min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->pri.ipv4_subnet)));
+ memcpy(ha->gateway, init_fw_cb->pri.ipv4_gw_addr,
+ min(sizeof(ha->gateway), sizeof(init_fw_cb->pri.ipv4_gw_addr)));
+ memcpy(ha->name_string, init_fw_cb->pri.iscsi_name,
min(sizeof(ha->name_string),
- sizeof(init_fw_cb->iSCSINameString)));
- memcpy(ha->alias, init_fw_cb->Alias,
- min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));
+ sizeof(init_fw_cb->pri.iscsi_name)));
+ /*memcpy(ha->alias, init_fw_cb->Alias,
+ min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/
/* Save Command Line Paramater info */
- ha->port_down_retry_count = le16_to_cpu(init_fw_cb->KeepAliveTimeout);
+ ha->port_down_retry_count = le16_to_cpu(init_fw_cb->pri.conn_ka_timeout);
ha->discovery_wait = ql4xdiscoverywait;
/* Send Initialize Firmware Control Block. */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE;
mbox_cmd[1] = 0;
mbox_cmd[2] = LSDW(init_fw_cb_dma);
mbox_cmd[3] = MSDW(init_fw_cb_dma);
- if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) ==
+ mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk);
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) ==
QLA_SUCCESS)
status = QLA_SUCCESS;
else {
@@ -368,12 +301,14 @@
/* Get Initialize Firmware Control Block. */
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk));
mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
mbox_cmd[2] = LSDW(init_fw_cb_dma);
mbox_cmd[3] = MSDW(init_fw_cb_dma);
+ mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk);
- if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n",
ha->host_no, __func__));
@@ -384,12 +319,12 @@
}
/* Save IP Address. */
- memcpy(ha->ip_address, init_fw_cb->IPAddr,
- min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr)));
- memcpy(ha->subnet_mask, init_fw_cb->SubnetMask,
- min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask)));
- memcpy(ha->gateway, init_fw_cb->GatewayIPAddr,
- min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr)));
+ memcpy(ha->ip_address, init_fw_cb->pri.ipv4_addr,
+ min(sizeof(ha->ip_address), sizeof(init_fw_cb->pri.ipv4_addr)));
+ memcpy(ha->subnet_mask, init_fw_cb->pri.ipv4_subnet,
+ min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->pri.ipv4_subnet)));
+ memcpy(ha->gateway, init_fw_cb->pri.ipv4_gw_addr,
+ min(sizeof(ha->gateway), sizeof(init_fw_cb->pri.ipv4_gw_addr)));
dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk),
init_fw_cb, init_fw_cb_dma);
@@ -409,8 +344,10 @@
/* Get firmware version */
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_GET_FW_STATE;
- if (qla4xxx_mailbox_command(ha, 1, 4, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 4, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ "
"status %04X\n", ha->host_no, __func__,
@@ -438,8 +375,10 @@
/* Get firmware version */
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_GET_FW_STATUS;
- if (qla4xxx_mailbox_command(ha, 1, 3, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ "
"status %04X\n", ha->host_no, __func__,
@@ -491,11 +430,14 @@
}
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY;
mbox_cmd[1] = (uint32_t) fw_ddb_index;
mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
- if (qla4xxx_mailbox_command(ha, 4, 7, &mbox_cmd[0], &mbox_sts[0]) ==
+ mbox_cmd[4] = sizeof(struct dev_db_entry);
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 7, &mbox_cmd[0], &mbox_sts[0]) ==
QLA_ERROR) {
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed"
" with status 0x%04X\n", ha->host_no, __func__,
@@ -512,11 +454,11 @@
dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d "
"State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n",
fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3],
- mbox_sts[4], mbox_sts[5], fw_ddb_entry->ipAddr[0],
- fw_ddb_entry->ipAddr[1], fw_ddb_entry->ipAddr[2],
- fw_ddb_entry->ipAddr[3],
- le16_to_cpu(fw_ddb_entry->portNumber),
- fw_ddb_entry->iscsiName);
+ mbox_sts[4], mbox_sts[5], fw_ddb_entry->ip_addr[0],
+ fw_ddb_entry->ip_addr[1], fw_ddb_entry->ip_addr[2],
+ fw_ddb_entry->ip_addr[3],
+ le16_to_cpu(fw_ddb_entry->port),
+ fw_ddb_entry->iscsi_name);
}
if (num_valid_ddb_entries)
*num_valid_ddb_entries = mbox_sts[2];
@@ -571,36 +513,11 @@
mbox_cmd[1] = (uint32_t) fw_ddb_index;
mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
- return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
+ mbox_cmd[4] = sizeof(struct dev_db_entry);
+
+ return qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]);
}
-#if 0
-int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
- uint16_t fw_ddb_index)
-{
- int status = QLA_ERROR;
- uint32_t mbox_cmd[MBOX_REG_COUNT];
- uint32_t mbox_sts[MBOX_REG_COUNT];
-
- /* Do not wait for completion. The firmware will send us an
- * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
- */
- memset(&mbox_cmd, 0, sizeof(mbox_cmd));
- memset(&mbox_sts, 0, sizeof(mbox_sts));
- mbox_cmd[0] = MBOX_CMD_CONN_OPEN_SESS_LOGIN;
- mbox_cmd[1] = (uint32_t) fw_ddb_index;
- mbox_cmd[2] = 0;
- mbox_cmd[3] = 0;
- mbox_cmd[4] = 0;
- status = qla4xxx_mailbox_command(ha, 4, 0, &mbox_cmd[0], &mbox_sts[0]);
- DEBUG2(printk("%s fw_ddb_index=%d status=%d mbx0_1=0x%x :0x%x\n",
- __func__, fw_ddb_index, status, mbox_sts[0],
- mbox_sts[1]);)
-
- return status;
-}
-#endif /* 0 */
-
/**
* qla4xxx_get_crash_record - retrieves crash record.
* @ha: Pointer to host adapter structure.
@@ -614,12 +531,14 @@
struct crash_record *crash_record = NULL;
dma_addr_t crash_record_dma = 0;
uint32_t crash_record_size = 0;
+
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_cmd));
/* Get size of crash record. */
mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
- if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve size!\n",
ha->host_no, __func__));
@@ -639,11 +558,15 @@
goto exit_get_crash_record;
/* Get Crash Record. */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_cmd));
+
mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
mbox_cmd[2] = LSDW(crash_record_dma);
mbox_cmd[3] = MSDW(crash_record_dma);
mbox_cmd[4] = crash_record_size;
- if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS)
goto exit_get_crash_record;
@@ -655,7 +578,6 @@
crash_record, crash_record_dma);
}
-#if 0
/**
* qla4xxx_get_conn_event_log - retrieves connection event log
* @ha: Pointer to host adapter structure.
@@ -678,7 +600,8 @@
/* Get size of crash record. */
mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
- if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS)
goto exit_get_event_log;
@@ -693,10 +616,14 @@
goto exit_get_event_log;
/* Get Crash Record. */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_cmd));
+
mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
mbox_cmd[2] = LSDW(event_log_dma);
mbox_cmd[3] = MSDW(event_log_dma);
- if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve event "
"log!\n", ha->host_no, __func__));
@@ -745,7 +672,6 @@
dma_free_coherent(&ha->pdev->dev, event_log_size, event_log,
event_log_dma);
}
-#endif /* 0 */
/**
* qla4xxx_reset_lun - issues LUN Reset
@@ -773,11 +699,13 @@
*/
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_LUN_RESET;
mbox_cmd[1] = ddb_entry->fw_ddb_index;
mbox_cmd[2] = lun << 8;
mbox_cmd[5] = 0x01; /* Immediate Command Enable */
- qla4xxx_mailbox_command(ha, 6, 1, &mbox_cmd[0], &mbox_sts[0]);
+
+ qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]);
if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE &&
mbox_sts[0] != MBOX_STS_COMMAND_ERROR)
status = QLA_ERROR;
@@ -794,12 +722,14 @@
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_READ_FLASH;
mbox_cmd[1] = LSDW(dma_addr);
mbox_cmd[2] = MSDW(dma_addr);
mbox_cmd[3] = offset;
mbox_cmd[4] = len;
- if (qla4xxx_mailbox_command(ha, 5, 2, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ "
"status %04X %04X, offset %08x, len %08x\n", ha->host_no,
@@ -825,8 +755,10 @@
/* Get firmware version. */
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_ABOUT_FW;
- if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_ABOUT_FW failed w/ "
"status %04X\n", ha->host_no, __func__, mbox_sts[0]));
@@ -855,7 +787,7 @@
mbox_cmd[2] = LSDW(dma_addr);
mbox_cmd[3] = MSDW(dma_addr);
- if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: failed status %04X\n",
ha->host_no, __func__, mbox_sts[0]));
@@ -875,7 +807,7 @@
mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY;
mbox_cmd[1] = MAX_PRST_DEV_DB_ENTRIES;
- if (qla4xxx_mailbox_command(ha, 2, 3, &mbox_cmd[0], &mbox_sts[0]) !=
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
if (mbox_sts[0] == MBOX_STS_COMMAND_ERROR) {
*ddb_index = mbox_sts[2];
@@ -918,23 +850,23 @@
if (ret_val != QLA_SUCCESS)
goto qla4xxx_send_tgts_exit;
- memset((void *)fw_ddb_entry->iSCSIAlias, 0,
- sizeof(fw_ddb_entry->iSCSIAlias));
+ memset(fw_ddb_entry->iscsi_alias, 0,
+ sizeof(fw_ddb_entry->iscsi_alias));
- memset((void *)fw_ddb_entry->iscsiName, 0,
- sizeof(fw_ddb_entry->iscsiName));
+ memset(fw_ddb_entry->iscsi_name, 0,
+ sizeof(fw_ddb_entry->iscsi_name));
- memset((void *)fw_ddb_entry->ipAddr, 0, sizeof(fw_ddb_entry->ipAddr));
- memset((void *)fw_ddb_entry->targetAddr, 0,
- sizeof(fw_ddb_entry->targetAddr));
+ memset(fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr));
+ memset(fw_ddb_entry->tgt_addr, 0,
+ sizeof(fw_ddb_entry->tgt_addr));
fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET);
- fw_ddb_entry->portNumber = cpu_to_le16(ntohs(port));
+ fw_ddb_entry->port = cpu_to_le16(ntohs(port));
- fw_ddb_entry->ipAddr[0] = *ip;
- fw_ddb_entry->ipAddr[1] = *(ip + 1);
- fw_ddb_entry->ipAddr[2] = *(ip + 2);
- fw_ddb_entry->ipAddr[3] = *(ip + 3);
+ fw_ddb_entry->ip_addr[0] = *ip;
+ fw_ddb_entry->ip_addr[1] = *(ip + 1);
+ fw_ddb_entry->ip_addr[2] = *(ip + 2);
+ fw_ddb_entry->ip_addr[3] = *(ip + 3);
ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma);
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c
index 58afd13..7fe0482 100644
--- a/drivers/scsi/qla4xxx/ql4_nvram.c
+++ b/drivers/scsi/qla4xxx/ql4_nvram.c
@@ -6,6 +6,9 @@
*/
#include "ql4_def.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
static inline void eeprom_cmd(uint32_t cmd, struct scsi_qla_host *ha)
{
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index da21f5f..e69160a 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -10,6 +10,10 @@
#include <scsi/scsicam.h>
#include "ql4_def.h"
+#include "ql4_version.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
/*
* Driver version
@@ -50,12 +54,15 @@
/*
* iSCSI template entry points
*/
-static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no,
- uint32_t enable, struct sockaddr *dst_addr);
+static int qla4xxx_tgt_dscvr(struct Scsi_Host *shost,
+ enum iscsi_tgt_dscvr type, uint32_t enable,
+ struct sockaddr *dst_addr);
static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
enum iscsi_param param, char *buf);
static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
enum iscsi_param param, char *buf);
+static int qla4xxx_host_get_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf);
static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag);
static int qla4xxx_conn_start(struct iscsi_cls_conn *conn);
static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
@@ -95,16 +102,20 @@
static struct iscsi_transport qla4xxx_iscsi_transport = {
.owner = THIS_MODULE,
.name = DRIVER_NAME,
- .param_mask = ISCSI_CONN_PORT |
- ISCSI_CONN_ADDRESS |
- ISCSI_TARGET_NAME |
- ISCSI_TPGT,
+ .caps = CAP_FW_DB | CAP_SENDTARGETS_OFFLOAD |
+ CAP_DATA_PATH_OFFLOAD,
+ .param_mask = ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS |
+ ISCSI_TARGET_NAME | ISCSI_TPGT,
+ .host_param_mask = ISCSI_HOST_HWADDRESS |
+ ISCSI_HOST_IPADDRESS |
+ ISCSI_HOST_INITIATOR_NAME,
.sessiondata_size = sizeof(struct ddb_entry),
.host_template = &qla4xxx_driver_template,
.tgt_dscvr = qla4xxx_tgt_dscvr,
.get_conn_param = qla4xxx_conn_get_param,
.get_session_param = qla4xxx_sess_get_param,
+ .get_host_param = qla4xxx_host_get_param,
.start_conn = qla4xxx_conn_start,
.stop_conn = qla4xxx_conn_stop,
.session_recovery_timedout = qla4xxx_recovery_timedout,
@@ -161,6 +172,43 @@
printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);
}
+static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
+{
+ int i;
+ char *cp = buf;
+
+ for (i = 0; i < len; i++)
+ cp += sprintf(cp, "%02x%c", addr[i],
+ i == (len - 1) ? '\n' : ':');
+ return cp - buf;
+}
+
+
+static int qla4xxx_host_get_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf)
+{
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ int len;
+
+ switch (param) {
+ case ISCSI_HOST_PARAM_HWADDRESS:
+ len = format_addr(buf, ha->my_mac, MAC_ADDR_LEN);
+ break;
+ case ISCSI_HOST_PARAM_IPADDRESS:
+ len = sprintf(buf, "%d.%d.%d.%d\n", ha->ip_address[0],
+ ha->ip_address[1], ha->ip_address[2],
+ ha->ip_address[3]);
+ break;
+ case ISCSI_HOST_PARAM_INITIATOR_NAME:
+ len = sprintf(buf, "%s\n", ha->name_string);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+
static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
enum iscsi_param param, char *buf)
{
@@ -208,21 +256,15 @@
return len;
}
-static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no,
- uint32_t enable, struct sockaddr *dst_addr)
+static int qla4xxx_tgt_dscvr(struct Scsi_Host *shost,
+ enum iscsi_tgt_dscvr type, uint32_t enable,
+ struct sockaddr *dst_addr)
{
struct scsi_qla_host *ha;
- struct Scsi_Host *shost;
struct sockaddr_in *addr;
struct sockaddr_in6 *addr6;
int ret = 0;
- shost = scsi_host_lookup(host_no);
- if (IS_ERR(shost)) {
- printk(KERN_ERR "Could not find host no %u\n", host_no);
- return -ENODEV;
- }
-
ha = (struct scsi_qla_host *) shost->hostdata;
switch (type) {
@@ -246,8 +288,6 @@
default:
ret = -ENOSYS;
}
-
- scsi_host_put(shost);
return ret;
}
@@ -369,14 +409,7 @@
struct scsi_cmnd *cmd = srb->cmd;
if (srb->flags & SRB_DMA_VALID) {
- if (cmd->use_sg) {
- pci_unmap_sg(ha->pdev, cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- } else if (cmd->request_bufflen) {
- pci_unmap_single(ha->pdev, srb->dma_handle,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
srb->flags &= ~SRB_DMA_VALID;
}
cmd->SCp.ptr = NULL;
@@ -711,7 +744,7 @@
return stat;
}
-static void qla4xxx_hw_reset(struct scsi_qla_host *ha)
+void qla4xxx_hw_reset(struct scsi_qla_host *ha)
{
uint32_t ctrl_status;
unsigned long flags = 0;
@@ -1081,13 +1114,13 @@
if (ha->timer_active)
qla4xxx_stop_timer(ha);
- /* free extra memory */
- qla4xxx_mem_free(ha);
-
/* Detach interrupts */
if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags))
free_irq(ha->pdev->irq, ha);
+ /* free extra memory */
+ qla4xxx_mem_free(ha);
+
pci_disable_device(ha->pdev);
}
@@ -1332,6 +1365,11 @@
ha = pci_get_drvdata(pdev);
+ qla4xxx_disable_intrs(ha);
+
+ while (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags))
+ ssleep(1);
+
/* remove devs from iscsi_sessions to scsi_devices */
qla4xxx_free_ddb_list(ha);
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index e5183a69..ab984cb 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -5,4 +5,5 @@
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.00.07-k1"
+#define QLA4XXX_DRIVER_VERSION "5.01.00-k8"
+
diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c
index 2e7db18..2bfbf26 100644
--- a/drivers/scsi/qlogicfas408.c
+++ b/drivers/scsi/qlogicfas408.c
@@ -265,8 +265,6 @@
unsigned int message; /* scsi returned message */
unsigned int phase; /* recorded scsi phase */
unsigned int reqlen; /* total length of transfer */
- struct scatterlist *sglist; /* scatter-gather list pointer */
- unsigned int sgcount; /* sg counter */
char *buf;
struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
int qbase = priv->qbase;
@@ -301,9 +299,10 @@
if (inb(qbase + 7) & 0x1f) /* if some bytes in fifo */
outb(1, qbase + 3); /* clear fifo */
/* note that request_bufflen is the total xfer size when sg is used */
- reqlen = cmd->request_bufflen;
+ reqlen = scsi_bufflen(cmd);
/* note that it won't work if transfers > 16M are requested */
if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */
+ struct scatterlist *sg;
rtrc(2)
outb(reqlen, qbase); /* low-mid xfer cnt */
outb(reqlen >> 8, qbase + 1); /* low-mid xfer cnt */
@@ -311,23 +310,16 @@
outb(0x90, qbase + 3); /* command do xfer */
/* PIO pseudo DMA to buffer or sglist */
REG1;
- if (!cmd->use_sg)
- ql_pdma(priv, phase, cmd->request_buffer,
- cmd->request_bufflen);
- else {
- sgcount = cmd->use_sg;
- sglist = cmd->request_buffer;
- while (sgcount--) {
- if (priv->qabort) {
- REG0;
- return ((priv->qabort == 1 ?
- DID_ABORT : DID_RESET) << 16);
- }
- buf = page_address(sglist->page) + sglist->offset;
- if (ql_pdma(priv, phase, buf, sglist->length))
- break;
- sglist++;
+
+ scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
+ if (priv->qabort) {
+ REG0;
+ return ((priv->qabort == 1 ?
+ DID_ABORT : DID_RESET) << 16);
}
+ buf = page_address(sg->page) + sg->offset;
+ if (ql_pdma(priv, phase, buf, sg->length))
+ break;
}
REG0;
rtrc(2)
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 4c1e313..a691dda 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -368,7 +368,7 @@
if (level > 3) {
printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
" done = 0x%p, queuecommand 0x%p\n",
- cmd->request_buffer, cmd->request_bufflen,
+ scsi_sglist(cmd), scsi_bufflen(cmd),
cmd->done,
cmd->device->host->hostt->queuecommand);
@@ -1016,52 +1016,6 @@
}
EXPORT_SYMBOL(scsi_device_lookup);
-/**
- * scsi_device_cancel - cancel outstanding IO to this device
- * @sdev: Pointer to struct scsi_device
- * @recovery: Boolean instructing function to recover device or not.
- *
- **/
-int scsi_device_cancel(struct scsi_device *sdev, int recovery)
-{
- struct scsi_cmnd *scmd;
- LIST_HEAD(active_list);
- struct list_head *lh, *lh_sf;
- unsigned long flags;
-
- scsi_device_set_state(sdev, SDEV_CANCEL);
-
- spin_lock_irqsave(&sdev->list_lock, flags);
- list_for_each_entry(scmd, &sdev->cmd_list, list) {
- if (scmd->request) {
- /*
- * If we are unable to remove the timer, it means
- * that the command has already timed out or
- * finished.
- */
- if (!scsi_delete_timer(scmd))
- continue;
- list_add_tail(&scmd->eh_entry, &active_list);
- }
- }
- spin_unlock_irqrestore(&sdev->list_lock, flags);
-
- if (!list_empty(&active_list)) {
- list_for_each_safe(lh, lh_sf, &active_list) {
- scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
- list_del_init(lh);
- if (recovery &&
- !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD)) {
- scmd->result = (DID_ABORT << 16);
- scsi_finish_command(scmd);
- }
- }
- }
-
- return 0;
-}
-EXPORT_SYMBOL(scsi_device_cancel);
-
MODULE_DESCRIPTION("SCSI core");
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 06229f2..4cd9c58 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -2405,7 +2405,7 @@
MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
-MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)");
+MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 18dd5cc..19c44f0 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -128,6 +128,7 @@
{"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN},
{"AFT PRO", "-IX CF", "0.0>", BLIST_FORCELUN},
{"BELKIN", "USB 2 HS-CF", "1.95", BLIST_FORCELUN | BLIST_INQUIRY_36},
+ {"BROWNIE", "1200U3P", NULL, BLIST_NOREPORTLUN},
{"BROWNIE", "1600U3P", NULL, BLIST_NOREPORTLUN},
{"CANON", "IPUBJD", NULL, BLIST_SPARSELUN},
{"CBOX3", "USB Storage-SMC", "300A", BLIST_FORCELUN | BLIST_INQUIRY_36},
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index e8350c5..9adb64a 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -18,12 +18,12 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
-#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
+#include <linux/scatterlist.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -640,16 +640,8 @@
memcpy(scmd->cmnd, cmnd, cmnd_size);
if (copy_sense) {
- gfp_t gfp_mask = GFP_ATOMIC;
-
- if (shost->hostt->unchecked_isa_dma)
- gfp_mask |= __GFP_DMA;
-
- sgl.page = alloc_page(gfp_mask);
- if (!sgl.page)
- return FAILED;
- sgl.offset = 0;
- sgl.length = 252;
+ sg_init_one(&sgl, scmd->sense_buffer,
+ sizeof(scmd->sense_buffer));
scmd->sc_data_direction = DMA_FROM_DEVICE;
scmd->request_bufflen = sgl.length;
@@ -720,18 +712,6 @@
/*
- * Last chance to have valid sense data.
- */
- if (copy_sense) {
- if (!SCSI_SENSE_VALID(scmd)) {
- memcpy(scmd->sense_buffer, page_address(sgl.page),
- sizeof(scmd->sense_buffer));
- }
- __free_page(sgl.page);
- }
-
-
- /*
* Restore original data
*/
scmd->request_buffer = old_buffer;
diff --git a/drivers/scsi/scsi_lib_dma.c b/drivers/scsi/scsi_lib_dma.c
new file mode 100644
index 0000000..ac6855c
--- /dev/null
+++ b/drivers/scsi/scsi_lib_dma.c
@@ -0,0 +1,50 @@
+/*
+ * SCSI library functions depending on DMA
+ */
+
+#include <linux/blkdev.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+/**
+ * scsi_dma_map - perform DMA mapping against command's sg lists
+ * @cmd: scsi command
+ *
+ * Returns the number of sg lists actually used, zero if the sg lists
+ * is NULL, or -ENOMEM if the mapping failed.
+ */
+int scsi_dma_map(struct scsi_cmnd *cmd)
+{
+ int nseg = 0;
+
+ if (scsi_sg_count(cmd)) {
+ struct device *dev = cmd->device->host->shost_gendev.parent;
+
+ nseg = dma_map_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
+ cmd->sc_data_direction);
+ if (unlikely(!nseg))
+ return -ENOMEM;
+ }
+ return nseg;
+}
+EXPORT_SYMBOL(scsi_dma_map);
+
+/**
+ * scsi_dma_unmap - unmap command's sg lists mapped by scsi_dma_map
+ * @cmd: scsi command
+ */
+void scsi_dma_unmap(struct scsi_cmnd *cmd)
+{
+ if (scsi_sg_count(cmd)) {
+ struct device *dev = cmd->device->host->shost_gendev.parent;
+
+ dma_unmap_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
+ cmd->sc_data_direction);
+ }
+}
+EXPORT_SYMBOL(scsi_dma_unmap);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 662577f..a86e62f 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -703,16 +703,14 @@
/**
* scsi_add_lun - allocate and fully initialze a scsi_device
- * @sdevscan: holds information to be stored in the new scsi_device
- * @sdevnew: store the address of the newly allocated scsi_device
+ * @sdev: holds information to be stored in the new scsi_device
* @inq_result: holds the result of a previous INQUIRY to the LUN
* @bflags: black/white list flag
+ * @async: 1 if this device is being scanned asynchronously
*
* Description:
- * Allocate and initialize a scsi_device matching sdevscan. Optionally
- * set fields based on values in *@bflags. If @sdevnew is not
- * NULL, store the address of the new scsi_device in *@sdevnew (needed
- * when scanning a particular LUN).
+ * Initialize the scsi_device @sdev. Optionally set fields based
+ * on values in *@bflags.
*
* Return:
* SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device
@@ -752,25 +750,15 @@
sdev->rev = (char *) (sdev->inquiry + 32);
if (*bflags & BLIST_ISROM) {
- /*
- * It would be better to modify sdev->type, and set
- * sdev->removable; this can now be done since
- * print_inquiry has gone away.
- */
- inq_result[0] = TYPE_ROM;
- inq_result[1] |= 0x80; /* removable */
- } else if (*bflags & BLIST_NO_ULD_ATTACH)
- sdev->no_uld_attach = 1;
+ sdev->type = TYPE_ROM;
+ sdev->removable = 1;
+ } else {
+ sdev->type = (inq_result[0] & 0x1f);
+ sdev->removable = (inq_result[1] & 0x80) >> 7;
+ }
- switch (sdev->type = (inq_result[0] & 0x1f)) {
+ switch (sdev->type) {
case TYPE_RBC:
- /* RBC devices can return SCSI-3 compliance and yet
- * still not support REPORT LUNS, so make them act as
- * BLIST_NOREPORTLUN unless BLIST_REPORTLUN2 is
- * specifically set */
- if ((*bflags & BLIST_REPORTLUN2) == 0)
- *bflags |= BLIST_NOREPORTLUN;
- /* fall through */
case TYPE_TAPE:
case TYPE_DISK:
case TYPE_PRINTER:
@@ -784,13 +772,6 @@
sdev->writeable = 1;
break;
case TYPE_ROM:
- /* MMC devices can return SCSI-3 compliance and yet
- * still not support REPORT LUNS, so make them act as
- * BLIST_NOREPORTLUN unless BLIST_REPORTLUN2 is
- * specifically set */
- if ((*bflags & BLIST_REPORTLUN2) == 0)
- *bflags |= BLIST_NOREPORTLUN;
- /* fall through */
case TYPE_WORM:
sdev->writeable = 0;
break;
@@ -798,6 +779,15 @@
printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type);
}
+ if (sdev->type == TYPE_RBC || sdev->type == TYPE_ROM) {
+ /* RBC and MMC devices can return SCSI-3 compliance and yet
+ * still not support REPORT LUNS, so make them act as
+ * BLIST_NOREPORTLUN unless BLIST_REPORTLUN2 is
+ * specifically set */
+ if ((*bflags & BLIST_REPORTLUN2) == 0)
+ *bflags |= BLIST_NOREPORTLUN;
+ }
+
/*
* For a peripheral qualifier (PQ) value of 1 (001b), the SCSI
* spec says: The device server is capable of supporting the
@@ -815,12 +805,11 @@
*/
sdev->inq_periph_qual = (inq_result[0] >> 5) & 7;
- sdev->removable = (0x80 & inq_result[1]) >> 7;
sdev->lockable = sdev->removable;
sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2);
- if (sdev->scsi_level >= SCSI_3 || (sdev->inquiry_len > 56 &&
- inq_result[56] & 0x04))
+ if (sdev->scsi_level >= SCSI_3 ||
+ (sdev->inquiry_len > 56 && inq_result[56] & 0x04))
sdev->ppr = 1;
if (inq_result[7] & 0x60)
sdev->wdtr = 1;
@@ -833,13 +822,10 @@
sdev->inq_periph_qual, inq_result[2] & 0x07,
(inq_result[3] & 0x0f) == 1 ? " CCS" : "");
- /*
- * End sysfs code.
- */
-
if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) &&
!(*bflags & BLIST_NOTQ))
sdev->tagged_supported = 1;
+
/*
* Some devices (Texel CD ROM drives) have handshaking problems
* when used with the Seagate controllers. borken is initialized
@@ -848,6 +834,9 @@
if ((*bflags & BLIST_BORKEN) == 0)
sdev->borken = 0;
+ if (*bflags & BLIST_NO_ULD_ATTACH)
+ sdev->no_uld_attach = 1;
+
/*
* Apparently some really broken devices (contrary to the SCSI
* standards) need to be selected without asserting ATN
@@ -872,7 +861,6 @@
if (*bflags & BLIST_SINGLELUN)
sdev->single_lun = 1;
-
sdev->use_10_for_rw = 1;
if (*bflags & BLIST_MS_SKIP_PAGE_08)
@@ -1213,7 +1201,7 @@
* Given a struct scsi_lun of: 0a 04 0b 03 00 00 00 00, this function returns
* the integer: 0x0b030a04
**/
-static int scsilun_to_int(struct scsi_lun *scsilun)
+int scsilun_to_int(struct scsi_lun *scsilun)
{
int i;
unsigned int lun;
@@ -1224,6 +1212,7 @@
scsilun->scsi_lun[i + 1]) << (i * 8));
return lun;
}
+EXPORT_SYMBOL(scsilun_to_int);
/**
* int_to_scsilun: reverts an int into a scsi_lun
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 67a38a1..ed72086 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -293,30 +293,18 @@
{
struct device_driver *drv = dev->driver;
struct scsi_device *sdev = to_scsi_device(dev);
- struct scsi_host_template *sht = sdev->host->hostt;
int err;
err = scsi_device_quiesce(sdev);
if (err)
return err;
- /* call HLD suspend first */
if (drv && drv->suspend) {
err = drv->suspend(dev, state);
if (err)
return err;
}
- /* then, call host suspend */
- if (sht->suspend) {
- err = sht->suspend(sdev, state);
- if (err) {
- if (drv && drv->resume)
- drv->resume(dev);
- return err;
- }
- }
-
return 0;
}
@@ -324,21 +312,14 @@
{
struct device_driver *drv = dev->driver;
struct scsi_device *sdev = to_scsi_device(dev);
- struct scsi_host_template *sht = sdev->host->hostt;
- int err = 0, err2 = 0;
+ int err = 0;
- /* call host resume first */
- if (sht->resume)
- err = sht->resume(sdev);
-
- /* then, call HLD resume */
if (drv && drv->resume)
- err2 = drv->resume(dev);
+ err = drv->resume(dev);
scsi_device_resume(sdev);
- /* favor LLD failure */
- return err ? err : err2;;
+ return err;
}
struct bus_type scsi_bus_type = {
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index b4d1ece..e882570 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -1,4 +1,4 @@
-/*
+/*
* FiberChannel transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
@@ -19,9 +19,10 @@
*
* ========
*
- * Copyright (C) 2004-2005 James Smart, Emulex Corporation
+ * Copyright (C) 2004-2007 James Smart, Emulex Corporation
* Rewrite for host, target, device, and remote port attributes,
* statistics, and service functions...
+ * Add vports, etc
*
*/
#include <linux/module.h>
@@ -37,6 +38,34 @@
#include "scsi_priv.h"
static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
+static void fc_vport_sched_delete(struct work_struct *work);
+
+/*
+ * This is a temporary carrier for creating a vport. It will eventually
+ * be replaced by a real message definition for sgio or netlink.
+ *
+ * fc_vport_identifiers: This set of data contains all elements
+ * to uniquely identify and instantiate a FC virtual port.
+ *
+ * Notes:
+ * symbolic_name: The driver is to append the symbolic_name string data
+ * to the symbolic_node_name data that it generates by default.
+ * the resulting combination should then be registered with the switch.
+ * It is expected that things like Xen may stuff a VM title into
+ * this field.
+ */
+struct fc_vport_identifiers {
+ u64 node_name;
+ u64 port_name;
+ u32 roles;
+ bool disable;
+ enum fc_port_type vport_type; /* only FC_PORTTYPE_NPIV allowed */
+ char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
+};
+
+static int fc_vport_create(struct Scsi_Host *shost, int channel,
+ struct device *pdev, struct fc_vport_identifiers *ids,
+ struct fc_vport **vport);
/*
* Redefine so that we can have same named attributes in the
@@ -90,10 +119,14 @@
{ FC_PORTTYPE_NLPORT, "NLPort (fabric via loop)" },
{ FC_PORTTYPE_LPORT, "LPort (private loop)" },
{ FC_PORTTYPE_PTP, "Point-To-Point (direct nport connection" },
+ { FC_PORTTYPE_NPIV, "NPIV VPORT" },
};
fc_enum_name_search(port_type, fc_port_type, fc_port_type_names)
#define FC_PORTTYPE_MAX_NAMELEN 50
+/* Reuse fc_port_type enum function for vport_type */
+#define get_fc_vport_type_name get_fc_port_type_name
+
/* Convert fc_host_event_code values to ascii string name */
static const struct {
@@ -139,6 +172,29 @@
#define FC_PORTSTATE_MAX_NAMELEN 20
+/* Convert fc_vport_state values to ascii string name */
+static struct {
+ enum fc_vport_state value;
+ char *name;
+} fc_vport_state_names[] = {
+ { FC_VPORT_UNKNOWN, "Unknown" },
+ { FC_VPORT_ACTIVE, "Active" },
+ { FC_VPORT_DISABLED, "Disabled" },
+ { FC_VPORT_LINKDOWN, "Linkdown" },
+ { FC_VPORT_INITIALIZING, "Initializing" },
+ { FC_VPORT_NO_FABRIC_SUPP, "No Fabric Support" },
+ { FC_VPORT_NO_FABRIC_RSCS, "No Fabric Resources" },
+ { FC_VPORT_FABRIC_LOGOUT, "Fabric Logout" },
+ { FC_VPORT_FABRIC_REJ_WWN, "Fabric Rejected WWN" },
+ { FC_VPORT_FAILED, "VPort Failed" },
+};
+fc_enum_name_search(vport_state, fc_vport_state, fc_vport_state_names)
+#define FC_VPORTSTATE_MAX_NAMELEN 24
+
+/* Reuse fc_vport_state enum function for vport_last_state */
+#define get_fc_vport_last_state_name get_fc_vport_state_name
+
+
/* Convert fc_tgtid_binding_type values to ascii string name */
static const struct {
enum fc_tgtid_binding_type value;
@@ -219,16 +275,16 @@
}
-/* Convert FC_RPORT_ROLE bit values to ascii string name */
+/* Convert FC_PORT_ROLE bit values to ascii string name */
static const struct {
u32 value;
char *name;
-} fc_remote_port_role_names[] = {
- { FC_RPORT_ROLE_FCP_TARGET, "FCP Target" },
- { FC_RPORT_ROLE_FCP_INITIATOR, "FCP Initiator" },
- { FC_RPORT_ROLE_IP_PORT, "IP Port" },
+} fc_port_role_names[] = {
+ { FC_PORT_ROLE_FCP_TARGET, "FCP Target" },
+ { FC_PORT_ROLE_FCP_INITIATOR, "FCP Initiator" },
+ { FC_PORT_ROLE_IP_PORT, "IP Port" },
};
-fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)
+fc_bitfield_name_search(port_roles, fc_port_role_names)
/*
* Define roles that are specific to port_id. Values are relative to ROLE_MASK.
@@ -252,7 +308,8 @@
*/
#define FC_STARGET_NUM_ATTRS 3
#define FC_RPORT_NUM_ATTRS 10
-#define FC_HOST_NUM_ATTRS 17
+#define FC_VPORT_NUM_ATTRS 9
+#define FC_HOST_NUM_ATTRS 21
struct fc_internal {
struct scsi_transport_template t;
@@ -278,6 +335,10 @@
struct transport_container rport_attr_cont;
struct class_device_attribute private_rport_attrs[FC_RPORT_NUM_ATTRS];
struct class_device_attribute *rport_attrs[FC_RPORT_NUM_ATTRS + 1];
+
+ struct transport_container vport_attr_cont;
+ struct class_device_attribute private_vport_attrs[FC_VPORT_NUM_ATTRS];
+ struct class_device_attribute *vport_attrs[FC_VPORT_NUM_ATTRS + 1];
};
#define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t)
@@ -318,7 +379,7 @@
struct Scsi_Host *shost = dev_to_shost(dev);
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
- /*
+ /*
* Set default values easily detected by the midlayer as
* failure cases. The scsi lldd is responsible for initializing
* all transport attributes to valid values per host.
@@ -331,6 +392,7 @@
sizeof(fc_host->supported_fc4s));
fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN;
fc_host->maxframe_size = -1;
+ fc_host->max_npiv_vports = 0;
memset(fc_host->serial_number, 0,
sizeof(fc_host->serial_number));
@@ -348,8 +410,11 @@
INIT_LIST_HEAD(&fc_host->rports);
INIT_LIST_HEAD(&fc_host->rport_bindings);
+ INIT_LIST_HEAD(&fc_host->vports);
fc_host->next_rport_number = 0;
fc_host->next_target_id = 0;
+ fc_host->next_vport_number = 0;
+ fc_host->npiv_vports_inuse = 0;
snprintf(fc_host->work_q_name, KOBJ_NAME_LEN, "fc_wq_%d",
shost->host_no);
@@ -388,6 +453,16 @@
NULL);
/*
+ * Setup and Remove actions for virtual ports are handled
+ * in the service functions below.
+ */
+static DECLARE_TRANSPORT_CLASS(fc_vport_class,
+ "fc_vports",
+ NULL,
+ NULL,
+ NULL);
+
+/*
* Module Parameters
*/
@@ -585,6 +660,9 @@
error = transport_class_register(&fc_host_class);
if (error)
return error;
+ error = transport_class_register(&fc_vport_class);
+ if (error)
+ return error;
error = transport_class_register(&fc_rport_class);
if (error)
return error;
@@ -596,6 +674,7 @@
transport_class_unregister(&fc_transport_class);
transport_class_unregister(&fc_rport_class);
transport_class_unregister(&fc_host_class);
+ transport_class_unregister(&fc_vport_class);
}
/*
@@ -800,9 +879,9 @@
return snprintf(buf, 30, "Unknown Fabric Entity\n");
}
} else {
- if (rport->roles == FC_RPORT_ROLE_UNKNOWN)
+ if (rport->roles == FC_PORT_ROLE_UNKNOWN)
return snprintf(buf, 20, "unknown\n");
- return get_fc_remote_port_roles_names(rport->roles, buf);
+ return get_fc_port_roles_names(rport->roles, buf);
}
}
static FC_CLASS_DEVICE_ATTR(rport, roles, S_IRUGO,
@@ -857,7 +936,7 @@
/*
* Note: in the target show function we recognize when the remote
- * port is in the hierarchy and do not allow the driver to get
+ * port is in the heirarchy and do not allow the driver to get
* involved in sysfs functions. The driver only gets involved if
* it's the "old" style that doesn't use rports.
*/
@@ -912,6 +991,257 @@
/*
+ * FC Virtual Port Attribute Management
+ */
+
+#define fc_vport_show_function(field, format_string, sz, cast) \
+static ssize_t \
+show_fc_vport_##field (struct class_device *cdev, char *buf) \
+{ \
+ struct fc_vport *vport = transport_class_to_vport(cdev); \
+ struct Scsi_Host *shost = vport_to_shost(vport); \
+ struct fc_internal *i = to_fc_internal(shost->transportt); \
+ if ((i->f->get_vport_##field) && \
+ !(vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING))) \
+ i->f->get_vport_##field(vport); \
+ return snprintf(buf, sz, format_string, cast vport->field); \
+}
+
+#define fc_vport_store_function(field) \
+static ssize_t \
+store_fc_vport_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ int val; \
+ struct fc_vport *vport = transport_class_to_vport(cdev); \
+ struct Scsi_Host *shost = vport_to_shost(vport); \
+ struct fc_internal *i = to_fc_internal(shost->transportt); \
+ char *cp; \
+ if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) \
+ return -EBUSY; \
+ val = simple_strtoul(buf, &cp, 0); \
+ if (*cp && (*cp != '\n')) \
+ return -EINVAL; \
+ i->f->set_vport_##field(vport, val); \
+ return count; \
+}
+
+#define fc_vport_store_str_function(field, slen) \
+static ssize_t \
+store_fc_vport_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ struct fc_vport *vport = transport_class_to_vport(cdev); \
+ struct Scsi_Host *shost = vport_to_shost(vport); \
+ struct fc_internal *i = to_fc_internal(shost->transportt); \
+ unsigned int cnt=count; \
+ \
+ /* count may include a LF at end of string */ \
+ if (buf[cnt-1] == '\n') \
+ cnt--; \
+ if (cnt > ((slen) - 1)) \
+ return -EINVAL; \
+ memcpy(vport->field, buf, cnt); \
+ i->f->set_vport_##field(vport); \
+ return count; \
+}
+
+#define fc_vport_rd_attr(field, format_string, sz) \
+ fc_vport_show_function(field, format_string, sz, ) \
+static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO, \
+ show_fc_vport_##field, NULL)
+
+#define fc_vport_rd_attr_cast(field, format_string, sz, cast) \
+ fc_vport_show_function(field, format_string, sz, (cast)) \
+static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO, \
+ show_fc_vport_##field, NULL)
+
+#define fc_vport_rw_attr(field, format_string, sz) \
+ fc_vport_show_function(field, format_string, sz, ) \
+ fc_vport_store_function(field) \
+static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO | S_IWUSR, \
+ show_fc_vport_##field, \
+ store_fc_vport_##field)
+
+#define fc_private_vport_show_function(field, format_string, sz, cast) \
+static ssize_t \
+show_fc_vport_##field (struct class_device *cdev, char *buf) \
+{ \
+ struct fc_vport *vport = transport_class_to_vport(cdev); \
+ return snprintf(buf, sz, format_string, cast vport->field); \
+}
+
+#define fc_private_vport_store_u32_function(field) \
+static ssize_t \
+store_fc_vport_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ u32 val; \
+ struct fc_vport *vport = transport_class_to_vport(cdev); \
+ char *cp; \
+ if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) \
+ return -EBUSY; \
+ val = simple_strtoul(buf, &cp, 0); \
+ if (*cp && (*cp != '\n')) \
+ return -EINVAL; \
+ vport->field = val; \
+ return count; \
+}
+
+
+#define fc_private_vport_rd_attr(field, format_string, sz) \
+ fc_private_vport_show_function(field, format_string, sz, ) \
+static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO, \
+ show_fc_vport_##field, NULL)
+
+#define fc_private_vport_rd_attr_cast(field, format_string, sz, cast) \
+ fc_private_vport_show_function(field, format_string, sz, (cast)) \
+static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO, \
+ show_fc_vport_##field, NULL)
+
+#define fc_private_vport_rw_u32_attr(field, format_string, sz) \
+ fc_private_vport_show_function(field, format_string, sz, ) \
+ fc_private_vport_store_u32_function(field) \
+static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO | S_IWUSR, \
+ show_fc_vport_##field, \
+ store_fc_vport_##field)
+
+
+#define fc_private_vport_rd_enum_attr(title, maxlen) \
+static ssize_t \
+show_fc_vport_##title (struct class_device *cdev, char *buf) \
+{ \
+ struct fc_vport *vport = transport_class_to_vport(cdev); \
+ const char *name; \
+ name = get_fc_##title##_name(vport->title); \
+ if (!name) \
+ return -EINVAL; \
+ return snprintf(buf, maxlen, "%s\n", name); \
+} \
+static FC_CLASS_DEVICE_ATTR(vport, title, S_IRUGO, \
+ show_fc_vport_##title, NULL)
+
+
+#define SETUP_VPORT_ATTRIBUTE_RD(field) \
+ i->private_vport_attrs[count] = class_device_attr_vport_##field; \
+ i->private_vport_attrs[count].attr.mode = S_IRUGO; \
+ i->private_vport_attrs[count].store = NULL; \
+ i->vport_attrs[count] = &i->private_vport_attrs[count]; \
+ if (i->f->get_##field) \
+ count++
+ /* NOTE: Above MACRO differs: checks function not show bit */
+
+#define SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(field) \
+ i->private_vport_attrs[count] = class_device_attr_vport_##field; \
+ i->private_vport_attrs[count].attr.mode = S_IRUGO; \
+ i->private_vport_attrs[count].store = NULL; \
+ i->vport_attrs[count] = &i->private_vport_attrs[count]; \
+ count++
+
+#define SETUP_VPORT_ATTRIBUTE_WR(field) \
+ i->private_vport_attrs[count] = class_device_attr_vport_##field; \
+ i->vport_attrs[count] = &i->private_vport_attrs[count]; \
+ if (i->f->field) \
+ count++
+ /* NOTE: Above MACRO differs: checks function */
+
+#define SETUP_VPORT_ATTRIBUTE_RW(field) \
+ i->private_vport_attrs[count] = class_device_attr_vport_##field; \
+ if (!i->f->set_vport_##field) { \
+ i->private_vport_attrs[count].attr.mode = S_IRUGO; \
+ i->private_vport_attrs[count].store = NULL; \
+ } \
+ i->vport_attrs[count] = &i->private_vport_attrs[count]; \
+ count++
+ /* NOTE: Above MACRO differs: does not check show bit */
+
+#define SETUP_PRIVATE_VPORT_ATTRIBUTE_RW(field) \
+{ \
+ i->private_vport_attrs[count] = class_device_attr_vport_##field; \
+ i->vport_attrs[count] = &i->private_vport_attrs[count]; \
+ count++; \
+}
+
+
+/* The FC Transport Virtual Port Attributes: */
+
+/* Fixed Virtual Port Attributes */
+
+/* Dynamic Virtual Port Attributes */
+
+/* Private Virtual Port Attributes */
+
+fc_private_vport_rd_enum_attr(vport_state, FC_VPORTSTATE_MAX_NAMELEN);
+fc_private_vport_rd_enum_attr(vport_last_state, FC_VPORTSTATE_MAX_NAMELEN);
+fc_private_vport_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long);
+fc_private_vport_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
+
+static ssize_t
+show_fc_vport_roles (struct class_device *cdev, char *buf)
+{
+ struct fc_vport *vport = transport_class_to_vport(cdev);
+
+ if (vport->roles == FC_PORT_ROLE_UNKNOWN)
+ return snprintf(buf, 20, "unknown\n");
+ return get_fc_port_roles_names(vport->roles, buf);
+}
+static FC_CLASS_DEVICE_ATTR(vport, roles, S_IRUGO, show_fc_vport_roles, NULL);
+
+fc_private_vport_rd_enum_attr(vport_type, FC_PORTTYPE_MAX_NAMELEN);
+
+fc_private_vport_show_function(symbolic_name, "%s\n",
+ FC_VPORT_SYMBOLIC_NAMELEN + 1, )
+fc_vport_store_str_function(symbolic_name, FC_VPORT_SYMBOLIC_NAMELEN)
+static FC_CLASS_DEVICE_ATTR(vport, symbolic_name, S_IRUGO | S_IWUSR,
+ show_fc_vport_symbolic_name, store_fc_vport_symbolic_name);
+
+static ssize_t
+store_fc_vport_delete(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct fc_vport *vport = transport_class_to_vport(cdev);
+ struct Scsi_Host *shost = vport_to_shost(vport);
+
+ fc_queue_work(shost, &vport->vport_delete_work);
+ return count;
+}
+static FC_CLASS_DEVICE_ATTR(vport, vport_delete, S_IWUSR,
+ NULL, store_fc_vport_delete);
+
+
+/*
+ * Enable/Disable vport
+ * Write "1" to disable, write "0" to enable
+ */
+static ssize_t
+store_fc_vport_disable(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct fc_vport *vport = transport_class_to_vport(cdev);
+ struct Scsi_Host *shost = vport_to_shost(vport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ int stat;
+
+ if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING))
+ return -EBUSY;
+
+ if (*buf == '0') {
+ if (vport->vport_state != FC_VPORT_DISABLED)
+ return -EALREADY;
+ } else if (*buf == '1') {
+ if (vport->vport_state == FC_VPORT_DISABLED)
+ return -EALREADY;
+ } else
+ return -EINVAL;
+
+ stat = i->f->vport_disable(vport, ((*buf == '0') ? false : true));
+ return stat ? stat : count;
+}
+static FC_CLASS_DEVICE_ATTR(vport, vport_disable, S_IWUSR,
+ NULL, store_fc_vport_disable);
+
+
+/*
* Host Attribute Management
*/
@@ -1003,6 +1333,13 @@
if (i->f->show_host_##field) \
count++
+#define SETUP_HOST_ATTRIBUTE_RD_NS(field) \
+ i->private_host_attrs[count] = class_device_attr_host_##field; \
+ i->private_host_attrs[count].attr.mode = S_IRUGO; \
+ i->private_host_attrs[count].store = NULL; \
+ i->host_attrs[count] = &i->private_host_attrs[count]; \
+ count++
+
#define SETUP_HOST_ATTRIBUTE_RW(field) \
i->private_host_attrs[count] = class_device_attr_host_##field; \
if (!i->f->set_host_##field) { \
@@ -1090,6 +1427,7 @@
fc_private_host_rd_attr_cast(permanent_port_name, "0x%llx\n", 20,
unsigned long long);
fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20);
+fc_private_host_rd_attr(max_npiv_vports, "%u\n", 20);
fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1));
@@ -1210,6 +1548,9 @@
static FC_CLASS_DEVICE_ATTR(host, issue_lip, S_IWUSR, NULL,
store_fc_private_host_issue_lip);
+fc_private_host_rd_attr(npiv_vports_inuse, "%u\n", 20);
+
+
/*
* Host Statistics Management
*/
@@ -1285,7 +1626,6 @@
static FC_CLASS_DEVICE_ATTR(host, reset_statistics, S_IWUSR, NULL,
fc_reset_statistics);
-
static struct attribute *fc_statistics_attrs[] = {
&class_device_attr_host_seconds_since_last_reset.attr,
&class_device_attr_host_tx_frames.attr,
@@ -1316,6 +1656,142 @@
.attrs = fc_statistics_attrs,
};
+
+/* Host Vport Attributes */
+
+static int
+fc_parse_wwn(const char *ns, u64 *nm)
+{
+ unsigned int i, j;
+ u8 wwn[8];
+
+ memset(wwn, 0, sizeof(wwn));
+
+ /* Validate and store the new name */
+ for (i=0, j=0; i < 16; i++) {
+ if ((*ns >= 'a') && (*ns <= 'f'))
+ j = ((j << 4) | ((*ns++ -'a') + 10));
+ else if ((*ns >= 'A') && (*ns <= 'F'))
+ j = ((j << 4) | ((*ns++ -'A') + 10));
+ else if ((*ns >= '0') && (*ns <= '9'))
+ j = ((j << 4) | (*ns++ -'0'));
+ else
+ return -EINVAL;
+ if (i % 2) {
+ wwn[i/2] = j & 0xff;
+ j = 0;
+ }
+ }
+
+ *nm = wwn_to_u64(wwn);
+
+ return 0;
+}
+
+
+/*
+ * "Short-cut" sysfs variable to create a new vport on a FC Host.
+ * Input is a string of the form "<WWPN>:<WWNN>". Other attributes
+ * will default to a NPIV-based FCP_Initiator; The WWNs are specified
+ * as hex characters, and may *not* contain any prefixes (e.g. 0x, x, etc)
+ */
+static ssize_t
+store_fc_host_vport_create(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct Scsi_Host *shost = transport_class_to_shost(cdev);
+ struct fc_vport_identifiers vid;
+ struct fc_vport *vport;
+ unsigned int cnt=count;
+ int stat;
+
+ memset(&vid, 0, sizeof(vid));
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ /* validate we have enough characters for WWPN */
+ if ((cnt != (16+1+16)) || (buf[16] != ':'))
+ return -EINVAL;
+
+ stat = fc_parse_wwn(&buf[0], &vid.port_name);
+ if (stat)
+ return stat;
+
+ stat = fc_parse_wwn(&buf[17], &vid.node_name);
+ if (stat)
+ return stat;
+
+ vid.roles = FC_PORT_ROLE_FCP_INITIATOR;
+ vid.vport_type = FC_PORTTYPE_NPIV;
+ /* vid.symbolic_name is already zero/NULL's */
+ vid.disable = false; /* always enabled */
+
+ /* we only allow support on Channel 0 !!! */
+ stat = fc_vport_create(shost, 0, &shost->shost_gendev, &vid, &vport);
+ return stat ? stat : count;
+}
+static FC_CLASS_DEVICE_ATTR(host, vport_create, S_IWUSR, NULL,
+ store_fc_host_vport_create);
+
+
+/*
+ * "Short-cut" sysfs variable to delete a vport on a FC Host.
+ * Vport is identified by a string containing "<WWPN>:<WWNN>".
+ * The WWNs are specified as hex characters, and may *not* contain
+ * any prefixes (e.g. 0x, x, etc)
+ */
+static ssize_t
+store_fc_host_vport_delete(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct Scsi_Host *shost = transport_class_to_shost(cdev);
+ struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
+ struct fc_vport *vport;
+ u64 wwpn, wwnn;
+ unsigned long flags;
+ unsigned int cnt=count;
+ int stat, match;
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ /* validate we have enough characters for WWPN */
+ if ((cnt != (16+1+16)) || (buf[16] != ':'))
+ return -EINVAL;
+
+ stat = fc_parse_wwn(&buf[0], &wwpn);
+ if (stat)
+ return stat;
+
+ stat = fc_parse_wwn(&buf[17], &wwnn);
+ if (stat)
+ return stat;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ match = 0;
+ /* we only allow support on Channel 0 !!! */
+ list_for_each_entry(vport, &fc_host->vports, peers) {
+ if ((vport->channel == 0) &&
+ (vport->port_name == wwpn) && (vport->node_name == wwnn)) {
+ match = 1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ if (!match)
+ return -ENODEV;
+
+ stat = fc_vport_terminate(vport);
+ return stat ? stat : count;
+}
+static FC_CLASS_DEVICE_ATTR(host, vport_delete, S_IWUSR, NULL,
+ store_fc_host_vport_delete);
+
+
static int fc_host_match(struct attribute_container *cont,
struct device *dev)
{
@@ -1387,6 +1863,40 @@
}
+static void fc_vport_dev_release(struct device *dev)
+{
+ struct fc_vport *vport = dev_to_vport(dev);
+ put_device(dev->parent); /* release kobj parent */
+ kfree(vport);
+}
+
+int scsi_is_fc_vport(const struct device *dev)
+{
+ return dev->release == fc_vport_dev_release;
+}
+EXPORT_SYMBOL(scsi_is_fc_vport);
+
+static int fc_vport_match(struct attribute_container *cont,
+ struct device *dev)
+{
+ struct fc_vport *vport;
+ struct Scsi_Host *shost;
+ struct fc_internal *i;
+
+ if (!scsi_is_fc_vport(dev))
+ return 0;
+ vport = dev_to_vport(dev);
+
+ shost = vport_to_shost(vport);
+ if (!shost->transportt || shost->transportt->host_attrs.ac.class
+ != &fc_host_class.class)
+ return 0;
+
+ i = to_fc_internal(shost->transportt);
+ return &i->vport_attr_cont.ac == cont;
+}
+
+
/**
* fc_timed_out - FC Transport I/O timeout intercept handler
*
@@ -1433,6 +1943,9 @@
if (rport->scsi_target_id == -1)
continue;
+ if (rport->port_state != FC_PORTSTATE_ONLINE)
+ continue;
+
if ((channel == SCAN_WILD_CARD || channel == rport->channel) &&
(id == SCAN_WILD_CARD || id == rport->scsi_target_id)) {
scsi_scan_target(&rport->dev, rport->channel,
@@ -1472,6 +1985,11 @@
i->rport_attr_cont.ac.match = fc_rport_match;
transport_container_register(&i->rport_attr_cont);
+ i->vport_attr_cont.ac.attrs = &i->vport_attrs[0];
+ i->vport_attr_cont.ac.class = &fc_vport_class.class;
+ i->vport_attr_cont.ac.match = fc_vport_match;
+ transport_container_register(&i->vport_attr_cont);
+
i->f = ft;
/* Transport uses the shost workq for scsi scanning */
@@ -1480,7 +1998,7 @@
i->t.eh_timed_out = fc_timed_out;
i->t.user_scan = fc_user_scan;
-
+
/*
* Setup SCSI Target Attributes.
*/
@@ -1505,6 +2023,10 @@
SETUP_HOST_ATTRIBUTE_RD(supported_fc4s);
SETUP_HOST_ATTRIBUTE_RD(supported_speeds);
SETUP_HOST_ATTRIBUTE_RD(maxframe_size);
+ if (ft->vport_create) {
+ SETUP_HOST_ATTRIBUTE_RD_NS(max_npiv_vports);
+ SETUP_HOST_ATTRIBUTE_RD_NS(npiv_vports_inuse);
+ }
SETUP_HOST_ATTRIBUTE_RD(serial_number);
SETUP_HOST_ATTRIBUTE_RD(port_id);
@@ -1520,6 +2042,10 @@
SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type);
if (ft->issue_fc_host_lip)
SETUP_PRIVATE_HOST_ATTRIBUTE_RW(issue_lip);
+ if (ft->vport_create)
+ SETUP_PRIVATE_HOST_ATTRIBUTE_RW(vport_create);
+ if (ft->vport_delete)
+ SETUP_PRIVATE_HOST_ATTRIBUTE_RW(vport_delete);
BUG_ON(count > FC_HOST_NUM_ATTRS);
@@ -1545,6 +2071,24 @@
i->rport_attrs[count] = NULL;
+ /*
+ * Setup Virtual Port Attributes.
+ */
+ count=0;
+ SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(vport_state);
+ SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(vport_last_state);
+ SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(node_name);
+ SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(port_name);
+ SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(roles);
+ SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(vport_type);
+ SETUP_VPORT_ATTRIBUTE_RW(symbolic_name);
+ SETUP_VPORT_ATTRIBUTE_WR(vport_delete);
+ SETUP_VPORT_ATTRIBUTE_WR(vport_disable);
+
+ BUG_ON(count > FC_VPORT_NUM_ATTRS);
+
+ i->vport_attrs[count] = NULL;
+
return &i->t;
}
EXPORT_SYMBOL(fc_attach_transport);
@@ -1556,6 +2100,7 @@
transport_container_unregister(&i->t.target_attrs);
transport_container_unregister(&i->t.host_attrs);
transport_container_unregister(&i->rport_attr_cont);
+ transport_container_unregister(&i->vport_attr_cont);
kfree(i);
}
@@ -1667,9 +2212,17 @@
void
fc_remove_host(struct Scsi_Host *shost)
{
- struct fc_rport *rport, *next_rport;
+ struct fc_vport *vport = NULL, *next_vport = NULL;
+ struct fc_rport *rport = NULL, *next_rport = NULL;
struct workqueue_struct *work_q;
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
+ unsigned long flags;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+
+ /* Remove any vports */
+ list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers)
+ fc_queue_work(shost, &vport->vport_delete_work);
/* Remove any remote ports */
list_for_each_entry_safe(rport, next_rport,
@@ -1686,6 +2239,8 @@
fc_queue_work(shost, &rport->rport_delete_work);
}
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
/* flush all scan work items */
scsi_flush_work(shost);
@@ -1744,7 +2299,7 @@
unsigned long flags;
/*
- * if a scan is pending, flush the SCSI Host work_q so that
+ * if a scan is pending, flush the SCSI Host work_q so that
* that we can reclaim the rport scan work element.
*/
if (rport->flags & FC_RPORT_SCAN_PENDING)
@@ -1844,7 +2399,7 @@
spin_lock_irqsave(shost->host_lock, flags);
rport->number = fc_host->next_rport_number++;
- if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+ if (rport->roles & FC_PORT_ROLE_FCP_TARGET)
rport->scsi_target_id = fc_host->next_target_id++;
else
rport->scsi_target_id = -1;
@@ -1869,7 +2424,7 @@
transport_add_device(dev);
transport_configure_device(dev);
- if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) {
+ if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
/* initiate a scan of the target */
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work);
@@ -2003,7 +2558,7 @@
/* was a target, not in roles */
if ((rport->scsi_target_id != -1) &&
- (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET)))
+ (!(ids->roles & FC_PORT_ROLE_FCP_TARGET)))
return rport;
/*
@@ -2086,7 +2641,7 @@
memset(rport->dd_data, 0,
fci->f->dd_fcrport_size);
- if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) {
+ if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
/* initiate a scan of the target */
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work);
@@ -2243,11 +2798,11 @@
int create = 0;
spin_lock_irqsave(shost->host_lock, flags);
- if (roles & FC_RPORT_ROLE_FCP_TARGET) {
+ if (roles & FC_PORT_ROLE_FCP_TARGET) {
if (rport->scsi_target_id == -1) {
rport->scsi_target_id = fc_host->next_target_id++;
create = 1;
- } else if (!(rport->roles & FC_RPORT_ROLE_FCP_TARGET))
+ } else if (!(rport->roles & FC_PORT_ROLE_FCP_TARGET))
create = 1;
}
@@ -2294,7 +2849,7 @@
* fc_timeout_deleted_rport - Timeout handler for a deleted remote port,
* which we blocked, and has now failed to return
* in the allotted time.
- *
+ *
* @work: rport target that failed to reappear in the allotted time.
**/
static void
@@ -2317,7 +2872,7 @@
*/
if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
(rport->scsi_target_id != -1) &&
- !(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
+ !(rport->roles & FC_PORT_ROLE_FCP_TARGET)) {
dev_printk(KERN_ERR, &rport->dev,
"blocked FC remote port time out: no longer"
" a FCP target, removing starget\n");
@@ -2367,7 +2922,7 @@
*/
rport->maxframe_size = -1;
rport->supported_classes = FC_COS_UNSPECIFIED;
- rport->roles = FC_RPORT_ROLE_UNKNOWN;
+ rport->roles = FC_PORT_ROLE_UNKNOWN;
rport->port_state = FC_PORTSTATE_NOTPRESENT;
/* remove the identifiers that aren't used in the consisting binding */
@@ -2436,7 +2991,7 @@
unsigned long flags;
if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
- (rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
+ (rport->roles & FC_PORT_ROLE_FCP_TARGET)) {
scsi_scan_target(&rport->dev, rport->channel,
rport->scsi_target_id, SCAN_WILD_CARD, 1);
}
@@ -2447,7 +3002,227 @@
}
-MODULE_AUTHOR("Martin Hicks");
+/**
+ * fc_vport_create - allocates and creates a FC virtual port.
+ * @shost: scsi host the virtual port is connected to.
+ * @channel: Channel on shost port connected to.
+ * @pdev: parent device for vport
+ * @ids: The world wide names, FC4 port roles, etc for
+ * the virtual port.
+ * @ret_vport: The pointer to the created vport.
+ *
+ * Allocates and creates the vport structure, calls the parent host
+ * to instantiate the vport, the completes w/ class and sysfs creation.
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ **/
+static int
+fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev,
+ struct fc_vport_identifiers *ids, struct fc_vport **ret_vport)
+{
+ struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
+ struct fc_internal *fci = to_fc_internal(shost->transportt);
+ struct fc_vport *vport;
+ struct device *dev;
+ unsigned long flags;
+ size_t size;
+ int error;
+
+ *ret_vport = NULL;
+
+ if ( ! fci->f->vport_create)
+ return -ENOENT;
+
+ size = (sizeof(struct fc_vport) + fci->f->dd_fcvport_size);
+ vport = kzalloc(size, GFP_KERNEL);
+ if (unlikely(!vport)) {
+ printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ vport->vport_state = FC_VPORT_UNKNOWN;
+ vport->vport_last_state = FC_VPORT_UNKNOWN;
+ vport->node_name = ids->node_name;
+ vport->port_name = ids->port_name;
+ vport->roles = ids->roles;
+ vport->vport_type = ids->vport_type;
+ if (fci->f->dd_fcvport_size)
+ vport->dd_data = &vport[1];
+ vport->shost = shost;
+ vport->channel = channel;
+ vport->flags = FC_VPORT_CREATING;
+ INIT_WORK(&vport->vport_delete_work, fc_vport_sched_delete);
+
+ spin_lock_irqsave(shost->host_lock, flags);
+
+ if (fc_host->npiv_vports_inuse >= fc_host->max_npiv_vports) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ kfree(vport);
+ return -ENOSPC;
+ }
+ fc_host->npiv_vports_inuse++;
+ vport->number = fc_host->next_vport_number++;
+ list_add_tail(&vport->peers, &fc_host->vports);
+ get_device(&shost->shost_gendev); /* for fc_host->vport list */
+
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ dev = &vport->dev;
+ device_initialize(dev); /* takes self reference */
+ dev->parent = get_device(pdev); /* takes parent reference */
+ dev->release = fc_vport_dev_release;
+ sprintf(dev->bus_id, "vport-%d:%d-%d",
+ shost->host_no, channel, vport->number);
+ transport_setup_device(dev);
+
+ error = device_add(dev);
+ if (error) {
+ printk(KERN_ERR "FC Virtual Port device_add failed\n");
+ goto delete_vport;
+ }
+ transport_add_device(dev);
+ transport_configure_device(dev);
+
+ error = fci->f->vport_create(vport, ids->disable);
+ if (error) {
+ printk(KERN_ERR "FC Virtual Port LLDD Create failed\n");
+ goto delete_vport_all;
+ }
+
+ /*
+ * if the parent isn't the physical adapter's Scsi_Host, ensure
+ * the Scsi_Host at least contains ia symlink to the vport.
+ */
+ if (pdev != &shost->shost_gendev) {
+ error = sysfs_create_link(&shost->shost_gendev.kobj,
+ &dev->kobj, dev->bus_id);
+ if (error)
+ printk(KERN_ERR
+ "%s: Cannot create vport symlinks for "
+ "%s, err=%d\n",
+ __FUNCTION__, dev->bus_id, error);
+ }
+ spin_lock_irqsave(shost->host_lock, flags);
+ vport->flags &= ~FC_VPORT_CREATING;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ dev_printk(KERN_NOTICE, pdev,
+ "%s created via shost%d channel %d\n", dev->bus_id,
+ shost->host_no, channel);
+
+ *ret_vport = vport;
+
+ return 0;
+
+delete_vport_all:
+ transport_remove_device(dev);
+ device_del(dev);
+delete_vport:
+ transport_destroy_device(dev);
+ spin_lock_irqsave(shost->host_lock, flags);
+ list_del(&vport->peers);
+ put_device(&shost->shost_gendev); /* for fc_host->vport list */
+ fc_host->npiv_vports_inuse--;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ put_device(dev->parent);
+ kfree(vport);
+
+ return error;
+}
+
+
+/**
+ * fc_vport_terminate - Admin App or LLDD requests termination of a vport
+ * @vport: fc_vport to be terminated
+ *
+ * Calls the LLDD vport_delete() function, then deallocates and removes
+ * the vport from the shost and object tree.
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ **/
+int
+fc_vport_terminate(struct fc_vport *vport)
+{
+ struct Scsi_Host *shost = vport_to_shost(vport);
+ struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ struct device *dev = &vport->dev;
+ unsigned long flags;
+ int stat;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ if (vport->flags & FC_VPORT_CREATING) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ return -EBUSY;
+ }
+ if (vport->flags & (FC_VPORT_DEL)) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ return -EALREADY;
+ }
+ vport->flags |= FC_VPORT_DELETING;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ if (i->f->vport_delete)
+ stat = i->f->vport_delete(vport);
+ else
+ stat = -ENOENT;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ vport->flags &= ~FC_VPORT_DELETING;
+ if (!stat) {
+ vport->flags |= FC_VPORT_DELETED;
+ list_del(&vport->peers);
+ fc_host->npiv_vports_inuse--;
+ put_device(&shost->shost_gendev); /* for fc_host->vport list */
+ }
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ if (stat)
+ return stat;
+
+ if (dev->parent != &shost->shost_gendev)
+ sysfs_remove_link(&shost->shost_gendev.kobj, dev->bus_id);
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+
+ /*
+ * Removing our self-reference should mean our
+ * release function gets called, which will drop the remaining
+ * parent reference and free the data structure.
+ */
+ put_device(dev); /* for self-reference */
+
+ return 0; /* SUCCESS */
+}
+EXPORT_SYMBOL(fc_vport_terminate);
+
+/**
+ * fc_vport_sched_delete - workq-based delete request for a vport
+ *
+ * @work: vport to be deleted.
+ **/
+static void
+fc_vport_sched_delete(struct work_struct *work)
+{
+ struct fc_vport *vport =
+ container_of(work, struct fc_vport, vport_delete_work);
+ int stat;
+
+ stat = fc_vport_terminate(vport);
+ if (stat)
+ dev_printk(KERN_ERR, vport->dev.parent,
+ "%s: %s could not be deleted created via "
+ "shost%d channel %d - error %d\n", __FUNCTION__,
+ vport->dev.bus_id, vport->shost->host_no,
+ vport->channel, stat);
+}
+
+
+/* Original Author: Martin Hicks */
+MODULE_AUTHOR("James Smart");
MODULE_DESCRIPTION("FC Transport Attributes");
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index caf1836..34c1860 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -30,9 +30,9 @@
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/iscsi_if.h>
-#define ISCSI_SESSION_ATTRS 11
+#define ISCSI_SESSION_ATTRS 15
#define ISCSI_CONN_ATTRS 11
-#define ISCSI_HOST_ATTRS 0
+#define ISCSI_HOST_ATTRS 4
#define ISCSI_TRANSPORT_VERSION "2.0-724"
struct iscsi_internal {
@@ -609,12 +609,10 @@
int t = done ? NLMSG_DONE : type;
skb = alloc_skb(len, GFP_ATOMIC);
- /*
- * FIXME:
- * user is supposed to react on iferror == -ENOMEM;
- * see iscsi_if_rx().
- */
- BUG_ON(!skb);
+ if (!skb) {
+ printk(KERN_ERR "Could not allocate skb to send reply.\n");
+ return -ENOMEM;
+ }
nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0);
nlh->nlmsg_flags = flags;
@@ -816,6 +814,8 @@
uint32_t hostno;
session = transport->create_session(transport, &priv->t,
+ ev->u.c_session.cmds_max,
+ ev->u.c_session.queue_depth,
ev->u.c_session.initial_cmdsn,
&hostno);
if (!session)
@@ -947,15 +947,50 @@
iscsi_tgt_dscvr(struct iscsi_transport *transport,
struct iscsi_uevent *ev)
{
+ struct Scsi_Host *shost;
struct sockaddr *dst_addr;
+ int err;
if (!transport->tgt_dscvr)
return -EINVAL;
+ shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no);
+ if (IS_ERR(shost)) {
+ printk(KERN_ERR "target discovery could not find host no %u\n",
+ ev->u.tgt_dscvr.host_no);
+ return -ENODEV;
+ }
+
+
dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
- return transport->tgt_dscvr(ev->u.tgt_dscvr.type,
- ev->u.tgt_dscvr.host_no,
- ev->u.tgt_dscvr.enable, dst_addr);
+ err = transport->tgt_dscvr(shost, ev->u.tgt_dscvr.type,
+ ev->u.tgt_dscvr.enable, dst_addr);
+ scsi_host_put(shost);
+ return err;
+}
+
+static int
+iscsi_set_host_param(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ char *data = (char*)ev + sizeof(*ev);
+ struct Scsi_Host *shost;
+ int err;
+
+ if (!transport->set_host_param)
+ return -ENOSYS;
+
+ shost = scsi_host_lookup(ev->u.set_host_param.host_no);
+ if (IS_ERR(shost)) {
+ printk(KERN_ERR "set_host_param could not find host no %u\n",
+ ev->u.set_host_param.host_no);
+ return -ENODEV;
+ }
+
+ err = transport->set_host_param(shost, ev->u.set_host_param.param,
+ data, ev->u.set_host_param.len);
+ scsi_host_put(shost);
+ return err;
}
static int
@@ -1049,8 +1084,11 @@
case ISCSI_UEVENT_TGT_DSCVR:
err = iscsi_tgt_dscvr(transport, ev);
break;
+ case ISCSI_UEVENT_SET_HOST_PARAM:
+ err = iscsi_set_host_param(transport, ev);
+ break;
default:
- err = -EINVAL;
+ err = -ENOSYS;
break;
}
@@ -1160,30 +1198,37 @@
/*
* iSCSI session attrs
*/
-#define iscsi_session_attr_show(param) \
+#define iscsi_session_attr_show(param, perm) \
static ssize_t \
show_session_param_##param(struct class_device *cdev, char *buf) \
{ \
struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
struct iscsi_transport *t = session->transport; \
+ \
+ if (perm && !capable(CAP_SYS_ADMIN)) \
+ return -EACCES; \
return t->get_session_param(session, param, buf); \
}
-#define iscsi_session_attr(field, param) \
- iscsi_session_attr_show(param) \
+#define iscsi_session_attr(field, param, perm) \
+ iscsi_session_attr_show(param, perm) \
static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \
NULL);
-iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME);
-iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN);
-iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T);
-iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN);
-iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST);
-iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST);
-iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN);
-iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN);
-iscsi_session_attr(erl, ISCSI_PARAM_ERL);
-iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT);
+iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME, 0);
+iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, 0);
+iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, 0);
+iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, 0);
+iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, 0);
+iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, 0);
+iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, 0);
+iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, 0);
+iscsi_session_attr(erl, ISCSI_PARAM_ERL, 0);
+iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT, 0);
+iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1);
+iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
+iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
+iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
#define iscsi_priv_session_attr_show(field, format) \
static ssize_t \
@@ -1199,6 +1244,28 @@
NULL)
iscsi_priv_session_attr(recovery_tmo, "%d");
+/*
+ * iSCSI host attrs
+ */
+#define iscsi_host_attr_show(param) \
+static ssize_t \
+show_host_param_##param(struct class_device *cdev, char *buf) \
+{ \
+ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
+ struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
+ return priv->iscsi_transport->get_host_param(shost, param, buf); \
+}
+
+#define iscsi_host_attr(field, param) \
+ iscsi_host_attr_show(param) \
+static ISCSI_CLASS_ATTR(host, field, S_IRUGO, show_host_param_##param, \
+ NULL);
+
+iscsi_host_attr(netdev, ISCSI_HOST_PARAM_NETDEV_NAME);
+iscsi_host_attr(hwaddress, ISCSI_HOST_PARAM_HWADDRESS);
+iscsi_host_attr(ipaddress, ISCSI_HOST_PARAM_IPADDRESS);
+iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
+
#define SETUP_PRIV_SESSION_RD_ATTR(field) \
do { \
priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
@@ -1222,6 +1289,14 @@
} \
} while (0)
+#define SETUP_HOST_RD_ATTR(field, param_flag) \
+do { \
+ if (tt->host_param_mask & param_flag) { \
+ priv->host_attrs[count] = &class_device_attr_host_##field; \
+ count++; \
+ } \
+} while (0)
+
static int iscsi_session_match(struct attribute_container *cont,
struct device *dev)
{
@@ -1323,9 +1398,16 @@
priv->t.host_attrs.ac.class = &iscsi_host_class.class;
priv->t.host_attrs.ac.match = iscsi_host_match;
priv->t.host_size = sizeof(struct iscsi_host);
- priv->host_attrs[0] = NULL;
transport_container_register(&priv->t.host_attrs);
+ SETUP_HOST_RD_ATTR(netdev, ISCSI_HOST_NETDEV_NAME);
+ SETUP_HOST_RD_ATTR(ipaddress, ISCSI_HOST_IPADDRESS);
+ SETUP_HOST_RD_ATTR(hwaddress, ISCSI_HOST_HWADDRESS);
+ SETUP_HOST_RD_ATTR(initiatorname, ISCSI_HOST_INITIATOR_NAME);
+ BUG_ON(count > ISCSI_HOST_ATTRS);
+ priv->host_attrs[count] = NULL;
+ count = 0;
+
/* connection parameters */
priv->conn_cont.ac.attrs = &priv->conn_attrs[0];
priv->conn_cont.ac.class = &iscsi_connection_class.class;
@@ -1364,6 +1446,10 @@
SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL);
SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT);
+ SETUP_SESSION_RD_ATTR(password, ISCSI_USERNAME);
+ SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN);
+ SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD);
+ SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN);
SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
BUG_ON(count > ISCSI_SESSION_ATTRS);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 3d8c9cb..448d316 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1515,7 +1515,7 @@
if (!scsi_device_online(sdp))
goto out;
- buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL | __GFP_DMA);
+ buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL);
if (!buffer) {
sd_printk(KERN_WARNING, sdkp, "sd_revalidate_disk: Memory "
"allocation failure.\n");
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 0c691a6..85d3894 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1842,7 +1842,7 @@
int blk_size = buff_size;
struct page *p = NULL;
- if ((blk_size < 0) || (!sfp))
+ if (blk_size < 0)
return -EFAULT;
if (0 == blk_size)
++blk_size; /* don't know why */
diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c
index a7dfb65..0a6b45b 100644
--- a/drivers/scsi/sni_53c710.c
+++ b/drivers/scsi/sni_53c710.c
@@ -84,7 +84,7 @@
hostdata->dev = &dev->dev;
dma_set_mask(&dev->dev, DMA_32BIT_MASK);
- hostdata->base = ioremap_nocache(CPHYSADDR(base), 0x100);
+ hostdata->base = ioremap_nocache(base, 0x100);
hostdata->differential = 0;
hostdata->clock = SNIRM710_CLOCK;
@@ -141,13 +141,7 @@
static int __init snirm710_init(void)
{
- int err;
-
- if ((err = platform_driver_register(&snirm710_driver))) {
- printk(KERN_ERR "Driver registration failed\n");
- return err;
- }
- return 0;
+ return platform_driver_register(&snirm710_driver);
}
static void __exit snirm710_exit(void)
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index f9a52af..5143c89 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -885,7 +885,11 @@
rc = register_blkdev(SCSI_CDROM_MAJOR, "sr");
if (rc)
return rc;
- return scsi_register_driver(&sr_template.gendrv);
+ rc = scsi_register_driver(&sr_template.gendrv);
+ if (rc)
+ unregister_blkdev(SCSI_CDROM_MAJOR, "sr");
+
+ return rc;
}
static void __exit exit_sr(void)
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 9ac83ab..72f6d80 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -395,53 +395,34 @@
static int stex_map_sg(struct st_hba *hba,
struct req_msg *req, struct st_ccb *ccb)
{
- struct pci_dev *pdev = hba->pdev;
struct scsi_cmnd *cmd;
- dma_addr_t dma_handle;
- struct scatterlist *src;
+ struct scatterlist *sg;
struct st_sgtable *dst;
- int i;
+ int i, nseg;
cmd = ccb->cmd;
dst = (struct st_sgtable *)req->variable;
dst->max_sg_count = cpu_to_le16(ST_MAX_SG);
- dst->sz_in_byte = cpu_to_le32(cmd->request_bufflen);
+ dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd));
- if (cmd->use_sg) {
- int n_elem;
+ nseg = scsi_dma_map(cmd);
+ if (nseg < 0)
+ return -EIO;
+ if (nseg) {
+ ccb->sg_count = nseg;
+ dst->sg_count = cpu_to_le16((u16)nseg);
- src = (struct scatterlist *) cmd->request_buffer;
- n_elem = pci_map_sg(pdev, src,
- cmd->use_sg, cmd->sc_data_direction);
- if (n_elem <= 0)
- return -EIO;
-
- ccb->sg_count = n_elem;
- dst->sg_count = cpu_to_le16((u16)n_elem);
-
- for (i = 0; i < n_elem; i++, src++) {
- dst->table[i].count = cpu_to_le32((u32)sg_dma_len(src));
+ scsi_for_each_sg(cmd, sg, nseg, i) {
+ dst->table[i].count = cpu_to_le32((u32)sg_dma_len(sg));
dst->table[i].addr =
- cpu_to_le32(sg_dma_address(src) & 0xffffffff);
+ cpu_to_le32(sg_dma_address(sg) & 0xffffffff);
dst->table[i].addr_hi =
- cpu_to_le32((sg_dma_address(src) >> 16) >> 16);
+ cpu_to_le32((sg_dma_address(sg) >> 16) >> 16);
dst->table[i].ctrl = SG_CF_64B | SG_CF_HOST;
}
dst->table[--i].ctrl |= SG_CF_EOT;
- return 0;
}
- dma_handle = pci_map_single(pdev, cmd->request_buffer,
- cmd->request_bufflen, cmd->sc_data_direction);
- cmd->SCp.dma_handle = dma_handle;
-
- ccb->sg_count = 1;
- dst->sg_count = cpu_to_le16(1);
- dst->table[0].addr = cpu_to_le32(dma_handle & 0xffffffff);
- dst->table[0].addr_hi = cpu_to_le32((dma_handle >> 16) >> 16);
- dst->table[0].count = cpu_to_le32((u32)cmd->request_bufflen);
- dst->table[0].ctrl = SG_CF_EOT | SG_CF_64B | SG_CF_HOST;
-
return 0;
}
@@ -451,24 +432,24 @@
size_t lcount;
size_t len;
void *s, *d, *base = NULL;
- if (*count > cmd->request_bufflen)
- *count = cmd->request_bufflen;
+ size_t offset;
+
+ if (*count > scsi_bufflen(cmd))
+ *count = scsi_bufflen(cmd);
lcount = *count;
while (lcount) {
len = lcount;
s = (void *)src;
- if (cmd->use_sg) {
- size_t offset = *count - lcount;
- s += offset;
- base = scsi_kmap_atomic_sg(cmd->request_buffer,
- sg_count, &offset, &len);
- if (base == NULL) {
- *count -= lcount;
- return;
- }
- d = base + offset;
- } else
- d = cmd->request_buffer;
+
+ offset = *count - lcount;
+ s += offset;
+ base = scsi_kmap_atomic_sg(scsi_sglist(cmd),
+ sg_count, &offset, &len);
+ if (!base) {
+ *count -= lcount;
+ return;
+ }
+ d = base + offset;
if (direction == ST_TO_CMD)
memcpy(d, s, len);
@@ -476,30 +457,24 @@
memcpy(s, d, len);
lcount -= len;
- if (cmd->use_sg)
- scsi_kunmap_atomic_sg(base);
+ scsi_kunmap_atomic_sg(base);
}
}
static int stex_direct_copy(struct scsi_cmnd *cmd,
const void *src, size_t count)
{
- struct st_hba *hba = (struct st_hba *) &cmd->device->host->hostdata[0];
size_t cp_len = count;
int n_elem = 0;
- if (cmd->use_sg) {
- n_elem = pci_map_sg(hba->pdev, cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- if (n_elem <= 0)
- return 0;
- }
+ n_elem = scsi_dma_map(cmd);
+ if (n_elem < 0)
+ return 0;
stex_internal_copy(cmd, src, &cp_len, n_elem, ST_TO_CMD);
- if (cmd->use_sg)
- pci_unmap_sg(hba->pdev, cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
+ scsi_dma_unmap(cmd);
+
return cp_len == count;
}
@@ -678,18 +653,6 @@
return 0;
}
-static void stex_unmap_sg(struct st_hba *hba, struct scsi_cmnd *cmd)
-{
- if (cmd->sc_data_direction != DMA_NONE) {
- if (cmd->use_sg)
- pci_unmap_sg(hba->pdev, cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- else
- pci_unmap_single(hba->pdev, cmd->SCp.dma_handle,
- cmd->request_bufflen, cmd->sc_data_direction);
- }
-}
-
static void stex_scsi_done(struct st_ccb *ccb)
{
struct scsi_cmnd *cmd = ccb->cmd;
@@ -756,8 +719,8 @@
if (ccb->cmd->cmnd[0] == MGT_CMD &&
resp->scsi_status != SAM_STAT_CHECK_CONDITION) {
- ccb->cmd->request_bufflen =
- le32_to_cpu(*(__le32 *)&resp->variable[0]);
+ scsi_set_resid(ccb->cmd, scsi_bufflen(ccb->cmd) -
+ le32_to_cpu(*(__le32 *)&resp->variable[0]));
return;
}
@@ -855,7 +818,7 @@
ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER))
stex_controller_info(hba, ccb);
- stex_unmap_sg(hba, ccb->cmd);
+ scsi_dma_unmap(ccb->cmd);
stex_scsi_done(ccb);
hba->out_req_cnt--;
} else if (ccb->req_type & PASSTHRU_REQ_TYPE) {
@@ -1028,7 +991,7 @@
}
fail_out:
- stex_unmap_sg(hba, cmd);
+ scsi_dma_unmap(cmd);
hba->wait_ccb->req = NULL; /* nullify the req's future return */
hba->wait_ccb = NULL;
result = FAILED;
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
index bbeb245..2c87db9 100644
--- a/drivers/scsi/sun_esp.c
+++ b/drivers/scsi/sun_esp.c
@@ -493,7 +493,7 @@
goto fail;
host->max_id = (hme ? 16 : 8);
- esp = host_to_esp(host);
+ esp = shost_priv(host);
esp->host = host;
esp->dev = esp_dev;
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 2ca9505..92bfaea 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -332,8 +332,7 @@
int i;
unsigned long flags = 0;
unsigned char status_reg, pio_int_reg, int_reg;
- struct scatterlist *sglist;
- unsigned int sgcount;
+ struct scatterlist *sg;
unsigned int tot_trans = 0;
/* We search the base address of the host adapter which caused the interrupt */
@@ -429,19 +428,15 @@
{
current_command->SCp.phase = data_out;
outb(FLUSH_FIFO, base + COMMAND_REG);
- sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+ sym53c416_set_transfer_counter(base,
+ scsi_bufflen(current_command));
outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
- if(!current_command->use_sg)
- tot_trans = sym53c416_write(base, current_command->request_buffer, current_command->request_bufflen);
- else
- {
- sgcount = current_command->use_sg;
- sglist = current_command->request_buffer;
- while(sgcount--)
- {
- tot_trans += sym53c416_write(base, SG_ADDRESS(sglist), sglist->length);
- sglist++;
- }
+
+ scsi_for_each_sg(current_command,
+ sg, scsi_sg_count(current_command), i) {
+ tot_trans += sym53c416_write(base,
+ SG_ADDRESS(sg),
+ sg->length);
}
if(tot_trans < current_command->underflow)
printk(KERN_WARNING "sym53c416: Underflow, wrote %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow);
@@ -455,19 +450,16 @@
{
current_command->SCp.phase = data_in;
outb(FLUSH_FIFO, base + COMMAND_REG);
- sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+ sym53c416_set_transfer_counter(base,
+ scsi_bufflen(current_command));
+
outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
- if(!current_command->use_sg)
- tot_trans = sym53c416_read(base, current_command->request_buffer, current_command->request_bufflen);
- else
- {
- sgcount = current_command->use_sg;
- sglist = current_command->request_buffer;
- while(sgcount--)
- {
- tot_trans += sym53c416_read(base, SG_ADDRESS(sglist), sglist->length);
- sglist++;
- }
+
+ scsi_for_each_sg(current_command,
+ sg, scsi_sg_count(current_command), i) {
+ tot_trans += sym53c416_read(base,
+ SG_ADDRESS(sg),
+ sg->length);
}
if(tot_trans < current_command->underflow)
printk(KERN_WARNING "sym53c416: Underflow, read %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow);
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 4d78c7e..15a5145 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -146,41 +146,17 @@
static void __unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
{
- int dma_dir = cmd->sc_data_direction;
+ if (SYM_UCMD_PTR(cmd)->data_mapped)
+ scsi_dma_unmap(cmd);
- switch(SYM_UCMD_PTR(cmd)->data_mapped) {
- case 2:
- pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
- break;
- case 1:
- pci_unmap_single(pdev, SYM_UCMD_PTR(cmd)->data_mapping,
- cmd->request_bufflen, dma_dir);
- break;
- }
SYM_UCMD_PTR(cmd)->data_mapped = 0;
}
-static dma_addr_t __map_scsi_single_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
- dma_addr_t mapping;
- int dma_dir = cmd->sc_data_direction;
-
- mapping = pci_map_single(pdev, cmd->request_buffer,
- cmd->request_bufflen, dma_dir);
- if (mapping) {
- SYM_UCMD_PTR(cmd)->data_mapped = 1;
- SYM_UCMD_PTR(cmd)->data_mapping = mapping;
- }
-
- return mapping;
-}
-
static int __map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
{
int use_sg;
- int dma_dir = cmd->sc_data_direction;
- use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
+ use_sg = scsi_dma_map(cmd);
if (use_sg > 0) {
SYM_UCMD_PTR(cmd)->data_mapped = 2;
SYM_UCMD_PTR(cmd)->data_mapping = use_sg;
@@ -191,8 +167,6 @@
#define unmap_scsi_data(np, cmd) \
__unmap_scsi_data(np->s.device, cmd)
-#define map_scsi_single_data(np, cmd) \
- __map_scsi_single_data(np->s.device, cmd)
#define map_scsi_sg_data(np, cmd) \
__map_scsi_sg_data(np->s.device, cmd)
/*
@@ -322,55 +296,20 @@
*/
cam_status = sym_xerr_cam_status(DID_ERROR, cp->xerr_status);
}
- cmd->resid = resid;
+ scsi_set_resid(cmd, resid);
cmd->result = (drv_status << 24) + (cam_status << 16) + scsi_status;
}
-
-/*
- * Build the scatter/gather array for an I/O.
- */
-
-static int sym_scatter_no_sglist(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd *cmd)
-{
- struct sym_tblmove *data = &cp->phys.data[SYM_CONF_MAX_SG-1];
- int segment;
- unsigned int len = cmd->request_bufflen;
-
- if (len) {
- dma_addr_t baddr = map_scsi_single_data(np, cmd);
- if (baddr) {
- if (len & 1) {
- struct sym_tcb *tp = &np->target[cp->target];
- if (tp->head.wval & EWS) {
- len++;
- cp->odd_byte_adjustment++;
- }
- }
- cp->data_len = len;
- sym_build_sge(np, data, baddr, len);
- segment = 1;
- } else {
- segment = -2;
- }
- } else {
- segment = 0;
- }
-
- return segment;
-}
-
static int sym_scatter(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd *cmd)
{
int segment;
- int use_sg = (int) cmd->use_sg;
+ int use_sg;
cp->data_len = 0;
- if (!use_sg)
- segment = sym_scatter_no_sglist(np, cp, cmd);
- else if ((use_sg = map_scsi_sg_data(np, cmd)) > 0) {
- struct scatterlist *scatter = (struct scatterlist *)cmd->request_buffer;
+ use_sg = map_scsi_sg_data(np, cmd);
+ if (use_sg > 0) {
+ struct scatterlist *sg;
struct sym_tcb *tp = &np->target[cp->target];
struct sym_tblmove *data;
@@ -381,9 +320,9 @@
data = &cp->phys.data[SYM_CONF_MAX_SG - use_sg];
- for (segment = 0; segment < use_sg; segment++) {
- dma_addr_t baddr = sg_dma_address(&scatter[segment]);
- unsigned int len = sg_dma_len(&scatter[segment]);
+ scsi_for_each_sg(cmd, sg, use_sg, segment) {
+ dma_addr_t baddr = sg_dma_address(sg);
+ unsigned int len = sg_dma_len(sg);
if ((len & 1) && (tp->head.wval & EWS)) {
len++;
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h
index e022d3c..0f097ba 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.h
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.h
@@ -255,7 +255,7 @@
*/
static __inline void sym_set_cam_result_ok(struct sym_ccb *cp, struct scsi_cmnd *cmd, int resid)
{
- cmd->resid = resid;
+ scsi_set_resid(cmd, resid);
cmd->result = (((DID_OK) << 16) + ((cp->ssss_status) & 0x7f));
}
void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid);
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index e7b85e8..14cba1c 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -457,28 +457,21 @@
error = 1;
DEBUG1(printk("%s(): Mapped sense buffer %p at %x\n", __FUNCTION__, pcmd->sense_buffer, cmdp->saved_dma_handle));
/* Map SG list */
- } else if (pcmd->use_sg) {
- pSRB->pSegmentList = (struct scatterlist *) pcmd->request_buffer;
- pSRB->SGcount = pci_map_sg(pdev, pSRB->pSegmentList, pcmd->use_sg,
- pcmd->sc_data_direction);
- /* TODO: error handling */
- if (!pSRB->SGcount)
- error = 1;
- DEBUG1(printk("%s(): Mapped SG %p with %d (%d) elements\n",\
- __FUNCTION__, pcmd->request_buffer, pSRB->SGcount, pcmd->use_sg));
- /* Map single segment */
- } else if (pcmd->request_buffer && pcmd->request_bufflen) {
- pSRB->pSegmentList = dc390_sg_build_single(&pSRB->Segmentx, pcmd->request_buffer, pcmd->request_bufflen);
- pSRB->SGcount = pci_map_sg(pdev, pSRB->pSegmentList, 1,
- pcmd->sc_data_direction);
- cmdp->saved_dma_handle = sg_dma_address(pSRB->pSegmentList);
+ } else if (scsi_sg_count(pcmd)) {
+ int nseg;
+
+ nseg = scsi_dma_map(pcmd);
+
+ pSRB->pSegmentList = scsi_sglist(pcmd);
+ pSRB->SGcount = nseg;
/* TODO: error handling */
- if (pSRB->SGcount != 1)
+ if (nseg < 0)
error = 1;
- DEBUG1(printk("%s(): Mapped request buffer %p at %x\n", __FUNCTION__, pcmd->request_buffer, cmdp->saved_dma_handle));
- /* No mapping !? */
- } else
+ DEBUG1(printk("%s(): Mapped SG %p with %d (%d) elements\n",\
+ __FUNCTION__, scsi_sglist(pcmd), nseg, scsi_sg_count(pcmd)));
+ /* Map single segment */
+ } else
pSRB->SGcount = 0;
return error;
@@ -494,12 +487,10 @@
if (pSRB->SRBFlag) {
pci_unmap_sg(pdev, &pSRB->Segmentx, 1, DMA_FROM_DEVICE);
DEBUG1(printk("%s(): Unmapped sense buffer at %x\n", __FUNCTION__, cmdp->saved_dma_handle));
- } else if (pcmd->use_sg) {
- pci_unmap_sg(pdev, pcmd->request_buffer, pcmd->use_sg, pcmd->sc_data_direction);
- DEBUG1(printk("%s(): Unmapped SG at %p with %d elements\n", __FUNCTION__, pcmd->request_buffer, pcmd->use_sg));
- } else if (pcmd->request_buffer && pcmd->request_bufflen) {
- pci_unmap_sg(pdev, &pSRB->Segmentx, 1, pcmd->sc_data_direction);
- DEBUG1(printk("%s(): Unmapped request buffer at %x\n", __FUNCTION__, cmdp->saved_dma_handle));
+ } else {
+ scsi_dma_unmap(pcmd);
+ DEBUG1(printk("%s(): Unmapped SG at %p with %d elements\n",
+ __FUNCTION__, scsi_sglist(pcmd), scsi_sg_count(pcmd)));
}
}
@@ -1153,9 +1144,9 @@
struct scatterlist *psgl;
pSRB->TotalXferredLen = 0;
pSRB->SGIndex = 0;
- if (pcmd->use_sg) {
+ if (scsi_sg_count(pcmd)) {
size_t saved;
- pSRB->pSegmentList = (struct scatterlist *)pcmd->request_buffer;
+ pSRB->pSegmentList = scsi_sglist(pcmd);
psgl = pSRB->pSegmentList;
//dc390_pci_sync(pSRB);
@@ -1179,12 +1170,6 @@
printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n",
pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr);
- } else if(pcmd->request_buffer) {
- //dc390_pci_sync(pSRB);
-
- sg_dma_len(&pSRB->Segmentx) = pcmd->request_bufflen - pSRB->Saved_Ptr;
- pSRB->SGcount = 1;
- pSRB->pSegmentList = (struct scatterlist *) &pSRB->Segmentx;
} else {
pSRB->SGcount = 0;
printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n");
@@ -1579,7 +1564,8 @@
if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
!(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
{ /* Selection time out */
- pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
+ pSRB->AdaptStatus = H_SEL_TIMEOUT;
+ pSRB->TargetStatus = 0;
goto disc1;
}
else if (!(pSRB->SRBState & SRB_DISCONNECT) && (pSRB->SRBState & SRB_COMPLETED))
@@ -1612,7 +1598,7 @@
if( !( pACB->scan_devices ) )
{
struct scsi_cmnd *pcmd = pSRB->pcmd;
- pcmd->resid = pcmd->request_bufflen;
+ scsi_set_resid(pcmd, scsi_bufflen(pcmd));
SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
dc390_Going_remove(pDCB, pSRB);
dc390_Free_insert(pACB, pSRB);
@@ -1695,7 +1681,6 @@
pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN));
pSRB->SRBFlag |= AUTO_REQSENSE;
- pSRB->SavedSGCount = pcmd->use_sg;
pSRB->SavedTotXLen = pSRB->TotalXferredLen;
pSRB->AdaptStatus = 0;
pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */
@@ -1728,22 +1713,21 @@
{ /* Last command was a Request Sense */
pSRB->SRBFlag &= ~AUTO_REQSENSE;
pSRB->AdaptStatus = 0;
- pSRB->TargetStatus = CHECK_CONDITION << 1;
+ pSRB->TargetStatus = SAM_STAT_CHECK_CONDITION;
//pcmd->result = MK_RES(DRIVER_SENSE,DID_OK,0,status);
- if (status == (CHECK_CONDITION << 1))
+ if (status == SAM_STAT_CHECK_CONDITION)
pcmd->result = MK_RES_LNX(0, DID_BAD_TARGET, 0, /*CHECK_CONDITION*/0);
else /* Retry */
{
if( pSRB->pcmd->cmnd[0] == TEST_UNIT_READY /* || pSRB->pcmd->cmnd[0] == START_STOP */)
{
/* Don't retry on TEST_UNIT_READY */
- pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION);
+ pcmd->result = MK_RES_LNX(DRIVER_SENSE, DID_OK, 0, SAM_STAT_CHECK_CONDITION);
REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->pcmd->cmnd[0],\
(u32) pcmd->result, (u32) pSRB->TotalXferredLen));
} else {
SET_RES_DRV(pcmd->result, DRIVER_SENSE);
- pcmd->use_sg = pSRB->SavedSGCount;
//pSRB->ScsiCmdLen = (u8) (pSRB->Segment1[0] >> 8);
DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
pSRB->TotalXferredLen = 0;
@@ -1754,7 +1738,7 @@
}
if( status )
{
- if( status_byte(status) == CHECK_CONDITION )
+ if (status == SAM_STAT_CHECK_CONDITION)
{
if (dc390_RequestSense(pACB, pDCB, pSRB)) {
SET_RES_DID(pcmd->result, DID_ERROR);
@@ -1762,22 +1746,14 @@
}
return;
}
- else if( status_byte(status) == QUEUE_FULL )
+ else if (status == SAM_STAT_TASK_SET_FULL)
{
scsi_track_queue_full(pcmd->device, pDCB->GoingSRBCnt - 1);
- pcmd->use_sg = pSRB->SavedSGCount;
DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
pSRB->TotalXferredLen = 0;
SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
}
- else if(status == SCSI_STAT_SEL_TIMEOUT)
- {
- pSRB->AdaptStatus = H_SEL_TIMEOUT;
- pSRB->TargetStatus = 0;
- pcmd->result = MK_RES(0,DID_NO_CONNECT,0,0);
- /* Devices are removed below ... */
- }
- else if (status_byte(status) == BUSY &&
+ else if (status == SAM_STAT_BUSY &&
(pcmd->cmnd[0] == TEST_UNIT_READY || pcmd->cmnd[0] == INQUIRY) &&
pACB->scan_devices)
{
@@ -1795,12 +1771,17 @@
else
{ /* Target status == 0 */
status = pSRB->AdaptStatus;
- if(status & H_OVER_UNDER_RUN)
+ if (status == H_OVER_UNDER_RUN)
{
pSRB->TargetStatus = 0;
SET_RES_DID(pcmd->result,DID_OK);
SET_RES_MSG(pcmd->result,pSRB->EndMessage);
}
+ else if (status == H_SEL_TIMEOUT)
+ {
+ pcmd->result = MK_RES(0, DID_NO_CONNECT, 0, 0);
+ /* Devices are removed below ... */
+ }
else if( pSRB->SRBStatus & PARITY_ERROR)
{
//pcmd->result = MK_RES(0,DID_PARITY,pSRB->EndMessage,0);
@@ -1816,7 +1797,7 @@
}
cmd_done:
- pcmd->resid = pcmd->request_bufflen - pSRB->TotalXferredLen;
+ scsi_set_resid(pcmd, scsi_bufflen(pcmd) - pSRB->TotalXferredLen);
dc390_Going_remove (pDCB, pSRB);
/* Add to free list */
diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h
index c3d8c80..77adc54 100644
--- a/drivers/scsi/tmscsim.h
+++ b/drivers/scsi/tmscsim.h
@@ -57,7 +57,6 @@
u8 MsgCnt;
u8 EndMessage;
-u8 SavedSGCount;
u8 MsgInBuf[6];
u8 MsgOutBuf[6];
@@ -258,13 +257,6 @@
#define H_BAD_CCB_OR_SG 0x1A
#define H_ABORT 0x0FF
-/*; SCSI Status byte codes*/
-/* The values defined in include/scsi/scsi.h, to be shifted << 1 */
-
-#define SCSI_STAT_UNEXP_BUS_F 0xFD /*; Unexpect Bus Free */
-#define SCSI_STAT_BUS_RST_DETECT 0xFE /*; Scsi Bus Reset detected */
-#define SCSI_STAT_SEL_TIMEOUT 0xFF /*; Selection Time out */
-
/* cmd->result */
#define RES_TARGET 0x000000FF /* Target State */
#define RES_TARGET_LNX STATUS_MASK /* Only official ... */
@@ -273,7 +265,7 @@
#define RES_DRV 0xFF000000 /* DRIVER_ codes */
#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))
-#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1)
+#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))
#define SET_RES_TARGET(who, tgt) do { who &= ~RES_TARGET; who |= (int)(tgt); } while (0)
#define SET_RES_TARGET_LNX(who, tgt) do { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; } while (0)
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 3de08a1..9e8232a 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -1111,7 +1111,7 @@
static void map_dma(unsigned int i, unsigned int j) {
unsigned int data_len = 0;
unsigned int k, count, pci_dir;
- struct scatterlist *sgpnt;
+ struct scatterlist *sg;
struct mscp *cpp;
struct scsi_cmnd *SCpnt;
@@ -1124,33 +1124,28 @@
cpp->sense_len = sizeof SCpnt->sense_buffer;
- if (!SCpnt->use_sg) {
+ if (scsi_bufflen(SCpnt)) {
+ count = scsi_dma_map(SCpnt);
+ BUG_ON(count < 0);
- /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */
- if (!SCpnt->request_bufflen) pci_dir = PCI_DMA_BIDIRECTIONAL;
+ scsi_for_each_sg(SCpnt, sg, count, k) {
+ cpp->sglist[k].address = H2DEV(sg_dma_address(sg));
+ cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(sg));
+ data_len += sg->length;
+ }
- if (SCpnt->request_buffer)
- cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev,
- SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir));
+ cpp->sg = TRUE;
+ cpp->use_sg = scsi_sg_count(SCpnt);
+ cpp->data_address =
+ H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist,
+ cpp->use_sg * sizeof(struct sg_list),
+ pci_dir));
+ cpp->data_len = H2DEV(data_len);
- cpp->data_len = H2DEV(SCpnt->request_bufflen);
- return;
- }
-
- sgpnt = (struct scatterlist *) SCpnt->request_buffer;
- count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir);
-
- for (k = 0; k < count; k++) {
- cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k]));
- cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k]));
- data_len += sgpnt[k].length;
- }
-
- cpp->sg = TRUE;
- cpp->use_sg = SCpnt->use_sg;
- cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist,
- SCpnt->use_sg * sizeof(struct sg_list), pci_dir));
- cpp->data_len = H2DEV(data_len);
+ } else {
+ pci_dir = PCI_DMA_BIDIRECTIONAL;
+ cpp->data_len = H2DEV(scsi_bufflen(SCpnt));
+ }
}
static void unmap_dma(unsigned int i, unsigned int j) {
@@ -1165,8 +1160,7 @@
pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
- if (SCpnt->use_sg)
- pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir);
+ scsi_dma_unmap(SCpnt);
if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
@@ -1187,9 +1181,9 @@
pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->sense_addr),
DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
- if (SCpnt->use_sg)
- pci_dma_sync_sg_for_cpu(HD(j)->pdev, SCpnt->request_buffer,
- SCpnt->use_sg, pci_dir);
+ if (scsi_sg_count(SCpnt))
+ pci_dma_sync_sg_for_cpu(HD(j)->pdev, scsi_sglist(SCpnt),
+ scsi_sg_count(SCpnt), pci_dir);
if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index 56906ab..c08235d 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -675,16 +675,15 @@
static inline void build_sg_list(struct mscp *mscp, struct scsi_cmnd *SCpnt)
{
- struct scatterlist *sl;
+ struct scatterlist *sg;
long transfer_length = 0;
int i, max;
- sl = (struct scatterlist *) SCpnt->request_buffer;
- max = SCpnt->use_sg;
- for (i = 0; i < max; i++) {
- mscp->sglist[i].address = isa_page_to_bus(sl[i].page) + sl[i].offset;
- mscp->sglist[i].num_bytes = sl[i].length;
- transfer_length += sl[i].length;
+ max = scsi_sg_count(SCpnt);
+ scsi_for_each_sg(SCpnt, sg, max, i) {
+ mscp->sglist[i].address = isa_page_to_bus(sg->page) + sg->offset;
+ mscp->sglist[i].num_bytes = sg->length;
+ transfer_length += sg->length;
}
mscp->number_of_sg_list = max;
mscp->transfer_data = isa_virt_to_bus(mscp->sglist);
@@ -730,15 +729,15 @@
my_mscp->target_id = SCpnt->device->id;
my_mscp->ch_no = 0;
my_mscp->lun = SCpnt->device->lun;
- if (SCpnt->use_sg) {
+ if (scsi_sg_count(SCpnt)) {
/* Set scatter/gather flag in SCSI command packet */
my_mscp->sg = TRUE;
build_sg_list(my_mscp, SCpnt);
} else {
/* Unset scatter/gather flag in SCSI command packet */
my_mscp->sg = FALSE;
- my_mscp->transfer_data = isa_virt_to_bus(SCpnt->request_buffer);
- my_mscp->transfer_data_length = SCpnt->request_bufflen;
+ my_mscp->transfer_data = isa_virt_to_bus(scsi_sglist(SCpnt));
+ my_mscp->transfer_data_length = scsi_bufflen(SCpnt);
}
my_mscp->command_link = 0; /*???*/
my_mscp->scsi_command_link_id = 0; /*???*/
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 30be765..d6fd425 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1091,6 +1091,7 @@
unchar *cdb = (unchar *) SCpnt->cmnd;
unchar idlun;
short cdblen;
+ int nseg;
Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
cdblen = SCpnt->cmd_len;
@@ -1106,28 +1107,29 @@
SCpnt->host_scribble = (unchar *) scb;
scb->host = host;
- if (SCpnt->use_sg) {
- struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+ nseg = scsi_sg_count(SCpnt);
+ if (nseg) {
+ struct scatterlist *sg;
unsigned i;
if (SCpnt->device->host->sg_tablesize == SG_NONE) {
panic("wd7000_queuecommand: scatter/gather not supported.\n");
}
- dprintk("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
+ dprintk("Using scatter/gather with %d elements.\n", nseg);
sgb = scb->sgb;
scb->op = 1;
any2scsi(scb->dataptr, (int) sgb);
- any2scsi(scb->maxlen, SCpnt->use_sg * sizeof(Sgb));
+ any2scsi(scb->maxlen, nseg * sizeof(Sgb));
- for (i = 0; i < SCpnt->use_sg; i++) {
- any2scsi(sgb[i].ptr, isa_page_to_bus(sg[i].page) + sg[i].offset);
- any2scsi(sgb[i].len, sg[i].length);
+ scsi_for_each_sg(SCpnt, sg, nseg, i) {
+ any2scsi(sgb[i].ptr, isa_page_to_bus(sg->page) + sg->offset);
+ any2scsi(sgb[i].len, sg->length);
}
} else {
scb->op = 0;
- any2scsi(scb->dataptr, isa_virt_to_bus(SCpnt->request_buffer));
- any2scsi(scb->maxlen, SCpnt->request_bufflen);
+ any2scsi(scb->dataptr, isa_virt_to_bus(scsi_sglist(SCpnt)));
+ any2scsi(scb->maxlen, scsi_bufflen(SCpnt));
}
/* FIXME: drop lock and yield here ? */
diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c
new file mode 100644
index 0000000..5070387
--- /dev/null
+++ b/drivers/scsi/zorro7xx.c
@@ -0,0 +1,180 @@
+/*
+ * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
+ * Amiga MacroSystemUS WarpEngine SCSI controller.
+ * Amiga Technologies/DKB A4091 SCSI controller.
+ *
+ * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * plus modifications of the 53c7xx.c driver to support the Amiga.
+ *
+ * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/zorro.h>
+#include <asm/amigaints.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+
+MODULE_AUTHOR("Alan Hourihane <alanh@fairlite.demon.co.uk> / Kars de Jong <jongk@linux-m68k.org>");
+MODULE_DESCRIPTION("Amiga Zorro NCR53C710 driver");
+MODULE_LICENSE("GPL");
+
+
+static struct scsi_host_template zorro7xx_scsi_driver_template = {
+ .proc_name = "zorro7xx",
+ .this_id = 7,
+ .module = THIS_MODULE,
+};
+
+static struct zorro_driver_data {
+ const char *name;
+ unsigned long offset;
+ int absolute; /* offset is absolute address */
+} zorro7xx_driver_data[] __devinitdata = {
+ { .name = "PowerUP 603e+", .offset = 0xf40000, .absolute = 1 },
+ { .name = "WarpEngine 40xx", .offset = 0x40000 },
+ { .name = "A4091", .offset = 0x800000 },
+ { .name = "GForce 040/060", .offset = 0x40000 },
+ { 0 }
+};
+
+static struct zorro_device_id zorro7xx_zorro_tbl[] __devinitdata = {
+ {
+ .id = ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS,
+ .driver_data = (unsigned long)&zorro7xx_driver_data[0],
+ },
+ {
+ .id = ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx,
+ .driver_data = (unsigned long)&zorro7xx_driver_data[1],
+ },
+ {
+ .id = ZORRO_PROD_CBM_A4091_1,
+ .driver_data = (unsigned long)&zorro7xx_driver_data[2],
+ },
+ {
+ .id = ZORRO_PROD_CBM_A4091_2,
+ .driver_data = (unsigned long)&zorro7xx_driver_data[2],
+ },
+ {
+ .id = ZORRO_PROD_GVP_GFORCE_040_060,
+ .driver_data = (unsigned long)&zorro7xx_driver_data[3],
+ },
+ { 0 }
+};
+
+static int __devinit zorro7xx_init_one(struct zorro_dev *z,
+ const struct zorro_device_id *ent)
+{
+ struct Scsi_Host * host = NULL;
+ struct NCR_700_Host_Parameters *hostdata;
+ struct zorro_driver_data *zdd;
+ unsigned long board, ioaddr;
+
+ board = zorro_resource_start(z);
+ zdd = (struct zorro_driver_data *)ent->driver_data;
+
+ if (zdd->absolute) {
+ ioaddr = zdd->offset;
+ } else {
+ ioaddr = board + zdd->offset;
+ }
+
+ if (!zorro_request_device(z, zdd->name)) {
+ printk(KERN_ERR "zorro7xx: cannot reserve region 0x%lx, abort\n",
+ board);
+ return -EBUSY;
+ }
+
+ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (hostdata == NULL) {
+ printk(KERN_ERR "zorro7xx: Failed to allocate host data\n");
+ goto out_release;
+ }
+
+ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
+
+ /* Fill in the required pieces of hostdata */
+ if (ioaddr > 0x01000000)
+ hostdata->base = ioremap(ioaddr, zorro_resource_len(z));
+ else
+ hostdata->base = (void __iomem *)ZTWO_VADDR(ioaddr);
+
+ hostdata->clock = 50;
+ hostdata->chip710 = 1;
+
+ /* Settings for at least WarpEngine 40xx */
+ hostdata->ctest7_extra = CTEST7_TT1;
+
+ zorro7xx_scsi_driver_template.name = zdd->name;
+
+ /* and register the chip */
+ host = NCR_700_detect(&zorro7xx_scsi_driver_template, hostdata,
+ &z->dev);
+ if (!host) {
+ printk(KERN_ERR "zorro7xx: No host detected; "
+ "board configuration problem?\n");
+ goto out_free;
+ }
+
+ host->this_id = 7;
+ host->base = ioaddr;
+ host->irq = IRQ_AMIGA_PORTS;
+
+ if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "zorro7xx-scsi",
+ host)) {
+ printk(KERN_ERR "zorro7xx: request_irq failed\n");
+ goto out_put_host;
+ }
+
+ scsi_scan_host(host);
+
+ return 0;
+
+ out_put_host:
+ scsi_host_put(host);
+ out_free:
+ if (ioaddr > 0x01000000)
+ iounmap(hostdata->base);
+ kfree(hostdata);
+ out_release:
+ zorro_release_device(z);
+
+ return -ENODEV;
+}
+
+static __devexit void zorro7xx_remove_one(struct zorro_dev *z)
+{
+ struct Scsi_Host *host = dev_to_shost(&z->dev);
+ struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
+
+ scsi_remove_host(host);
+
+ NCR_700_release(host);
+ kfree(hostdata);
+ free_irq(host->irq, host);
+ zorro_release_device(z);
+}
+
+static struct zorro_driver zorro7xx_driver = {
+ .name = "zorro7xx-scsi",
+ .id_table = zorro7xx_zorro_tbl,
+ .probe = zorro7xx_init_one,
+ .remove = __devexit_p(zorro7xx_remove_one),
+};
+
+static int __init zorro7xx_scsi_init(void)
+{
+ return zorro_register_driver(&zorro7xx_driver);
+}
+
+static void __exit zorro7xx_scsi_exit(void)
+{
+ zorro_unregister_driver(&zorro7xx_driver);
+}
+
+module_init(zorro7xx_scsi_init);
+module_exit(zorro7xx_scsi_exit);
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index c0a962b..0174a32 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -937,6 +937,7 @@
*m66592->ep0_buf = status;
m66592->ep0_req->buf = m66592->ep0_buf;
m66592->ep0_req->length = 2;
+ /* AV: what happens if we get called again before that gets through? */
m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL);
}
@@ -1254,24 +1255,6 @@
kfree(req);
}
-static void *m66592_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
- dma_addr_t *dma, gfp_t gfp_flags)
-{
- void *buf;
-
- buf = kzalloc(bytes, gfp_flags);
- if (dma)
- *dma = virt_to_bus(buf);
-
- return buf;
-}
-
-static void m66592_free_buffer(struct usb_ep *_ep, void *buf,
- dma_addr_t dma, unsigned bytes)
-{
- kfree(buf);
-}
-
static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
gfp_t gfp_flags)
{
@@ -1378,9 +1361,6 @@
.alloc_request = m66592_alloc_request,
.free_request = m66592_free_request,
- .alloc_buffer = m66592_alloc_buffer,
- .free_buffer = m66592_free_buffer,
-
.queue = m66592_queue,
.dequeue = m66592_dequeue,
@@ -1603,11 +1583,12 @@
the_controller = m66592;
+ /* AV: leaks */
m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
if (m66592->ep0_req == NULL)
goto clean_up;
- m66592->ep0_buf = m66592_alloc_buffer(&m66592->ep[0].ep, 2, NULL,
- GFP_KERNEL);
+ /* AV: leaks, and do we really need it separately allocated? */
+ m66592->ep0_buf = kzalloc(2, GFP_KERNEL);
if (m66592->ep0_buf == NULL)
goto clean_up;
diff --git a/fs/9p/9p.h b/fs/9p/9p.h
deleted file mode 100644
index 94e2f92..0000000
--- a/fs/9p/9p.h
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * linux/fs/9p/9p.h
- *
- * 9P protocol definitions.
- *
- * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-/* Message Types */
-enum {
- TVERSION = 100,
- RVERSION,
- TAUTH = 102,
- RAUTH,
- TATTACH = 104,
- RATTACH,
- TERROR = 106,
- RERROR,
- TFLUSH = 108,
- RFLUSH,
- TWALK = 110,
- RWALK,
- TOPEN = 112,
- ROPEN,
- TCREATE = 114,
- RCREATE,
- TREAD = 116,
- RREAD,
- TWRITE = 118,
- RWRITE,
- TCLUNK = 120,
- RCLUNK,
- TREMOVE = 122,
- RREMOVE,
- TSTAT = 124,
- RSTAT,
- TWSTAT = 126,
- RWSTAT,
-};
-
-/* modes */
-enum {
- V9FS_OREAD = 0x00,
- V9FS_OWRITE = 0x01,
- V9FS_ORDWR = 0x02,
- V9FS_OEXEC = 0x03,
- V9FS_OEXCL = 0x04,
- V9FS_OTRUNC = 0x10,
- V9FS_OREXEC = 0x20,
- V9FS_ORCLOSE = 0x40,
- V9FS_OAPPEND = 0x80,
-};
-
-/* permissions */
-enum {
- V9FS_DMDIR = 0x80000000,
- V9FS_DMAPPEND = 0x40000000,
- V9FS_DMEXCL = 0x20000000,
- V9FS_DMMOUNT = 0x10000000,
- V9FS_DMAUTH = 0x08000000,
- V9FS_DMTMP = 0x04000000,
- V9FS_DMSYMLINK = 0x02000000,
- V9FS_DMLINK = 0x01000000,
- /* 9P2000.u extensions */
- V9FS_DMDEVICE = 0x00800000,
- V9FS_DMNAMEDPIPE = 0x00200000,
- V9FS_DMSOCKET = 0x00100000,
- V9FS_DMSETUID = 0x00080000,
- V9FS_DMSETGID = 0x00040000,
-};
-
-/* qid.types */
-enum {
- V9FS_QTDIR = 0x80,
- V9FS_QTAPPEND = 0x40,
- V9FS_QTEXCL = 0x20,
- V9FS_QTMOUNT = 0x10,
- V9FS_QTAUTH = 0x08,
- V9FS_QTTMP = 0x04,
- V9FS_QTSYMLINK = 0x02,
- V9FS_QTLINK = 0x01,
- V9FS_QTFILE = 0x00,
-};
-
-#define V9FS_NOTAG (u16)(~0)
-#define V9FS_NOFID (u32)(~0)
-#define V9FS_MAXWELEM 16
-
-/* ample room for Twrite/Rread header (iounit) */
-#define V9FS_IOHDRSZ 24
-
-struct v9fs_str {
- u16 len;
- char *str;
-};
-
-/* qids are the unique ID for a file (like an inode */
-struct v9fs_qid {
- u8 type;
- u32 version;
- u64 path;
-};
-
-/* Plan 9 file metadata (stat) structure */
-struct v9fs_stat {
- u16 size;
- u16 type;
- u32 dev;
- struct v9fs_qid qid;
- u32 mode;
- u32 atime;
- u32 mtime;
- u64 length;
- struct v9fs_str name;
- struct v9fs_str uid;
- struct v9fs_str gid;
- struct v9fs_str muid;
- struct v9fs_str extension; /* 9p2000.u extensions */
- u32 n_uid; /* 9p2000.u extensions */
- u32 n_gid; /* 9p2000.u extensions */
- u32 n_muid; /* 9p2000.u extensions */
-};
-
-/* file metadata (stat) structure used to create Twstat message
- The is similar to v9fs_stat, but the strings don't point to
- the same memory block and should be freed separately
-*/
-struct v9fs_wstat {
- u16 size;
- u16 type;
- u32 dev;
- struct v9fs_qid qid;
- u32 mode;
- u32 atime;
- u32 mtime;
- u64 length;
- char *name;
- char *uid;
- char *gid;
- char *muid;
- char *extension; /* 9p2000.u extensions */
- u32 n_uid; /* 9p2000.u extensions */
- u32 n_gid; /* 9p2000.u extensions */
- u32 n_muid; /* 9p2000.u extensions */
-};
-
-/* Structures for Protocol Operations */
-
-struct Tversion {
- u32 msize;
- struct v9fs_str version;
-};
-
-struct Rversion {
- u32 msize;
- struct v9fs_str version;
-};
-
-struct Tauth {
- u32 afid;
- struct v9fs_str uname;
- struct v9fs_str aname;
-};
-
-struct Rauth {
- struct v9fs_qid qid;
-};
-
-struct Rerror {
- struct v9fs_str error;
- u32 errno; /* 9p2000.u extension */
-};
-
-struct Tflush {
- u16 oldtag;
-};
-
-struct Rflush {
-};
-
-struct Tattach {
- u32 fid;
- u32 afid;
- struct v9fs_str uname;
- struct v9fs_str aname;
-};
-
-struct Rattach {
- struct v9fs_qid qid;
-};
-
-struct Twalk {
- u32 fid;
- u32 newfid;
- u16 nwname;
- struct v9fs_str wnames[16];
-};
-
-struct Rwalk {
- u16 nwqid;
- struct v9fs_qid wqids[16];
-};
-
-struct Topen {
- u32 fid;
- u8 mode;
-};
-
-struct Ropen {
- struct v9fs_qid qid;
- u32 iounit;
-};
-
-struct Tcreate {
- u32 fid;
- struct v9fs_str name;
- u32 perm;
- u8 mode;
- struct v9fs_str extension;
-};
-
-struct Rcreate {
- struct v9fs_qid qid;
- u32 iounit;
-};
-
-struct Tread {
- u32 fid;
- u64 offset;
- u32 count;
-};
-
-struct Rread {
- u32 count;
- u8 *data;
-};
-
-struct Twrite {
- u32 fid;
- u64 offset;
- u32 count;
- u8 *data;
-};
-
-struct Rwrite {
- u32 count;
-};
-
-struct Tclunk {
- u32 fid;
-};
-
-struct Rclunk {
-};
-
-struct Tremove {
- u32 fid;
-};
-
-struct Rremove {
-};
-
-struct Tstat {
- u32 fid;
-};
-
-struct Rstat {
- struct v9fs_stat stat;
-};
-
-struct Twstat {
- u32 fid;
- struct v9fs_stat stat;
-};
-
-struct Rwstat {
-};
-
-/*
- * fcall is the primary packet structure
- *
- */
-
-struct v9fs_fcall {
- u32 size;
- u8 id;
- u16 tag;
- void *sdata;
-
- union {
- struct Tversion tversion;
- struct Rversion rversion;
- struct Tauth tauth;
- struct Rauth rauth;
- struct Rerror rerror;
- struct Tflush tflush;
- struct Rflush rflush;
- struct Tattach tattach;
- struct Rattach rattach;
- struct Twalk twalk;
- struct Rwalk rwalk;
- struct Topen topen;
- struct Ropen ropen;
- struct Tcreate tcreate;
- struct Rcreate rcreate;
- struct Tread tread;
- struct Rread rread;
- struct Twrite twrite;
- struct Rwrite rwrite;
- struct Tclunk tclunk;
- struct Rclunk rclunk;
- struct Tremove tremove;
- struct Rremove rremove;
- struct Tstat tstat;
- struct Rstat rstat;
- struct Twstat twstat;
- struct Rwstat rwstat;
- } params;
-};
-
-#define PRINT_FCALL_ERROR(s, fcall) dprintk(DEBUG_ERROR, "%s: %.*s\n", s, \
- fcall?fcall->params.rerror.error.len:0, \
- fcall?fcall->params.rerror.error.str:"");
-
-int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
- char *version, struct v9fs_fcall **rcall);
-
-int v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
- u32 fid, u32 afid, struct v9fs_fcall **rcall);
-
-int v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid);
-
-int v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid,
- struct v9fs_fcall **rcall);
-
-int v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
- struct v9fs_wstat *wstat, struct v9fs_fcall **rcall);
-
-int v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
- char *name, struct v9fs_fcall **rcall);
-
-int v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
- struct v9fs_fcall **rcall);
-
-int v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
- struct v9fs_fcall **rcall);
-
-int v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
- u32 perm, u8 mode, char *extension, struct v9fs_fcall **rcall);
-
-int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid,
- u64 offset, u32 count, struct v9fs_fcall **rcall);
-
-int v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
- u32 count, const char __user * data,
- struct v9fs_fcall **rcall);
-int v9fs_printfcall(char *, int, struct v9fs_fcall *, int);
diff --git a/fs/9p/Makefile b/fs/9p/Makefile
index 87897f8..bc7f0d1 100644
--- a/fs/9p/Makefile
+++ b/fs/9p/Makefile
@@ -1,18 +1,12 @@
obj-$(CONFIG_9P_FS) := 9p.o
9p-objs := \
- trans_fd.o \
- mux.o \
- fcall.o \
- conv.o \
vfs_super.o \
vfs_inode.o \
vfs_addr.o \
vfs_file.o \
vfs_dir.o \
vfs_dentry.o \
- error.o \
v9fs.o \
fid.o \
- fcprint.o
diff --git a/fs/9p/conv.c b/fs/9p/conv.c
deleted file mode 100644
index a3ed571..0000000
--- a/fs/9p/conv.c
+++ /dev/null
@@ -1,845 +0,0 @@
-/*
- * linux/fs/9p/conv.c
- *
- * 9P protocol conversion functions
- *
- * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/idr.h>
-#include <asm/uaccess.h>
-#include "debug.h"
-#include "v9fs.h"
-#include "9p.h"
-#include "conv.h"
-
-/*
- * Buffer to help with string parsing
- */
-struct cbuf {
- unsigned char *sp;
- unsigned char *p;
- unsigned char *ep;
-};
-
-static inline void buf_init(struct cbuf *buf, void *data, int datalen)
-{
- buf->sp = buf->p = data;
- buf->ep = data + datalen;
-}
-
-static inline int buf_check_overflow(struct cbuf *buf)
-{
- return buf->p > buf->ep;
-}
-
-static int buf_check_size(struct cbuf *buf, int len)
-{
- if (buf->p + len > buf->ep) {
- if (buf->p < buf->ep) {
- eprintk(KERN_ERR, "buffer overflow: want %d has %d\n",
- len, (int)(buf->ep - buf->p));
- dump_stack();
- buf->p = buf->ep + 1;
- }
-
- return 0;
- }
-
- return 1;
-}
-
-static void *buf_alloc(struct cbuf *buf, int len)
-{
- void *ret = NULL;
-
- if (buf_check_size(buf, len)) {
- ret = buf->p;
- buf->p += len;
- }
-
- return ret;
-}
-
-static void buf_put_int8(struct cbuf *buf, u8 val)
-{
- if (buf_check_size(buf, 1)) {
- buf->p[0] = val;
- buf->p++;
- }
-}
-
-static void buf_put_int16(struct cbuf *buf, u16 val)
-{
- if (buf_check_size(buf, 2)) {
- *(__le16 *) buf->p = cpu_to_le16(val);
- buf->p += 2;
- }
-}
-
-static void buf_put_int32(struct cbuf *buf, u32 val)
-{
- if (buf_check_size(buf, 4)) {
- *(__le32 *)buf->p = cpu_to_le32(val);
- buf->p += 4;
- }
-}
-
-static void buf_put_int64(struct cbuf *buf, u64 val)
-{
- if (buf_check_size(buf, 8)) {
- *(__le64 *)buf->p = cpu_to_le64(val);
- buf->p += 8;
- }
-}
-
-static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
-{
- char *ret;
-
- ret = NULL;
- if (buf_check_size(buf, slen + 2)) {
- buf_put_int16(buf, slen);
- ret = buf->p;
- memcpy(buf->p, s, slen);
- buf->p += slen;
- }
-
- return ret;
-}
-
-static inline void buf_put_string(struct cbuf *buf, const char *s)
-{
- buf_put_stringn(buf, s, strlen(s));
-}
-
-static u8 buf_get_int8(struct cbuf *buf)
-{
- u8 ret = 0;
-
- if (buf_check_size(buf, 1)) {
- ret = buf->p[0];
- buf->p++;
- }
-
- return ret;
-}
-
-static u16 buf_get_int16(struct cbuf *buf)
-{
- u16 ret = 0;
-
- if (buf_check_size(buf, 2)) {
- ret = le16_to_cpu(*(__le16 *)buf->p);
- buf->p += 2;
- }
-
- return ret;
-}
-
-static u32 buf_get_int32(struct cbuf *buf)
-{
- u32 ret = 0;
-
- if (buf_check_size(buf, 4)) {
- ret = le32_to_cpu(*(__le32 *)buf->p);
- buf->p += 4;
- }
-
- return ret;
-}
-
-static u64 buf_get_int64(struct cbuf *buf)
-{
- u64 ret = 0;
-
- if (buf_check_size(buf, 8)) {
- ret = le64_to_cpu(*(__le64 *)buf->p);
- buf->p += 8;
- }
-
- return ret;
-}
-
-static void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
-{
- vstr->len = buf_get_int16(buf);
- if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
- vstr->str = buf->p;
- buf->p += vstr->len;
- } else {
- vstr->len = 0;
- vstr->str = NULL;
- }
-}
-
-static void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
-{
- qid->type = buf_get_int8(bufp);
- qid->version = buf_get_int32(bufp);
- qid->path = buf_get_int64(bufp);
-}
-
-/**
- * v9fs_size_wstat - calculate the size of a variable length stat struct
- * @stat: metadata (stat) structure
- * @extended: non-zero if 9P2000.u
- *
- */
-
-static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
-{
- int size = 0;
-
- if (wstat == NULL) {
- eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n");
- return 0;
- }
-
- size = /* 2 + *//* size[2] */
- 2 + /* type[2] */
- 4 + /* dev[4] */
- 1 + /* qid.type[1] */
- 4 + /* qid.vers[4] */
- 8 + /* qid.path[8] */
- 4 + /* mode[4] */
- 4 + /* atime[4] */
- 4 + /* mtime[4] */
- 8 + /* length[8] */
- 8; /* minimum sum of string lengths */
-
- if (wstat->name)
- size += strlen(wstat->name);
- if (wstat->uid)
- size += strlen(wstat->uid);
- if (wstat->gid)
- size += strlen(wstat->gid);
- if (wstat->muid)
- size += strlen(wstat->muid);
-
- if (extended) {
- size += 4 + /* n_uid[4] */
- 4 + /* n_gid[4] */
- 4 + /* n_muid[4] */
- 2; /* string length of extension[4] */
- if (wstat->extension)
- size += strlen(wstat->extension);
- }
-
- return size;
-}
-
-/**
- * buf_get_stat - safely decode a recieved metadata (stat) structure
- * @bufp: buffer to deserialize
- * @stat: metadata (stat) structure
- * @extended: non-zero if 9P2000.u
- *
- */
-
-static void
-buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
-{
- stat->size = buf_get_int16(bufp);
- stat->type = buf_get_int16(bufp);
- stat->dev = buf_get_int32(bufp);
- stat->qid.type = buf_get_int8(bufp);
- stat->qid.version = buf_get_int32(bufp);
- stat->qid.path = buf_get_int64(bufp);
- stat->mode = buf_get_int32(bufp);
- stat->atime = buf_get_int32(bufp);
- stat->mtime = buf_get_int32(bufp);
- stat->length = buf_get_int64(bufp);
- buf_get_str(bufp, &stat->name);
- buf_get_str(bufp, &stat->uid);
- buf_get_str(bufp, &stat->gid);
- buf_get_str(bufp, &stat->muid);
-
- if (extended) {
- buf_get_str(bufp, &stat->extension);
- stat->n_uid = buf_get_int32(bufp);
- stat->n_gid = buf_get_int32(bufp);
- stat->n_muid = buf_get_int32(bufp);
- }
-}
-
-/**
- * v9fs_deserialize_stat - decode a received metadata structure
- * @buf: buffer to deserialize
- * @buflen: length of received buffer
- * @stat: metadata structure to decode into
- * @extended: non-zero if 9P2000.u
- *
- * Note: stat will point to the buf region.
- */
-
-int
-v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
- int extended)
-{
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
- unsigned char *p;
-
- buf_init(bufp, buf, buflen);
- p = bufp->p;
- buf_get_stat(bufp, stat, extended);
-
- if (buf_check_overflow(bufp))
- return 0;
- else
- return bufp->p - p;
-}
-
-/**
- * deserialize_fcall - unmarshal a response
- * @buf: recieved buffer
- * @buflen: length of received buffer
- * @rcall: fcall structure to populate
- * @rcalllen: length of fcall structure to populate
- * @extended: non-zero if 9P2000.u
- *
- */
-
-int
-v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
- int extended)
-{
-
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
- int i = 0;
-
- buf_init(bufp, buf, buflen);
-
- rcall->size = buf_get_int32(bufp);
- rcall->id = buf_get_int8(bufp);
- rcall->tag = buf_get_int16(bufp);
-
- dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id,
- rcall->tag);
-
- switch (rcall->id) {
- default:
- eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id);
- return -EPROTO;
- case RVERSION:
- rcall->params.rversion.msize = buf_get_int32(bufp);
- buf_get_str(bufp, &rcall->params.rversion.version);
- break;
- case RFLUSH:
- break;
- case RATTACH:
- rcall->params.rattach.qid.type = buf_get_int8(bufp);
- rcall->params.rattach.qid.version = buf_get_int32(bufp);
- rcall->params.rattach.qid.path = buf_get_int64(bufp);
- break;
- case RWALK:
- rcall->params.rwalk.nwqid = buf_get_int16(bufp);
- if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) {
- eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n",
- V9FS_MAXWELEM, rcall->params.rwalk.nwqid);
- return -EPROTO;
- }
-
- for (i = 0; i < rcall->params.rwalk.nwqid; i++)
- buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
- break;
- case ROPEN:
- buf_get_qid(bufp, &rcall->params.ropen.qid);
- rcall->params.ropen.iounit = buf_get_int32(bufp);
- break;
- case RCREATE:
- buf_get_qid(bufp, &rcall->params.rcreate.qid);
- rcall->params.rcreate.iounit = buf_get_int32(bufp);
- break;
- case RREAD:
- rcall->params.rread.count = buf_get_int32(bufp);
- rcall->params.rread.data = bufp->p;
- buf_check_size(bufp, rcall->params.rread.count);
- break;
- case RWRITE:
- rcall->params.rwrite.count = buf_get_int32(bufp);
- break;
- case RCLUNK:
- break;
- case RREMOVE:
- break;
- case RSTAT:
- buf_get_int16(bufp);
- buf_get_stat(bufp, &rcall->params.rstat.stat, extended);
- break;
- case RWSTAT:
- break;
- case RERROR:
- buf_get_str(bufp, &rcall->params.rerror.error);
- if (extended)
- rcall->params.rerror.errno = buf_get_int16(bufp);
- break;
- }
-
- if (buf_check_overflow(bufp)) {
- dprintk(DEBUG_ERROR, "buffer overflow\n");
- return -EIO;
- }
-
- return bufp->p - bufp->sp;
-}
-
-static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p)
-{
- *p = val;
- buf_put_int8(bufp, val);
-}
-
-static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p)
-{
- *p = val;
- buf_put_int16(bufp, val);
-}
-
-static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p)
-{
- *p = val;
- buf_put_int32(bufp, val);
-}
-
-static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
-{
- *p = val;
- buf_put_int64(bufp, val);
-}
-
-static void
-v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
-{
- int len;
- char *s;
-
- if (data)
- len = strlen(data);
- else
- len = 0;
-
- s = buf_put_stringn(bufp, data, len);
- if (str) {
- str->len = len;
- str->str = s;
- }
-}
-
-static int
-v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
- unsigned char **pdata)
-{
- *pdata = buf_alloc(bufp, count);
- return copy_from_user(*pdata, data, count);
-}
-
-static void
-v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat,
- struct v9fs_stat *stat, int statsz, int extended)
-{
- v9fs_put_int16(bufp, statsz, &stat->size);
- v9fs_put_int16(bufp, wstat->type, &stat->type);
- v9fs_put_int32(bufp, wstat->dev, &stat->dev);
- v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type);
- v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version);
- v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path);
- v9fs_put_int32(bufp, wstat->mode, &stat->mode);
- v9fs_put_int32(bufp, wstat->atime, &stat->atime);
- v9fs_put_int32(bufp, wstat->mtime, &stat->mtime);
- v9fs_put_int64(bufp, wstat->length, &stat->length);
-
- v9fs_put_str(bufp, wstat->name, &stat->name);
- v9fs_put_str(bufp, wstat->uid, &stat->uid);
- v9fs_put_str(bufp, wstat->gid, &stat->gid);
- v9fs_put_str(bufp, wstat->muid, &stat->muid);
-
- if (extended) {
- v9fs_put_str(bufp, wstat->extension, &stat->extension);
- v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid);
- v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid);
- v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid);
- }
-}
-
-static struct v9fs_fcall *
-v9fs_create_common(struct cbuf *bufp, u32 size, u8 id)
-{
- struct v9fs_fcall *fc;
-
- size += 4 + 1 + 2; /* size[4] id[1] tag[2] */
- fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL);
- if (!fc)
- return ERR_PTR(-ENOMEM);
-
- fc->sdata = (char *)fc + sizeof(*fc);
-
- buf_init(bufp, (char *)fc->sdata, size);
- v9fs_put_int32(bufp, size, &fc->size);
- v9fs_put_int8(bufp, id, &fc->id);
- v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag);
-
- return fc;
-}
-
-void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag)
-{
- fc->tag = tag;
- *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
-}
-
-struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version)
-{
- int size;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- size = 4 + 2 + strlen(version); /* msize[4] version[s] */
- fc = v9fs_create_common(bufp, size, TVERSION);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int32(bufp, msize, &fc->params.tversion.msize);
- v9fs_put_str(bufp, version, &fc->params.tversion.version);
-
- if (buf_check_overflow(bufp)) {
- kfree(fc);
- fc = ERR_PTR(-ENOMEM);
- }
- error:
- return fc;
-}
-
-#if 0
-struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname)
-{
- int size;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */
- fc = v9fs_create_common(bufp, size, TAUTH);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int32(bufp, afid, &fc->params.tauth.afid);
- v9fs_put_str(bufp, uname, &fc->params.tauth.uname);
- v9fs_put_str(bufp, aname, &fc->params.tauth.aname);
-
- if (buf_check_overflow(bufp)) {
- kfree(fc);
- fc = ERR_PTR(-ENOMEM);
- }
- error:
- return fc;
-}
-#endif /* 0 */
-
-struct v9fs_fcall *
-v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
-{
- int size;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */
- fc = v9fs_create_common(bufp, size, TATTACH);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int32(bufp, fid, &fc->params.tattach.fid);
- v9fs_put_int32(bufp, afid, &fc->params.tattach.afid);
- v9fs_put_str(bufp, uname, &fc->params.tattach.uname);
- v9fs_put_str(bufp, aname, &fc->params.tattach.aname);
-
- error:
- return fc;
-}
-
-struct v9fs_fcall *v9fs_create_tflush(u16 oldtag)
-{
- int size;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- size = 2; /* oldtag[2] */
- fc = v9fs_create_common(bufp, size, TFLUSH);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
-
- if (buf_check_overflow(bufp)) {
- kfree(fc);
- fc = ERR_PTR(-ENOMEM);
- }
- error:
- return fc;
-}
-
-struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
- char **wnames)
-{
- int i, size;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- if (nwname > V9FS_MAXWELEM) {
- dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM);
- return NULL;
- }
-
- size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */
- for (i = 0; i < nwname; i++) {
- size += 2 + strlen(wnames[i]); /* wname[s] */
- }
-
- fc = v9fs_create_common(bufp, size, TWALK);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int32(bufp, fid, &fc->params.twalk.fid);
- v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid);
- v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname);
- for (i = 0; i < nwname; i++) {
- v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
- }
-
- if (buf_check_overflow(bufp)) {
- kfree(fc);
- fc = ERR_PTR(-ENOMEM);
- }
- error:
- return fc;
-}
-
-struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode)
-{
- int size;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- size = 4 + 1; /* fid[4] mode[1] */
- fc = v9fs_create_common(bufp, size, TOPEN);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int32(bufp, fid, &fc->params.topen.fid);
- v9fs_put_int8(bufp, mode, &fc->params.topen.mode);
-
- if (buf_check_overflow(bufp)) {
- kfree(fc);
- fc = ERR_PTR(-ENOMEM);
- }
- error:
- return fc;
-}
-
-struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
- char *extension, int extended)
-{
- int size;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */
- if (extended) {
- size += 2 + /* extension[s] */
- (extension == NULL ? 0 : strlen(extension));
- }
-
- fc = v9fs_create_common(bufp, size, TCREATE);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid);
- v9fs_put_str(bufp, name, &fc->params.tcreate.name);
- v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm);
- v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode);
- if (extended)
- v9fs_put_str(bufp, extension, &fc->params.tcreate.extension);
-
- if (buf_check_overflow(bufp)) {
- kfree(fc);
- fc = ERR_PTR(-ENOMEM);
- }
- error:
- return fc;
-}
-
-struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count)
-{
- int size;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */
- fc = v9fs_create_common(bufp, size, TREAD);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int32(bufp, fid, &fc->params.tread.fid);
- v9fs_put_int64(bufp, offset, &fc->params.tread.offset);
- v9fs_put_int32(bufp, count, &fc->params.tread.count);
-
- if (buf_check_overflow(bufp)) {
- kfree(fc);
- fc = ERR_PTR(-ENOMEM);
- }
- error:
- return fc;
-}
-
-struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
- const char __user * data)
-{
- int size, err;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */
- fc = v9fs_create_common(bufp, size, TWRITE);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int32(bufp, fid, &fc->params.twrite.fid);
- v9fs_put_int64(bufp, offset, &fc->params.twrite.offset);
- v9fs_put_int32(bufp, count, &fc->params.twrite.count);
- err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data);
- if (err) {
- kfree(fc);
- fc = ERR_PTR(err);
- }
-
- if (buf_check_overflow(bufp)) {
- kfree(fc);
- fc = ERR_PTR(-ENOMEM);
- }
- error:
- return fc;
-}
-
-struct v9fs_fcall *v9fs_create_tclunk(u32 fid)
-{
- int size;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- size = 4; /* fid[4] */
- fc = v9fs_create_common(bufp, size, TCLUNK);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid);
-
- if (buf_check_overflow(bufp)) {
- kfree(fc);
- fc = ERR_PTR(-ENOMEM);
- }
- error:
- return fc;
-}
-
-struct v9fs_fcall *v9fs_create_tremove(u32 fid)
-{
- int size;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- size = 4; /* fid[4] */
- fc = v9fs_create_common(bufp, size, TREMOVE);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int32(bufp, fid, &fc->params.tremove.fid);
-
- if (buf_check_overflow(bufp)) {
- kfree(fc);
- fc = ERR_PTR(-ENOMEM);
- }
- error:
- return fc;
-}
-
-struct v9fs_fcall *v9fs_create_tstat(u32 fid)
-{
- int size;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- size = 4; /* fid[4] */
- fc = v9fs_create_common(bufp, size, TSTAT);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int32(bufp, fid, &fc->params.tstat.fid);
-
- if (buf_check_overflow(bufp)) {
- kfree(fc);
- fc = ERR_PTR(-ENOMEM);
- }
- error:
- return fc;
-}
-
-struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
- int extended)
-{
- int size, statsz;
- struct v9fs_fcall *fc;
- struct cbuf buffer;
- struct cbuf *bufp = &buffer;
-
- statsz = v9fs_size_wstat(wstat, extended);
- size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */
- fc = v9fs_create_common(bufp, size, TWSTAT);
- if (IS_ERR(fc))
- goto error;
-
- v9fs_put_int32(bufp, fid, &fc->params.twstat.fid);
- buf_put_int16(bufp, statsz + 2);
- v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended);
-
- if (buf_check_overflow(bufp)) {
- kfree(fc);
- fc = ERR_PTR(-ENOMEM);
- }
- error:
- return fc;
-}
diff --git a/fs/9p/conv.h b/fs/9p/conv.h
deleted file mode 100644
index dd5b6b1..0000000
--- a/fs/9p/conv.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * linux/fs/9p/conv.h
- *
- * 9P protocol conversion definitions.
- *
- * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
- int extended);
-int v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
- int extended);
-
-void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag);
-
-struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version);
-struct v9fs_fcall *v9fs_create_tattach(u32 fid, u32 afid, char *uname,
- char *aname);
-struct v9fs_fcall *v9fs_create_tflush(u16 oldtag);
-struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
- char **wnames);
-struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode);
-struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
- char *extension, int extended);
-struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count);
-struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
- const char __user *data);
-struct v9fs_fcall *v9fs_create_tclunk(u32 fid);
-struct v9fs_fcall *v9fs_create_tremove(u32 fid);
-struct v9fs_fcall *v9fs_create_tstat(u32 fid);
-struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
- int extended);
diff --git a/fs/9p/debug.h b/fs/9p/debug.h
deleted file mode 100644
index 4228c0b..0000000
--- a/fs/9p/debug.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * linux/fs/9p/debug.h - V9FS Debug Definitions
- *
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-#define DEBUG_ERROR (1<<0)
-#define DEBUG_CURRENT (1<<1)
-#define DEBUG_9P (1<<2)
-#define DEBUG_VFS (1<<3)
-#define DEBUG_CONV (1<<4)
-#define DEBUG_MUX (1<<5)
-#define DEBUG_TRANS (1<<6)
-#define DEBUG_SLABS (1<<7)
-#define DEBUG_FCALL (1<<8)
-
-#define DEBUG_DUMP_PKT 0
-
-extern int v9fs_debug_level;
-
-#define dprintk(level, format, arg...) \
-do { \
- if((v9fs_debug_level & level)==level) \
- printk(KERN_NOTICE "-- %s (%d): " \
- format , __FUNCTION__, current->pid , ## arg); \
-} while(0)
-
-#define eprintk(level, format, arg...) \
-do { \
- printk(level "v9fs: %s (%d): " \
- format , __FUNCTION__, current->pid , ## arg); \
-} while(0)
-
-#if DEBUG_DUMP_PKT
-static inline void dump_data(const unsigned char *data, unsigned int datalen)
-{
- int i, n;
- char buf[5*8];
-
- n = 0;
- i = 0;
- while (i < datalen) {
- n += snprintf(buf+n, sizeof(buf)-n, "%02x", data[i++]);
- if (i%4 == 0)
- n += snprintf(buf+n, sizeof(buf)-n, " ");
-
- if (i%16 == 0) {
- dprintk(DEBUG_ERROR, "%s\n", buf);
- n = 0;
- }
- }
-
- dprintk(DEBUG_ERROR, "%s\n", buf);
-}
-#else /* DEBUG_DUMP_PKT */
-static inline void dump_data(const unsigned char *data, unsigned int datalen)
-{
-
-}
-#endif /* DEBUG_DUMP_PKT */
diff --git a/fs/9p/error.c b/fs/9p/error.c
deleted file mode 100644
index 0d7fa4e..0000000
--- a/fs/9p/error.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * linux/fs/9p/error.c
- *
- * Error string handling
- *
- * Plan 9 uses error strings, Unix uses error numbers. These functions
- * try to help manage that and provide for dynamically adding error
- * mappings.
- *
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-#include <linux/module.h>
-
-#include <linux/list.h>
-#include <linux/jhash.h>
-
-#include "debug.h"
-#include "error.h"
-
-/**
- * v9fs_error_init - preload
- * @errstr: error string
- *
- */
-
-int v9fs_error_init(void)
-{
- struct errormap *c;
- int bucket;
-
- /* initialize hash table */
- for (bucket = 0; bucket < ERRHASHSZ; bucket++)
- INIT_HLIST_HEAD(&hash_errmap[bucket]);
-
- /* load initial error map into hash table */
- for (c = errmap; c->name != NULL; c++) {
- c->namelen = strlen(c->name);
- bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ;
- INIT_HLIST_NODE(&c->list);
- hlist_add_head(&c->list, &hash_errmap[bucket]);
- }
-
- return 1;
-}
-
-/**
- * errstr2errno - convert error string to error number
- * @errstr: error string
- *
- */
-
-int v9fs_errstr2errno(char *errstr, int len)
-{
- int errno = 0;
- struct hlist_node *p = NULL;
- struct errormap *c = NULL;
- int bucket = jhash(errstr, len, 0) % ERRHASHSZ;
-
- hlist_for_each_entry(c, p, &hash_errmap[bucket], list) {
- if (c->namelen==len && !memcmp(c->name, errstr, len)) {
- errno = c->val;
- break;
- }
- }
-
- if (errno == 0) {
- /* TODO: if error isn't found, add it dynamically */
- errstr[len] = 0;
- printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__,
- errstr);
- errno = 1;
- }
-
- return -errno;
-}
diff --git a/fs/9p/fcall.c b/fs/9p/fcall.c
deleted file mode 100644
index dc336a6..0000000
--- a/fs/9p/fcall.c
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * linux/fs/9p/fcall.c
- *
- * This file contains functions to perform synchronous 9P calls
- *
- * Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/idr.h>
-
-#include "debug.h"
-#include "v9fs.h"
-#include "9p.h"
-#include "conv.h"
-#include "mux.h"
-
-/**
- * v9fs_t_version - negotiate protocol parameters with sever
- * @v9ses: 9P2000 session information
- * @msize: requested max size packet
- * @version: requested version.extension string
- * @fcall: pointer to response fcall pointer
- *
- */
-
-int
-v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
- char *version, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version);
- tc = v9fs_create_tversion(msize, version);
-
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_attach - mount the server
- * @v9ses: 9P2000 session information
- * @uname: user name doing the attach
- * @aname: remote name being attached to
- * @fid: mount fid to attatch to root node
- * @afid: authentication fid (in this case result key)
- * @fcall: pointer to response fcall pointer
- *
- */
-
-int
-v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
- u32 fid, u32 afid, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall* tc;
-
- dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname,
- aname, fid, afid);
-
- tc = v9fs_create_tattach(fid, afid, uname, aname);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc,
- struct v9fs_fcall *rc, int err)
-{
- int fid, id;
- struct v9fs_session_info *v9ses;
-
- id = 0;
- fid = tc->params.tclunk.fid;
- if (rc)
- id = rc->id;
-
- kfree(tc);
- kfree(rc);
- if (id == RCLUNK) {
- v9ses = a;
- v9fs_put_idpool(fid, &v9ses->fidpool);
- }
-}
-
-/**
- * v9fs_t_clunk - release a fid (finish a transaction)
- * @v9ses: 9P2000 session information
- * @fid: fid to release
- * @fcall: pointer to response fcall pointer
- *
- */
-
-int
-v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid)
-{
- int ret;
- struct v9fs_fcall *tc, *rc;
-
- dprintk(DEBUG_9P, "fid %d\n", fid);
-
- rc = NULL;
- tc = v9fs_create_tclunk(fid);
- if (!IS_ERR(tc))
- ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
- else
- ret = PTR_ERR(tc);
-
- if (ret)
- dprintk(DEBUG_ERROR, "failed fid %d err %d\n", fid, ret);
-
- v9fs_t_clunk_cb(v9ses, tc, rc, ret);
- return ret;
-}
-
-#if 0
-/**
- * v9fs_v9fs_t_flush - flush a pending transaction
- * @v9ses: 9P2000 session information
- * @tag: tag to release
- *
- */
-int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "oldtag %d\n", oldtag);
-
- tc = v9fs_create_tflush(oldtag);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, NULL);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-#endif
-
-/**
- * v9fs_t_stat - read a file's meta-data
- * @v9ses: 9P2000 session information
- * @fid: fid pointing to file or directory to get info about
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "fid %d\n", fid);
-
- ret = -ENOMEM;
- tc = v9fs_create_tstat(fid);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_wstat - write a file's meta-data
- * @v9ses: 9P2000 session information
- * @fid: fid pointing to file or directory to write info about
- * @stat: metadata
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
- struct v9fs_wstat *wstat, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "fid %d\n", fid);
-
- tc = v9fs_create_twstat(fid, wstat, v9ses->extended);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_walk - walk a fid to a new file or directory
- * @v9ses: 9P2000 session information
- * @fid: fid to walk
- * @newfid: new fid (for clone operations)
- * @name: path to walk fid to
- * @fcall: pointer to response fcall
- *
- */
-
-/* TODO: support multiple walk */
-
-int
-v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
- char *name, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
- int nwname;
-
- dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name);
-
- if (name)
- nwname = 1;
- else
- nwname = 0;
-
- tc = v9fs_create_twalk(fid, newfid, nwname, &name);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_open - open a file
- *
- * @v9ses - 9P2000 session information
- * @fid - fid to open
- * @mode - mode to open file (R, RW, etc)
- * @fcall - pointer to response fcall
- *
- */
-
-int
-v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
- struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode);
-
- tc = v9fs_create_topen(fid, mode);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_remove - remove a file or directory
- * @v9ses: 9P2000 session information
- * @fid: fid to remove
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
- struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "fid %d\n", fid);
-
- tc = v9fs_create_tremove(fid);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_create - create a file or directory
- * @v9ses: 9P2000 session information
- * @fid: fid to create
- * @name: name of the file or directory to create
- * @perm: permissions to create with
- * @mode: mode to open file (R, RW, etc)
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, u32 perm,
- u8 mode, char *extension, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n",
- fid, name, perm, mode);
-
- tc = v9fs_create_tcreate(fid, name, perm, mode, extension,
- v9ses->extended);
-
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_read - read data
- * @v9ses: 9P2000 session information
- * @fid: fid to read from
- * @offset: offset to start read at
- * @count: how many bytes to read
- * @fcall: pointer to response fcall (with data)
- *
- */
-
-int
-v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
- u32 count, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc, *rc;
-
- dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
- (long long unsigned) offset, count);
-
- tc = v9fs_create_tread(fid, offset, count);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
- if (!ret)
- ret = rc->params.rread.count;
- if (rcp)
- *rcp = rc;
- else
- kfree(rc);
-
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_write - write data
- * @v9ses: 9P2000 session information
- * @fid: fid to write to
- * @offset: offset to start write at
- * @count: how many bytes to write
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, u32 count,
- const char __user *data, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc, *rc;
-
- dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
- (long long unsigned) offset, count);
-
- tc = v9fs_create_twrite(fid, offset, count, data);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
-
- if (!ret)
- ret = rc->params.rwrite.count;
- if (rcp)
- *rcp = rc;
- else
- kfree(rc);
-
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 9041971..08fa320 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -26,10 +26,10 @@
#include <linux/sched.h>
#include <linux/idr.h>
#include <asm/semaphore.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -40,70 +40,32 @@
*
*/
-int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
+int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
{
- struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
- dprintk(DEBUG_9P, "fid %d (%p) dentry %s (%p)\n", fid->fid, fid,
- dentry->d_iname, dentry);
- if (dentry->d_fsdata == NULL) {
- dentry->d_fsdata =
- kmalloc(sizeof(struct list_head), GFP_KERNEL);
- if (dentry->d_fsdata == NULL) {
- dprintk(DEBUG_ERROR, "Out of memory\n");
+ struct v9fs_dentry *dent;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "fid %d dentry %s\n",
+ fid->fid, dentry->d_iname);
+
+ dent = dentry->d_fsdata;
+ if (!dent) {
+ dent = kmalloc(sizeof(struct v9fs_dentry), GFP_KERNEL);
+ if (!dent)
return -ENOMEM;
- }
- fid_list = (struct list_head *)dentry->d_fsdata;
- INIT_LIST_HEAD(fid_list); /* Initialize list head */
+
+ spin_lock_init(&dent->lock);
+ INIT_LIST_HEAD(&dent->fidlist);
+ dentry->d_fsdata = dent;
}
- fid->uid = current->uid;
- list_add(&fid->list, fid_list);
+ spin_lock(&dent->lock);
+ list_add(&fid->dlist, &dent->fidlist);
+ spin_unlock(&dent->lock);
+
return 0;
}
/**
- * v9fs_fid_create - allocate a FID structure
- * @dentry - dentry to link newly created fid to
- *
- */
-
-struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *v9ses, int fid)
-{
- struct v9fs_fid *new;
-
- dprintk(DEBUG_9P, "fid create fid %d\n", fid);
- new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
- if (new == NULL) {
- dprintk(DEBUG_ERROR, "Out of Memory\n");
- return ERR_PTR(-ENOMEM);
- }
-
- new->fid = fid;
- new->v9ses = v9ses;
- new->fidopen = 0;
- new->fidclunked = 0;
- new->iounit = 0;
- new->rdir_pos = 0;
- new->rdir_fcall = NULL;
- init_MUTEX(&new->lock);
- INIT_LIST_HEAD(&new->list);
-
- return new;
-}
-
-/**
- * v9fs_fid_destroy - deallocate a FID structure
- * @fid: fid to destroy
- *
- */
-
-void v9fs_fid_destroy(struct v9fs_fid *fid)
-{
- list_del(&fid->list);
- kfree(fid);
-}
-
-/**
* v9fs_fid_lookup - return a locked fid from a dentry
* @dentry: dentry to look for fid in
*
@@ -114,30 +76,42 @@
*
*/
-struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry)
+struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
{
- struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
- struct v9fs_fid *return_fid = NULL;
+ struct v9fs_dentry *dent;
+ struct p9_fid *fid;
- dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ dent = dentry->d_fsdata;
+ if (dent)
+ fid = list_entry(dent->fidlist.next, struct p9_fid, dlist);
+ else
+ fid = ERR_PTR(-EBADF);
- if (fid_list)
- return_fid = list_entry(fid_list->next, struct v9fs_fid, list);
+ P9_DPRINTK(P9_DEBUG_VFS, " fid: %p\n", fid);
+ return fid;
+}
- if (!return_fid) {
- dprintk(DEBUG_ERROR, "Couldn't find a fid in dentry\n");
- return_fid = ERR_PTR(-EBADF);
+struct p9_fid *v9fs_fid_lookup_remove(struct dentry *dentry)
+{
+ struct p9_fid *fid;
+ struct v9fs_dentry *dent;
+
+ dent = dentry->d_fsdata;
+ fid = v9fs_fid_lookup(dentry);
+ if (!IS_ERR(fid)) {
+ spin_lock(&dent->lock);
+ list_del(&fid->dlist);
+ spin_unlock(&dent->lock);
}
- if(down_interruptible(&return_fid->lock))
- return ERR_PTR(-EINTR);
-
- return return_fid;
+ return fid;
}
+
/**
* v9fs_fid_clone - lookup the fid for a dentry, clone a private copy and
- * release it
+ * release it
* @dentry: dentry to look for fid in
*
* find a fid in the dentry and then clone to a new private fid
@@ -146,49 +120,15 @@
*
*/
-struct v9fs_fid *v9fs_fid_clone(struct dentry *dentry)
+struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
{
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *base_fid, *new_fid = ERR_PTR(-EBADF);
- struct v9fs_fcall *fcall = NULL;
- int fid, err;
+ struct p9_fid *ofid, *fid;
- base_fid = v9fs_fid_lookup(dentry);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ ofid = v9fs_fid_lookup(dentry);
+ if (IS_ERR(ofid))
+ return ofid;
- if(IS_ERR(base_fid))
- return base_fid;
-
- if(base_fid) { /* clone fid */
- fid = v9fs_get_idpool(&v9ses->fidpool);
- if (fid < 0) {
- eprintk(KERN_WARNING, "newfid fails!\n");
- new_fid = ERR_PTR(-ENOSPC);
- goto Release_Fid;
- }
-
- err = v9fs_t_walk(v9ses, base_fid->fid, fid, NULL, &fcall);
- if (err < 0) {
- dprintk(DEBUG_ERROR, "clone walk didn't work\n");
- v9fs_put_idpool(fid, &v9ses->fidpool);
- new_fid = ERR_PTR(err);
- goto Free_Fcall;
- }
- new_fid = v9fs_fid_create(v9ses, fid);
- if (new_fid == NULL) {
- dprintk(DEBUG_ERROR, "out of memory\n");
- new_fid = ERR_PTR(-ENOMEM);
- }
-Free_Fcall:
- kfree(fcall);
- }
-
-Release_Fid:
- up(&base_fid->lock);
- return new_fid;
-}
-
-void v9fs_fid_clunk(struct v9fs_session_info *v9ses, struct v9fs_fid *fid)
-{
- v9fs_t_clunk(v9ses, fid->fid);
- v9fs_fid_destroy(fid);
+ fid = p9_client_walk(ofid, 0, NULL, 1);
+ return fid;
}
diff --git a/fs/9p/fid.h b/fs/9p/fid.h
index 48fc170..47a0ba7 100644
--- a/fs/9p/fid.h
+++ b/fs/9p/fid.h
@@ -22,41 +22,12 @@
#include <linux/list.h>
-#define FID_OP 0
-#define FID_WALK 1
-#define FID_CREATE 2
-
-struct v9fs_fid {
- struct list_head list; /* list of fids associated with a dentry */
- struct list_head active; /* XXX - debug */
-
- struct semaphore lock;
-
- u32 fid;
- unsigned char fidopen; /* set when fid is opened */
- unsigned char fidclunked; /* set when fid has already been clunked */
-
- struct v9fs_qid qid;
- u32 iounit;
-
- /* readdir stuff */
- int rdir_fpos;
- loff_t rdir_pos;
- struct v9fs_fcall *rdir_fcall;
-
- /* management stuff */
- uid_t uid; /* user associated with this fid */
-
- /* private data */
- struct file *filp; /* backpointer to File struct for open files */
- struct v9fs_session_info *v9ses; /* session info for this FID */
+struct v9fs_dentry {
+ spinlock_t lock; /* protect fidlist */
+ struct list_head fidlist;
};
-struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry);
-struct v9fs_fid *v9fs_fid_get_created(struct dentry *);
-void v9fs_fid_destroy(struct v9fs_fid *fid);
-struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *, int fid);
-int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry);
-struct v9fs_fid *v9fs_fid_clone(struct dentry *dentry);
-void v9fs_fid_clunk(struct v9fs_session_info *v9ses, struct v9fs_fid *fid);
-
+struct p9_fid *v9fs_fid_lookup(struct dentry *dentry);
+struct p9_fid *v9fs_fid_lookup_remove(struct dentry *dentry);
+struct p9_fid *v9fs_fid_clone(struct dentry *dentry);
+int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid);
diff --git a/fs/9p/mux.c b/fs/9p/mux.c
deleted file mode 100644
index c783874..0000000
--- a/fs/9p/mux.c
+++ /dev/null
@@ -1,1033 +0,0 @@
-/*
- * linux/fs/9p/mux.c
- *
- * Protocol Multiplexer
- *
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/kthread.h>
-#include <linux/idr.h>
-#include <linux/mutex.h>
-
-#include "debug.h"
-#include "v9fs.h"
-#include "9p.h"
-#include "conv.h"
-#include "transport.h"
-#include "mux.h"
-
-#define ERREQFLUSH 1
-#define SCHED_TIMEOUT 10
-#define MAXPOLLWADDR 2
-
-enum {
- Rworksched = 1, /* read work scheduled or running */
- Rpending = 2, /* can read */
- Wworksched = 4, /* write work scheduled or running */
- Wpending = 8, /* can write */
-};
-
-enum {
- None,
- Flushing,
- Flushed,
-};
-
-struct v9fs_mux_poll_task;
-
-struct v9fs_req {
- spinlock_t lock;
- int tag;
- struct v9fs_fcall *tcall;
- struct v9fs_fcall *rcall;
- int err;
- v9fs_mux_req_callback cb;
- void *cba;
- int flush;
- struct list_head req_list;
-};
-
-struct v9fs_mux_data {
- spinlock_t lock;
- struct list_head mux_list;
- struct v9fs_mux_poll_task *poll_task;
- int msize;
- unsigned char *extended;
- struct v9fs_transport *trans;
- struct v9fs_idpool tagpool;
- int err;
- wait_queue_head_t equeue;
- struct list_head req_list;
- struct list_head unsent_req_list;
- struct v9fs_fcall *rcall;
- int rpos;
- char *rbuf;
- int wpos;
- int wsize;
- char *wbuf;
- wait_queue_t poll_wait[MAXPOLLWADDR];
- wait_queue_head_t *poll_waddr[MAXPOLLWADDR];
- poll_table pt;
- struct work_struct rq;
- struct work_struct wq;
- unsigned long wsched;
-};
-
-struct v9fs_mux_poll_task {
- struct task_struct *task;
- struct list_head mux_list;
- int muxnum;
-};
-
-struct v9fs_mux_rpc {
- struct v9fs_mux_data *m;
- int err;
- struct v9fs_fcall *tcall;
- struct v9fs_fcall *rcall;
- wait_queue_head_t wqueue;
-};
-
-static int v9fs_poll_proc(void *);
-static void v9fs_read_work(struct work_struct *work);
-static void v9fs_write_work(struct work_struct *work);
-static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address,
- poll_table * p);
-static u16 v9fs_mux_get_tag(struct v9fs_mux_data *);
-static void v9fs_mux_put_tag(struct v9fs_mux_data *, u16);
-
-static DEFINE_MUTEX(v9fs_mux_task_lock);
-static struct workqueue_struct *v9fs_mux_wq;
-
-static int v9fs_mux_num;
-static int v9fs_mux_poll_task_num;
-static struct v9fs_mux_poll_task v9fs_mux_poll_tasks[100];
-
-int v9fs_mux_global_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++)
- v9fs_mux_poll_tasks[i].task = NULL;
-
- v9fs_mux_wq = create_workqueue("v9fs");
- if (!v9fs_mux_wq) {
- printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void v9fs_mux_global_exit(void)
-{
- destroy_workqueue(v9fs_mux_wq);
-}
-
-/**
- * v9fs_mux_calc_poll_procs - calculates the number of polling procs
- * based on the number of mounted v9fs filesystems.
- *
- * The current implementation returns sqrt of the number of mounts.
- */
-static int v9fs_mux_calc_poll_procs(int muxnum)
-{
- int n;
-
- if (v9fs_mux_poll_task_num)
- n = muxnum / v9fs_mux_poll_task_num +
- (muxnum % v9fs_mux_poll_task_num ? 1 : 0);
- else
- n = 1;
-
- if (n > ARRAY_SIZE(v9fs_mux_poll_tasks))
- n = ARRAY_SIZE(v9fs_mux_poll_tasks);
-
- return n;
-}
-
-static int v9fs_mux_poll_start(struct v9fs_mux_data *m)
-{
- int i, n;
- struct v9fs_mux_poll_task *vpt, *vptlast;
- struct task_struct *pproc;
-
- dprintk(DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, v9fs_mux_num,
- v9fs_mux_poll_task_num);
- mutex_lock(&v9fs_mux_task_lock);
-
- n = v9fs_mux_calc_poll_procs(v9fs_mux_num + 1);
- if (n > v9fs_mux_poll_task_num) {
- for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) {
- if (v9fs_mux_poll_tasks[i].task == NULL) {
- vpt = &v9fs_mux_poll_tasks[i];
- dprintk(DEBUG_MUX, "create proc %p\n", vpt);
- pproc = kthread_create(v9fs_poll_proc, vpt,
- "v9fs-poll");
-
- if (!IS_ERR(pproc)) {
- vpt->task = pproc;
- INIT_LIST_HEAD(&vpt->mux_list);
- vpt->muxnum = 0;
- v9fs_mux_poll_task_num++;
- wake_up_process(vpt->task);
- }
- break;
- }
- }
-
- if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks))
- dprintk(DEBUG_ERROR, "warning: no free poll slots\n");
- }
-
- n = (v9fs_mux_num + 1) / v9fs_mux_poll_task_num +
- ((v9fs_mux_num + 1) % v9fs_mux_poll_task_num ? 1 : 0);
-
- vptlast = NULL;
- for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) {
- vpt = &v9fs_mux_poll_tasks[i];
- if (vpt->task != NULL) {
- vptlast = vpt;
- if (vpt->muxnum < n) {
- dprintk(DEBUG_MUX, "put in proc %d\n", i);
- list_add(&m->mux_list, &vpt->mux_list);
- vpt->muxnum++;
- m->poll_task = vpt;
- memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
- init_poll_funcptr(&m->pt, v9fs_pollwait);
- break;
- }
- }
- }
-
- if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) {
- if (vptlast == NULL)
- return -ENOMEM;
-
- dprintk(DEBUG_MUX, "put in proc %d\n", i);
- list_add(&m->mux_list, &vptlast->mux_list);
- vptlast->muxnum++;
- m->poll_task = vptlast;
- memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
- init_poll_funcptr(&m->pt, v9fs_pollwait);
- }
-
- v9fs_mux_num++;
- mutex_unlock(&v9fs_mux_task_lock);
-
- return 0;
-}
-
-static void v9fs_mux_poll_stop(struct v9fs_mux_data *m)
-{
- int i;
- struct v9fs_mux_poll_task *vpt;
-
- mutex_lock(&v9fs_mux_task_lock);
- vpt = m->poll_task;
- list_del(&m->mux_list);
- for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
- if (m->poll_waddr[i] != NULL) {
- remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]);
- m->poll_waddr[i] = NULL;
- }
- }
- vpt->muxnum--;
- if (!vpt->muxnum) {
- dprintk(DEBUG_MUX, "destroy proc %p\n", vpt);
- kthread_stop(vpt->task);
- vpt->task = NULL;
- v9fs_mux_poll_task_num--;
- }
- v9fs_mux_num--;
- mutex_unlock(&v9fs_mux_task_lock);
-}
-
-/**
- * v9fs_mux_init - allocate and initialize the per-session mux data
- * Creates the polling task if this is the first session.
- *
- * @trans - transport structure
- * @msize - maximum message size
- * @extended - pointer to the extended flag
- */
-struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
- unsigned char *extended)
-{
- int i, n;
- struct v9fs_mux_data *m, *mtmp;
-
- dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize);
- m = kmalloc(sizeof(struct v9fs_mux_data), GFP_KERNEL);
- if (!m)
- return ERR_PTR(-ENOMEM);
-
- spin_lock_init(&m->lock);
- INIT_LIST_HEAD(&m->mux_list);
- m->msize = msize;
- m->extended = extended;
- m->trans = trans;
- idr_init(&m->tagpool.pool);
- init_MUTEX(&m->tagpool.lock);
- m->err = 0;
- init_waitqueue_head(&m->equeue);
- INIT_LIST_HEAD(&m->req_list);
- INIT_LIST_HEAD(&m->unsent_req_list);
- m->rcall = NULL;
- m->rpos = 0;
- m->rbuf = NULL;
- m->wpos = m->wsize = 0;
- m->wbuf = NULL;
- INIT_WORK(&m->rq, v9fs_read_work);
- INIT_WORK(&m->wq, v9fs_write_work);
- m->wsched = 0;
- memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
- m->poll_task = NULL;
- n = v9fs_mux_poll_start(m);
- if (n)
- return ERR_PTR(n);
-
- n = trans->poll(trans, &m->pt);
- if (n & POLLIN) {
- dprintk(DEBUG_MUX, "mux %p can read\n", m);
- set_bit(Rpending, &m->wsched);
- }
-
- if (n & POLLOUT) {
- dprintk(DEBUG_MUX, "mux %p can write\n", m);
- set_bit(Wpending, &m->wsched);
- }
-
- for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
- if (IS_ERR(m->poll_waddr[i])) {
- v9fs_mux_poll_stop(m);
- mtmp = (void *)m->poll_waddr; /* the error code */
- kfree(m);
- m = mtmp;
- break;
- }
- }
-
- return m;
-}
-
-/**
- * v9fs_mux_destroy - cancels all pending requests and frees mux resources
- */
-void v9fs_mux_destroy(struct v9fs_mux_data *m)
-{
- dprintk(DEBUG_MUX, "mux %p prev %p next %p\n", m,
- m->mux_list.prev, m->mux_list.next);
- v9fs_mux_cancel(m, -ECONNRESET);
-
- if (!list_empty(&m->req_list)) {
- /* wait until all processes waiting on this session exit */
- dprintk(DEBUG_MUX, "mux %p waiting for empty request queue\n",
- m);
- wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000);
- dprintk(DEBUG_MUX, "mux %p request queue empty: %d\n", m,
- list_empty(&m->req_list));
- }
-
- v9fs_mux_poll_stop(m);
- m->trans = NULL;
-
- kfree(m);
-}
-
-/**
- * v9fs_pollwait - called by files poll operation to add v9fs-poll task
- * to files wait queue
- */
-static void
-v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address,
- poll_table * p)
-{
- int i;
- struct v9fs_mux_data *m;
-
- m = container_of(p, struct v9fs_mux_data, pt);
- for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++)
- if (m->poll_waddr[i] == NULL)
- break;
-
- if (i >= ARRAY_SIZE(m->poll_waddr)) {
- dprintk(DEBUG_ERROR, "not enough wait_address slots\n");
- return;
- }
-
- m->poll_waddr[i] = wait_address;
-
- if (!wait_address) {
- dprintk(DEBUG_ERROR, "no wait_address\n");
- m->poll_waddr[i] = ERR_PTR(-EIO);
- return;
- }
-
- init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task);
- add_wait_queue(wait_address, &m->poll_wait[i]);
-}
-
-/**
- * v9fs_poll_mux - polls a mux and schedules read or write works if necessary
- */
-static void v9fs_poll_mux(struct v9fs_mux_data *m)
-{
- int n;
-
- if (m->err < 0)
- return;
-
- n = m->trans->poll(m->trans, NULL);
- if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
- dprintk(DEBUG_MUX, "error mux %p err %d\n", m, n);
- if (n >= 0)
- n = -ECONNRESET;
- v9fs_mux_cancel(m, n);
- }
-
- if (n & POLLIN) {
- set_bit(Rpending, &m->wsched);
- dprintk(DEBUG_MUX, "mux %p can read\n", m);
- if (!test_and_set_bit(Rworksched, &m->wsched)) {
- dprintk(DEBUG_MUX, "schedule read work mux %p\n", m);
- queue_work(v9fs_mux_wq, &m->rq);
- }
- }
-
- if (n & POLLOUT) {
- set_bit(Wpending, &m->wsched);
- dprintk(DEBUG_MUX, "mux %p can write\n", m);
- if ((m->wsize || !list_empty(&m->unsent_req_list))
- && !test_and_set_bit(Wworksched, &m->wsched)) {
- dprintk(DEBUG_MUX, "schedule write work mux %p\n", m);
- queue_work(v9fs_mux_wq, &m->wq);
- }
- }
-}
-
-/**
- * v9fs_poll_proc - polls all v9fs transports for new events and queues
- * the appropriate work to the work queue
- */
-static int v9fs_poll_proc(void *a)
-{
- struct v9fs_mux_data *m, *mtmp;
- struct v9fs_mux_poll_task *vpt;
-
- vpt = a;
- dprintk(DEBUG_MUX, "start %p %p\n", current, vpt);
- while (!kthread_should_stop()) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) {
- v9fs_poll_mux(m);
- }
-
- dprintk(DEBUG_MUX, "sleeping...\n");
- schedule_timeout(SCHED_TIMEOUT * HZ);
- }
-
- __set_current_state(TASK_RUNNING);
- dprintk(DEBUG_MUX, "finish\n");
- return 0;
-}
-
-/**
- * v9fs_write_work - called when a transport can send some data
- */
-static void v9fs_write_work(struct work_struct *work)
-{
- int n, err;
- struct v9fs_mux_data *m;
- struct v9fs_req *req;
-
- m = container_of(work, struct v9fs_mux_data, wq);
-
- if (m->err < 0) {
- clear_bit(Wworksched, &m->wsched);
- return;
- }
-
- if (!m->wsize) {
- if (list_empty(&m->unsent_req_list)) {
- clear_bit(Wworksched, &m->wsched);
- return;
- }
-
- spin_lock(&m->lock);
-again:
- req = list_entry(m->unsent_req_list.next, struct v9fs_req,
- req_list);
- list_move_tail(&req->req_list, &m->req_list);
- if (req->err == ERREQFLUSH)
- goto again;
-
- m->wbuf = req->tcall->sdata;
- m->wsize = req->tcall->size;
- m->wpos = 0;
- dump_data(m->wbuf, m->wsize);
- spin_unlock(&m->lock);
- }
-
- dprintk(DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, m->wsize);
- clear_bit(Wpending, &m->wsched);
- err = m->trans->write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos);
- dprintk(DEBUG_MUX, "mux %p sent %d bytes\n", m, err);
- if (err == -EAGAIN) {
- clear_bit(Wworksched, &m->wsched);
- return;
- }
-
- if (err <= 0)
- goto error;
-
- m->wpos += err;
- if (m->wpos == m->wsize)
- m->wpos = m->wsize = 0;
-
- if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
- if (test_and_clear_bit(Wpending, &m->wsched))
- n = POLLOUT;
- else
- n = m->trans->poll(m->trans, NULL);
-
- if (n & POLLOUT) {
- dprintk(DEBUG_MUX, "schedule write work mux %p\n", m);
- queue_work(v9fs_mux_wq, &m->wq);
- } else
- clear_bit(Wworksched, &m->wsched);
- } else
- clear_bit(Wworksched, &m->wsched);
-
- return;
-
- error:
- v9fs_mux_cancel(m, err);
- clear_bit(Wworksched, &m->wsched);
-}
-
-static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
-{
- int ecode;
- struct v9fs_str *ename;
-
- if (!req->err && req->rcall->id == RERROR) {
- ecode = req->rcall->params.rerror.errno;
- ename = &req->rcall->params.rerror.error;
-
- dprintk(DEBUG_MUX, "Rerror %.*s\n", ename->len, ename->str);
-
- if (*m->extended)
- req->err = -ecode;
-
- if (!req->err) {
- req->err = v9fs_errstr2errno(ename->str, ename->len);
-
- if (!req->err) { /* string match failed */
- PRINT_FCALL_ERROR("unknown error", req->rcall);
- }
-
- if (!req->err)
- req->err = -ESERVERFAULT;
- }
- } else if (req->tcall && req->rcall->id != req->tcall->id + 1) {
- dprintk(DEBUG_ERROR, "fcall mismatch: expected %d, got %d\n",
- req->tcall->id + 1, req->rcall->id);
- if (!req->err)
- req->err = -EIO;
- }
-}
-
-/**
- * v9fs_read_work - called when there is some data to be read from a transport
- */
-static void v9fs_read_work(struct work_struct *work)
-{
- int n, err;
- struct v9fs_mux_data *m;
- struct v9fs_req *req, *rptr, *rreq;
- struct v9fs_fcall *rcall;
- char *rbuf;
-
- m = container_of(work, struct v9fs_mux_data, rq);
-
- if (m->err < 0)
- return;
-
- rcall = NULL;
- dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
-
- if (!m->rcall) {
- m->rcall =
- kmalloc(sizeof(struct v9fs_fcall) + m->msize, GFP_KERNEL);
- if (!m->rcall) {
- err = -ENOMEM;
- goto error;
- }
-
- m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall);
- m->rpos = 0;
- }
-
- clear_bit(Rpending, &m->wsched);
- err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);
- dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err);
- if (err == -EAGAIN) {
- clear_bit(Rworksched, &m->wsched);
- return;
- }
-
- if (err <= 0)
- goto error;
-
- m->rpos += err;
- while (m->rpos > 4) {
- n = le32_to_cpu(*(__le32 *) m->rbuf);
- if (n >= m->msize) {
- dprintk(DEBUG_ERROR,
- "requested packet size too big: %d\n", n);
- err = -EIO;
- goto error;
- }
-
- if (m->rpos < n)
- break;
-
- dump_data(m->rbuf, n);
- err =
- v9fs_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended);
- if (err < 0) {
- goto error;
- }
-
- if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) {
- char buf[150];
-
- v9fs_printfcall(buf, sizeof(buf), m->rcall,
- *m->extended);
- printk(KERN_NOTICE ">>> %p %s\n", m, buf);
- }
-
- rcall = m->rcall;
- rbuf = m->rbuf;
- if (m->rpos > n) {
- m->rcall = kmalloc(sizeof(struct v9fs_fcall) + m->msize,
- GFP_KERNEL);
- if (!m->rcall) {
- err = -ENOMEM;
- goto error;
- }
-
- m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall);
- memmove(m->rbuf, rbuf + n, m->rpos - n);
- m->rpos -= n;
- } else {
- m->rcall = NULL;
- m->rbuf = NULL;
- m->rpos = 0;
- }
-
- dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id,
- rcall->tag);
-
- req = NULL;
- spin_lock(&m->lock);
- list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
- if (rreq->tag == rcall->tag) {
- req = rreq;
- if (req->flush != Flushing)
- list_del(&req->req_list);
- break;
- }
- }
- spin_unlock(&m->lock);
-
- if (req) {
- req->rcall = rcall;
- process_request(m, req);
-
- if (req->flush != Flushing) {
- if (req->cb)
- (*req->cb) (req, req->cba);
- else
- kfree(req->rcall);
-
- wake_up(&m->equeue);
- }
- } else {
- if (err >= 0 && rcall->id != RFLUSH)
- dprintk(DEBUG_ERROR,
- "unexpected response mux %p id %d tag %d\n",
- m, rcall->id, rcall->tag);
- kfree(rcall);
- }
- }
-
- if (!list_empty(&m->req_list)) {
- if (test_and_clear_bit(Rpending, &m->wsched))
- n = POLLIN;
- else
- n = m->trans->poll(m->trans, NULL);
-
- if (n & POLLIN) {
- dprintk(DEBUG_MUX, "schedule read work mux %p\n", m);
- queue_work(v9fs_mux_wq, &m->rq);
- } else
- clear_bit(Rworksched, &m->wsched);
- } else
- clear_bit(Rworksched, &m->wsched);
-
- return;
-
- error:
- v9fs_mux_cancel(m, err);
- clear_bit(Rworksched, &m->wsched);
-}
-
-/**
- * v9fs_send_request - send 9P request
- * The function can sleep until the request is scheduled for sending.
- * The function can be interrupted. Return from the function is not
- * a guarantee that the request is sent successfully. Can return errors
- * that can be retrieved by PTR_ERR macros.
- *
- * @m: mux data
- * @tc: request to be sent
- * @cb: callback function to call when response is received
- * @cba: parameter to pass to the callback function
- */
-static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m,
- struct v9fs_fcall *tc,
- v9fs_mux_req_callback cb, void *cba)
-{
- int n;
- struct v9fs_req *req;
-
- dprintk(DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
- tc, tc->id);
- if (m->err < 0)
- return ERR_PTR(m->err);
-
- req = kmalloc(sizeof(struct v9fs_req), GFP_KERNEL);
- if (!req)
- return ERR_PTR(-ENOMEM);
-
- if (tc->id == TVERSION)
- n = V9FS_NOTAG;
- else
- n = v9fs_mux_get_tag(m);
-
- if (n < 0)
- return ERR_PTR(-ENOMEM);
-
- v9fs_set_tag(tc, n);
- if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) {
- char buf[150];
-
- v9fs_printfcall(buf, sizeof(buf), tc, *m->extended);
- printk(KERN_NOTICE "<<< %p %s\n", m, buf);
- }
-
- spin_lock_init(&req->lock);
- req->tag = n;
- req->tcall = tc;
- req->rcall = NULL;
- req->err = 0;
- req->cb = cb;
- req->cba = cba;
- req->flush = None;
-
- spin_lock(&m->lock);
- list_add_tail(&req->req_list, &m->unsent_req_list);
- spin_unlock(&m->lock);
-
- if (test_and_clear_bit(Wpending, &m->wsched))
- n = POLLOUT;
- else
- n = m->trans->poll(m->trans, NULL);
-
- if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
- queue_work(v9fs_mux_wq, &m->wq);
-
- return req;
-}
-
-static void v9fs_mux_free_request(struct v9fs_mux_data *m, struct v9fs_req *req)
-{
- v9fs_mux_put_tag(m, req->tag);
- kfree(req);
-}
-
-static void v9fs_mux_flush_cb(struct v9fs_req *freq, void *a)
-{
- v9fs_mux_req_callback cb;
- int tag;
- struct v9fs_mux_data *m;
- struct v9fs_req *req, *rreq, *rptr;
-
- m = a;
- dprintk(DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,
- freq->tcall, freq->rcall, freq->err,
- freq->tcall->params.tflush.oldtag);
-
- spin_lock(&m->lock);
- cb = NULL;
- tag = freq->tcall->params.tflush.oldtag;
- req = NULL;
- list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
- if (rreq->tag == tag) {
- req = rreq;
- list_del(&req->req_list);
- break;
- }
- }
- spin_unlock(&m->lock);
-
- if (req) {
- spin_lock(&req->lock);
- req->flush = Flushed;
- spin_unlock(&req->lock);
-
- if (req->cb)
- (*req->cb) (req, req->cba);
- else
- kfree(req->rcall);
-
- wake_up(&m->equeue);
- }
-
- kfree(freq->tcall);
- kfree(freq->rcall);
- v9fs_mux_free_request(m, freq);
-}
-
-static int
-v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req)
-{
- struct v9fs_fcall *fc;
- struct v9fs_req *rreq, *rptr;
-
- dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
-
- /* if a response was received for a request, do nothing */
- spin_lock(&req->lock);
- if (req->rcall || req->err) {
- spin_unlock(&req->lock);
- dprintk(DEBUG_MUX, "mux %p req %p response already received\n", m, req);
- return 0;
- }
-
- req->flush = Flushing;
- spin_unlock(&req->lock);
-
- spin_lock(&m->lock);
- /* if the request is not sent yet, just remove it from the list */
- list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) {
- if (rreq->tag == req->tag) {
- dprintk(DEBUG_MUX, "mux %p req %p request is not sent yet\n", m, req);
- list_del(&rreq->req_list);
- req->flush = Flushed;
- spin_unlock(&m->lock);
- if (req->cb)
- (*req->cb) (req, req->cba);
- return 0;
- }
- }
- spin_unlock(&m->lock);
-
- clear_thread_flag(TIF_SIGPENDING);
- fc = v9fs_create_tflush(req->tag);
- v9fs_send_request(m, fc, v9fs_mux_flush_cb, m);
- return 1;
-}
-
-static void
-v9fs_mux_rpc_cb(struct v9fs_req *req, void *a)
-{
- struct v9fs_mux_rpc *r;
-
- dprintk(DEBUG_MUX, "req %p r %p\n", req, a);
- r = a;
- r->rcall = req->rcall;
- r->err = req->err;
-
- if (req->flush!=None && !req->err)
- r->err = -ERESTARTSYS;
-
- wake_up(&r->wqueue);
-}
-
-/**
- * v9fs_mux_rpc - sends 9P request and waits until a response is available.
- * The function can be interrupted.
- * @m: mux data
- * @tc: request to be sent
- * @rc: pointer where a pointer to the response is stored
- */
-int
-v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc,
- struct v9fs_fcall **rc)
-{
- int err, sigpending;
- unsigned long flags;
- struct v9fs_req *req;
- struct v9fs_mux_rpc r;
-
- r.err = 0;
- r.tcall = tc;
- r.rcall = NULL;
- r.m = m;
- init_waitqueue_head(&r.wqueue);
-
- if (rc)
- *rc = NULL;
-
- sigpending = 0;
- if (signal_pending(current)) {
- sigpending = 1;
- clear_thread_flag(TIF_SIGPENDING);
- }
-
- req = v9fs_send_request(m, tc, v9fs_mux_rpc_cb, &r);
- if (IS_ERR(req)) {
- err = PTR_ERR(req);
- dprintk(DEBUG_MUX, "error %d\n", err);
- return err;
- }
-
- err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0);
- if (r.err < 0)
- err = r.err;
-
- if (err == -ERESTARTSYS && m->trans->status == Connected && m->err == 0) {
- if (v9fs_mux_flush_request(m, req)) {
- /* wait until we get response of the flush message */
- do {
- clear_thread_flag(TIF_SIGPENDING);
- err = wait_event_interruptible(r.wqueue,
- r.rcall || r.err);
- } while (!r.rcall && !r.err && err==-ERESTARTSYS &&
- m->trans->status==Connected && !m->err);
-
- err = -ERESTARTSYS;
- }
- sigpending = 1;
- }
-
- if (sigpending) {
- spin_lock_irqsave(¤t->sighand->siglock, flags);
- recalc_sigpending();
- spin_unlock_irqrestore(¤t->sighand->siglock, flags);
- }
-
- if (rc)
- *rc = r.rcall;
- else
- kfree(r.rcall);
-
- v9fs_mux_free_request(m, req);
- if (err > 0)
- err = -EIO;
-
- return err;
-}
-
-#if 0
-/**
- * v9fs_mux_rpcnb - sends 9P request without waiting for response.
- * @m: mux data
- * @tc: request to be sent
- * @cb: callback function to be called when response arrives
- * @cba: value to pass to the callback function
- */
-int v9fs_mux_rpcnb(struct v9fs_mux_data *m, struct v9fs_fcall *tc,
- v9fs_mux_req_callback cb, void *a)
-{
- int err;
- struct v9fs_req *req;
-
- req = v9fs_send_request(m, tc, cb, a);
- if (IS_ERR(req)) {
- err = PTR_ERR(req);
- dprintk(DEBUG_MUX, "error %d\n", err);
- return PTR_ERR(req);
- }
-
- dprintk(DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag);
- return 0;
-}
-#endif /* 0 */
-
-/**
- * v9fs_mux_cancel - cancel all pending requests with error
- * @m: mux data
- * @err: error code
- */
-void v9fs_mux_cancel(struct v9fs_mux_data *m, int err)
-{
- struct v9fs_req *req, *rtmp;
- LIST_HEAD(cancel_list);
-
- dprintk(DEBUG_ERROR, "mux %p err %d\n", m, err);
- m->err = err;
- spin_lock(&m->lock);
- list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
- list_move(&req->req_list, &cancel_list);
- }
- list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
- list_move(&req->req_list, &cancel_list);
- }
- spin_unlock(&m->lock);
-
- list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
- list_del(&req->req_list);
- if (!req->err)
- req->err = err;
-
- if (req->cb)
- (*req->cb) (req, req->cba);
- else
- kfree(req->rcall);
- }
-
- wake_up(&m->equeue);
-}
-
-static u16 v9fs_mux_get_tag(struct v9fs_mux_data *m)
-{
- int tag;
-
- tag = v9fs_get_idpool(&m->tagpool);
- if (tag < 0)
- return V9FS_NOTAG;
- else
- return (u16) tag;
-}
-
-static void v9fs_mux_put_tag(struct v9fs_mux_data *m, u16 tag)
-{
- if (tag != V9FS_NOTAG && v9fs_check_idpool(tag, &m->tagpool))
- v9fs_put_idpool(tag, &m->tagpool);
-}
diff --git a/fs/9p/mux.h b/fs/9p/mux.h
deleted file mode 100644
index fb10c50..0000000
--- a/fs/9p/mux.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * linux/fs/9p/mux.h
- *
- * Multiplexer Definitions
- *
- * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-struct v9fs_mux_data;
-struct v9fs_req;
-
-/**
- * v9fs_mux_req_callback - callback function that is called when the
- * response of a request is received. The callback is called from
- * a workqueue and shouldn't block.
- *
- * @a - the pointer that was specified when the request was send to be
- * passed to the callback
- * @tc - request call
- * @rc - response call
- * @err - error code (non-zero if error occured)
- */
-typedef void (*v9fs_mux_req_callback)(struct v9fs_req *req, void *a);
-
-int v9fs_mux_global_init(void);
-void v9fs_mux_global_exit(void);
-
-struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
- unsigned char *extended);
-void v9fs_mux_destroy(struct v9fs_mux_data *);
-
-int v9fs_mux_send(struct v9fs_mux_data *m, struct v9fs_fcall *tc);
-struct v9fs_fcall *v9fs_mux_recv(struct v9fs_mux_data *m);
-int v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, struct v9fs_fcall **rc);
-
-void v9fs_mux_flush(struct v9fs_mux_data *m, int sendflush);
-void v9fs_mux_cancel(struct v9fs_mux_data *m, int err);
-int v9fs_errstr2errno(char *errstr, int len);
diff --git a/fs/9p/trans_fd.c b/fs/9p/trans_fd.c
deleted file mode 100644
index 34d4335..0000000
--- a/fs/9p/trans_fd.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * linux/fs/9p/trans_fd.c
- *
- * Fd transport layer. Includes deprecated socket layer.
- *
- * Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
- * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004-2005 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-#include <linux/in.h>
-#include <linux/module.h>
-#include <linux/net.h>
-#include <linux/ipv6.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/un.h>
-#include <asm/uaccess.h>
-#include <linux/inet.h>
-#include <linux/idr.h>
-#include <linux/file.h>
-
-#include "debug.h"
-#include "v9fs.h"
-#include "transport.h"
-
-#define V9FS_PORT 564
-
-struct v9fs_trans_fd {
- struct file *rd;
- struct file *wr;
-};
-
-/**
- * v9fs_fd_read- read from a fd
- * @v9ses: session information
- * @v: buffer to receive data into
- * @len: size of receive buffer
- *
- */
-static int v9fs_fd_read(struct v9fs_transport *trans, void *v, int len)
-{
- int ret;
- struct v9fs_trans_fd *ts;
-
- if (!trans || trans->status == Disconnected || !(ts = trans->priv))
- return -EREMOTEIO;
-
- if (!(ts->rd->f_flags & O_NONBLOCK))
- dprintk(DEBUG_ERROR, "blocking read ...\n");
-
- ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
- if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
- trans->status = Disconnected;
- return ret;
-}
-
-/**
- * v9fs_fd_write - write to a socket
- * @v9ses: session information
- * @v: buffer to send data from
- * @len: size of send buffer
- *
- */
-static int v9fs_fd_write(struct v9fs_transport *trans, void *v, int len)
-{
- int ret;
- mm_segment_t oldfs;
- struct v9fs_trans_fd *ts;
-
- if (!trans || trans->status == Disconnected || !(ts = trans->priv))
- return -EREMOTEIO;
-
- if (!(ts->wr->f_flags & O_NONBLOCK))
- dprintk(DEBUG_ERROR, "blocking write ...\n");
-
- oldfs = get_fs();
- set_fs(get_ds());
- /* The cast to a user pointer is valid due to the set_fs() */
- ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
- set_fs(oldfs);
-
- if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
- trans->status = Disconnected;
- return ret;
-}
-
-static unsigned int
-v9fs_fd_poll(struct v9fs_transport *trans, struct poll_table_struct *pt)
-{
- int ret, n;
- struct v9fs_trans_fd *ts;
- mm_segment_t oldfs;
-
- if (!trans || trans->status != Connected || !(ts = trans->priv))
- return -EREMOTEIO;
-
- if (!ts->rd->f_op || !ts->rd->f_op->poll)
- return -EIO;
-
- if (!ts->wr->f_op || !ts->wr->f_op->poll)
- return -EIO;
-
- oldfs = get_fs();
- set_fs(get_ds());
-
- ret = ts->rd->f_op->poll(ts->rd, pt);
- if (ret < 0)
- goto end;
-
- if (ts->rd != ts->wr) {
- n = ts->wr->f_op->poll(ts->wr, pt);
- if (n < 0) {
- ret = n;
- goto end;
- }
- ret = (ret & ~POLLOUT) | (n & ~POLLIN);
- }
-
- end:
- set_fs(oldfs);
- return ret;
-}
-
-static int v9fs_fd_open(struct v9fs_session_info *v9ses, int rfd, int wfd)
-{
- struct v9fs_transport *trans = v9ses->transport;
- struct v9fs_trans_fd *ts = kmalloc(sizeof(struct v9fs_trans_fd),
- GFP_KERNEL);
- if (!ts)
- return -ENOMEM;
-
- ts->rd = fget(rfd);
- ts->wr = fget(wfd);
- if (!ts->rd || !ts->wr) {
- if (ts->rd)
- fput(ts->rd);
- if (ts->wr)
- fput(ts->wr);
- kfree(ts);
- return -EIO;
- }
-
- trans->priv = ts;
- trans->status = Connected;
-
- return 0;
-}
-
-static int v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr,
- char *data)
-{
- if (v9ses->rfdno == ~0 || v9ses->wfdno == ~0) {
- printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
- return -ENOPROTOOPT;
- }
-
- return v9fs_fd_open(v9ses, v9ses->rfdno, v9ses->wfdno);
-}
-
-static int v9fs_socket_open(struct v9fs_session_info *v9ses,
- struct socket *csocket)
-{
- int fd, ret;
-
- csocket->sk->sk_allocation = GFP_NOIO;
- if ((fd = sock_map_fd(csocket)) < 0) {
- eprintk(KERN_ERR, "v9fs_socket_open: failed to map fd\n");
- ret = fd;
- release_csocket:
- sock_release(csocket);
- return ret;
- }
-
- if ((ret = v9fs_fd_open(v9ses, fd, fd)) < 0) {
- sockfd_put(csocket);
- eprintk(KERN_ERR, "v9fs_socket_open: failed to open fd\n");
- goto release_csocket;
- }
-
- ((struct v9fs_trans_fd *)v9ses->transport->priv)->rd->f_flags |=
- O_NONBLOCK;
- return 0;
-}
-
-static int v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr,
- char *data)
-{
- int ret;
- struct socket *csocket = NULL;
- struct sockaddr_in sin_server;
-
- sin_server.sin_family = AF_INET;
- sin_server.sin_addr.s_addr = in_aton(addr);
- sin_server.sin_port = htons(v9ses->port);
- sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
-
- if (!csocket) {
- eprintk(KERN_ERR, "v9fs_trans_tcp: problem creating socket\n");
- return -1;
- }
-
- ret = csocket->ops->connect(csocket,
- (struct sockaddr *)&sin_server,
- sizeof(struct sockaddr_in), 0);
- if (ret < 0) {
- eprintk(KERN_ERR,
- "v9fs_trans_tcp: problem connecting socket to %s\n",
- addr);
- return ret;
- }
-
- return v9fs_socket_open(v9ses, csocket);
-}
-
-static int
-v9fs_unix_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
-{
- int ret;
- struct socket *csocket;
- struct sockaddr_un sun_server;
-
- if (strlen(addr) > UNIX_PATH_MAX) {
- eprintk(KERN_ERR, "v9fs_trans_unix: address too long: %s\n",
- addr);
- return -ENAMETOOLONG;
- }
-
- sun_server.sun_family = PF_UNIX;
- strcpy(sun_server.sun_path, addr);
- sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
- ret = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
- sizeof(struct sockaddr_un) - 1, 0);
- if (ret < 0) {
- eprintk(KERN_ERR,
- "v9fs_trans_unix: problem connecting socket: %s: %d\n",
- addr, ret);
- return ret;
- }
-
- return v9fs_socket_open(v9ses, csocket);
-}
-
-/**
- * v9fs_sock_close - shutdown socket
- * @trans: private socket structure
- *
- */
-static void v9fs_fd_close(struct v9fs_transport *trans)
-{
- struct v9fs_trans_fd *ts;
-
- if (!trans)
- return;
-
- ts = xchg(&trans->priv, NULL);
-
- if (!ts)
- return;
-
- trans->status = Disconnected;
- if (ts->rd)
- fput(ts->rd);
- if (ts->wr)
- fput(ts->wr);
- kfree(ts);
-}
-
-struct v9fs_transport v9fs_trans_fd = {
- .init = v9fs_fd_init,
- .write = v9fs_fd_write,
- .read = v9fs_fd_read,
- .close = v9fs_fd_close,
- .poll = v9fs_fd_poll,
-};
-
-struct v9fs_transport v9fs_trans_tcp = {
- .init = v9fs_tcp_init,
- .write = v9fs_fd_write,
- .read = v9fs_fd_read,
- .close = v9fs_fd_close,
- .poll = v9fs_fd_poll,
-};
-
-struct v9fs_transport v9fs_trans_unix = {
- .init = v9fs_unix_init,
- .write = v9fs_fd_write,
- .read = v9fs_fd_read,
- .close = v9fs_fd_close,
- .poll = v9fs_fd_poll,
-};
diff --git a/fs/9p/transport.h b/fs/9p/transport.h
deleted file mode 100644
index b38a4b8..0000000
--- a/fs/9p/transport.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * linux/fs/9p/transport.h
- *
- * Transport Definition
- *
- * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-enum v9fs_transport_status {
- Connected,
- Disconnected,
- Hung,
-};
-
-struct v9fs_transport {
- enum v9fs_transport_status status;
- void *priv;
-
- int (*init) (struct v9fs_session_info *, const char *, char *);
- int (*write) (struct v9fs_transport *, void *, int);
- int (*read) (struct v9fs_transport *, void *, int);
- void (*close) (struct v9fs_transport *);
- unsigned int (*poll)(struct v9fs_transport *, struct poll_table_struct *);
-};
-
-extern struct v9fs_transport v9fs_trans_tcp;
-extern struct v9fs_transport v9fs_trans_unix;
-extern struct v9fs_transport v9fs_trans_fd;
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 6ad6f19..45c3598 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -29,16 +29,12 @@
#include <linux/sched.h>
#include <linux/parser.h>
#include <linux/idr.h>
-
-#include "debug.h"
+#include <net/9p/9p.h>
+#include <net/9p/transport.h>
+#include <net/9p/conn.h>
+#include <net/9p/client.h>
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
-#include "transport.h"
-#include "mux.h"
-
-/* TODO: sysfs or debugfs interface */
-int v9fs_debug_level = 0; /* feature-rific global debug level */
/*
* Option Parsing (code inspired by NFS code)
@@ -47,12 +43,12 @@
enum {
/* Options that take integer arguments */
- Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, Opt_debug,
+ Opt_debug, Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid,
Opt_rfdno, Opt_wfdno,
/* String options */
Opt_uname, Opt_remotename,
/* Options that take no arguments */
- Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd,
+ Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, Opt_pci,
/* Cache options */
Opt_cache_loose,
/* Error token */
@@ -60,6 +56,7 @@
};
static match_table_t tokens = {
+ {Opt_debug, "debug=%x"},
{Opt_port, "port=%u"},
{Opt_msize, "msize=%u"},
{Opt_uid, "uid=%u"},
@@ -67,12 +64,14 @@
{Opt_afid, "afid=%u"},
{Opt_rfdno, "rfdno=%u"},
{Opt_wfdno, "wfdno=%u"},
- {Opt_debug, "debug=%x"},
{Opt_uname, "uname=%s"},
{Opt_remotename, "aname=%s"},
{Opt_unix, "proto=unix"},
{Opt_tcp, "proto=tcp"},
{Opt_fd, "proto=fd"},
+#ifdef CONFIG_PCI_9P
+ {Opt_pci, "proto=pci"},
+#endif
{Opt_tcp, "tcp"},
{Opt_unix, "unix"},
{Opt_fd, "fd"},
@@ -83,6 +82,8 @@
{Opt_err, NULL}
};
+extern struct p9_transport *p9pci_trans_create(void);
+
/*
* Parse option string.
*/
@@ -122,12 +123,16 @@
token = match_token(p, tokens, args);
if (token < Opt_uname) {
if ((ret = match_int(&args[0], &option)) < 0) {
- dprintk(DEBUG_ERROR,
+ P9_DPRINTK(P9_DEBUG_ERROR,
"integer field, but no integer?\n");
continue;
}
}
switch (token) {
+ case Opt_debug:
+ v9ses->debug = option;
+ p9_debug_level = option;
+ break;
case Opt_port:
v9ses->port = option;
break;
@@ -149,15 +154,15 @@
case Opt_wfdno:
v9ses->wfdno = option;
break;
- case Opt_debug:
- v9ses->debug = option;
- break;
case Opt_tcp:
v9ses->proto = PROTO_TCP;
break;
case Opt_unix:
v9ses->proto = PROTO_UNIX;
break;
+ case Opt_pci:
+ v9ses->proto = PROTO_PCI;
+ break;
case Opt_fd:
v9ses->proto = PROTO_FD;
break;
@@ -183,82 +188,6 @@
}
/**
- * v9fs_inode2v9ses - safely extract v9fs session info from super block
- * @inode: inode to extract information from
- *
- * Paranoid function to extract v9ses information from superblock,
- * if anything is missing it will report an error.
- *
- */
-
-struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
-{
- return (inode->i_sb->s_fs_info);
-}
-
-/**
- * v9fs_get_idpool - allocate numeric id from pool
- * @p - pool to allocate from
- *
- * XXX - This seems to be an awful generic function, should it be in idr.c with
- * the lock included in struct idr?
- */
-
-int v9fs_get_idpool(struct v9fs_idpool *p)
-{
- int i = 0;
- int error;
-
-retry:
- if (idr_pre_get(&p->pool, GFP_KERNEL) == 0)
- return 0;
-
- if (down_interruptible(&p->lock) == -EINTR) {
- eprintk(KERN_WARNING, "Interrupted while locking\n");
- return -1;
- }
-
- /* no need to store exactly p, we just need something non-null */
- error = idr_get_new(&p->pool, p, &i);
- up(&p->lock);
-
- if (error == -EAGAIN)
- goto retry;
- else if (error)
- return -1;
-
- return i;
-}
-
-/**
- * v9fs_put_idpool - release numeric id from pool
- * @p - pool to allocate from
- *
- * XXX - This seems to be an awful generic function, should it be in idr.c with
- * the lock included in struct idr?
- */
-
-void v9fs_put_idpool(int id, struct v9fs_idpool *p)
-{
- if (down_interruptible(&p->lock) == -EINTR) {
- eprintk(KERN_WARNING, "Interrupted while locking\n");
- return;
- }
- idr_remove(&p->pool, id);
- up(&p->lock);
-}
-
-/**
- * v9fs_check_idpool - check if the specified id is available
- * @id - id to check
- * @p - pool
- */
-int v9fs_check_idpool(int id, struct v9fs_idpool *p)
-{
- return idr_find(&p->pool, id) != NULL;
-}
-
-/**
* v9fs_session_init - initialize session
* @v9ses: session information structure
* @dev_name: device being mounted
@@ -266,25 +195,21 @@
*
*/
-int
-v9fs_session_init(struct v9fs_session_info *v9ses,
+struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
const char *dev_name, char *data)
{
- struct v9fs_fcall *fcall = NULL;
- struct v9fs_transport *trans_proto;
- int n = 0;
- int newfid = -1;
int retval = -EINVAL;
- struct v9fs_str *version;
+ struct p9_transport *trans;
+ struct p9_fid *fid;
v9ses->name = __getname();
if (!v9ses->name)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
v9ses->remotename = __getname();
if (!v9ses->remotename) {
__putname(v9ses->name);
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
strcpy(v9ses->name, V9FS_DEFUSER);
@@ -292,130 +217,60 @@
v9fs_parse_options(data, v9ses);
- /* set global debug level */
- v9fs_debug_level = v9ses->debug;
-
- /* id pools that are session-dependent: fids and tags */
- idr_init(&v9ses->fidpool.pool);
- init_MUTEX(&v9ses->fidpool.lock);
-
switch (v9ses->proto) {
case PROTO_TCP:
- trans_proto = &v9fs_trans_tcp;
+ trans = p9_trans_create_tcp(dev_name, v9ses->port);
break;
case PROTO_UNIX:
- trans_proto = &v9fs_trans_unix;
+ trans = p9_trans_create_unix(dev_name);
*v9ses->remotename = 0;
break;
case PROTO_FD:
- trans_proto = &v9fs_trans_fd;
+ trans = p9_trans_create_fd(v9ses->rfdno, v9ses->wfdno);
*v9ses->remotename = 0;
break;
+#ifdef CONFIG_PCI_9P
+ case PROTO_PCI:
+ trans = p9pci_trans_create();
+ *v9ses->remotename = 0;
+ break;
+#endif
default:
printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto);
retval = -ENOPROTOOPT;
- goto SessCleanUp;
+ goto error;
};
- v9ses->transport = kmalloc(sizeof(*v9ses->transport), GFP_KERNEL);
- if (!v9ses->transport) {
- retval = -ENOMEM;
- goto SessCleanUp;
+ if (IS_ERR(trans)) {
+ retval = PTR_ERR(trans);
+ trans = NULL;
+ goto error;
}
- memmove(v9ses->transport, trans_proto, sizeof(*v9ses->transport));
+ v9ses->clnt = p9_client_create(trans, v9ses->maxdata + P9_IOHDRSZ,
+ v9ses->extended);
- if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) {
- eprintk(KERN_ERR, "problem initializing transport\n");
- goto SessCleanUp;
+ if (IS_ERR(v9ses->clnt)) {
+ retval = PTR_ERR(v9ses->clnt);
+ v9ses->clnt = NULL;
+ P9_DPRINTK(P9_DEBUG_ERROR, "problem initializing 9p client\n");
+ goto error;
}
- v9ses->inprogress = 0;
- v9ses->shutdown = 0;
- v9ses->session_hung = 0;
-
- v9ses->mux = v9fs_mux_init(v9ses->transport, v9ses->maxdata + V9FS_IOHDRSZ,
- &v9ses->extended);
-
- if (IS_ERR(v9ses->mux)) {
- retval = PTR_ERR(v9ses->mux);
- v9ses->mux = NULL;
- dprintk(DEBUG_ERROR, "problem initializing mux\n");
- goto SessCleanUp;
+ fid = p9_client_attach(v9ses->clnt, NULL, v9ses->name,
+ v9ses->remotename);
+ if (IS_ERR(fid)) {
+ retval = PTR_ERR(fid);
+ fid = NULL;
+ P9_DPRINTK(P9_DEBUG_ERROR, "cannot attach\n");
+ goto error;
}
- if (v9ses->afid == ~0) {
- if (v9ses->extended)
- retval =
- v9fs_t_version(v9ses, v9ses->maxdata, "9P2000.u",
- &fcall);
- else
- retval = v9fs_t_version(v9ses, v9ses->maxdata, "9P2000",
- &fcall);
+ return fid;
- if (retval < 0) {
- dprintk(DEBUG_ERROR, "v9fs_t_version failed\n");
- goto FreeFcall;
- }
-
- version = &fcall->params.rversion.version;
- if (version->len==8 && !memcmp(version->str, "9P2000.u", 8)) {
- dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n");
- v9ses->extended = 1;
- } else if (version->len==6 && !memcmp(version->str, "9P2000", 6)) {
- dprintk(DEBUG_9P, "9P2000 legacy mode enabled\n");
- v9ses->extended = 0;
- } else {
- retval = -EREMOTEIO;
- goto FreeFcall;
- }
-
- n = fcall->params.rversion.msize;
- kfree(fcall);
-
- if (n < v9ses->maxdata)
- v9ses->maxdata = n;
- }
-
- newfid = v9fs_get_idpool(&v9ses->fidpool);
- if (newfid < 0) {
- eprintk(KERN_WARNING, "couldn't allocate FID\n");
- retval = -ENOMEM;
- goto SessCleanUp;
- }
- /* it is a little bit ugly, but we have to prevent newfid */
- /* being the same as afid, so if it is, get a new fid */
- if (v9ses->afid != ~0 && newfid == v9ses->afid) {
- newfid = v9fs_get_idpool(&v9ses->fidpool);
- if (newfid < 0) {
- eprintk(KERN_WARNING, "couldn't allocate FID\n");
- retval = -ENOMEM;
- goto SessCleanUp;
- }
- }
-
- if ((retval =
- v9fs_t_attach(v9ses, v9ses->name, v9ses->remotename, newfid,
- v9ses->afid, NULL))
- < 0) {
- dprintk(DEBUG_ERROR, "cannot attach\n");
- goto SessCleanUp;
- }
-
- if (v9ses->afid != ~0) {
- dprintk(DEBUG_ERROR, "afid not equal to ~0\n");
- if (v9fs_t_clunk(v9ses, v9ses->afid))
- dprintk(DEBUG_ERROR, "clunk failed\n");
- }
-
- return newfid;
-
- FreeFcall:
- kfree(fcall);
-
- SessCleanUp:
+error:
v9fs_session_close(v9ses);
- return retval;
+ return ERR_PTR(retval);
}
/**
@@ -426,15 +281,9 @@
void v9fs_session_close(struct v9fs_session_info *v9ses)
{
- if (v9ses->mux) {
- v9fs_mux_destroy(v9ses->mux);
- v9ses->mux = NULL;
- }
-
- if (v9ses->transport) {
- v9ses->transport->close(v9ses->transport);
- kfree(v9ses->transport);
- v9ses->transport = NULL;
+ if (v9ses->clnt) {
+ p9_client_destroy(v9ses->clnt);
+ v9ses->clnt = NULL;
}
__putname(v9ses->name);
@@ -446,9 +295,8 @@
* and cancel all pending requests.
*/
void v9fs_session_cancel(struct v9fs_session_info *v9ses) {
- dprintk(DEBUG_ERROR, "cancel session %p\n", v9ses);
- v9ses->transport->status = Disconnected;
- v9fs_mux_cancel(v9ses->mux, -EIO);
+ P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses);
+ p9_client_disconnect(v9ses->clnt);
}
extern int v9fs_error_init(void);
@@ -460,24 +308,9 @@
static int __init init_v9fs(void)
{
- int ret;
-
- v9fs_error_init();
-
printk(KERN_INFO "Installing v9fs 9p2000 file system support\n");
- ret = v9fs_mux_global_init();
- if (ret) {
- printk(KERN_WARNING "v9fs: starting mux failed\n");
- return ret;
- }
- ret = register_filesystem(&v9fs_fs_type);
- if (ret) {
- printk(KERN_WARNING "v9fs: registering file system failed\n");
- v9fs_mux_global_exit();
- }
-
- return ret;
+ return register_filesystem(&v9fs_fs_type);
}
/**
@@ -487,13 +320,13 @@
static void __exit exit_v9fs(void)
{
- v9fs_mux_global_exit();
unregister_filesystem(&v9fs_fs_type);
}
module_init(init_v9fs)
module_exit(exit_v9fs)
+MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
MODULE_LICENSE("GPL");
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 820bf5c..abc4b16 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -22,16 +22,6 @@
*/
/*
- * Idpool structure provides lock and id management
- *
- */
-
-struct v9fs_idpool {
- struct semaphore lock;
- struct idr pool;
-};
-
-/*
* Session structure provides information for an opened session
*
*/
@@ -54,15 +44,7 @@
unsigned int uid; /* default uid/muid for legacy support */
unsigned int gid; /* default gid for legacy support */
- /* book keeping */
- struct v9fs_idpool fidpool; /* The FID pool for file descriptors */
-
- struct v9fs_transport *transport;
- struct v9fs_mux_data *mux;
-
- int inprogress; /* session in progress => true */
- int shutdown; /* session shutting down. no more attaches. */
- unsigned char session_hung;
+ struct p9_client *clnt; /* 9p client */
struct dentry *debugfs_dir;
};
@@ -71,6 +53,7 @@
PROTO_TCP,
PROTO_UNIX,
PROTO_FD,
+ PROTO_PCI,
};
/* possible values of ->cache */
@@ -82,12 +65,9 @@
extern struct dentry *v9fs_debugfs_root;
-int v9fs_session_init(struct v9fs_session_info *, const char *, char *);
-struct v9fs_session_info *v9fs_inode2v9ses(struct inode *);
+struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *,
+ char *);
void v9fs_session_close(struct v9fs_session_info *v9ses);
-int v9fs_get_idpool(struct v9fs_idpool *p);
-void v9fs_put_idpool(int id, struct v9fs_idpool *p);
-int v9fs_check_idpool(int id, struct v9fs_idpool *p);
void v9fs_session_cancel(struct v9fs_session_info *v9ses);
#define V9FS_MAGIC 0x01021997
@@ -97,3 +77,7 @@
#define V9FS_DEFUSER "nobody"
#define V9FS_DEFANAME ""
+static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
+{
+ return (inode->i_sb->s_fs_info);
+}
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 6a82d39..fd01d90 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -45,10 +45,10 @@
extern struct dentry_operations v9fs_cached_dentry_operations;
struct inode *v9fs_get_inode(struct super_block *sb, int mode);
-ino_t v9fs_qid2ino(struct v9fs_qid *qid);
-void v9fs_stat2inode(struct v9fs_stat *, struct inode *, struct super_block *);
+ino_t v9fs_qid2ino(struct p9_qid *qid);
+void v9fs_stat2inode(struct p9_stat *, struct inode *, struct super_block *);
int v9fs_dir_release(struct inode *inode, struct file *filp);
int v9fs_file_open(struct inode *inode, struct file *file);
-void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat);
+void v9fs_inode2stat(struct inode *inode, struct p9_stat *stat);
void v9fs_dentry_release(struct dentry *);
int v9fs_uflags2omode(int uflags);
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 9ac4ffe9..6248f0e 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -33,10 +33,10 @@
#include <linux/pagemap.h>
#include <linux/idr.h>
#include <linux/sched.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -50,55 +50,26 @@
static int v9fs_vfs_readpage(struct file *filp, struct page *page)
{
- char *buffer = NULL;
- int retval = -EIO;
- loff_t offset = page_offset(page);
- int count = PAGE_CACHE_SIZE;
- struct inode *inode = filp->f_path.dentry->d_inode;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- int rsize = v9ses->maxdata - V9FS_IOHDRSZ;
- struct v9fs_fid *v9f = filp->private_data;
- struct v9fs_fcall *fcall = NULL;
- int fid = v9f->fid;
- int total = 0;
- int result = 0;
+ int retval;
+ loff_t offset;
+ char *buffer;
+ struct p9_fid *fid;
- dprintk(DEBUG_VFS, "\n");
-
+ P9_DPRINTK(P9_DEBUG_VFS, "\n");
+ fid = filp->private_data;
buffer = kmap(page);
- do {
- if (count < rsize)
- rsize = count;
+ offset = page_offset(page);
- result = v9fs_t_read(v9ses, fid, offset, rsize, &fcall);
+ retval = p9_client_readn(fid, buffer, offset, PAGE_CACHE_SIZE);
+ if (retval < 0)
+ goto done;
- if (result < 0) {
- printk(KERN_ERR "v9fs_t_read returned %d\n",
- result);
-
- kfree(fcall);
- goto UnmapAndUnlock;
- } else
- offset += result;
-
- memcpy(buffer, fcall->params.rread.data, result);
-
- count -= result;
- buffer += result;
- total += result;
-
- kfree(fcall);
-
- if (result < rsize)
- break;
- } while (count);
-
- memset(buffer, 0, count);
+ memset(buffer + retval, 0, PAGE_CACHE_SIZE - retval);
flush_dcache_page(page);
SetPageUptodate(page);
retval = 0;
-UnmapAndUnlock:
+done:
kunmap(page);
unlock_page(page);
return retval;
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index d939604..f9534f1 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -34,10 +34,10 @@
#include <linux/namei.h>
#include <linux/idr.h>
#include <linux/sched.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -52,7 +52,7 @@
static int v9fs_dentry_delete(struct dentry *dentry)
{
- dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
return 1;
}
@@ -69,7 +69,7 @@
static int v9fs_cached_dentry_delete(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
- dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
if(!inode)
return 1;
@@ -85,26 +85,19 @@
void v9fs_dentry_release(struct dentry *dentry)
{
- int err;
+ struct v9fs_dentry *dent;
+ struct p9_fid *temp, *current_fid;
- dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
-
- if (dentry->d_fsdata != NULL) {
- struct list_head *fid_list = dentry->d_fsdata;
- struct v9fs_fid *temp = NULL;
- struct v9fs_fid *current_fid = NULL;
-
- list_for_each_entry_safe(current_fid, temp, fid_list, list) {
- err = v9fs_t_clunk(current_fid->v9ses, current_fid->fid);
-
- if (err < 0)
- dprintk(DEBUG_ERROR, "clunk failed: %d name %s\n",
- err, dentry->d_iname);
-
- v9fs_fid_destroy(current_fid);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ dent = dentry->d_fsdata;
+ if (dent) {
+ list_for_each_entry_safe(current_fid, temp, &dent->fidlist,
+ dlist) {
+ p9_client_clunk(current_fid);
}
- kfree(dentry->d_fsdata); /* free the list_head */
+ kfree(dent);
+ dentry->d_fsdata = NULL;
}
}
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 1dd86ee..0924d44 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -32,11 +32,10 @@
#include <linux/sched.h>
#include <linux/inet.h>
#include <linux/idr.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
-#include "conv.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -46,14 +45,14 @@
*
*/
-static inline int dt_type(struct v9fs_stat *mistat)
+static inline int dt_type(struct p9_stat *mistat)
{
unsigned long perm = mistat->mode;
int rettype = DT_REG;
- if (perm & V9FS_DMDIR)
+ if (perm & P9_DMDIR)
rettype = DT_DIR;
- if (perm & V9FS_DMSYMLINK)
+ if (perm & P9_DMSYMLINK)
rettype = DT_LNK;
return rettype;
@@ -69,106 +68,36 @@
static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct v9fs_fcall *fcall = NULL;
- struct inode *inode = filp->f_path.dentry->d_inode;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- struct v9fs_fid *file = filp->private_data;
- unsigned int i, n, s;
- int fid = -1;
- int ret = 0;
- struct v9fs_stat stat;
- int over = 0;
+ int over;
+ struct p9_fid *fid;
+ struct v9fs_session_info *v9ses;
+ struct inode *inode;
+ struct p9_stat *st;
- dprintk(DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
+ P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
+ inode = filp->f_path.dentry->d_inode;
+ v9ses = v9fs_inode2v9ses(inode);
+ fid = filp->private_data;
+ while ((st = p9_client_dirread(fid, filp->f_pos)) != NULL) {
+ if (IS_ERR(st))
+ return PTR_ERR(st);
- fid = file->fid;
+ over = filldir(dirent, st->name.str, st->name.len, filp->f_pos,
+ v9fs_qid2ino(&st->qid), dt_type(st));
- if (file->rdir_fcall && (filp->f_pos != file->rdir_pos)) {
- kfree(file->rdir_fcall);
- file->rdir_fcall = NULL;
- }
-
- if (file->rdir_fcall) {
- n = file->rdir_fcall->params.rread.count;
- i = file->rdir_fpos;
- while (i < n) {
- s = v9fs_deserialize_stat(
- file->rdir_fcall->params.rread.data + i,
- n - i, &stat, v9ses->extended);
-
- if (s == 0) {
- dprintk(DEBUG_ERROR,
- "error while deserializing stat\n");
- ret = -EIO;
- goto FreeStructs;
- }
-
- over = filldir(dirent, stat.name.str, stat.name.len,
- filp->f_pos, v9fs_qid2ino(&stat.qid),
- dt_type(&stat));
-
- if (over) {
- file->rdir_fpos = i;
- file->rdir_pos = filp->f_pos;
- break;
- }
-
- i += s;
- filp->f_pos += s;
- }
-
- if (!over) {
- kfree(file->rdir_fcall);
- file->rdir_fcall = NULL;
- }
- }
-
- while (!over) {
- ret = v9fs_t_read(v9ses, fid, filp->f_pos,
- v9ses->maxdata-V9FS_IOHDRSZ, &fcall);
- if (ret < 0) {
- dprintk(DEBUG_ERROR, "error while reading: %d: %p\n",
- ret, fcall);
- goto FreeStructs;
- } else if (ret == 0)
+ if (over)
break;
- n = ret;
- i = 0;
- while (i < n) {
- s = v9fs_deserialize_stat(fcall->params.rread.data + i,
- n - i, &stat, v9ses->extended);
-
- if (s == 0) {
- dprintk(DEBUG_ERROR,
- "error while deserializing stat\n");
- return -EIO;
- }
-
- over = filldir(dirent, stat.name.str, stat.name.len,
- filp->f_pos, v9fs_qid2ino(&stat.qid),
- dt_type(&stat));
-
- if (over) {
- file->rdir_fcall = fcall;
- file->rdir_fpos = i;
- file->rdir_pos = filp->f_pos;
- fcall = NULL;
- break;
- }
-
- i += s;
- filp->f_pos += s;
- }
-
- kfree(fcall);
+ filp->f_pos += st->size;
+ kfree(st);
+ st = NULL;
}
- FreeStructs:
- kfree(fcall);
- return ret;
+ kfree(st);
+ return 0;
}
+
/**
* v9fs_dir_release - close a directory
* @inode: inode of the directory
@@ -178,29 +107,13 @@
int v9fs_dir_release(struct inode *inode, struct file *filp)
{
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- struct v9fs_fid *fid = filp->private_data;
- int fidnum = -1;
+ struct p9_fid *fid;
- dprintk(DEBUG_VFS, "inode: %p filp: %p fid: %d\n", inode, filp,
- fid->fid);
- fidnum = fid->fid;
-
+ fid = filp->private_data;
+ P9_DPRINTK(P9_DEBUG_VFS,
+ "inode: %p filp: %p fid: %d\n", inode, filp, fid->fid);
filemap_write_and_wait(inode->i_mapping);
-
- if (fidnum >= 0) {
- dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen,
- fid->fid);
-
- if (v9fs_t_clunk(v9ses, fidnum))
- dprintk(DEBUG_ERROR, "clunk failed\n");
-
- kfree(fid->rdir_fcall);
- kfree(fid);
-
- filp->private_data = NULL;
- }
-
+ p9_client_clunk(fid);
return 0;
}
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 6e7678e..2a40c29 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -34,10 +34,10 @@
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/idr.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -52,48 +52,40 @@
int v9fs_file_open(struct inode *inode, struct file *file)
{
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- struct v9fs_fid *vfid;
- struct v9fs_fcall *fcall = NULL;
- int omode;
int err;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid;
+ int omode;
- dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file);
-
- vfid = v9fs_fid_clone(file->f_path.dentry);
- if (IS_ERR(vfid))
- return PTR_ERR(vfid);
-
+ P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file);
+ v9ses = v9fs_inode2v9ses(inode);
omode = v9fs_uflags2omode(file->f_flags);
- err = v9fs_t_open(v9ses, vfid->fid, omode, &fcall);
- if (err < 0) {
- PRINT_FCALL_ERROR("open failed", fcall);
- goto Clunk_Fid;
+ fid = file->private_data;
+ if (!fid) {
+ fid = v9fs_fid_clone(file->f_path.dentry);
+ if (IS_ERR(fid))
+ return PTR_ERR(fid);
+
+ err = p9_client_open(fid, omode);
+ if (err < 0) {
+ p9_client_clunk(fid);
+ return err;
+ }
+ if (omode & P9_OTRUNC) {
+ inode->i_size = 0;
+ inode->i_blocks = 0;
+ }
}
- file->private_data = vfid;
- vfid->fidopen = 1;
- vfid->fidclunked = 0;
- vfid->iounit = fcall->params.ropen.iounit;
- vfid->rdir_pos = 0;
- vfid->rdir_fcall = NULL;
- vfid->filp = file;
- kfree(fcall);
-
- if((vfid->qid.version) && (v9ses->cache)) {
- dprintk(DEBUG_VFS, "cached");
+ file->private_data = fid;
+ if ((fid->qid.version) && (v9ses->cache)) {
+ P9_DPRINTK(P9_DEBUG_VFS, "cached");
/* enable cached file options */
if(file->f_op == &v9fs_file_operations)
file->f_op = &v9fs_cached_file_operations;
}
return 0;
-
-Clunk_Fid:
- v9fs_fid_clunk(v9ses, vfid);
- kfree(fcall);
-
- return err;
}
/**
@@ -110,7 +102,7 @@
int res = 0;
struct inode *inode = filp->f_path.dentry->d_inode;
- dprintk(DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
+ P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
/* No mandatory locks */
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
@@ -136,55 +128,16 @@
v9fs_file_read(struct file *filp, char __user * data, size_t count,
loff_t * offset)
{
- struct inode *inode = filp->f_path.dentry->d_inode;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- struct v9fs_fid *v9f = filp->private_data;
- struct v9fs_fcall *fcall = NULL;
- int fid = v9f->fid;
- int rsize = 0;
- int result = 0;
- int total = 0;
- int n;
+ int ret;
+ struct p9_fid *fid;
- dprintk(DEBUG_VFS, "\n");
+ P9_DPRINTK(P9_DEBUG_VFS, "\n");
+ fid = filp->private_data;
+ ret = p9_client_uread(fid, data, *offset, count);
+ if (ret > 0)
+ *offset += ret;
- rsize = v9ses->maxdata - V9FS_IOHDRSZ;
- if (v9f->iounit != 0 && rsize > v9f->iounit)
- rsize = v9f->iounit;
-
- do {
- if (count < rsize)
- rsize = count;
-
- result = v9fs_t_read(v9ses, fid, *offset, rsize, &fcall);
-
- if (result < 0) {
- printk(KERN_ERR "9P2000: v9fs_t_read returned %d\n",
- result);
-
- kfree(fcall);
- return total;
- } else
- *offset += result;
-
- n = copy_to_user(data, fcall->params.rread.data, result);
- if (n) {
- dprintk(DEBUG_ERROR, "Problem copying to user %d\n", n);
- kfree(fcall);
- return -EFAULT;
- }
-
- count -= result;
- data += result;
- total += result;
-
- kfree(fcall);
-
- if (result < rsize)
- break;
- } while (count);
-
- return total;
+ return ret;
}
/**
@@ -200,50 +153,25 @@
v9fs_file_write(struct file *filp, const char __user * data,
size_t count, loff_t * offset)
{
+ int ret;
+ struct p9_fid *fid;
struct inode *inode = filp->f_path.dentry->d_inode;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- struct v9fs_fid *v9fid = filp->private_data;
- struct v9fs_fcall *fcall;
- int fid = v9fid->fid;
- int result = -EIO;
- int rsize = 0;
- int total = 0;
- dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count,
- (int)*offset);
- rsize = v9ses->maxdata - V9FS_IOHDRSZ;
- if (v9fid->iounit != 0 && rsize > v9fid->iounit)
- rsize = v9fid->iounit;
+ P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
+ (int)count, (int)*offset);
- do {
- if (count < rsize)
- rsize = count;
+ fid = filp->private_data;
+ ret = p9_client_uwrite(fid, data, *offset, count);
+ if (ret > 0)
+ *offset += ret;
- result = v9fs_t_write(v9ses, fid, *offset, rsize, data, &fcall);
- if (result < 0) {
- PRINT_FCALL_ERROR("error while writing", fcall);
- kfree(fcall);
- return result;
- } else
- *offset += result;
-
- kfree(fcall);
- fcall = NULL;
-
- if (result != rsize) {
- eprintk(KERN_ERR,
- "short write: v9fs_t_write returned %d\n",
- result);
- break;
- }
-
- count -= result;
- data += result;
- total += result;
- } while (count);
+ if (*offset > inode->i_size) {
+ inode->i_size = *offset;
+ inode->i_blocks = (inode->i_size + 512 - 1) >> 9;
+ }
invalidate_inode_pages2(inode->i_mapping);
- return total;
+ return ret;
}
static const struct file_operations v9fs_cached_file_operations = {
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index c76cd8f..e5c45ee 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -34,10 +34,10 @@
#include <linux/namei.h>
#include <linux/idr.h>
#include <linux/sched.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -58,27 +58,27 @@
int res;
res = mode & 0777;
if (S_ISDIR(mode))
- res |= V9FS_DMDIR;
+ res |= P9_DMDIR;
if (v9ses->extended) {
if (S_ISLNK(mode))
- res |= V9FS_DMSYMLINK;
+ res |= P9_DMSYMLINK;
if (v9ses->nodev == 0) {
if (S_ISSOCK(mode))
- res |= V9FS_DMSOCKET;
+ res |= P9_DMSOCKET;
if (S_ISFIFO(mode))
- res |= V9FS_DMNAMEDPIPE;
+ res |= P9_DMNAMEDPIPE;
if (S_ISBLK(mode))
- res |= V9FS_DMDEVICE;
+ res |= P9_DMDEVICE;
if (S_ISCHR(mode))
- res |= V9FS_DMDEVICE;
+ res |= P9_DMDEVICE;
}
if ((mode & S_ISUID) == S_ISUID)
- res |= V9FS_DMSETUID;
+ res |= P9_DMSETUID;
if ((mode & S_ISGID) == S_ISGID)
- res |= V9FS_DMSETGID;
- if ((mode & V9FS_DMLINK))
- res |= V9FS_DMLINK;
+ res |= P9_DMSETGID;
+ if ((mode & P9_DMLINK))
+ res |= P9_DMLINK;
}
return res;
@@ -97,27 +97,27 @@
res = mode & 0777;
- if ((mode & V9FS_DMDIR) == V9FS_DMDIR)
+ if ((mode & P9_DMDIR) == P9_DMDIR)
res |= S_IFDIR;
- else if ((mode & V9FS_DMSYMLINK) && (v9ses->extended))
+ else if ((mode & P9_DMSYMLINK) && (v9ses->extended))
res |= S_IFLNK;
- else if ((mode & V9FS_DMSOCKET) && (v9ses->extended)
+ else if ((mode & P9_DMSOCKET) && (v9ses->extended)
&& (v9ses->nodev == 0))
res |= S_IFSOCK;
- else if ((mode & V9FS_DMNAMEDPIPE) && (v9ses->extended)
+ else if ((mode & P9_DMNAMEDPIPE) && (v9ses->extended)
&& (v9ses->nodev == 0))
res |= S_IFIFO;
- else if ((mode & V9FS_DMDEVICE) && (v9ses->extended)
+ else if ((mode & P9_DMDEVICE) && (v9ses->extended)
&& (v9ses->nodev == 0))
res |= S_IFBLK;
else
res |= S_IFREG;
if (v9ses->extended) {
- if ((mode & V9FS_DMSETUID) == V9FS_DMSETUID)
+ if ((mode & P9_DMSETUID) == P9_DMSETUID)
res |= S_ISUID;
- if ((mode & V9FS_DMSETGID) == V9FS_DMSETGID)
+ if ((mode & P9_DMSETGID) == P9_DMSETGID)
res |= S_ISGID;
}
@@ -132,26 +132,26 @@
switch (uflags&3) {
default:
case O_RDONLY:
- ret = V9FS_OREAD;
+ ret = P9_OREAD;
break;
case O_WRONLY:
- ret = V9FS_OWRITE;
+ ret = P9_OWRITE;
break;
case O_RDWR:
- ret = V9FS_ORDWR;
+ ret = P9_ORDWR;
break;
}
if (uflags & O_EXCL)
- ret |= V9FS_OEXCL;
+ ret |= P9_OEXCL;
if (uflags & O_TRUNC)
- ret |= V9FS_OTRUNC;
+ ret |= P9_OTRUNC;
if (uflags & O_APPEND)
- ret |= V9FS_OAPPEND;
+ ret |= P9_OAPPEND;
return ret;
}
@@ -164,7 +164,7 @@
*/
static void
-v9fs_blank_wstat(struct v9fs_wstat *wstat)
+v9fs_blank_wstat(struct p9_wstat *wstat)
{
wstat->type = ~0;
wstat->dev = ~0;
@@ -197,7 +197,7 @@
struct inode *inode;
struct v9fs_session_info *v9ses = sb->s_fs_info;
- dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);
+ P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);
inode = new_inode(sb);
if (inode) {
@@ -215,7 +215,8 @@
case S_IFCHR:
case S_IFSOCK:
if(!v9ses->extended) {
- dprintk(DEBUG_ERROR, "special files without extended mode\n");
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "special files without extended mode\n");
return ERR_PTR(-EINVAL);
}
init_special_inode(inode, inode->i_mode,
@@ -227,7 +228,8 @@
break;
case S_IFLNK:
if(!v9ses->extended) {
- dprintk(DEBUG_ERROR, "extended modes used w/o 9P2000.u\n");
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "extended modes used w/o 9P2000.u\n");
return ERR_PTR(-EINVAL);
}
inode->i_op = &v9fs_symlink_inode_operations;
@@ -241,71 +243,19 @@
inode->i_fop = &v9fs_dir_operations;
break;
default:
- dprintk(DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n",
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "BAD mode 0x%x S_IFMT 0x%x\n",
mode, mode & S_IFMT);
return ERR_PTR(-EINVAL);
}
} else {
- eprintk(KERN_WARNING, "Problem allocating inode\n");
+ P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
return ERR_PTR(-ENOMEM);
}
return inode;
}
-static int
-v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name, u32 perm,
- u8 mode, char *extension, u32 *fidp, struct v9fs_qid *qid, u32 *iounit)
-{
- int fid;
- int err;
- struct v9fs_fcall *fcall;
-
- fid = v9fs_get_idpool(&v9ses->fidpool);
- if (fid < 0) {
- eprintk(KERN_WARNING, "no free fids available\n");
- return -ENOSPC;
- }
-
- err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall);
- if (err < 0) {
- PRINT_FCALL_ERROR("clone error", fcall);
- if (fcall && fcall->id == RWALK)
- goto clunk_fid;
- else
- goto put_fid;
- }
- kfree(fcall);
-
- err = v9fs_t_create(v9ses, fid, name, perm, mode, extension, &fcall);
- if (err < 0) {
- PRINT_FCALL_ERROR("create fails", fcall);
- goto clunk_fid;
- }
-
- if (iounit)
- *iounit = fcall->params.rcreate.iounit;
-
- if (qid)
- *qid = fcall->params.rcreate.qid;
-
- if (fidp)
- *fidp = fid;
-
- kfree(fcall);
- return 0;
-
-clunk_fid:
- v9fs_t_clunk(v9ses, fid);
- fid = V9FS_NOFID;
-
-put_fid:
- if (fid != V9FS_NOFID)
- v9fs_put_idpool(fid, &v9ses->fidpool);
-
- kfree(fcall);
- return err;
-}
-
+/*
static struct v9fs_fid*
v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry)
{
@@ -355,23 +305,25 @@
kfree(fcall);
return ERR_PTR(err);
}
+*/
static struct inode *
-v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid,
+v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
struct super_block *sb)
{
int err, umode;
struct inode *ret;
- struct v9fs_fcall *fcall;
+ struct p9_stat *st;
ret = NULL;
- err = v9fs_t_stat(v9ses, fid, &fcall);
- if (err) {
- PRINT_FCALL_ERROR("stat error", fcall);
+ st = p9_client_stat(fid);
+ if (IS_ERR(st)) {
+ err = PTR_ERR(st);
+ st = NULL;
goto error;
}
- umode = p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode);
+ umode = p9mode2unixmode(v9ses, st->mode);
ret = v9fs_get_inode(sb, umode);
if (IS_ERR(ret)) {
err = PTR_ERR(ret);
@@ -379,12 +331,13 @@
goto error;
}
- v9fs_stat2inode(&fcall->params.rstat.stat, ret, sb);
- kfree(fcall);
+ v9fs_stat2inode(st, ret, sb);
+ ret->i_ino = v9fs_qid2ino(&st->qid);
+ kfree(st);
return ret;
error:
- kfree(fcall);
+ kfree(st);
if (ret)
iput(ret);
@@ -401,43 +354,20 @@
static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
{
- struct v9fs_fcall *fcall = NULL;
- struct super_block *sb = NULL;
- struct v9fs_session_info *v9ses = NULL;
- struct v9fs_fid *v9fid = NULL;
- struct inode *file_inode = NULL;
- int fid = -1;
- int result = 0;
+ struct inode *file_inode;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *v9fid;
- dprintk(DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
+ P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
rmdir);
file_inode = file->d_inode;
- sb = file_inode->i_sb;
v9ses = v9fs_inode2v9ses(file_inode);
v9fid = v9fs_fid_clone(file);
if(IS_ERR(v9fid))
return PTR_ERR(v9fid);
- fid = v9fid->fid;
- if (fid < 0) {
- dprintk(DEBUG_ERROR, "inode #%lu, no fid!\n",
- file_inode->i_ino);
- return -EBADF;
- }
-
- result = v9fs_t_remove(v9ses, fid, &fcall);
- if (result < 0) {
- PRINT_FCALL_ERROR("remove fails", fcall);
- goto Error;
- }
-
- v9fs_put_idpool(fid, &v9ses->fidpool);
- v9fs_fid_destroy(v9fid);
-
-Error:
- kfree(fcall);
- return result;
+ return p9_client_remove(v9fid);
}
static int
@@ -446,9 +376,87 @@
return 0;
}
+
+/**
+ * v9fs_create - Create a file
+ * @dentry: dentry that is being created
+ * @perm: create permissions
+ * @mode: open mode
+ *
+ */
+static struct p9_fid *
+v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
+ struct dentry *dentry, char *extension, u32 perm, u8 mode)
+{
+ int err;
+ char *name;
+ struct p9_fid *dfid, *ofid, *fid;
+ struct inode *inode;
+
+ err = 0;
+ ofid = NULL;
+ fid = NULL;
+ name = (char *) dentry->d_name.name;
+ dfid = v9fs_fid_clone(dentry->d_parent);
+ if(IS_ERR(dfid)) {
+ err = PTR_ERR(dfid);
+ dfid = NULL;
+ goto error;
+ }
+
+ /* clone a fid to use for creation */
+ ofid = p9_client_walk(dfid, 0, NULL, 1);
+ if (IS_ERR(ofid)) {
+ err = PTR_ERR(ofid);
+ ofid = NULL;
+ goto error;
+ }
+
+ err = p9_client_fcreate(ofid, name, perm, mode, extension);
+ if (err < 0)
+ goto error;
+
+ /* now walk from the parent so we can get unopened fid */
+ fid = p9_client_walk(dfid, 1, &name, 0);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ fid = NULL;
+ goto error;
+ } else
+ dfid = NULL;
+
+ /* instantiate inode and assign the unopened fid to the dentry */
+ inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto error;
+ }
+
+ if(v9ses->cache)
+ dentry->d_op = &v9fs_cached_dentry_operations;
+ else
+ dentry->d_op = &v9fs_dentry_operations;
+
+ d_instantiate(dentry, inode);
+ v9fs_fid_add(dentry, fid);
+ return ofid;
+
+error:
+ if (dfid)
+ p9_client_clunk(dfid);
+
+ if (ofid)
+ p9_client_clunk(ofid);
+
+ if (fid)
+ p9_client_clunk(fid);
+
+ return ERR_PTR(err);
+}
+
/**
* v9fs_vfs_create - VFS hook to create files
- * @inode: directory inode that is being deleted
+ * @inode: directory inode that is being created
* @dentry: dentry that is being deleted
* @mode: create permissions
* @nd: path information
@@ -460,83 +468,46 @@
struct nameidata *nd)
{
int err;
- u32 fid, perm, iounit;
+ u32 perm;
int flags;
struct v9fs_session_info *v9ses;
- struct v9fs_fid *dfid, *vfid, *ffid;
- struct inode *inode;
- struct v9fs_qid qid;
+ struct p9_fid *fid;
struct file *filp;
- inode = NULL;
- vfid = NULL;
+ err = 0;
+ fid = NULL;
v9ses = v9fs_inode2v9ses(dir);
- dfid = v9fs_fid_clone(dentry->d_parent);
- if(IS_ERR(dfid)) {
- err = PTR_ERR(dfid);
- goto error;
- }
-
perm = unixmode2p9mode(v9ses, mode);
if (nd && nd->flags & LOOKUP_OPEN)
flags = nd->intent.open.flags - 1;
else
flags = O_RDWR;
- err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
- perm, v9fs_uflags2omode(flags), NULL, &fid, &qid, &iounit);
-
- if (err)
- goto clunk_dfid;
-
- vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
- v9fs_fid_clunk(v9ses, dfid);
- if (IS_ERR(vfid)) {
- err = PTR_ERR(vfid);
- vfid = NULL;
+ fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
+ v9fs_uflags2omode(flags));
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ fid = NULL;
goto error;
}
- inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
- if (IS_ERR(inode)) {
- err = PTR_ERR(inode);
- inode = NULL;
- goto error;
- }
-
- if(v9ses->cache)
- dentry->d_op = &v9fs_cached_dentry_operations;
- else
- dentry->d_op = &v9fs_dentry_operations;
- d_instantiate(dentry, inode);
-
+ /* if we are opening a file, assign the open fid to the file */
if (nd && nd->flags & LOOKUP_OPEN) {
- ffid = v9fs_fid_create(v9ses, fid);
- if (!ffid)
- return -ENOMEM;
-
filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
if (IS_ERR(filp)) {
- v9fs_fid_destroy(ffid);
- return PTR_ERR(filp);
+ err = PTR_ERR(filp);
+ goto error;
}
- ffid->rdir_pos = 0;
- ffid->rdir_fcall = NULL;
- ffid->fidopen = 1;
- ffid->iounit = iounit;
- ffid->filp = filp;
- filp->private_data = ffid;
- }
+ filp->private_data = fid;
+ } else
+ p9_client_clunk(fid);
return 0;
-clunk_dfid:
- v9fs_fid_clunk(v9ses, dfid);
-
error:
- if (vfid)
- v9fs_fid_destroy(vfid);
+ if (fid)
+ p9_client_clunk(fid);
return err;
}
@@ -552,57 +523,23 @@
static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int err;
- u32 fid, perm;
+ u32 perm;
struct v9fs_session_info *v9ses;
- struct v9fs_fid *dfid, *vfid;
- struct inode *inode;
+ struct p9_fid *fid;
- inode = NULL;
- vfid = NULL;
+ P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
+ err = 0;
v9ses = v9fs_inode2v9ses(dir);
- dfid = v9fs_fid_clone(dentry->d_parent);
- if(IS_ERR(dfid)) {
- err = PTR_ERR(dfid);
- goto error;
- }
-
perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
-
- err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
- perm, V9FS_OREAD, NULL, &fid, NULL, NULL);
-
- if (err) {
- dprintk(DEBUG_ERROR, "create error %d\n", err);
- goto clean_up_dfid;
+ fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_OREAD);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ fid = NULL;
}
- vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
- if (IS_ERR(vfid)) {
- err = PTR_ERR(vfid);
- vfid = NULL;
- goto clean_up_dfid;
- }
+ if (fid)
+ p9_client_clunk(fid);
- v9fs_fid_clunk(v9ses, dfid);
- inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
- if (IS_ERR(inode)) {
- err = PTR_ERR(inode);
- inode = NULL;
- v9fs_fid_destroy(vfid);
- goto error;
- }
-
- if(v9ses->cache)
- dentry->d_op = &v9fs_cached_dentry_operations;
- else
- dentry->d_op = &v9fs_dentry_operations;
- d_instantiate(dentry, inode);
- return 0;
-
-clean_up_dfid:
- v9fs_fid_clunk(v9ses, dfid);
-
-error:
return err;
}
@@ -619,104 +556,54 @@
{
struct super_block *sb;
struct v9fs_session_info *v9ses;
- struct v9fs_fid *dirfid;
- struct v9fs_fid *fid;
+ struct p9_fid *dfid, *fid;
struct inode *inode;
- struct v9fs_fcall *fcall = NULL;
- int dirfidnum = -1;
- int newfid = -1;
+ char *name;
int result = 0;
- dprintk(DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
+ P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
dir, dentry->d_name.name, dentry, nameidata);
sb = dir->i_sb;
v9ses = v9fs_inode2v9ses(dir);
- dirfid = v9fs_fid_lookup(dentry->d_parent);
+ dfid = v9fs_fid_lookup(dentry->d_parent);
+ if (IS_ERR(dfid))
+ return ERR_PTR(PTR_ERR(dfid));
- if(IS_ERR(dirfid))
- return ERR_PTR(PTR_ERR(dirfid));
-
- dirfidnum = dirfid->fid;
-
- newfid = v9fs_get_idpool(&v9ses->fidpool);
- if (newfid < 0) {
- eprintk(KERN_WARNING, "newfid fails!\n");
- result = -ENOSPC;
- goto Release_Dirfid;
- }
-
- result = v9fs_t_walk(v9ses, dirfidnum, newfid,
- (char *)dentry->d_name.name, &fcall);
-
- up(&dirfid->lock);
-
- if (result < 0) {
- if (fcall && fcall->id == RWALK)
- v9fs_t_clunk(v9ses, newfid);
- else
- v9fs_put_idpool(newfid, &v9ses->fidpool);
-
+ name = (char *) dentry->d_name.name;
+ fid = p9_client_walk(dfid, 1, &name, 1);
+ if (IS_ERR(fid)) {
+ result = PTR_ERR(fid);
if (result == -ENOENT) {
d_add(dentry, NULL);
- dprintk(DEBUG_VFS,
- "Return negative dentry %p count %d\n",
- dentry, atomic_read(&dentry->d_count));
- kfree(fcall);
return NULL;
}
- dprintk(DEBUG_ERROR, "walk error:%d\n", result);
- goto FreeFcall;
- }
- kfree(fcall);
- result = v9fs_t_stat(v9ses, newfid, &fcall);
- if (result < 0) {
- dprintk(DEBUG_ERROR, "stat error\n");
- goto FreeFcall;
+ return ERR_PTR(result);
}
- inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses,
- fcall->params.rstat.stat.mode));
-
- if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) {
- eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n",
- PTR_ERR(inode));
-
- result = -ENOSPC;
- goto FreeFcall;
+ inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+ if (IS_ERR(inode)) {
+ result = PTR_ERR(inode);
+ inode = NULL;
+ goto error;
}
- inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid);
-
- fid = v9fs_fid_create(v9ses, newfid);
- if (fid == NULL) {
- dprintk(DEBUG_ERROR, "couldn't insert\n");
- result = -ENOMEM;
- goto FreeFcall;
- }
-
- result = v9fs_fid_insert(fid, dentry);
+ result = v9fs_fid_add(dentry, fid);
if (result < 0)
- goto FreeFcall;
+ goto error;
- fid->qid = fcall->params.rstat.stat.qid;
- v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb);
if((fid->qid.version)&&(v9ses->cache))
dentry->d_op = &v9fs_cached_dentry_operations;
else
dentry->d_op = &v9fs_dentry_operations;
d_add(dentry, inode);
- kfree(fcall);
-
return NULL;
-Release_Dirfid:
- up(&dirfid->lock);
-
-FreeFcall:
- kfree(fcall);
+error:
+ if (fid)
+ p9_client_clunk(fid);
return ERR_PTR(result);
}
@@ -758,73 +645,54 @@
v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
- struct inode *old_inode = old_dentry->d_inode;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode);
- struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry);
- struct v9fs_fid *olddirfid;
- struct v9fs_fid *newdirfid;
- struct v9fs_wstat wstat;
- struct v9fs_fcall *fcall = NULL;
- int fid = -1;
- int olddirfidnum = -1;
- int newdirfidnum = -1;
- int retval = 0;
+ struct inode *old_inode;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *oldfid;
+ struct p9_fid *olddirfid;
+ struct p9_fid *newdirfid;
+ struct p9_wstat wstat;
+ int retval;
- dprintk(DEBUG_VFS, "\n");
-
+ P9_DPRINTK(P9_DEBUG_VFS, "\n");
+ retval = 0;
+ old_inode = old_dentry->d_inode;
+ v9ses = v9fs_inode2v9ses(old_inode);
+ oldfid = v9fs_fid_lookup(old_dentry);
if(IS_ERR(oldfid))
return PTR_ERR(oldfid);
olddirfid = v9fs_fid_clone(old_dentry->d_parent);
if(IS_ERR(olddirfid)) {
retval = PTR_ERR(olddirfid);
- goto Release_lock;
+ goto done;
}
newdirfid = v9fs_fid_clone(new_dentry->d_parent);
if(IS_ERR(newdirfid)) {
retval = PTR_ERR(newdirfid);
- goto Clunk_olddir;
+ goto clunk_olddir;
}
/* 9P can only handle file rename in the same directory */
if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) {
- dprintk(DEBUG_ERROR, "old dir and new dir are different\n");
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "old dir and new dir are different\n");
retval = -EXDEV;
- goto Clunk_newdir;
- }
-
- fid = oldfid->fid;
- olddirfidnum = olddirfid->fid;
- newdirfidnum = newdirfid->fid;
-
- if (fid < 0) {
- dprintk(DEBUG_ERROR, "no fid for old file #%lu\n",
- old_inode->i_ino);
- retval = -EBADF;
- goto Clunk_newdir;
+ goto clunk_newdir;
}
v9fs_blank_wstat(&wstat);
wstat.muid = v9ses->name;
wstat.name = (char *) new_dentry->d_name.name;
+ retval = p9_client_wstat(oldfid, &wstat);
- retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall);
+clunk_newdir:
+ p9_client_clunk(olddirfid);
- if (retval < 0)
- PRINT_FCALL_ERROR("wstat error", fcall);
+clunk_olddir:
+ p9_client_clunk(newdirfid);
- kfree(fcall);
-
-Clunk_newdir:
- v9fs_fid_clunk(v9ses, newdirfid);
-
-Clunk_olddir:
- v9fs_fid_clunk(v9ses, olddirfid);
-
-Release_lock:
- up(&oldfid->lock);
-
+done:
return retval;
}
@@ -840,28 +708,30 @@
v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
{
- struct v9fs_fcall *fcall = NULL;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *fid = v9fs_fid_clone(dentry);
- int err = -EPERM;
+ int err;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid;
+ struct p9_stat *st;
- dprintk(DEBUG_VFS, "dentry: %p\n", dentry);
- if(IS_ERR(fid))
+ P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
+ err = -EPERM;
+ v9ses = v9fs_inode2v9ses(dentry->d_inode);
+ if (v9ses->cache == CACHE_LOOSE)
+ return simple_getattr(mnt, dentry, stat);
+
+ fid = v9fs_fid_lookup(dentry);
+ if (IS_ERR(fid))
return PTR_ERR(fid);
- err = v9fs_t_stat(v9ses, fid->fid, &fcall);
+ st = p9_client_stat(fid);
+ if (IS_ERR(st))
+ return PTR_ERR(st);
- if (err < 0)
- dprintk(DEBUG_ERROR, "stat error\n");
- else {
- v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode,
- dentry->d_inode->i_sb);
+ v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb);
generic_fillattr(dentry->d_inode, stat);
- }
- kfree(fcall);
- v9fs_fid_clunk(v9ses, fid);
- return err;
+ kfree(st);
+ return 0;
}
/**
@@ -873,13 +743,15 @@
static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *fid = v9fs_fid_clone(dentry);
- struct v9fs_fcall *fcall = NULL;
- struct v9fs_wstat wstat;
- int res = -EPERM;
+ int retval;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid;
+ struct p9_wstat wstat;
- dprintk(DEBUG_VFS, "\n");
+ P9_DPRINTK(P9_DEBUG_VFS, "\n");
+ retval = -EPERM;
+ v9ses = v9fs_inode2v9ses(dentry->d_inode);
+ fid = v9fs_fid_lookup(dentry);
if(IS_ERR(fid))
return PTR_ERR(fid);
@@ -904,17 +776,11 @@
wstat.n_gid = iattr->ia_gid;
}
- res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall);
+ retval = p9_client_wstat(fid, &wstat);
+ if (retval >= 0)
+ retval = inode_setattr(dentry->d_inode, iattr);
- if (res < 0)
- PRINT_FCALL_ERROR("wstat error", fcall);
-
- kfree(fcall);
- if (res >= 0)
- res = inode_setattr(dentry->d_inode, iattr);
-
- v9fs_fid_clunk(v9ses, fid);
- return res;
+ return retval;
}
/**
@@ -926,7 +792,7 @@
*/
void
-v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode,
+v9fs_stat2inode(struct p9_stat *stat, struct inode *inode,
struct super_block *sb)
{
int n;
@@ -967,8 +833,9 @@
case 'b':
break;
default:
- dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n",
- type, stat->extension.len, stat->extension.str);
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "Unknown special type %c (%.*s)\n", type,
+ stat->extension.len, stat->extension.str);
};
inode->i_rdev = MKDEV(major, minor);
} else
@@ -976,8 +843,8 @@
inode->i_size = stat->length;
- inode->i_blocks =
- (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+ /* not real number of blocks, but 512 byte ones ... */
+ inode->i_blocks = (inode->i_size + 512 - 1) >> 9;
}
/**
@@ -987,7 +854,7 @@
* BUG: potential for inode number collisions?
*/
-ino_t v9fs_qid2ino(struct v9fs_qid *qid)
+ino_t v9fs_qid2ino(struct p9_qid *qid)
{
u64 path = qid->path + 2;
ino_t i = 0;
@@ -1010,56 +877,46 @@
static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
{
- int retval = -EPERM;
+ int retval;
- struct v9fs_fcall *fcall = NULL;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *fid = v9fs_fid_clone(dentry);
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid;
+ struct p9_stat *st;
+ P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
+ retval = -EPERM;
+ v9ses = v9fs_inode2v9ses(dentry->d_inode);
+ fid = v9fs_fid_lookup(dentry);
if(IS_ERR(fid))
return PTR_ERR(fid);
- if (!v9ses->extended) {
- retval = -EBADF;
- dprintk(DEBUG_ERROR, "not extended\n");
- goto ClunkFid;
- }
+ if (!v9ses->extended)
+ return -EBADF;
- dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name);
- retval = v9fs_t_stat(v9ses, fid->fid, &fcall);
+ st = p9_client_stat(fid);
+ if (IS_ERR(st))
+ return PTR_ERR(st);
- if (retval < 0) {
- dprintk(DEBUG_ERROR, "stat error\n");
- goto FreeFcall;
- }
-
- if (!fcall) {
- retval = -EIO;
- goto ClunkFid;
- }
-
- if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) {
+ if (!(st->mode & P9_DMSYMLINK)) {
retval = -EINVAL;
- goto FreeFcall;
+ goto done;
}
/* copy extension buffer into buffer */
- if (fcall->params.rstat.stat.extension.len < buflen)
- buflen = fcall->params.rstat.stat.extension.len + 1;
+ if (st->extension.len < buflen)
+ buflen = st->extension.len + 1;
- memmove(buffer, fcall->params.rstat.stat.extension.str, buflen - 1);
+ memmove(buffer, st->extension.str, buflen - 1);
buffer[buflen-1] = 0;
- dprintk(DEBUG_ERROR, "%s -> %.*s (%s)\n", dentry->d_name.name, fcall->params.rstat.stat.extension.len,
- fcall->params.rstat.stat.extension.str, buffer);
+ P9_DPRINTK(P9_DEBUG_VFS,
+ "%s -> %.*s (%s)\n", dentry->d_name.name, st->extension.len,
+ st->extension.str, buffer);
+
retval = buflen;
-FreeFcall:
- kfree(fcall);
-
-ClunkFid:
- v9fs_fid_clunk(v9ses, fid);
-
+done:
+ kfree(st);
return retval;
}
@@ -1084,14 +941,14 @@
if (buflen > PATH_MAX)
buflen = PATH_MAX;
- dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
retval = v9fs_readlink(dentry, link, buflen);
if (retval > 0) {
if ((ret = copy_to_user(buffer, link, retval)) != 0) {
- dprintk(DEBUG_ERROR, "problem copying to user: %d\n",
- ret);
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "problem copying to user: %d\n", ret);
retval = ret;
}
}
@@ -1112,7 +969,7 @@
int len = 0;
char *link = __getname();
- dprintk(DEBUG_VFS, "%s n", dentry->d_name.name);
+ P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name);
if (!link)
link = ERR_PTR(-ENOMEM);
@@ -1141,7 +998,7 @@
{
char *s = nd_get_link(nd);
- dprintk(DEBUG_VFS, " %s %s\n", dentry->d_name.name, s);
+ P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name, s);
if (!IS_ERR(s))
__putname(s);
}
@@ -1149,66 +1006,24 @@
static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
int mode, const char *extension)
{
- int err;
- u32 fid, perm;
+ u32 perm;
struct v9fs_session_info *v9ses;
- struct v9fs_fid *dfid, *vfid = NULL;
- struct inode *inode = NULL;
+ struct p9_fid *fid;
v9ses = v9fs_inode2v9ses(dir);
if (!v9ses->extended) {
- dprintk(DEBUG_ERROR, "not extended\n");
+ P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n");
return -EPERM;
}
- dfid = v9fs_fid_clone(dentry->d_parent);
- if(IS_ERR(dfid)) {
- err = PTR_ERR(dfid);
- goto error;
- }
-
perm = unixmode2p9mode(v9ses, mode);
+ fid = v9fs_create(v9ses, dir, dentry, (char *) extension, perm,
+ P9_OREAD);
+ if (IS_ERR(fid))
+ return PTR_ERR(fid);
- err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
- perm, V9FS_OREAD, (char *) extension, &fid, NULL, NULL);
-
- if (err)
- goto clunk_dfid;
-
- err = v9fs_t_clunk(v9ses, fid);
- if (err)
- goto clunk_dfid;
-
- vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
- if (IS_ERR(vfid)) {
- err = PTR_ERR(vfid);
- vfid = NULL;
- goto clunk_dfid;
- }
-
- inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
- if (IS_ERR(inode)) {
- err = PTR_ERR(inode);
- inode = NULL;
- goto free_vfid;
- }
-
- if(v9ses->cache)
- dentry->d_op = &v9fs_cached_dentry_operations;
- else
- dentry->d_op = &v9fs_dentry_operations;
- d_instantiate(dentry, inode);
+ p9_client_clunk(fid);
return 0;
-
-free_vfid:
- v9fs_fid_destroy(vfid);
-
-clunk_dfid:
- v9fs_fid_clunk(v9ses, dfid);
-
-error:
- return err;
-
}
/**
@@ -1224,8 +1039,8 @@
static int
v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
- dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
- symname);
+ P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino,
+ dentry->d_name.name, symname);
return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname);
}
@@ -1247,11 +1062,11 @@
struct dentry *dentry)
{
int retval;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
- struct v9fs_fid *oldfid;
+ struct p9_fid *oldfid;
char *name;
- dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
+ P9_DPRINTK(P9_DEBUG_VFS,
+ " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
old_dentry->d_name.name);
oldfid = v9fs_fid_clone(old_dentry);
@@ -1265,11 +1080,11 @@
}
sprintf(name, "%d\n", oldfid->fid);
- retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name);
+ retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name);
__putname(name);
clunk_fid:
- v9fs_fid_clunk(v9ses, oldfid);
+ p9_client_clunk(oldfid);
return retval;
}
@@ -1288,7 +1103,8 @@
int retval;
char *name;
- dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
+ P9_DPRINTK(P9_DEBUG_VFS,
+ " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
if (!new_valid_dev(rdev))
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 7bdf8b3..ba90437 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -37,10 +37,10 @@
#include <linux/mount.h>
#include <linux/idr.h>
#include <linux/sched.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -107,41 +107,48 @@
struct vfsmount *mnt)
{
struct super_block *sb = NULL;
- struct v9fs_fcall *fcall = NULL;
struct inode *inode = NULL;
struct dentry *root = NULL;
struct v9fs_session_info *v9ses = NULL;
- struct v9fs_fid *root_fid = NULL;
+ struct p9_stat *st = NULL;
int mode = S_IRWXUGO | S_ISVTX;
uid_t uid = current->fsuid;
gid_t gid = current->fsgid;
- int stat_result = 0;
- int newfid = 0;
+ struct p9_fid *fid;
int retval = 0;
- dprintk(DEBUG_VFS, " \n");
+ P9_DPRINTK(P9_DEBUG_VFS, " \n");
v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
if (!v9ses)
return -ENOMEM;
- if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) {
- dprintk(DEBUG_ERROR, "problem initiating session\n");
- retval = newfid;
- goto out_free_session;
+ fid = v9fs_session_init(v9ses, dev_name, data);
+ if (IS_ERR(fid)) {
+ retval = PTR_ERR(fid);
+ fid = NULL;
+ kfree(v9ses);
+ v9ses = NULL;
+ goto error;
+ }
+
+ st = p9_client_stat(fid);
+ if (IS_ERR(st)) {
+ retval = PTR_ERR(st);
+ goto error;
}
sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
if (IS_ERR(sb)) {
retval = PTR_ERR(sb);
- goto out_close_session;
+ goto error;
}
v9fs_fill_super(sb, v9ses, flags);
inode = v9fs_get_inode(sb, S_IFDIR | mode);
if (IS_ERR(inode)) {
retval = PTR_ERR(inode);
- goto put_back_sb;
+ goto error;
}
inode->i_uid = uid;
@@ -150,54 +157,30 @@
root = d_alloc_root(inode);
if (!root) {
retval = -ENOMEM;
- goto put_back_sb;
+ goto error;
}
sb->s_root = root;
-
- stat_result = v9fs_t_stat(v9ses, newfid, &fcall);
- if (stat_result < 0) {
- dprintk(DEBUG_ERROR, "stat error\n");
- v9fs_t_clunk(v9ses, newfid);
- } else {
- /* Setup the Root Inode */
- root_fid = v9fs_fid_create(v9ses, newfid);
- if (root_fid == NULL) {
- retval = -ENOMEM;
- goto put_back_sb;
- }
-
- retval = v9fs_fid_insert(root_fid, root);
- if (retval < 0) {
- kfree(fcall);
- goto put_back_sb;
- }
-
- root_fid->qid = fcall->params.rstat.stat.qid;
- root->d_inode->i_ino =
- v9fs_qid2ino(&fcall->params.rstat.stat.qid);
- v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb);
- }
-
- kfree(fcall);
-
- if (stat_result < 0) {
- retval = stat_result;
- goto put_back_sb;
- }
+ root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
+ v9fs_stat2inode(st, root->d_inode, sb);
+ v9fs_fid_add(root, fid);
return simple_set_mnt(mnt, sb);
-out_close_session:
- v9fs_session_close(v9ses);
-out_free_session:
- kfree(v9ses);
- return retval;
+error:
+ if (fid)
+ p9_client_clunk(fid);
-put_back_sb:
- /* deactivate_super calls v9fs_kill_super which will frees the rest */
- up_write(&sb->s_umount);
- deactivate_super(sb);
+ if (v9ses) {
+ v9fs_session_close(v9ses);
+ kfree(v9ses);
+ }
+
+ if (sb) {
+ up_write(&sb->s_umount);
+ deactivate_super(sb);
+ }
+
return retval;
}
@@ -211,7 +194,7 @@
{
struct v9fs_session_info *v9ses = s->s_fs_info;
- dprintk(DEBUG_VFS, " %p\n", s);
+ P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s);
v9fs_dentry_release(s->s_root); /* clunk root */
@@ -219,7 +202,7 @@
v9fs_session_close(v9ses);
kfree(v9ses);
- dprintk(DEBUG_VFS, "exiting kill_super\n");
+ P9_DPRINTK(P9_DEBUG_VFS, "exiting kill_super\n");
}
/**
@@ -234,7 +217,7 @@
struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info;
if (v9ses->debug != 0)
- seq_printf(m, ",debug=%u", v9ses->debug);
+ seq_printf(m, ",debug=%x", v9ses->debug);
if (v9ses->port != V9FS_PORT)
seq_printf(m, ",port=%u", v9ses->port);
if (v9ses->maxdata != 9000)
diff --git a/fs/Kconfig b/fs/Kconfig
index 0fa0c11..94b9d86 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -2048,7 +2048,7 @@
config 9P_FS
tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)"
- depends on INET && EXPERIMENTAL
+ depends on INET && NET_9P && EXPERIMENTAL
help
If you say Y here, you will get experimental support for
Plan 9 resource sharing via the 9P2000 protocol.
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 9ddf5ed..898a86d 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -470,7 +470,7 @@
ret = -ENOENT;
if (!IS_DEADDIR(host_inode)) {
- ret = host_file->f_op->readdir(host_file, filldir, dirent);
+ ret = host_file->f_op->readdir(host_file, dirent, filldir);
file_accessed(host_file);
}
}
diff --git a/fs/xfs/Makefile-linux-2.6 b/fs/xfs/Makefile-linux-2.6
index b49989b..e7a9a83 100644
--- a/fs/xfs/Makefile-linux-2.6
+++ b/fs/xfs/Makefile-linux-2.6
@@ -64,6 +64,7 @@
xfs_dir2_sf.o \
xfs_error.o \
xfs_extfree_item.o \
+ xfs_filestream.o \
xfs_fsops.o \
xfs_ialloc.o \
xfs_ialloc_btree.o \
@@ -77,6 +78,7 @@
xfs_log.o \
xfs_log_recover.o \
xfs_mount.o \
+ xfs_mru_cache.o \
xfs_rename.o \
xfs_trans.o \
xfs_trans_ail.o \
diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h
index 9ebabdf..4b6470c 100644
--- a/fs/xfs/linux-2.6/kmem.h
+++ b/fs/xfs/linux-2.6/kmem.h
@@ -100,25 +100,6 @@
extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast);
extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast);
-/*
- * Low memory cache shrinkers
- */
-
-typedef struct shrinker *kmem_shaker_t;
-typedef int (*kmem_shake_func_t)(int, gfp_t);
-
-static inline kmem_shaker_t
-kmem_shake_register(kmem_shake_func_t sfunc)
-{
- return set_shrinker(DEFAULT_SEEKS, sfunc);
-}
-
-static inline void
-kmem_shake_deregister(kmem_shaker_t shrinker)
-{
- remove_shrinker(shrinker);
-}
-
static inline int
kmem_shake_allow(gfp_t gfp_mask)
{
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 7361861..fd4105d 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -108,14 +108,19 @@
/*
* Schedule IO completion handling on a xfsdatad if this was
- * the final hold on this ioend.
+ * the final hold on this ioend. If we are asked to wait,
+ * flush the workqueue.
*/
STATIC void
xfs_finish_ioend(
- xfs_ioend_t *ioend)
+ xfs_ioend_t *ioend,
+ int wait)
{
- if (atomic_dec_and_test(&ioend->io_remaining))
+ if (atomic_dec_and_test(&ioend->io_remaining)) {
queue_work(xfsdatad_workqueue, &ioend->io_work);
+ if (wait)
+ flush_workqueue(xfsdatad_workqueue);
+ }
}
/*
@@ -156,6 +161,8 @@
xfs_fsize_t bsize;
ip = xfs_vtoi(ioend->io_vnode);
+ if (!ip)
+ return;
ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG);
ASSERT(ioend->io_type != IOMAP_READ);
@@ -334,7 +341,7 @@
bio->bi_end_io = NULL;
bio_put(bio);
- xfs_finish_ioend(ioend);
+ xfs_finish_ioend(ioend, 0);
return 0;
}
@@ -470,7 +477,7 @@
}
if (bio)
xfs_submit_ioend_bio(ioend, bio);
- xfs_finish_ioend(ioend);
+ xfs_finish_ioend(ioend, 0);
} while ((ioend = next) != NULL);
}
@@ -1003,6 +1010,8 @@
if (buffer_unwritten(bh) || buffer_delay(bh) ||
((buffer_uptodate(bh) || PageUptodate(page)) &&
!buffer_mapped(bh) && (unmapped || startio))) {
+ int new_ioend = 0;
+
/*
* Make sure we don't use a read-only iomap
*/
@@ -1021,6 +1030,15 @@
}
if (!iomap_valid) {
+ /*
+ * if we didn't have a valid mapping then we
+ * need to ensure that we put the new mapping
+ * in a new ioend structure. This needs to be
+ * done to ensure that the ioends correctly
+ * reflect the block mappings at io completion
+ * for unwritten extent conversion.
+ */
+ new_ioend = 1;
if (type == IOMAP_NEW) {
size = xfs_probe_cluster(inode,
page, bh, head, 0);
@@ -1040,7 +1058,7 @@
if (startio) {
xfs_add_to_ioend(inode, bh, offset,
type, &ioend,
- !iomap_valid);
+ new_ioend);
} else {
set_buffer_dirty(bh);
unlock_buffer(bh);
@@ -1416,6 +1434,13 @@
* This is not necessary for synchronous direct I/O, but we do
* it anyway to keep the code uniform and simpler.
*
+ * Well, if only it were that simple. Because synchronous direct I/O
+ * requires extent conversion to occur *before* we return to userspace,
+ * we have to wait for extent conversion to complete. Look at the
+ * iocb that has been passed to us to determine if this is AIO or
+ * not. If it is synchronous, tell xfs_finish_ioend() to kick the
+ * workqueue and wait for it to complete.
+ *
* The core direct I/O code might be changed to always call the
* completion handler in the future, in which case all this can
* go away.
@@ -1423,9 +1448,9 @@
ioend->io_offset = offset;
ioend->io_size = size;
if (ioend->io_type == IOMAP_READ) {
- xfs_finish_ioend(ioend);
+ xfs_finish_ioend(ioend, 0);
} else if (private && size > 0) {
- xfs_finish_ioend(ioend);
+ xfs_finish_ioend(ioend, is_sync_kiocb(iocb));
} else {
/*
* A direct I/O write ioend starts it's life in unwritten
@@ -1434,7 +1459,7 @@
* handler.
*/
INIT_WORK(&ioend->io_work, xfs_end_bio_written);
- xfs_finish_ioend(ioend);
+ xfs_finish_ioend(ioend, 0);
}
/*
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index fe4f66a..2df6362 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -35,7 +35,7 @@
#include <linux/freezer.h>
static kmem_zone_t *xfs_buf_zone;
-static kmem_shaker_t xfs_buf_shake;
+static struct shrinker *xfs_buf_shake;
STATIC int xfsbufd(void *);
STATIC int xfsbufd_wakeup(int, gfp_t);
STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int);
@@ -314,7 +314,7 @@
ASSERT(list_empty(&bp->b_hash_list));
- if (bp->b_flags & _XBF_PAGE_CACHE) {
+ if (bp->b_flags & (_XBF_PAGE_CACHE|_XBF_PAGES)) {
uint i;
if ((bp->b_flags & XBF_MAPPED) && (bp->b_page_count > 1))
@@ -323,18 +323,11 @@
for (i = 0; i < bp->b_page_count; i++) {
struct page *page = bp->b_pages[i];
- ASSERT(!PagePrivate(page));
+ if (bp->b_flags & _XBF_PAGE_CACHE)
+ ASSERT(!PagePrivate(page));
page_cache_release(page);
}
_xfs_buf_free_pages(bp);
- } else if (bp->b_flags & _XBF_KMEM_ALLOC) {
- /*
- * XXX(hch): bp->b_count_desired might be incorrect (see
- * xfs_buf_associate_memory for details), but fortunately
- * the Linux version of kmem_free ignores the len argument..
- */
- kmem_free(bp->b_addr, bp->b_count_desired);
- _xfs_buf_free_pages(bp);
}
xfs_buf_deallocate(bp);
@@ -764,43 +757,44 @@
size_t len,
xfs_buftarg_t *target)
{
- size_t malloc_len = len;
+ unsigned long page_count = PAGE_ALIGN(len) >> PAGE_SHIFT;
+ int error, i;
xfs_buf_t *bp;
- void *data;
- int error;
bp = xfs_buf_allocate(0);
if (unlikely(bp == NULL))
goto fail;
_xfs_buf_initialize(bp, target, 0, len, 0);
- try_again:
- data = kmem_alloc(malloc_len, KM_SLEEP | KM_MAYFAIL | KM_LARGE);
- if (unlikely(data == NULL))
+ error = _xfs_buf_get_pages(bp, page_count, 0);
+ if (error)
goto fail_free_buf;
- /* check whether alignment matches.. */
- if ((__psunsigned_t)data !=
- ((__psunsigned_t)data & ~target->bt_smask)) {
- /* .. else double the size and try again */
- kmem_free(data, malloc_len);
- malloc_len <<= 1;
- goto try_again;
+ for (i = 0; i < page_count; i++) {
+ bp->b_pages[i] = alloc_page(GFP_KERNEL);
+ if (!bp->b_pages[i])
+ goto fail_free_mem;
}
+ bp->b_flags |= _XBF_PAGES;
- error = xfs_buf_associate_memory(bp, data, len);
- if (error)
+ error = _xfs_buf_map_pages(bp, XBF_MAPPED);
+ if (unlikely(error)) {
+ printk(KERN_WARNING "%s: failed to map pages\n",
+ __FUNCTION__);
goto fail_free_mem;
- bp->b_flags |= _XBF_KMEM_ALLOC;
+ }
xfs_buf_unlock(bp);
- XB_TRACE(bp, "no_daddr", data);
+ XB_TRACE(bp, "no_daddr", len);
return bp;
+
fail_free_mem:
- kmem_free(data, malloc_len);
+ while (--i >= 0)
+ __free_page(bp->b_pages[i]);
+ _xfs_buf_free_pages(bp);
fail_free_buf:
- xfs_buf_free(bp);
+ xfs_buf_deallocate(bp);
fail:
return NULL;
}
@@ -1453,6 +1447,7 @@
int external)
{
xfs_flush_buftarg(btp, 1);
+ xfs_blkdev_issue_flush(btp);
if (external)
xfs_blkdev_put(btp->bt_bdev);
xfs_free_bufhash(btp);
@@ -1837,7 +1832,7 @@
if (!xfsdatad_workqueue)
goto out_destroy_xfslogd_workqueue;
- xfs_buf_shake = kmem_shake_register(xfsbufd_wakeup);
+ xfs_buf_shake = set_shrinker(DEFAULT_SEEKS, xfsbufd_wakeup);
if (!xfs_buf_shake)
goto out_destroy_xfsdatad_workqueue;
@@ -1859,7 +1854,7 @@
void
xfs_buf_terminate(void)
{
- kmem_shake_deregister(xfs_buf_shake);
+ remove_shrinker(xfs_buf_shake);
destroy_workqueue(xfsdatad_workqueue);
destroy_workqueue(xfslogd_workqueue);
kmem_zone_destroy(xfs_buf_zone);
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h
index b6241f6..b5908a3 100644
--- a/fs/xfs/linux-2.6/xfs_buf.h
+++ b/fs/xfs/linux-2.6/xfs_buf.h
@@ -63,7 +63,7 @@
/* flags used only internally */
_XBF_PAGE_CACHE = (1 << 17),/* backed by pagecache */
- _XBF_KMEM_ALLOC = (1 << 18),/* backed by kmem_alloc() */
+ _XBF_PAGES = (1 << 18), /* backed by refcounted pages */
_XBF_RUN_QUEUES = (1 << 19),/* run block device task queue */
_XBF_DELWRI_Q = (1 << 21), /* buffer on delwri queue */
} xfs_buf_flags_t;
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index 8c43cd2..cbcd40c 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -184,15 +184,6 @@
}
STATIC int
-xfs_file_close(
- struct file *filp,
- fl_owner_t id)
-{
- return -bhv_vop_close(vn_from_inode(filp->f_path.dentry->d_inode), 0,
- file_count(filp) > 1 ? L_FALSE : L_TRUE, NULL);
-}
-
-STATIC int
xfs_file_release(
struct inode *inode,
struct file *filp)
@@ -436,7 +427,6 @@
#endif
.mmap = xfs_file_mmap,
.open = xfs_file_open,
- .flush = xfs_file_close,
.release = xfs_file_release,
.fsync = xfs_file_fsync,
#ifdef HAVE_FOP_OPEN_EXEC
@@ -458,7 +448,6 @@
#endif
.mmap = xfs_file_mmap,
.open = xfs_file_open,
- .flush = xfs_file_close,
.release = xfs_file_release,
.fsync = xfs_file_fsync,
};
diff --git a/fs/xfs/linux-2.6/xfs_globals.c b/fs/xfs/linux-2.6/xfs_globals.c
index ed3a5e1..bb72c3d 100644
--- a/fs/xfs/linux-2.6/xfs_globals.c
+++ b/fs/xfs/linux-2.6/xfs_globals.c
@@ -46,6 +46,7 @@
.inherit_nosym = { 0, 0, 1 },
.rotorstep = { 1, 1, 255 },
.inherit_nodfrg = { 0, 1, 1 },
+ .fstrm_timer = { 1, 50, 3600*100},
};
/*
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index ff5c41f..5917808 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -1019,7 +1019,7 @@
if (cmd == XFS_IOC_FSINUMBERS)
error = xfs_inumbers(mp, &inlast, &count,
- bulkreq.ubuffer);
+ bulkreq.ubuffer, xfs_inumbers_fmt);
else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
error = xfs_bulkstat_single(mp, &inlast,
bulkreq.ubuffer, &done);
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index b83cebc..141cf15 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -23,10 +23,25 @@
#include <linux/fs.h>
#include <asm/uaccess.h>
#include "xfs.h"
-#include "xfs_types.h"
#include "xfs_fs.h"
+#include "xfs_bit.h"
+#include "xfs_log.h"
+#include "xfs_inum.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir2.h"
+#include "xfs_dmapi.h"
+#include "xfs_mount.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dir2_sf.h"
#include "xfs_vfs.h"
#include "xfs_vnode.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_itable.h"
+#include "xfs_error.h"
#include "xfs_dfrag.h"
#define _NATIVE_IOC(cmd, type) \
@@ -34,6 +49,7 @@
#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
#define BROKEN_X86_ALIGNMENT
+#define _PACKED __attribute__((packed))
/* on ia32 l_start is on a 32-bit boundary */
typedef struct xfs_flock64_32 {
__s16 l_type;
@@ -75,35 +91,276 @@
return (unsigned long)p;
}
+typedef struct compat_xfs_fsop_geom_v1 {
+ __u32 blocksize; /* filesystem (data) block size */
+ __u32 rtextsize; /* realtime extent size */
+ __u32 agblocks; /* fsblocks in an AG */
+ __u32 agcount; /* number of allocation groups */
+ __u32 logblocks; /* fsblocks in the log */
+ __u32 sectsize; /* (data) sector size, bytes */
+ __u32 inodesize; /* inode size in bytes */
+ __u32 imaxpct; /* max allowed inode space(%) */
+ __u64 datablocks; /* fsblocks in data subvolume */
+ __u64 rtblocks; /* fsblocks in realtime subvol */
+ __u64 rtextents; /* rt extents in realtime subvol*/
+ __u64 logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ __u32 sunit; /* stripe unit, fsblocks */
+ __u32 swidth; /* stripe width, fsblocks */
+ __s32 version; /* structure version */
+ __u32 flags; /* superblock version flags */
+ __u32 logsectsize; /* log sector size, bytes */
+ __u32 rtsectsize; /* realtime sector size, bytes */
+ __u32 dirblocksize; /* directory block size, bytes */
+} __attribute__((packed)) compat_xfs_fsop_geom_v1_t;
+
+#define XFS_IOC_FSGEOMETRY_V1_32 \
+ _IOR ('X', 100, struct compat_xfs_fsop_geom_v1)
+
+STATIC unsigned long xfs_ioctl32_geom_v1(unsigned long arg)
+{
+ compat_xfs_fsop_geom_v1_t __user *p32 = (void __user *)arg;
+ xfs_fsop_geom_v1_t __user *p = compat_alloc_user_space(sizeof(*p));
+
+ if (copy_in_user(p, p32, sizeof(*p32)))
+ return -EFAULT;
+ return (unsigned long)p;
+}
+
+typedef struct compat_xfs_inogrp {
+ __u64 xi_startino; /* starting inode number */
+ __s32 xi_alloccount; /* # bits set in allocmask */
+ __u64 xi_allocmask; /* mask of allocated inodes */
+} __attribute__((packed)) compat_xfs_inogrp_t;
+
+STATIC int xfs_inumbers_fmt_compat(
+ void __user *ubuffer,
+ const xfs_inogrp_t *buffer,
+ long count,
+ long *written)
+{
+ compat_xfs_inogrp_t *p32 = ubuffer;
+ long i;
+
+ for (i = 0; i < count; i++) {
+ if (put_user(buffer[i].xi_startino, &p32[i].xi_startino) ||
+ put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) ||
+ put_user(buffer[i].xi_allocmask, &p32[i].xi_allocmask))
+ return -EFAULT;
+ }
+ *written = count * sizeof(*p32);
+ return 0;
+}
+
#else
-typedef struct xfs_fsop_bulkreq32 {
+#define xfs_inumbers_fmt_compat xfs_inumbers_fmt
+#define _PACKED
+
+#endif
+
+/* XFS_IOC_FSBULKSTAT and friends */
+
+typedef struct compat_xfs_bstime {
+ __s32 tv_sec; /* seconds */
+ __s32 tv_nsec; /* and nanoseconds */
+} compat_xfs_bstime_t;
+
+STATIC int xfs_bstime_store_compat(
+ compat_xfs_bstime_t __user *p32,
+ const xfs_bstime_t *p)
+{
+ __s32 sec32;
+
+ sec32 = p->tv_sec;
+ if (put_user(sec32, &p32->tv_sec) ||
+ put_user(p->tv_nsec, &p32->tv_nsec))
+ return -EFAULT;
+ return 0;
+}
+
+typedef struct compat_xfs_bstat {
+ __u64 bs_ino; /* inode number */
+ __u16 bs_mode; /* type and mode */
+ __u16 bs_nlink; /* number of links */
+ __u32 bs_uid; /* user id */
+ __u32 bs_gid; /* group id */
+ __u32 bs_rdev; /* device value */
+ __s32 bs_blksize; /* block size */
+ __s64 bs_size; /* file size */
+ compat_xfs_bstime_t bs_atime; /* access time */
+ compat_xfs_bstime_t bs_mtime; /* modify time */
+ compat_xfs_bstime_t bs_ctime; /* inode change time */
+ int64_t bs_blocks; /* number of blocks */
+ __u32 bs_xflags; /* extended flags */
+ __s32 bs_extsize; /* extent size */
+ __s32 bs_extents; /* number of extents */
+ __u32 bs_gen; /* generation count */
+ __u16 bs_projid; /* project id */
+ unsigned char bs_pad[14]; /* pad space, unused */
+ __u32 bs_dmevmask; /* DMIG event mask */
+ __u16 bs_dmstate; /* DMIG state info */
+ __u16 bs_aextents; /* attribute number of extents */
+} _PACKED compat_xfs_bstat_t;
+
+STATIC int xfs_bulkstat_one_fmt_compat(
+ void __user *ubuffer,
+ const xfs_bstat_t *buffer)
+{
+ compat_xfs_bstat_t __user *p32 = ubuffer;
+
+ if (put_user(buffer->bs_ino, &p32->bs_ino) ||
+ put_user(buffer->bs_mode, &p32->bs_mode) ||
+ put_user(buffer->bs_nlink, &p32->bs_nlink) ||
+ put_user(buffer->bs_uid, &p32->bs_uid) ||
+ put_user(buffer->bs_gid, &p32->bs_gid) ||
+ put_user(buffer->bs_rdev, &p32->bs_rdev) ||
+ put_user(buffer->bs_blksize, &p32->bs_blksize) ||
+ put_user(buffer->bs_size, &p32->bs_size) ||
+ xfs_bstime_store_compat(&p32->bs_atime, &buffer->bs_atime) ||
+ xfs_bstime_store_compat(&p32->bs_mtime, &buffer->bs_mtime) ||
+ xfs_bstime_store_compat(&p32->bs_ctime, &buffer->bs_ctime) ||
+ put_user(buffer->bs_blocks, &p32->bs_blocks) ||
+ put_user(buffer->bs_xflags, &p32->bs_xflags) ||
+ put_user(buffer->bs_extsize, &p32->bs_extsize) ||
+ put_user(buffer->bs_extents, &p32->bs_extents) ||
+ put_user(buffer->bs_gen, &p32->bs_gen) ||
+ put_user(buffer->bs_projid, &p32->bs_projid) ||
+ put_user(buffer->bs_dmevmask, &p32->bs_dmevmask) ||
+ put_user(buffer->bs_dmstate, &p32->bs_dmstate) ||
+ put_user(buffer->bs_aextents, &p32->bs_aextents))
+ return -EFAULT;
+ return sizeof(*p32);
+}
+
+
+
+typedef struct compat_xfs_fsop_bulkreq {
compat_uptr_t lastip; /* last inode # pointer */
__s32 icount; /* count of entries in buffer */
compat_uptr_t ubuffer; /* user buffer for inode desc. */
- __s32 ocount; /* output count pointer */
-} xfs_fsop_bulkreq32_t;
+ compat_uptr_t ocount; /* output count pointer */
+} compat_xfs_fsop_bulkreq_t;
-STATIC unsigned long
-xfs_ioctl32_bulkstat(
- unsigned long arg)
+#define XFS_IOC_FSBULKSTAT_32 \
+ _IOWR('X', 101, struct compat_xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_SINGLE_32 \
+ _IOWR('X', 102, struct compat_xfs_fsop_bulkreq)
+#define XFS_IOC_FSINUMBERS_32 \
+ _IOWR('X', 103, struct compat_xfs_fsop_bulkreq)
+
+/* copied from xfs_ioctl.c */
+STATIC int
+xfs_ioc_bulkstat_compat(
+ xfs_mount_t *mp,
+ unsigned int cmd,
+ void __user *arg)
{
- xfs_fsop_bulkreq32_t __user *p32 = (void __user *)arg;
- xfs_fsop_bulkreq_t __user *p = compat_alloc_user_space(sizeof(*p));
+ compat_xfs_fsop_bulkreq_t __user *p32 = (void __user *)arg;
u32 addr;
+ xfs_fsop_bulkreq_t bulkreq;
+ int count; /* # of records returned */
+ xfs_ino_t inlast; /* last inode number */
+ int done;
+ int error;
- if (get_user(addr, &p32->lastip) ||
- put_user(compat_ptr(addr), &p->lastip) ||
- copy_in_user(&p->icount, &p32->icount, sizeof(s32)) ||
- get_user(addr, &p32->ubuffer) ||
- put_user(compat_ptr(addr), &p->ubuffer) ||
- get_user(addr, &p32->ocount) ||
- put_user(compat_ptr(addr), &p->ocount))
+ /* done = 1 if there are more stats to get and if bulkstat */
+ /* should be called again (unused here, but used in dmapi) */
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (XFS_FORCED_SHUTDOWN(mp))
+ return -XFS_ERROR(EIO);
+
+ if (get_user(addr, &p32->lastip))
+ return -EFAULT;
+ bulkreq.lastip = compat_ptr(addr);
+ if (get_user(bulkreq.icount, &p32->icount) ||
+ get_user(addr, &p32->ubuffer))
+ return -EFAULT;
+ bulkreq.ubuffer = compat_ptr(addr);
+ if (get_user(addr, &p32->ocount))
+ return -EFAULT;
+ bulkreq.ocount = compat_ptr(addr);
+
+ if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
+ return -XFS_ERROR(EFAULT);
+
+ if ((count = bulkreq.icount) <= 0)
+ return -XFS_ERROR(EINVAL);
+
+ if (cmd == XFS_IOC_FSINUMBERS)
+ error = xfs_inumbers(mp, &inlast, &count,
+ bulkreq.ubuffer, xfs_inumbers_fmt_compat);
+ else {
+ /* declare a var to get a warning in case the type changes */
+ bulkstat_one_fmt_pf formatter = xfs_bulkstat_one_fmt_compat;
+ error = xfs_bulkstat(mp, &inlast, &count,
+ xfs_bulkstat_one, formatter,
+ sizeof(compat_xfs_bstat_t), bulkreq.ubuffer,
+ BULKSTAT_FG_QUICK, &done);
+ }
+ if (error)
+ return -error;
+
+ if (bulkreq.ocount != NULL) {
+ if (copy_to_user(bulkreq.lastip, &inlast,
+ sizeof(xfs_ino_t)))
+ return -XFS_ERROR(EFAULT);
+
+ if (copy_to_user(bulkreq.ocount, &count, sizeof(count)))
+ return -XFS_ERROR(EFAULT);
+ }
+
+ return 0;
+}
+
+
+
+typedef struct compat_xfs_fsop_handlereq {
+ __u32 fd; /* fd for FD_TO_HANDLE */
+ compat_uptr_t path; /* user pathname */
+ __u32 oflags; /* open flags */
+ compat_uptr_t ihandle; /* user supplied handle */
+ __u32 ihandlen; /* user supplied length */
+ compat_uptr_t ohandle; /* user buffer for handle */
+ compat_uptr_t ohandlen; /* user buffer length */
+} compat_xfs_fsop_handlereq_t;
+
+#define XFS_IOC_PATH_TO_FSHANDLE_32 \
+ _IOWR('X', 104, struct compat_xfs_fsop_handlereq)
+#define XFS_IOC_PATH_TO_HANDLE_32 \
+ _IOWR('X', 105, struct compat_xfs_fsop_handlereq)
+#define XFS_IOC_FD_TO_HANDLE_32 \
+ _IOWR('X', 106, struct compat_xfs_fsop_handlereq)
+#define XFS_IOC_OPEN_BY_HANDLE_32 \
+ _IOWR('X', 107, struct compat_xfs_fsop_handlereq)
+#define XFS_IOC_READLINK_BY_HANDLE_32 \
+ _IOWR('X', 108, struct compat_xfs_fsop_handlereq)
+
+STATIC unsigned long xfs_ioctl32_fshandle(unsigned long arg)
+{
+ compat_xfs_fsop_handlereq_t __user *p32 = (void __user *)arg;
+ xfs_fsop_handlereq_t __user *p = compat_alloc_user_space(sizeof(*p));
+ u32 addr;
+
+ if (copy_in_user(&p->fd, &p32->fd, sizeof(__u32)) ||
+ get_user(addr, &p32->path) ||
+ put_user(compat_ptr(addr), &p->path) ||
+ copy_in_user(&p->oflags, &p32->oflags, sizeof(__u32)) ||
+ get_user(addr, &p32->ihandle) ||
+ put_user(compat_ptr(addr), &p->ihandle) ||
+ copy_in_user(&p->ihandlen, &p32->ihandlen, sizeof(__u32)) ||
+ get_user(addr, &p32->ohandle) ||
+ put_user(compat_ptr(addr), &p->ohandle) ||
+ get_user(addr, &p32->ohandlen) ||
+ put_user(compat_ptr(addr), &p->ohandlen))
return -EFAULT;
return (unsigned long)p;
}
-#endif
+
STATIC long
xfs_compat_ioctl(
@@ -118,7 +375,6 @@
switch (cmd) {
case XFS_IOC_DIOINFO:
- case XFS_IOC_FSGEOMETRY_V1:
case XFS_IOC_FSGEOMETRY:
case XFS_IOC_GETVERSION:
case XFS_IOC_GETXFLAGS:
@@ -131,12 +387,7 @@
case XFS_IOC_GETBMAPA:
case XFS_IOC_GETBMAPX:
/* not handled
- case XFS_IOC_FD_TO_HANDLE:
- case XFS_IOC_PATH_TO_HANDLE:
- case XFS_IOC_PATH_TO_FSHANDLE:
- case XFS_IOC_OPEN_BY_HANDLE:
case XFS_IOC_FSSETDM_BY_HANDLE:
- case XFS_IOC_READLINK_BY_HANDLE:
case XFS_IOC_ATTRLIST_BY_HANDLE:
case XFS_IOC_ATTRMULTI_BY_HANDLE:
*/
@@ -166,6 +417,10 @@
arg = xfs_ioctl32_flock(arg);
cmd = _NATIVE_IOC(cmd, struct xfs_flock64);
break;
+ case XFS_IOC_FSGEOMETRY_V1_32:
+ arg = xfs_ioctl32_geom_v1(arg);
+ cmd = _NATIVE_IOC(cmd, struct xfs_fsop_geom_v1);
+ break;
#else /* These are handled fine if no alignment issues */
case XFS_IOC_ALLOCSP:
@@ -176,18 +431,28 @@
case XFS_IOC_FREESP64:
case XFS_IOC_RESVSP64:
case XFS_IOC_UNRESVSP64:
+ case XFS_IOC_FSGEOMETRY_V1:
break;
/* xfs_bstat_t still has wrong u32 vs u64 alignment */
case XFS_IOC_SWAPEXT:
break;
- case XFS_IOC_FSBULKSTAT_SINGLE:
- case XFS_IOC_FSBULKSTAT:
- case XFS_IOC_FSINUMBERS:
- arg = xfs_ioctl32_bulkstat(arg);
- break;
#endif
+ case XFS_IOC_FSBULKSTAT_32:
+ case XFS_IOC_FSBULKSTAT_SINGLE_32:
+ case XFS_IOC_FSINUMBERS_32:
+ cmd = _NATIVE_IOC(cmd, struct xfs_fsop_bulkreq);
+ return xfs_ioc_bulkstat_compat(XFS_BHVTOI(VNHEAD(vp))->i_mount,
+ cmd, (void*)arg);
+ case XFS_IOC_FD_TO_HANDLE_32:
+ case XFS_IOC_PATH_TO_HANDLE_32:
+ case XFS_IOC_PATH_TO_FSHANDLE_32:
+ case XFS_IOC_OPEN_BY_HANDLE_32:
+ case XFS_IOC_READLINK_BY_HANDLE_32:
+ arg = xfs_ioctl32_fshandle(arg);
+ cmd = _NATIVE_IOC(cmd, struct xfs_fsop_handlereq);
+ break;
default:
return -ENOIOCTLCMD;
}
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index af24a45..330c4ba 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -123,6 +123,7 @@
#define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val
#define xfs_rotorstep xfs_params.rotorstep.val
#define xfs_inherit_nodefrag xfs_params.inherit_nodfrg.val
+#define xfs_fstrm_centisecs xfs_params.fstrm_timer.val
#define current_cpu() (raw_smp_processor_id())
#define current_pid() (current->pid)
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index bf9a9d5..06894cf 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -547,7 +547,8 @@
if (!(vfsp->vfs_flag & VFS_RDONLY))
error = bhv_vfs_sync(vfsp, SYNC_FSDATA | SYNC_BDFLUSH | \
- SYNC_ATTR | SYNC_REFCACHE, NULL);
+ SYNC_ATTR | SYNC_REFCACHE | SYNC_SUPER,
+ NULL);
vfsp->vfs_sync_seq++;
wake_up(&vfsp->vfs_wait_single_sync_task);
}
@@ -663,7 +664,7 @@
* occur here so don't bother flushing the buftarg (i.e
* SYNC_QUIESCE) because it'll just get dirty again.
*/
- flags = SYNC_FSDATA | SYNC_DELWRI | SYNC_WAIT | SYNC_IOWAIT;
+ flags = SYNC_DATA_QUIESCE;
} else
flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0);
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c
index cd6eaa4..bb997d7 100644
--- a/fs/xfs/linux-2.6/xfs_sysctl.c
+++ b/fs/xfs/linux-2.6/xfs_sysctl.c
@@ -210,6 +210,17 @@
.extra1 = &xfs_params.inherit_nodfrg.min,
.extra2 = &xfs_params.inherit_nodfrg.max
},
+ {
+ .ctl_name = XFS_FILESTREAM_TIMER,
+ .procname = "filestream_centisecs",
+ .data = &xfs_params.fstrm_timer.val,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &xfs_params.fstrm_timer.min,
+ .extra2 = &xfs_params.fstrm_timer.max,
+ },
/* please keep this the last entry */
#ifdef CONFIG_PROC_FS
{
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.h b/fs/xfs/linux-2.6/xfs_sysctl.h
index a631fb8..98b97e3 100644
--- a/fs/xfs/linux-2.6/xfs_sysctl.h
+++ b/fs/xfs/linux-2.6/xfs_sysctl.h
@@ -47,6 +47,7 @@
xfs_sysctl_val_t inherit_nosym; /* Inherit the "nosymlinks" flag. */
xfs_sysctl_val_t rotorstep; /* inode32 AG rotoring control knob */
xfs_sysctl_val_t inherit_nodfrg;/* Inherit the "nodefrag" inode flag. */
+ xfs_sysctl_val_t fstrm_timer; /* Filestream dir-AG assoc'n timeout. */
} xfs_param_t;
/*
@@ -86,6 +87,7 @@
XFS_INHERIT_NOSYM = 19,
XFS_ROTORSTEP = 20,
XFS_INHERIT_NODFRG = 21,
+ XFS_FILESTREAM_TIMER = 22,
};
extern xfs_param_t xfs_params;
diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h
index e2c2ce9..dca3481 100644
--- a/fs/xfs/linux-2.6/xfs_vfs.h
+++ b/fs/xfs/linux-2.6/xfs_vfs.h
@@ -92,6 +92,21 @@
#define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */
#define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */
#define SYNC_IOWAIT 0x0100 /* wait for all I/O to complete */
+#define SYNC_SUPER 0x0200 /* flush superblock to disk */
+
+/*
+ * When remounting a filesystem read-only or freezing the filesystem,
+ * we have two phases to execute. This first phase is syncing the data
+ * before we quiesce the fielsystem, and the second is flushing all the
+ * inodes out after we've waited for all the transactions created by
+ * the first phase to complete. The second phase uses SYNC_INODE_QUIESCE
+ * to ensure that the inodes are written to their location on disk
+ * rather than just existing in transactions in the log. This means
+ * after a quiesce there is no log replay required to write the inodes
+ * to disk (this is the main difference between a sync and a quiesce).
+ */
+#define SYNC_DATA_QUIESCE (SYNC_DELWRI|SYNC_FSDATA|SYNC_WAIT|SYNC_IOWAIT)
+#define SYNC_INODE_QUIESCE (SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT)
#define SHUTDOWN_META_IO_ERROR 0x0001 /* write attempt to metadata failed */
#define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
index 013048a..5742d65 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/linux-2.6/xfs_vnode.h
@@ -129,10 +129,7 @@
VCHANGE_FLAGS_IOEXCL_COUNT = 4
} bhv_vchange_t;
-typedef enum { L_FALSE, L_TRUE } lastclose_t;
-
typedef int (*vop_open_t)(bhv_desc_t *, struct cred *);
-typedef int (*vop_close_t)(bhv_desc_t *, int, lastclose_t, struct cred *);
typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct kiocb *,
const struct iovec *, unsigned int,
loff_t *, int, struct cred *);
@@ -200,7 +197,6 @@
typedef struct bhv_vnodeops {
bhv_position_t vn_position; /* position within behavior chain */
vop_open_t vop_open;
- vop_close_t vop_close;
vop_read_t vop_read;
vop_write_t vop_write;
vop_splice_read_t vop_splice_read;
@@ -245,7 +241,6 @@
#define VNHEAD(vp) ((vp)->v_bh.bh_first)
#define VOP(op, vp) (*((bhv_vnodeops_t *)VNHEAD(vp)->bd_ops)->op)
#define bhv_vop_open(vp, cr) VOP(vop_open, vp)(VNHEAD(vp),cr)
-#define bhv_vop_close(vp, f,last,cr) VOP(vop_close, vp)(VNHEAD(vp),f,last,cr)
#define bhv_vop_read(vp,file,iov,segs,offset,ioflags,cr) \
VOP(vop_read, vp)(VNHEAD(vp),file,iov,segs,offset,ioflags,cr)
#define bhv_vop_write(vp,file,iov,segs,offset,ioflags,cr) \
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 3e4a8ad..7def4c6 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -62,10 +62,9 @@
kmem_zone_t *qm_dqzone;
kmem_zone_t *qm_dqtrxzone;
-static kmem_shaker_t xfs_qm_shaker;
+static struct shrinker *xfs_qm_shaker;
static cred_t xfs_zerocr;
-static xfs_inode_t xfs_zeroino;
STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int);
STATIC void xfs_qm_list_destroy(xfs_dqlist_t *);
@@ -150,7 +149,7 @@
} else
xqm->qm_dqzone = qm_dqzone;
- xfs_qm_shaker = kmem_shake_register(xfs_qm_shake);
+ xfs_qm_shaker = set_shrinker(DEFAULT_SEEKS, xfs_qm_shake);
/*
* The t_dqinfo portion of transactions.
@@ -182,7 +181,7 @@
ASSERT(xqm != NULL);
ASSERT(xqm->qm_nrefs == 0);
- kmem_shake_deregister(xfs_qm_shaker);
+ remove_shrinker(xfs_qm_shaker);
hsize = xqm->qm_dqhashmask + 1;
for (i = 0; i < hsize; i++) {
xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
@@ -1415,7 +1414,7 @@
return error;
}
- if ((error = xfs_dir_ialloc(&tp, &xfs_zeroino, S_IFREG, 1, 0,
+ if ((error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0,
&xfs_zerocr, 0, 1, ip, &committed))) {
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
XFS_TRANS_ABORT);
diff --git a/fs/xfs/xfs.h b/fs/xfs/xfs.h
index bf0a120..b5a7d92 100644
--- a/fs/xfs/xfs.h
+++ b/fs/xfs/xfs.h
@@ -38,6 +38,7 @@
#define XFS_RW_TRACE 1
#define XFS_BUF_TRACE 1
#define XFS_VNODE_TRACE 1
+#define XFS_FILESTREAMS_TRACE 1
#endif
#include <linux-2.6/xfs_linux.h>
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h
index 9ece7f87..51c09c1 100644
--- a/fs/xfs/xfs_ag.h
+++ b/fs/xfs/xfs_ag.h
@@ -68,6 +68,7 @@
__be32 agf_flcount; /* count of blocks in freelist */
__be32 agf_freeblks; /* total free blocks */
__be32 agf_longest; /* longest free space */
+ __be32 agf_btreeblks; /* # of blocks held in AGF btrees */
} xfs_agf_t;
#define XFS_AGF_MAGICNUM 0x00000001
@@ -81,7 +82,8 @@
#define XFS_AGF_FLCOUNT 0x00000100
#define XFS_AGF_FREEBLKS 0x00000200
#define XFS_AGF_LONGEST 0x00000400
-#define XFS_AGF_NUM_BITS 11
+#define XFS_AGF_BTREEBLKS 0x00000800
+#define XFS_AGF_NUM_BITS 12
#define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1)
/* disk block (xfs_daddr_t) in the AG */
@@ -186,12 +188,15 @@
__uint32_t pagf_flcount; /* count of blocks in freelist */
xfs_extlen_t pagf_freeblks; /* total free blocks */
xfs_extlen_t pagf_longest; /* longest free space */
+ __uint32_t pagf_btreeblks; /* # of blocks held in AGF btrees */
xfs_agino_t pagi_freecount; /* number of free inodes */
+ xfs_agino_t pagi_count; /* number of allocated inodes */
+ int pagb_count; /* pagb slots in use */
#ifdef __KERNEL__
lock_t pagb_lock; /* lock for pagb_list */
#endif
- int pagb_count; /* pagb slots in use */
xfs_perag_busy_t *pagb_list; /* unstable blocks */
+ atomic_t pagf_fstrms; /* # of filestreams active in this AG */
} xfs_perag_t;
#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels)
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index 8e9a40a..012a649 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -55,17 +55,17 @@
ktrace_t *xfs_alloc_trace_buf;
#define TRACE_ALLOC(s,a) \
- xfs_alloc_trace_alloc(fname, s, a, __LINE__)
+ xfs_alloc_trace_alloc(__FUNCTION__, s, a, __LINE__)
#define TRACE_FREE(s,a,b,x,f) \
- xfs_alloc_trace_free(fname, s, mp, a, b, x, f, __LINE__)
+ xfs_alloc_trace_free(__FUNCTION__, s, mp, a, b, x, f, __LINE__)
#define TRACE_MODAGF(s,a,f) \
- xfs_alloc_trace_modagf(fname, s, mp, a, f, __LINE__)
-#define TRACE_BUSY(fname,s,ag,agb,l,sl,tp) \
- xfs_alloc_trace_busy(fname, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSY, __LINE__)
-#define TRACE_UNBUSY(fname,s,ag,sl,tp) \
- xfs_alloc_trace_busy(fname, s, mp, ag, -1, -1, sl, tp, XFS_ALLOC_KTRACE_UNBUSY, __LINE__)
-#define TRACE_BUSYSEARCH(fname,s,ag,agb,l,sl,tp) \
- xfs_alloc_trace_busy(fname, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSYSEARCH, __LINE__)
+ xfs_alloc_trace_modagf(__FUNCTION__, s, mp, a, f, __LINE__)
+#define TRACE_BUSY(__FUNCTION__,s,ag,agb,l,sl,tp) \
+ xfs_alloc_trace_busy(__FUNCTION__, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSY, __LINE__)
+#define TRACE_UNBUSY(__FUNCTION__,s,ag,sl,tp) \
+ xfs_alloc_trace_busy(__FUNCTION__, s, mp, ag, -1, -1, sl, tp, XFS_ALLOC_KTRACE_UNBUSY, __LINE__)
+#define TRACE_BUSYSEARCH(__FUNCTION__,s,ag,agb,l,sl,tp) \
+ xfs_alloc_trace_busy(__FUNCTION__, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSYSEARCH, __LINE__)
#else
#define TRACE_ALLOC(s,a)
#define TRACE_FREE(s,a,b,x,f)
@@ -420,7 +420,7 @@
*/
STATIC void
xfs_alloc_trace_alloc(
- char *name, /* function tag string */
+ const char *name, /* function tag string */
char *str, /* additional string */
xfs_alloc_arg_t *args, /* allocation argument structure */
int line) /* source line number */
@@ -453,7 +453,7 @@
*/
STATIC void
xfs_alloc_trace_free(
- char *name, /* function tag string */
+ const char *name, /* function tag string */
char *str, /* additional string */
xfs_mount_t *mp, /* file system mount point */
xfs_agnumber_t agno, /* allocation group number */
@@ -479,7 +479,7 @@
*/
STATIC void
xfs_alloc_trace_modagf(
- char *name, /* function tag string */
+ const char *name, /* function tag string */
char *str, /* additional string */
xfs_mount_t *mp, /* file system mount point */
xfs_agf_t *agf, /* new agf value */
@@ -507,7 +507,7 @@
STATIC void
xfs_alloc_trace_busy(
- char *name, /* function tag string */
+ const char *name, /* function tag string */
char *str, /* additional string */
xfs_mount_t *mp, /* file system mount point */
xfs_agnumber_t agno, /* allocation group number */
@@ -549,9 +549,6 @@
xfs_alloc_arg_t *args) /* argument structure for allocation */
{
int error=0;
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_ag_vextent";
-#endif
ASSERT(args->minlen > 0);
ASSERT(args->maxlen > 0);
@@ -635,9 +632,6 @@
xfs_agblock_t fbno; /* start block of found extent */
xfs_agblock_t fend; /* end block of found extent */
xfs_extlen_t flen; /* length of found extent */
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_ag_vextent_exact";
-#endif
int i; /* success/failure of operation */
xfs_agblock_t maxend; /* end of maximal extent */
xfs_agblock_t minend; /* end of minimal extent */
@@ -737,9 +731,6 @@
xfs_btree_cur_t *bno_cur_gt; /* cursor for bno btree, right side */
xfs_btree_cur_t *bno_cur_lt; /* cursor for bno btree, left side */
xfs_btree_cur_t *cnt_cur; /* cursor for count btree */
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_ag_vextent_near";
-#endif
xfs_agblock_t gtbno; /* start bno of right side entry */
xfs_agblock_t gtbnoa; /* aligned ... */
xfs_extlen_t gtdiff; /* difference to right side entry */
@@ -1270,9 +1261,6 @@
int error; /* error result */
xfs_agblock_t fbno; /* start of found freespace */
xfs_extlen_t flen; /* length of found freespace */
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_ag_vextent_size";
-#endif
int i; /* temp status variable */
xfs_agblock_t rbno; /* returned block number */
xfs_extlen_t rlen; /* length of returned extent */
@@ -1427,9 +1415,6 @@
int error;
xfs_agblock_t fbno;
xfs_extlen_t flen;
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_ag_vextent_small";
-#endif
int i;
if ((error = xfs_alloc_decrement(ccur, 0, &i)))
@@ -1447,7 +1432,8 @@
else if (args->minlen == 1 && args->alignment == 1 && !args->isfl &&
(be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_flcount)
> args->minleft)) {
- if ((error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno)))
+ error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno, 0);
+ if (error)
goto error0;
if (fbno != NULLAGBLOCK) {
if (args->userdata) {
@@ -1515,9 +1501,6 @@
xfs_btree_cur_t *bno_cur; /* cursor for by-block btree */
xfs_btree_cur_t *cnt_cur; /* cursor for by-size btree */
int error; /* error return value */
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_free_ag_extent";
-#endif
xfs_agblock_t gtbno; /* start of right neighbor block */
xfs_extlen_t gtlen; /* length of right neighbor block */
int haveleft; /* have a left neighbor block */
@@ -1923,7 +1906,8 @@
while (be32_to_cpu(agf->agf_flcount) > need) {
xfs_buf_t *bp;
- if ((error = xfs_alloc_get_freelist(tp, agbp, &bno)))
+ error = xfs_alloc_get_freelist(tp, agbp, &bno, 0);
+ if (error)
return error;
if ((error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1)))
return error;
@@ -1973,8 +1957,9 @@
* Put each allocated block on the list.
*/
for (bno = targs.agbno; bno < targs.agbno + targs.len; bno++) {
- if ((error = xfs_alloc_put_freelist(tp, agbp, agflbp,
- bno)))
+ error = xfs_alloc_put_freelist(tp, agbp,
+ agflbp, bno, 0);
+ if (error)
return error;
}
}
@@ -1991,16 +1976,15 @@
xfs_alloc_get_freelist(
xfs_trans_t *tp, /* transaction pointer */
xfs_buf_t *agbp, /* buffer containing the agf structure */
- xfs_agblock_t *bnop) /* block address retrieved from freelist */
+ xfs_agblock_t *bnop, /* block address retrieved from freelist */
+ int btreeblk) /* destination is a AGF btree */
{
xfs_agf_t *agf; /* a.g. freespace structure */
xfs_agfl_t *agfl; /* a.g. freelist structure */
xfs_buf_t *agflbp;/* buffer for a.g. freelist structure */
xfs_agblock_t bno; /* block number returned */
int error;
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_get_freelist";
-#endif
+ int logflags;
xfs_mount_t *mp; /* mount structure */
xfs_perag_t *pag; /* per allocation group data */
@@ -2032,8 +2016,16 @@
be32_add(&agf->agf_flcount, -1);
xfs_trans_agflist_delta(tp, -1);
pag->pagf_flcount--;
- TRACE_MODAGF(NULL, agf, XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT);
- xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT);
+
+ logflags = XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT;
+ if (btreeblk) {
+ be32_add(&agf->agf_btreeblks, 1);
+ pag->pagf_btreeblks++;
+ logflags |= XFS_AGF_BTREEBLKS;
+ }
+
+ TRACE_MODAGF(NULL, agf, logflags);
+ xfs_alloc_log_agf(tp, agbp, logflags);
*bnop = bno;
/*
@@ -2071,6 +2063,7 @@
offsetof(xfs_agf_t, agf_flcount),
offsetof(xfs_agf_t, agf_freeblks),
offsetof(xfs_agf_t, agf_longest),
+ offsetof(xfs_agf_t, agf_btreeblks),
sizeof(xfs_agf_t)
};
@@ -2106,15 +2099,14 @@
xfs_trans_t *tp, /* transaction pointer */
xfs_buf_t *agbp, /* buffer for a.g. freelist header */
xfs_buf_t *agflbp,/* buffer for a.g. free block array */
- xfs_agblock_t bno) /* block being freed */
+ xfs_agblock_t bno, /* block being freed */
+ int btreeblk) /* block came from a AGF btree */
{
xfs_agf_t *agf; /* a.g. freespace structure */
xfs_agfl_t *agfl; /* a.g. free block array */
__be32 *blockp;/* pointer to array entry */
int error;
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_put_freelist";
-#endif
+ int logflags;
xfs_mount_t *mp; /* mount structure */
xfs_perag_t *pag; /* per allocation group data */
@@ -2132,11 +2124,22 @@
be32_add(&agf->agf_flcount, 1);
xfs_trans_agflist_delta(tp, 1);
pag->pagf_flcount++;
+
+ logflags = XFS_AGF_FLLAST | XFS_AGF_FLCOUNT;
+ if (btreeblk) {
+ be32_add(&agf->agf_btreeblks, -1);
+ pag->pagf_btreeblks--;
+ logflags |= XFS_AGF_BTREEBLKS;
+ }
+
+ TRACE_MODAGF(NULL, agf, logflags);
+ xfs_alloc_log_agf(tp, agbp, logflags);
+
ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp));
blockp = &agfl->agfl_bno[be32_to_cpu(agf->agf_fllast)];
*blockp = cpu_to_be32(bno);
- TRACE_MODAGF(NULL, agf, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
- xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
+ TRACE_MODAGF(NULL, agf, logflags);
+ xfs_alloc_log_agf(tp, agbp, logflags);
xfs_trans_log_buf(tp, agflbp,
(int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl),
(int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl +
@@ -2196,6 +2199,7 @@
pag = &mp->m_perag[agno];
if (!pag->pagf_init) {
pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks);
+ pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks);
pag->pagf_flcount = be32_to_cpu(agf->agf_flcount);
pag->pagf_longest = be32_to_cpu(agf->agf_longest);
pag->pagf_levels[XFS_BTNUM_BNOi] =
@@ -2235,9 +2239,6 @@
xfs_agblock_t agsize; /* allocation group size */
int error;
int flags; /* XFS_ALLOC_FLAG_... locking flags */
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_vextent";
-#endif
xfs_extlen_t minleft;/* minimum left value, temp copy */
xfs_mount_t *mp; /* mount structure pointer */
xfs_agnumber_t sagno; /* starting allocation group number */
diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h
index 5a42561..5aec15d 100644
--- a/fs/xfs/xfs_alloc.h
+++ b/fs/xfs/xfs_alloc.h
@@ -136,7 +136,8 @@
xfs_alloc_get_freelist(
struct xfs_trans *tp, /* transaction pointer */
struct xfs_buf *agbp, /* buffer containing the agf structure */
- xfs_agblock_t *bnop); /* block address retrieved from freelist */
+ xfs_agblock_t *bnop, /* block address retrieved from freelist */
+ int btreeblk); /* destination is a AGF btree */
/*
* Log the given fields from the agf structure.
@@ -165,7 +166,8 @@
struct xfs_trans *tp, /* transaction pointer */
struct xfs_buf *agbp, /* buffer for a.g. freelist header */
struct xfs_buf *agflbp,/* buffer for a.g. free block array */
- xfs_agblock_t bno); /* block being freed */
+ xfs_agblock_t bno, /* block being freed */
+ int btreeblk); /* owner was a AGF btree */
/*
* Read in the allocation group header (free/alloc section).
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c
index 74cadf9..1603ce5 100644
--- a/fs/xfs/xfs_alloc_btree.c
+++ b/fs/xfs/xfs_alloc_btree.c
@@ -226,8 +226,9 @@
/*
* Put this buffer/block on the ag's freelist.
*/
- if ((error = xfs_alloc_put_freelist(cur->bc_tp,
- cur->bc_private.a.agbp, NULL, bno)))
+ error = xfs_alloc_put_freelist(cur->bc_tp,
+ cur->bc_private.a.agbp, NULL, bno, 1);
+ if (error)
return error;
/*
* Since blocks move to the free list without the
@@ -549,8 +550,9 @@
/*
* Free the deleting block by putting it on the freelist.
*/
- if ((error = xfs_alloc_put_freelist(cur->bc_tp, cur->bc_private.a.agbp,
- NULL, rbno)))
+ error = xfs_alloc_put_freelist(cur->bc_tp,
+ cur->bc_private.a.agbp, NULL, rbno, 1);
+ if (error)
return error;
/*
* Since blocks move to the free list without the coordination
@@ -1320,8 +1322,9 @@
/*
* Get a buffer from the freelist blocks, for the new root.
*/
- if ((error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp,
- &nbno)))
+ error = xfs_alloc_get_freelist(cur->bc_tp,
+ cur->bc_private.a.agbp, &nbno, 1);
+ if (error)
return error;
/*
* None available, we fail.
@@ -1604,8 +1607,9 @@
* Allocate the new block from the freelist.
* If we can't do it, we're toast. Give up.
*/
- if ((error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp,
- &rbno)))
+ error = xfs_alloc_get_freelist(cur->bc_tp,
+ cur->bc_private.a.agbp, &rbno, 1);
+ if (error)
return error;
if (rbno == NULLAGBLOCK) {
*stat = 0;
diff --git a/fs/xfs/xfs_bit.c b/fs/xfs/xfs_bit.c
index 1afe07f..fab0b6d 100644
--- a/fs/xfs/xfs_bit.c
+++ b/fs/xfs/xfs_bit.c
@@ -66,44 +66,6 @@
#endif
/*
- * Count of bits set in byte, 0..8.
- */
-static const char xfs_countbit[256] = {
- 0, 1, 1, 2, 1, 2, 2, 3, /* 00 .. 07 */
- 1, 2, 2, 3, 2, 3, 3, 4, /* 08 .. 0f */
- 1, 2, 2, 3, 2, 3, 3, 4, /* 10 .. 17 */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 18 .. 1f */
- 1, 2, 2, 3, 2, 3, 3, 4, /* 20 .. 27 */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 28 .. 2f */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 30 .. 37 */
- 3, 4, 4, 5, 4, 5, 5, 6, /* 38 .. 3f */
- 1, 2, 2, 3, 2, 3, 3, 4, /* 40 .. 47 */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 48 .. 4f */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 50 .. 57 */
- 3, 4, 4, 5, 4, 5, 5, 6, /* 58 .. 5f */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 60 .. 67 */
- 3, 4, 4, 5, 4, 5, 5, 6, /* 68 .. 6f */
- 3, 4, 4, 5, 4, 5, 5, 6, /* 70 .. 77 */
- 4, 5, 5, 6, 5, 6, 6, 7, /* 78 .. 7f */
- 1, 2, 2, 3, 2, 3, 3, 4, /* 80 .. 87 */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 88 .. 8f */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 90 .. 97 */
- 3, 4, 4, 5, 4, 5, 5, 6, /* 98 .. 9f */
- 2, 3, 3, 4, 3, 4, 4, 5, /* a0 .. a7 */
- 3, 4, 4, 5, 4, 5, 5, 6, /* a8 .. af */
- 3, 4, 4, 5, 4, 5, 5, 6, /* b0 .. b7 */
- 4, 5, 5, 6, 5, 6, 6, 7, /* b8 .. bf */
- 2, 3, 3, 4, 3, 4, 4, 5, /* c0 .. c7 */
- 3, 4, 4, 5, 4, 5, 5, 6, /* c8 .. cf */
- 3, 4, 4, 5, 4, 5, 5, 6, /* d0 .. d7 */
- 4, 5, 5, 6, 5, 6, 6, 7, /* d8 .. df */
- 3, 4, 4, 5, 4, 5, 5, 6, /* e0 .. e7 */
- 4, 5, 5, 6, 5, 6, 6, 7, /* e8 .. ef */
- 4, 5, 5, 6, 5, 6, 6, 7, /* f0 .. f7 */
- 5, 6, 6, 7, 6, 7, 7, 8, /* f8 .. ff */
-};
-
-/*
* xfs_highbit32: get high bit set out of 32-bit argument, -1 if none set.
*/
inline int
@@ -167,56 +129,21 @@
/*
- * Count the number of bits set in the bitmap starting with bit
- * start_bit. Size is the size of the bitmap in words.
- *
- * Do the counting by mapping a byte value to the number of set
- * bits for that value using the xfs_countbit array, i.e.
- * xfs_countbit[0] == 0, xfs_countbit[1] == 1, xfs_countbit[2] == 1,
- * xfs_countbit[3] == 2, etc.
+ * Return whether bitmap is empty.
+ * Size is number of words in the bitmap, which is padded to word boundary
+ * Returns 1 for empty, 0 for non-empty.
*/
int
-xfs_count_bits(uint *map, uint size, uint start_bit)
+xfs_bitmap_empty(uint *map, uint size)
{
- register int bits;
- register unsigned char *bytep;
- register unsigned char *end_map;
- int byte_bit;
+ uint i;
+ uint ret = 0;
- bits = 0;
- end_map = (char*)(map + size);
- bytep = (char*)(map + (start_bit & ~0x7));
- byte_bit = start_bit & 0x7;
-
- /*
- * If the caller fell off the end of the map, return 0.
- */
- if (bytep >= end_map) {
- return (0);
+ for (i = 0; i < size; i++) {
+ ret |= map[i];
}
- /*
- * If start_bit is not byte aligned, then process the
- * first byte separately.
- */
- if (byte_bit != 0) {
- /*
- * Shift off the bits we don't want to look at,
- * before indexing into xfs_countbit.
- */
- bits += xfs_countbit[(*bytep >> byte_bit)];
- bytep++;
- }
-
- /*
- * Count the bits in each byte until the end of the bitmap.
- */
- while (bytep < end_map) {
- bits += xfs_countbit[*bytep];
- bytep++;
- }
-
- return (bits);
+ return (ret == 0);
}
/*
diff --git a/fs/xfs/xfs_bit.h b/fs/xfs/xfs_bit.h
index 0bbe568..082641a 100644
--- a/fs/xfs/xfs_bit.h
+++ b/fs/xfs/xfs_bit.h
@@ -55,8 +55,8 @@
/* Get high bit set out of 64-bit argument, -1 if none set */
extern int xfs_highbit64(__uint64_t);
-/* Count set bits in map starting with start_bit */
-extern int xfs_count_bits(uint *map, uint size, uint start_bit);
+/* Return whether bitmap is empty (1 == empty) */
+extern int xfs_bitmap_empty(uint *map, uint size);
/* Count continuous one bits in map starting with start_bit */
extern int xfs_contig_bits(uint *map, uint size, uint start_bit);
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index b1ea26e..94b5c5f 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -52,6 +52,7 @@
#include "xfs_quota.h"
#include "xfs_trans_space.h"
#include "xfs_buf_item.h"
+#include "xfs_filestream.h"
#ifdef DEBUG
@@ -277,7 +278,7 @@
STATIC void
xfs_bmap_trace_addentry(
int opcode, /* operation */
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry(ies) */
@@ -291,7 +292,7 @@
*/
STATIC void
xfs_bmap_trace_delete(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry(entries) deleted */
@@ -304,7 +305,7 @@
*/
STATIC void
xfs_bmap_trace_insert(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry(entries) inserted */
@@ -318,7 +319,7 @@
*/
STATIC void
xfs_bmap_trace_post_update(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry updated */
@@ -329,17 +330,25 @@
*/
STATIC void
xfs_bmap_trace_pre_update(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry to be updated */
int whichfork); /* data or attr fork */
+#define XFS_BMAP_TRACE_DELETE(d,ip,i,c,w) \
+ xfs_bmap_trace_delete(__FUNCTION__,d,ip,i,c,w)
+#define XFS_BMAP_TRACE_INSERT(d,ip,i,c,r1,r2,w) \
+ xfs_bmap_trace_insert(__FUNCTION__,d,ip,i,c,r1,r2,w)
+#define XFS_BMAP_TRACE_POST_UPDATE(d,ip,i,w) \
+ xfs_bmap_trace_post_update(__FUNCTION__,d,ip,i,w)
+#define XFS_BMAP_TRACE_PRE_UPDATE(d,ip,i,w) \
+ xfs_bmap_trace_pre_update(__FUNCTION__,d,ip,i,w)
#else
-#define xfs_bmap_trace_delete(f,d,ip,i,c,w)
-#define xfs_bmap_trace_insert(f,d,ip,i,c,r1,r2,w)
-#define xfs_bmap_trace_post_update(f,d,ip,i,w)
-#define xfs_bmap_trace_pre_update(f,d,ip,i,w)
+#define XFS_BMAP_TRACE_DELETE(d,ip,i,c,w)
+#define XFS_BMAP_TRACE_INSERT(d,ip,i,c,r1,r2,w)
+#define XFS_BMAP_TRACE_POST_UPDATE(d,ip,i,w)
+#define XFS_BMAP_TRACE_PRE_UPDATE(d,ip,i,w)
#endif /* XFS_BMAP_TRACE */
/*
@@ -531,9 +540,6 @@
xfs_filblks_t da_new; /* new count del alloc blocks used */
xfs_filblks_t da_old; /* old count del alloc blocks used */
int error; /* error return value */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_add_extent";
-#endif
xfs_ifork_t *ifp; /* inode fork ptr */
int logflags; /* returned value */
xfs_extnum_t nextents; /* number of extents in file now */
@@ -551,8 +557,8 @@
* already extents in the list.
*/
if (nextents == 0) {
- xfs_bmap_trace_insert(fname, "insert empty", ip, 0, 1, new,
- NULL, whichfork);
+ XFS_BMAP_TRACE_INSERT("insert empty", ip, 0, 1, new, NULL,
+ whichfork);
xfs_iext_insert(ifp, 0, 1, new);
ASSERT(cur == NULL);
ifp->if_lastex = 0;
@@ -710,9 +716,6 @@
int diff; /* temp value */
xfs_bmbt_rec_t *ep; /* extent entry for idx */
int error; /* error return value */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_add_extent_delay_real";
-#endif
int i; /* temp state */
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_fileoff_t new_endoff; /* end offset of new entry */
@@ -808,15 +811,14 @@
* Filling in all of a previously delayed allocation extent.
* The left and right neighbors are both contiguous with new.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF|LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|LC|RC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
LEFT.br_blockcount + PREV.br_blockcount +
RIGHT.br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|RF|LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF|LC|RC", ip, idx - 1,
XFS_DATA_FORK);
- xfs_bmap_trace_delete(fname, "LF|RF|LC|RC", ip, idx, 2,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LF|RF|LC|RC", ip, idx, 2, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx, 2);
ip->i_df.if_lastex = idx - 1;
ip->i_d.di_nextents--;
@@ -855,15 +857,14 @@
* Filling in all of a previously delayed allocation extent.
* The left neighbor is contiguous, the right is not.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF|LC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|LC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
LEFT.br_blockcount + PREV.br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|RF|LC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF|LC", ip, idx - 1,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx - 1;
- xfs_bmap_trace_delete(fname, "LF|RF|LC", ip, idx, 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LF|RF|LC", ip, idx, 1, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx, 1);
if (cur == NULL)
rval = XFS_ILOG_DEXT;
@@ -892,16 +893,13 @@
* Filling in all of a previously delayed allocation extent.
* The right neighbor is contiguous, the left is not.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF|RC", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|RC", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_startblock(ep, new->br_startblock);
xfs_bmbt_set_blockcount(ep,
PREV.br_blockcount + RIGHT.br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|RF|RC", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF|RC", ip, idx, XFS_DATA_FORK);
ip->i_df.if_lastex = idx;
- xfs_bmap_trace_delete(fname, "LF|RF|RC", ip, idx + 1, 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LF|RF|RC", ip, idx + 1, 1, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx + 1, 1);
if (cur == NULL)
rval = XFS_ILOG_DEXT;
@@ -931,11 +929,9 @@
* Neither the left nor right neighbors are contiguous with
* the new one.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_startblock(ep, new->br_startblock);
- xfs_bmap_trace_post_update(fname, "LF|RF", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF", ip, idx, XFS_DATA_FORK);
ip->i_df.if_lastex = idx;
ip->i_d.di_nextents++;
if (cur == NULL)
@@ -963,17 +959,14 @@
* Filling in the first part of a previous delayed allocation.
* The left neighbor is contiguous.
*/
- xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx - 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|LC", ip, idx - 1, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
LEFT.br_blockcount + new->br_blockcount);
xfs_bmbt_set_startoff(ep,
PREV.br_startoff + new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx - 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("LF|LC", ip, idx - 1, XFS_DATA_FORK);
temp = PREV.br_blockcount - new->br_blockcount;
- xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|LC", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep, temp);
ip->i_df.if_lastex = idx - 1;
if (cur == NULL)
@@ -995,8 +988,7 @@
temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
STARTBLOCKVAL(PREV.br_startblock));
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("LF|LC", ip, idx, XFS_DATA_FORK);
*dnew = temp;
/* DELTA: The boundary between two in-core extents moved. */
temp = LEFT.br_startoff;
@@ -1009,11 +1001,11 @@
* Filling in the first part of a previous delayed allocation.
* The left neighbor is not contiguous.
*/
- xfs_bmap_trace_pre_update(fname, "LF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("LF", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_startoff(ep, new_endoff);
temp = PREV.br_blockcount - new->br_blockcount;
xfs_bmbt_set_blockcount(ep, temp);
- xfs_bmap_trace_insert(fname, "LF", ip, idx, 1, new, NULL,
+ XFS_BMAP_TRACE_INSERT("LF", ip, idx, 1, new, NULL,
XFS_DATA_FORK);
xfs_iext_insert(ifp, idx, 1, new);
ip->i_df.if_lastex = idx;
@@ -1046,8 +1038,7 @@
(cur ? cur->bc_private.b.allocated : 0));
ep = xfs_iext_get_ext(ifp, idx + 1);
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "LF", ip, idx + 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("LF", ip, idx + 1, XFS_DATA_FORK);
*dnew = temp;
/* DELTA: One in-core extent is split in two. */
temp = PREV.br_startoff;
@@ -1060,17 +1051,14 @@
* The right neighbor is contiguous with the new allocation.
*/
temp = PREV.br_blockcount - new->br_blockcount;
- xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx,
- XFS_DATA_FORK);
- xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx + 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("RF|RC", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("RF|RC", ip, idx + 1, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep, temp);
xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, idx + 1),
new->br_startoff, new->br_startblock,
new->br_blockcount + RIGHT.br_blockcount,
RIGHT.br_state);
- xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx + 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("RF|RC", ip, idx + 1, XFS_DATA_FORK);
ip->i_df.if_lastex = idx + 1;
if (cur == NULL)
rval = XFS_ILOG_DEXT;
@@ -1091,8 +1079,7 @@
temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
STARTBLOCKVAL(PREV.br_startblock));
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("RF|RC", ip, idx, XFS_DATA_FORK);
*dnew = temp;
/* DELTA: The boundary between two in-core extents moved. */
temp = PREV.br_startoff;
@@ -1106,10 +1093,10 @@
* The right neighbor is not contiguous.
*/
temp = PREV.br_blockcount - new->br_blockcount;
- xfs_bmap_trace_pre_update(fname, "RF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("RF", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep, temp);
- xfs_bmap_trace_insert(fname, "RF", ip, idx + 1, 1,
- new, NULL, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_INSERT("RF", ip, idx + 1, 1, new, NULL,
+ XFS_DATA_FORK);
xfs_iext_insert(ifp, idx + 1, 1, new);
ip->i_df.if_lastex = idx + 1;
ip->i_d.di_nextents++;
@@ -1141,7 +1128,7 @@
(cur ? cur->bc_private.b.allocated : 0));
ep = xfs_iext_get_ext(ifp, idx);
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("RF", ip, idx, XFS_DATA_FORK);
*dnew = temp;
/* DELTA: One in-core extent is split in two. */
temp = PREV.br_startoff;
@@ -1155,7 +1142,7 @@
* This case is avoided almost all the time.
*/
temp = new->br_startoff - PREV.br_startoff;
- xfs_bmap_trace_pre_update(fname, "0", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("0", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep, temp);
r[0] = *new;
r[1].br_state = PREV.br_state;
@@ -1163,7 +1150,7 @@
r[1].br_startoff = new_endoff;
temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff;
r[1].br_blockcount = temp2;
- xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 2, &r[0], &r[1],
+ XFS_BMAP_TRACE_INSERT("0", ip, idx + 1, 2, &r[0], &r[1],
XFS_DATA_FORK);
xfs_iext_insert(ifp, idx + 1, 2, &r[0]);
ip->i_df.if_lastex = idx + 1;
@@ -1222,13 +1209,11 @@
}
ep = xfs_iext_get_ext(ifp, idx);
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "0", ip, idx, XFS_DATA_FORK);
- xfs_bmap_trace_pre_update(fname, "0", ip, idx + 2,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("0", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("0", ip, idx + 2, XFS_DATA_FORK);
xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, idx + 2),
NULLSTARTBLOCK((int)temp2));
- xfs_bmap_trace_post_update(fname, "0", ip, idx + 2,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("0", ip, idx + 2, XFS_DATA_FORK);
*dnew = temp + temp2;
/* DELTA: One in-core extent is split in three. */
temp = PREV.br_startoff;
@@ -1287,9 +1272,6 @@
xfs_btree_cur_t *cur; /* btree cursor */
xfs_bmbt_rec_t *ep; /* extent entry for idx */
int error; /* error return value */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_add_extent_unwritten_real";
-#endif
int i; /* temp state */
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_fileoff_t new_endoff; /* end offset of new entry */
@@ -1390,15 +1372,14 @@
* Setting all of a previous oldext extent to newext.
* The left and right neighbors are both contiguous with new.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF|LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|LC|RC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
LEFT.br_blockcount + PREV.br_blockcount +
RIGHT.br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|RF|LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF|LC|RC", ip, idx - 1,
XFS_DATA_FORK);
- xfs_bmap_trace_delete(fname, "LF|RF|LC|RC", ip, idx, 2,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LF|RF|LC|RC", ip, idx, 2, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx, 2);
ip->i_df.if_lastex = idx - 1;
ip->i_d.di_nextents -= 2;
@@ -1441,15 +1422,14 @@
* Setting all of a previous oldext extent to newext.
* The left neighbor is contiguous, the right is not.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF|LC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|LC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
LEFT.br_blockcount + PREV.br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|RF|LC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF|LC", ip, idx - 1,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx - 1;
- xfs_bmap_trace_delete(fname, "LF|RF|LC", ip, idx, 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LF|RF|LC", ip, idx, 1, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx, 1);
ip->i_d.di_nextents--;
if (cur == NULL)
@@ -1484,16 +1464,15 @@
* Setting all of a previous oldext extent to newext.
* The right neighbor is contiguous, the left is not.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF|RC", ip, idx,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|RC", ip, idx,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep,
PREV.br_blockcount + RIGHT.br_blockcount);
xfs_bmbt_set_state(ep, newext);
- xfs_bmap_trace_post_update(fname, "LF|RF|RC", ip, idx,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF|RC", ip, idx,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx;
- xfs_bmap_trace_delete(fname, "LF|RF|RC", ip, idx + 1, 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LF|RF|RC", ip, idx + 1, 1, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx + 1, 1);
ip->i_d.di_nextents--;
if (cur == NULL)
@@ -1529,10 +1508,10 @@
* Neither the left nor right neighbors are contiguous with
* the new one.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF", ip, idx,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF", ip, idx,
XFS_DATA_FORK);
xfs_bmbt_set_state(ep, newext);
- xfs_bmap_trace_post_update(fname, "LF|RF", ip, idx,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF", ip, idx,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx;
if (cur == NULL)
@@ -1559,21 +1538,21 @@
* Setting the first part of a previous oldext extent to newext.
* The left neighbor is contiguous.
*/
- xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|LC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
LEFT.br_blockcount + new->br_blockcount);
xfs_bmbt_set_startoff(ep,
PREV.br_startoff + new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|LC", ip, idx - 1,
XFS_DATA_FORK);
- xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|LC", ip, idx,
XFS_DATA_FORK);
xfs_bmbt_set_startblock(ep,
new->br_startblock + new->br_blockcount);
xfs_bmbt_set_blockcount(ep,
PREV.br_blockcount - new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|LC", ip, idx,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx - 1;
if (cur == NULL)
@@ -1610,15 +1589,15 @@
* Setting the first part of a previous oldext extent to newext.
* The left neighbor is not contiguous.
*/
- xfs_bmap_trace_pre_update(fname, "LF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("LF", ip, idx, XFS_DATA_FORK);
ASSERT(ep && xfs_bmbt_get_state(ep) == oldext);
xfs_bmbt_set_startoff(ep, new_endoff);
xfs_bmbt_set_blockcount(ep,
PREV.br_blockcount - new->br_blockcount);
xfs_bmbt_set_startblock(ep,
new->br_startblock + new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF", ip, idx, XFS_DATA_FORK);
- xfs_bmap_trace_insert(fname, "LF", ip, idx, 1, new, NULL,
+ XFS_BMAP_TRACE_POST_UPDATE("LF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_INSERT("LF", ip, idx, 1, new, NULL,
XFS_DATA_FORK);
xfs_iext_insert(ifp, idx, 1, new);
ip->i_df.if_lastex = idx;
@@ -1653,18 +1632,18 @@
* Setting the last part of a previous oldext extent to newext.
* The right neighbor is contiguous with the new allocation.
*/
- xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx,
+ XFS_BMAP_TRACE_PRE_UPDATE("RF|RC", ip, idx,
XFS_DATA_FORK);
- xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx + 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("RF|RC", ip, idx + 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep,
PREV.br_blockcount - new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx,
+ XFS_BMAP_TRACE_POST_UPDATE("RF|RC", ip, idx,
XFS_DATA_FORK);
xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, idx + 1),
new->br_startoff, new->br_startblock,
new->br_blockcount + RIGHT.br_blockcount, newext);
- xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx + 1,
+ XFS_BMAP_TRACE_POST_UPDATE("RF|RC", ip, idx + 1,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx + 1;
if (cur == NULL)
@@ -1700,12 +1679,12 @@
* Setting the last part of a previous oldext extent to newext.
* The right neighbor is not contiguous.
*/
- xfs_bmap_trace_pre_update(fname, "RF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("RF", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep,
PREV.br_blockcount - new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK);
- xfs_bmap_trace_insert(fname, "RF", ip, idx + 1, 1,
- new, NULL, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("RF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_INSERT("RF", ip, idx + 1, 1, new, NULL,
+ XFS_DATA_FORK);
xfs_iext_insert(ifp, idx + 1, 1, new);
ip->i_df.if_lastex = idx + 1;
ip->i_d.di_nextents++;
@@ -1744,17 +1723,17 @@
* newext. Contiguity is impossible here.
* One extent becomes three extents.
*/
- xfs_bmap_trace_pre_update(fname, "0", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("0", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep,
new->br_startoff - PREV.br_startoff);
- xfs_bmap_trace_post_update(fname, "0", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("0", ip, idx, XFS_DATA_FORK);
r[0] = *new;
r[1].br_startoff = new_endoff;
r[1].br_blockcount =
PREV.br_startoff + PREV.br_blockcount - new_endoff;
r[1].br_startblock = new->br_startblock + new->br_blockcount;
r[1].br_state = oldext;
- xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 2, &r[0], &r[1],
+ XFS_BMAP_TRACE_INSERT("0", ip, idx + 1, 2, &r[0], &r[1],
XFS_DATA_FORK);
xfs_iext_insert(ifp, idx + 1, 2, &r[0]);
ip->i_df.if_lastex = idx + 1;
@@ -1845,9 +1824,6 @@
int rsvd) /* OK to allocate reserved blocks */
{
xfs_bmbt_rec_t *ep; /* extent record for idx */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_add_extent_hole_delay";
-#endif
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_bmbt_irec_t left; /* left neighbor extent entry */
xfs_filblks_t newlen=0; /* new indirect size */
@@ -1919,7 +1895,7 @@
*/
temp = left.br_blockcount + new->br_blockcount +
right.br_blockcount;
- xfs_bmap_trace_pre_update(fname, "LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LC|RC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1), temp);
oldlen = STARTBLOCKVAL(left.br_startblock) +
@@ -1928,10 +1904,9 @@
newlen = xfs_bmap_worst_indlen(ip, temp);
xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, idx - 1),
NULLSTARTBLOCK((int)newlen));
- xfs_bmap_trace_post_update(fname, "LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LC|RC", ip, idx - 1,
XFS_DATA_FORK);
- xfs_bmap_trace_delete(fname, "LC|RC", ip, idx, 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LC|RC", ip, idx, 1, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx, 1);
ip->i_df.if_lastex = idx - 1;
/* DELTA: Two in-core extents were replaced by one. */
@@ -1946,7 +1921,7 @@
* Merge the new allocation with the left neighbor.
*/
temp = left.br_blockcount + new->br_blockcount;
- xfs_bmap_trace_pre_update(fname, "LC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1), temp);
oldlen = STARTBLOCKVAL(left.br_startblock) +
@@ -1954,7 +1929,7 @@
newlen = xfs_bmap_worst_indlen(ip, temp);
xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, idx - 1),
NULLSTARTBLOCK((int)newlen));
- xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LC", ip, idx - 1,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx - 1;
/* DELTA: One in-core extent grew into a hole. */
@@ -1968,14 +1943,14 @@
* on the right.
* Merge the new allocation with the right neighbor.
*/
- xfs_bmap_trace_pre_update(fname, "RC", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("RC", ip, idx, XFS_DATA_FORK);
temp = new->br_blockcount + right.br_blockcount;
oldlen = STARTBLOCKVAL(new->br_startblock) +
STARTBLOCKVAL(right.br_startblock);
newlen = xfs_bmap_worst_indlen(ip, temp);
xfs_bmbt_set_allf(ep, new->br_startoff,
NULLSTARTBLOCK((int)newlen), temp, right.br_state);
- xfs_bmap_trace_post_update(fname, "RC", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("RC", ip, idx, XFS_DATA_FORK);
ip->i_df.if_lastex = idx;
/* DELTA: One in-core extent grew into a hole. */
temp2 = temp;
@@ -1989,7 +1964,7 @@
* Insert a new entry.
*/
oldlen = newlen = 0;
- xfs_bmap_trace_insert(fname, "0", ip, idx, 1, new, NULL,
+ XFS_BMAP_TRACE_INSERT("0", ip, idx, 1, new, NULL,
XFS_DATA_FORK);
xfs_iext_insert(ifp, idx, 1, new);
ip->i_df.if_lastex = idx;
@@ -2039,9 +2014,6 @@
{
xfs_bmbt_rec_t *ep; /* pointer to extent entry ins. point */
int error; /* error return value */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_add_extent_hole_real";
-#endif
int i; /* temp state */
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_bmbt_irec_t left; /* left neighbor extent entry */
@@ -2118,15 +2090,14 @@
* left and on the right.
* Merge all three into a single extent record.
*/
- xfs_bmap_trace_pre_update(fname, "LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LC|RC", ip, idx - 1,
whichfork);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
left.br_blockcount + new->br_blockcount +
right.br_blockcount);
- xfs_bmap_trace_post_update(fname, "LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LC|RC", ip, idx - 1,
whichfork);
- xfs_bmap_trace_delete(fname, "LC|RC", ip,
- idx, 1, whichfork);
+ XFS_BMAP_TRACE_DELETE("LC|RC", ip, idx, 1, whichfork);
xfs_iext_remove(ifp, idx, 1);
ifp->if_lastex = idx - 1;
XFS_IFORK_NEXT_SET(ip, whichfork,
@@ -2168,10 +2139,10 @@
* on the left.
* Merge the new allocation with the left neighbor.
*/
- xfs_bmap_trace_pre_update(fname, "LC", ip, idx - 1, whichfork);
+ XFS_BMAP_TRACE_PRE_UPDATE("LC", ip, idx - 1, whichfork);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
left.br_blockcount + new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, whichfork);
+ XFS_BMAP_TRACE_POST_UPDATE("LC", ip, idx - 1, whichfork);
ifp->if_lastex = idx - 1;
if (cur == NULL) {
rval = XFS_ILOG_FEXT(whichfork);
@@ -2202,11 +2173,11 @@
* on the right.
* Merge the new allocation with the right neighbor.
*/
- xfs_bmap_trace_pre_update(fname, "RC", ip, idx, whichfork);
+ XFS_BMAP_TRACE_PRE_UPDATE("RC", ip, idx, whichfork);
xfs_bmbt_set_allf(ep, new->br_startoff, new->br_startblock,
new->br_blockcount + right.br_blockcount,
right.br_state);
- xfs_bmap_trace_post_update(fname, "RC", ip, idx, whichfork);
+ XFS_BMAP_TRACE_POST_UPDATE("RC", ip, idx, whichfork);
ifp->if_lastex = idx;
if (cur == NULL) {
rval = XFS_ILOG_FEXT(whichfork);
@@ -2237,8 +2208,7 @@
* real allocation.
* Insert a new entry.
*/
- xfs_bmap_trace_insert(fname, "0", ip, idx, 1, new, NULL,
- whichfork);
+ XFS_BMAP_TRACE_INSERT("0", ip, idx, 1, new, NULL, whichfork);
xfs_iext_insert(ifp, idx, 1, new);
ifp->if_lastex = idx;
XFS_IFORK_NEXT_SET(ip, whichfork,
@@ -2605,12 +2575,10 @@
xfs_extlen_t prod = 0; /* product factor for allocators */
xfs_extlen_t ralen = 0; /* realtime allocation length */
xfs_extlen_t align; /* minimum allocation alignment */
- xfs_rtblock_t rtx; /* realtime extent number */
xfs_rtblock_t rtb;
mp = ap->ip->i_mount;
- align = ap->ip->i_d.di_extsize ?
- ap->ip->i_d.di_extsize : mp->m_sb.sb_rextsize;
+ align = xfs_get_extsz_hint(ap->ip);
prod = align / mp->m_sb.sb_rextsize;
error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp,
align, 1, ap->eof, 0,
@@ -2644,6 +2612,8 @@
* pick an extent that will space things out in the rt area.
*/
if (ap->eof && ap->off == 0) {
+ xfs_rtblock_t uninitialized_var(rtx); /* realtime extent no */
+
error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx);
if (error)
return error;
@@ -2715,9 +2685,7 @@
int error;
mp = ap->ip->i_mount;
- align = (ap->userdata && ap->ip->i_d.di_extsize &&
- (ap->ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)) ?
- ap->ip->i_d.di_extsize : 0;
+ align = ap->userdata ? xfs_get_extsz_hint(ap->ip) : 0;
if (unlikely(align)) {
error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp,
align, 0, ap->eof, 0, ap->conv,
@@ -2727,9 +2695,15 @@
}
nullfb = ap->firstblock == NULLFSBLOCK;
fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock);
- if (nullfb)
- ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino);
- else
+ if (nullfb) {
+ if (ap->userdata && xfs_inode_is_filestream(ap->ip)) {
+ ag = xfs_filestream_lookup_ag(ap->ip);
+ ag = (ag != NULLAGNUMBER) ? ag : 0;
+ ap->rval = XFS_AGB_TO_FSB(mp, ag, 0);
+ } else {
+ ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino);
+ }
+ } else
ap->rval = ap->firstblock;
xfs_bmap_adjacent(ap);
@@ -2753,13 +2727,22 @@
args.firstblock = ap->firstblock;
blen = 0;
if (nullfb) {
- args.type = XFS_ALLOCTYPE_START_BNO;
+ if (ap->userdata && xfs_inode_is_filestream(ap->ip))
+ args.type = XFS_ALLOCTYPE_NEAR_BNO;
+ else
+ args.type = XFS_ALLOCTYPE_START_BNO;
args.total = ap->total;
+
/*
- * Find the longest available space.
- * We're going to try for the whole allocation at once.
+ * Search for an allocation group with a single extent
+ * large enough for the request.
+ *
+ * If one isn't found, then adjust the minimum allocation
+ * size to the largest space found.
*/
startag = ag = XFS_FSB_TO_AGNO(mp, args.fsbno);
+ if (startag == NULLAGNUMBER)
+ startag = ag = 0;
notinit = 0;
down_read(&mp->m_peraglock);
while (blen < ap->alen) {
@@ -2785,6 +2768,35 @@
blen = longest;
} else
notinit = 1;
+
+ if (xfs_inode_is_filestream(ap->ip)) {
+ if (blen >= ap->alen)
+ break;
+
+ if (ap->userdata) {
+ /*
+ * If startag is an invalid AG, we've
+ * come here once before and
+ * xfs_filestream_new_ag picked the
+ * best currently available.
+ *
+ * Don't continue looping, since we
+ * could loop forever.
+ */
+ if (startag == NULLAGNUMBER)
+ break;
+
+ error = xfs_filestream_new_ag(ap, &ag);
+ if (error) {
+ up_read(&mp->m_peraglock);
+ return error;
+ }
+
+ /* loop again to set 'blen'*/
+ startag = NULLAGNUMBER;
+ continue;
+ }
+ }
if (++ag == mp->m_sb.sb_agcount)
ag = 0;
if (ag == startag)
@@ -2809,17 +2821,27 @@
*/
else
args.minlen = ap->alen;
+
+ /*
+ * set the failure fallback case to look in the selected
+ * AG as the stream may have moved.
+ */
+ if (xfs_inode_is_filestream(ap->ip))
+ ap->rval = args.fsbno = XFS_AGB_TO_FSB(mp, ag, 0);
} else if (ap->low) {
- args.type = XFS_ALLOCTYPE_START_BNO;
+ if (xfs_inode_is_filestream(ap->ip))
+ args.type = XFS_ALLOCTYPE_FIRST_AG;
+ else
+ args.type = XFS_ALLOCTYPE_START_BNO;
args.total = args.minlen = ap->minlen;
} else {
args.type = XFS_ALLOCTYPE_NEAR_BNO;
args.total = ap->total;
args.minlen = ap->minlen;
}
- if (unlikely(ap->userdata && ap->ip->i_d.di_extsize &&
- (ap->ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE))) {
- args.prod = ap->ip->i_d.di_extsize;
+ /* apply extent size hints if obtained earlier */
+ if (unlikely(align)) {
+ args.prod = align;
if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod)))
args.mod = (xfs_extlen_t)(args.prod - args.mod);
} else if (mp->m_sb.sb_blocksize >= NBPP) {
@@ -3051,9 +3073,6 @@
xfs_bmbt_rec_t *ep; /* current extent entry pointer */
int error; /* error return value */
int flags; /* inode logging flags */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_del_extent";
-#endif
xfs_bmbt_irec_t got; /* current extent entry */
xfs_fileoff_t got_endoff; /* first offset past got */
int i; /* temp state */
@@ -3147,7 +3166,7 @@
/*
* Matches the whole extent. Delete the entry.
*/
- xfs_bmap_trace_delete(fname, "3", ip, idx, 1, whichfork);
+ XFS_BMAP_TRACE_DELETE("3", ip, idx, 1, whichfork);
xfs_iext_remove(ifp, idx, 1);
ifp->if_lastex = idx;
if (delay)
@@ -3168,7 +3187,7 @@
/*
* Deleting the first part of the extent.
*/
- xfs_bmap_trace_pre_update(fname, "2", ip, idx, whichfork);
+ XFS_BMAP_TRACE_PRE_UPDATE("2", ip, idx, whichfork);
xfs_bmbt_set_startoff(ep, del_endoff);
temp = got.br_blockcount - del->br_blockcount;
xfs_bmbt_set_blockcount(ep, temp);
@@ -3177,13 +3196,13 @@
temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
da_old);
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "2", ip, idx,
+ XFS_BMAP_TRACE_POST_UPDATE("2", ip, idx,
whichfork);
da_new = temp;
break;
}
xfs_bmbt_set_startblock(ep, del_endblock);
- xfs_bmap_trace_post_update(fname, "2", ip, idx, whichfork);
+ XFS_BMAP_TRACE_POST_UPDATE("2", ip, idx, whichfork);
if (!cur) {
flags |= XFS_ILOG_FEXT(whichfork);
break;
@@ -3199,19 +3218,19 @@
* Deleting the last part of the extent.
*/
temp = got.br_blockcount - del->br_blockcount;
- xfs_bmap_trace_pre_update(fname, "1", ip, idx, whichfork);
+ XFS_BMAP_TRACE_PRE_UPDATE("1", ip, idx, whichfork);
xfs_bmbt_set_blockcount(ep, temp);
ifp->if_lastex = idx;
if (delay) {
temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
da_old);
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "1", ip, idx,
+ XFS_BMAP_TRACE_POST_UPDATE("1", ip, idx,
whichfork);
da_new = temp;
break;
}
- xfs_bmap_trace_post_update(fname, "1", ip, idx, whichfork);
+ XFS_BMAP_TRACE_POST_UPDATE("1", ip, idx, whichfork);
if (!cur) {
flags |= XFS_ILOG_FEXT(whichfork);
break;
@@ -3228,7 +3247,7 @@
* Deleting the middle of the extent.
*/
temp = del->br_startoff - got.br_startoff;
- xfs_bmap_trace_pre_update(fname, "0", ip, idx, whichfork);
+ XFS_BMAP_TRACE_PRE_UPDATE("0", ip, idx, whichfork);
xfs_bmbt_set_blockcount(ep, temp);
new.br_startoff = del_endoff;
temp2 = got_endoff - del_endoff;
@@ -3315,8 +3334,8 @@
}
}
}
- xfs_bmap_trace_post_update(fname, "0", ip, idx, whichfork);
- xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 1, &new, NULL,
+ XFS_BMAP_TRACE_POST_UPDATE("0", ip, idx, whichfork);
+ XFS_BMAP_TRACE_INSERT("0", ip, idx + 1, 1, &new, NULL,
whichfork);
xfs_iext_insert(ifp, idx + 1, 1, &new);
ifp->if_lastex = idx + 1;
@@ -3556,9 +3575,6 @@
{
int error; /* error return value */
int flags; /* logging flags returned */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_local_to_extents";
-#endif
xfs_ifork_t *ifp; /* inode fork pointer */
/*
@@ -3613,7 +3629,7 @@
xfs_iext_add(ifp, 0, 1);
ep = xfs_iext_get_ext(ifp, 0);
xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM);
- xfs_bmap_trace_post_update(fname, "new", ip, 0, whichfork);
+ XFS_BMAP_TRACE_POST_UPDATE("new", ip, 0, whichfork);
XFS_IFORK_NEXT_SET(ip, whichfork, 1);
ip->i_d.di_nblocks = 1;
XFS_TRANS_MOD_DQUOT_BYINO(args.mp, tp, ip,
@@ -3736,7 +3752,7 @@
STATIC void
xfs_bmap_trace_addentry(
int opcode, /* operation */
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry(ies) */
@@ -3795,7 +3811,7 @@
*/
STATIC void
xfs_bmap_trace_delete(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry(entries) deleted */
@@ -3817,7 +3833,7 @@
*/
STATIC void
xfs_bmap_trace_insert(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry(entries) inserted */
@@ -3846,7 +3862,7 @@
*/
STATIC void
xfs_bmap_trace_post_update(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry updated */
@@ -3864,7 +3880,7 @@
*/
STATIC void
xfs_bmap_trace_pre_update(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry to be updated */
@@ -4481,9 +4497,6 @@
xfs_buf_t *bp; /* buffer for "block" */
int error; /* error return value */
xfs_exntfmt_t exntf; /* XFS_EXTFMT_NOSTATE, if checking */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_read_extents";
-#endif
xfs_extnum_t i, j; /* index into the extents list */
xfs_ifork_t *ifp; /* fork structure */
int level; /* btree level, for checking */
@@ -4600,7 +4613,7 @@
}
ASSERT(i == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)));
ASSERT(i == XFS_IFORK_NEXTENTS(ip, whichfork));
- xfs_bmap_trace_exlist(fname, ip, i, whichfork);
+ XFS_BMAP_TRACE_EXLIST(ip, i, whichfork);
return 0;
error0:
xfs_trans_brelse(tp, bp);
@@ -4613,7 +4626,7 @@
*/
void
xfs_bmap_trace_exlist(
- char *fname, /* function name */
+ const char *fname, /* function name */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t cnt, /* count of entries in the list */
int whichfork) /* data or attr fork */
@@ -4628,7 +4641,7 @@
for (idx = 0; idx < cnt; idx++) {
ep = xfs_iext_get_ext(ifp, idx);
xfs_bmbt_get_all(ep, &s);
- xfs_bmap_trace_insert(fname, "exlist", ip, idx, 1, &s, NULL,
+ XFS_BMAP_TRACE_INSERT("exlist", ip, idx, 1, &s, NULL,
whichfork);
}
}
@@ -4868,12 +4881,7 @@
xfs_extlen_t extsz;
/* Figure out the extent size, adjust alen */
- if (rt) {
- if (!(extsz = ip->i_d.di_extsize))
- extsz = mp->m_sb.sb_rextsize;
- } else {
- extsz = ip->i_d.di_extsize;
- }
+ extsz = xfs_get_extsz_hint(ip);
if (extsz) {
error = xfs_bmap_extsize_align(mp,
&got, &prev, extsz,
@@ -5219,10 +5227,10 @@
* Else go on to the next record.
*/
ep = xfs_iext_get_ext(ifp, ++lastx);
- if (lastx >= nextents) {
+ prev = got;
+ if (lastx >= nextents)
eof = 1;
- prev = got;
- } else
+ else
xfs_bmbt_get_all(ep, &got);
}
ifp->if_lastex = lastx;
@@ -5813,8 +5821,7 @@
ip->i_d.di_format != XFS_DINODE_FMT_LOCAL)
return XFS_ERROR(EINVAL);
if (whichfork == XFS_DATA_FORK) {
- if ((ip->i_d.di_extsize && (ip->i_d.di_flags &
- (XFS_DIFLAG_REALTIME|XFS_DIFLAG_EXTSIZE))) ||
+ if (xfs_get_extsz_hint(ip) ||
ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){
prealloced = 1;
fixlen = XFS_MAXIOFFSET(mp);
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h
index 4f24c7e..524b1c9 100644
--- a/fs/xfs/xfs_bmap.h
+++ b/fs/xfs/xfs_bmap.h
@@ -144,12 +144,14 @@
*/
void
xfs_bmap_trace_exlist(
- char *fname, /* function name */
+ const char *fname, /* function name */
struct xfs_inode *ip, /* incore inode pointer */
xfs_extnum_t cnt, /* count of entries in list */
int whichfork); /* data or attr fork */
+#define XFS_BMAP_TRACE_EXLIST(ip,c,w) \
+ xfs_bmap_trace_exlist(__FUNCTION__,ip,c,w)
#else
-#define xfs_bmap_trace_exlist(f,ip,c,w)
+#define XFS_BMAP_TRACE_EXLIST(ip,c,w)
#endif
/*
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
index 0bf192f..89b891f 100644
--- a/fs/xfs/xfs_bmap_btree.c
+++ b/fs/xfs/xfs_bmap_btree.c
@@ -76,7 +76,7 @@
*/
STATIC void
xfs_bmbt_trace_enter(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
char *s,
int type,
@@ -117,7 +117,7 @@
*/
STATIC void
xfs_bmbt_trace_argbi(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
xfs_buf_t *b,
int i,
@@ -134,7 +134,7 @@
*/
STATIC void
xfs_bmbt_trace_argbii(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
xfs_buf_t *b,
int i0,
@@ -153,7 +153,7 @@
*/
STATIC void
xfs_bmbt_trace_argfffi(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
xfs_dfiloff_t o,
xfs_dfsbno_t b,
@@ -172,7 +172,7 @@
*/
STATIC void
xfs_bmbt_trace_argi(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
int i,
int line)
@@ -188,7 +188,7 @@
*/
STATIC void
xfs_bmbt_trace_argifk(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
int i,
xfs_fsblock_t f,
@@ -206,7 +206,7 @@
*/
STATIC void
xfs_bmbt_trace_argifr(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
int i,
xfs_fsblock_t f,
@@ -235,7 +235,7 @@
*/
STATIC void
xfs_bmbt_trace_argik(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
int i,
xfs_bmbt_key_t *k,
@@ -255,7 +255,7 @@
*/
STATIC void
xfs_bmbt_trace_cursor(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
char *s,
int line)
@@ -274,21 +274,21 @@
}
#define XFS_BMBT_TRACE_ARGBI(c,b,i) \
- xfs_bmbt_trace_argbi(fname, c, b, i, __LINE__)
+ xfs_bmbt_trace_argbi(__FUNCTION__, c, b, i, __LINE__)
#define XFS_BMBT_TRACE_ARGBII(c,b,i,j) \
- xfs_bmbt_trace_argbii(fname, c, b, i, j, __LINE__)
+ xfs_bmbt_trace_argbii(__FUNCTION__, c, b, i, j, __LINE__)
#define XFS_BMBT_TRACE_ARGFFFI(c,o,b,i,j) \
- xfs_bmbt_trace_argfffi(fname, c, o, b, i, j, __LINE__)
+ xfs_bmbt_trace_argfffi(__FUNCTION__, c, o, b, i, j, __LINE__)
#define XFS_BMBT_TRACE_ARGI(c,i) \
- xfs_bmbt_trace_argi(fname, c, i, __LINE__)
+ xfs_bmbt_trace_argi(__FUNCTION__, c, i, __LINE__)
#define XFS_BMBT_TRACE_ARGIFK(c,i,f,s) \
- xfs_bmbt_trace_argifk(fname, c, i, f, s, __LINE__)
+ xfs_bmbt_trace_argifk(__FUNCTION__, c, i, f, s, __LINE__)
#define XFS_BMBT_TRACE_ARGIFR(c,i,f,r) \
- xfs_bmbt_trace_argifr(fname, c, i, f, r, __LINE__)
+ xfs_bmbt_trace_argifr(__FUNCTION__, c, i, f, r, __LINE__)
#define XFS_BMBT_TRACE_ARGIK(c,i,k) \
- xfs_bmbt_trace_argik(fname, c, i, k, __LINE__)
+ xfs_bmbt_trace_argik(__FUNCTION__, c, i, k, __LINE__)
#define XFS_BMBT_TRACE_CURSOR(c,s) \
- xfs_bmbt_trace_cursor(fname, c, s, __LINE__)
+ xfs_bmbt_trace_cursor(__FUNCTION__, c, s, __LINE__)
#else
#define XFS_BMBT_TRACE_ARGBI(c,b,i)
#define XFS_BMBT_TRACE_ARGBII(c,b,i,j)
@@ -318,9 +318,6 @@
xfs_fsblock_t bno; /* fs-relative block number */
xfs_buf_t *bp; /* buffer for block */
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_delrec";
-#endif
int i; /* loop counter */
int j; /* temp state */
xfs_bmbt_key_t key; /* bmap btree key */
@@ -694,9 +691,6 @@
xfs_bmbt_block_t *block; /* bmap btree block */
xfs_buf_t *bp; /* buffer for block */
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_insrec";
-#endif
int i; /* loop index */
xfs_bmbt_key_t key; /* bmap btree key */
xfs_bmbt_key_t *kp=NULL; /* pointer to bmap btree key */
@@ -881,9 +875,6 @@
#ifdef DEBUG
int error;
#endif
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_killroot";
-#endif
int i;
xfs_bmbt_key_t *kp;
xfs_inode_t *ip;
@@ -973,9 +964,6 @@
int kfirst,
int klast)
{
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_log_keys";
-#endif
xfs_trans_t *tp;
XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
@@ -1012,9 +1000,6 @@
int pfirst,
int plast)
{
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_log_ptrs";
-#endif
xfs_trans_t *tp;
XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
@@ -1055,9 +1040,6 @@
xfs_daddr_t d;
xfs_sfiloff_t diff;
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_lookup";
-#endif
xfs_fsblock_t fsbno=0;
int high;
int i;
@@ -1195,9 +1177,6 @@
int *stat) /* success/failure */
{
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_lshift";
-#endif
#ifdef DEBUG
int i; /* loop counter */
#endif
@@ -1331,9 +1310,6 @@
int *stat) /* success/failure */
{
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_rshift";
-#endif
int i; /* loop counter */
xfs_bmbt_key_t key; /* bmap btree key */
xfs_buf_t *lbp; /* left buffer pointer */
@@ -1492,9 +1468,6 @@
{
xfs_alloc_arg_t args; /* block allocation args */
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_split";
-#endif
int i; /* loop counter */
xfs_fsblock_t lbno; /* left sibling block number */
xfs_buf_t *lbp; /* left buffer pointer */
@@ -1641,9 +1614,6 @@
#ifdef DEBUG
int error;
#endif
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_updkey";
-#endif
xfs_bmbt_key_t *kp;
int ptr;
@@ -1712,9 +1682,6 @@
xfs_bmbt_block_t *block;
xfs_buf_t *bp;
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_decrement";
-#endif
xfs_fsblock_t fsbno;
int lev;
xfs_mount_t *mp;
@@ -1785,9 +1752,6 @@
int *stat) /* success/failure */
{
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_delete";
-#endif
int i;
int level;
@@ -2000,9 +1964,6 @@
xfs_bmbt_block_t *block;
xfs_buf_t *bp;
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_increment";
-#endif
xfs_fsblock_t fsbno;
int lev;
xfs_mount_t *mp;
@@ -2080,9 +2041,6 @@
int *stat) /* success/failure */
{
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_insert";
-#endif
int i;
int level;
xfs_fsblock_t nbno;
@@ -2142,9 +2100,6 @@
int fields)
{
int first;
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_log_block";
-#endif
int last;
xfs_trans_t *tp;
static const short offsets[] = {
@@ -2181,9 +2136,6 @@
{
xfs_bmbt_block_t *block;
int first;
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_log_recs";
-#endif
int last;
xfs_bmbt_rec_t *rp;
xfs_trans_t *tp;
@@ -2245,9 +2197,6 @@
xfs_bmbt_key_t *ckp; /* child key pointer */
xfs_bmbt_ptr_t *cpp; /* child ptr pointer */
int error; /* error return code */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_newroot";
-#endif
#ifdef DEBUG
int i; /* loop counter */
#endif
@@ -2630,9 +2579,6 @@
xfs_bmbt_block_t *block;
xfs_buf_t *bp;
int error;
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_update";
-#endif
xfs_bmbt_key_t key;
int ptr;
xfs_bmbt_rec_t *rp;
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h
index 4e27d55..6e40a0a 100644
--- a/fs/xfs/xfs_btree.h
+++ b/fs/xfs/xfs_btree.h
@@ -444,30 +444,14 @@
/*
* Min and max functions for extlen, agblock, fileoff, and filblks types.
*/
-#define XFS_EXTLEN_MIN(a,b) \
- ((xfs_extlen_t)(a) < (xfs_extlen_t)(b) ? \
- (xfs_extlen_t)(a) : (xfs_extlen_t)(b))
-#define XFS_EXTLEN_MAX(a,b) \
- ((xfs_extlen_t)(a) > (xfs_extlen_t)(b) ? \
- (xfs_extlen_t)(a) : (xfs_extlen_t)(b))
-#define XFS_AGBLOCK_MIN(a,b) \
- ((xfs_agblock_t)(a) < (xfs_agblock_t)(b) ? \
- (xfs_agblock_t)(a) : (xfs_agblock_t)(b))
-#define XFS_AGBLOCK_MAX(a,b) \
- ((xfs_agblock_t)(a) > (xfs_agblock_t)(b) ? \
- (xfs_agblock_t)(a) : (xfs_agblock_t)(b))
-#define XFS_FILEOFF_MIN(a,b) \
- ((xfs_fileoff_t)(a) < (xfs_fileoff_t)(b) ? \
- (xfs_fileoff_t)(a) : (xfs_fileoff_t)(b))
-#define XFS_FILEOFF_MAX(a,b) \
- ((xfs_fileoff_t)(a) > (xfs_fileoff_t)(b) ? \
- (xfs_fileoff_t)(a) : (xfs_fileoff_t)(b))
-#define XFS_FILBLKS_MIN(a,b) \
- ((xfs_filblks_t)(a) < (xfs_filblks_t)(b) ? \
- (xfs_filblks_t)(a) : (xfs_filblks_t)(b))
-#define XFS_FILBLKS_MAX(a,b) \
- ((xfs_filblks_t)(a) > (xfs_filblks_t)(b) ? \
- (xfs_filblks_t)(a) : (xfs_filblks_t)(b))
+#define XFS_EXTLEN_MIN(a,b) min_t(xfs_extlen_t, (a), (b))
+#define XFS_EXTLEN_MAX(a,b) max_t(xfs_extlen_t, (a), (b))
+#define XFS_AGBLOCK_MIN(a,b) min_t(xfs_agblock_t, (a), (b))
+#define XFS_AGBLOCK_MAX(a,b) max_t(xfs_agblock_t, (a), (b))
+#define XFS_FILEOFF_MIN(a,b) min_t(xfs_fileoff_t, (a), (b))
+#define XFS_FILEOFF_MAX(a,b) max_t(xfs_fileoff_t, (a), (b))
+#define XFS_FILBLKS_MIN(a,b) min_t(xfs_filblks_t, (a), (b))
+#define XFS_FILBLKS_MAX(a,b) max_t(xfs_filblks_t, (a), (b))
#define XFS_FSB_SANITY_CHECK(mp,fsb) \
(XFS_FSB_TO_AGNO(mp, fsb) < mp->m_sb.sb_agcount && \
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 6c1bddc..b0667cb 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -580,8 +580,8 @@
* If the buf item isn't tracking any data, free it.
* Otherwise, if XFS_BLI_HOLD is set clear it.
*/
- if (xfs_count_bits(bip->bli_format.blf_data_map,
- bip->bli_format.blf_map_size, 0) == 0) {
+ if (xfs_bitmap_empty(bip->bli_format.blf_data_map,
+ bip->bli_format.blf_map_size)) {
xfs_buf_item_relse(bp);
} else if (hold) {
bip->bli_flags &= ~XFS_BLI_HOLD;
diff --git a/fs/xfs/xfs_clnt.h b/fs/xfs/xfs_clnt.h
index 5b7eb81..f89196c 100644
--- a/fs/xfs/xfs_clnt.h
+++ b/fs/xfs/xfs_clnt.h
@@ -99,5 +99,7 @@
*/
#define XFSMNT2_COMPAT_IOSIZE 0x00000001 /* don't report large preferred
* I/O size in stat(2) */
+#define XFSMNT2_FILESTREAMS 0x00000002 /* enable the filestreams
+ * allocator */
#endif /* __XFS_CLNT_H__ */
diff --git a/fs/xfs/xfs_dinode.h b/fs/xfs/xfs_dinode.h
index b338269..fefd011 100644
--- a/fs/xfs/xfs_dinode.h
+++ b/fs/xfs/xfs_dinode.h
@@ -257,6 +257,7 @@
#define XFS_DIFLAG_EXTSIZE_BIT 11 /* inode extent size allocator hint */
#define XFS_DIFLAG_EXTSZINHERIT_BIT 12 /* inherit inode extent size */
#define XFS_DIFLAG_NODEFRAG_BIT 13 /* do not reorganize/defragment */
+#define XFS_DIFLAG_FILESTREAM_BIT 14 /* use filestream allocator */
#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT)
#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT)
#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT)
@@ -271,12 +272,13 @@
#define XFS_DIFLAG_EXTSIZE (1 << XFS_DIFLAG_EXTSIZE_BIT)
#define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT)
#define XFS_DIFLAG_NODEFRAG (1 << XFS_DIFLAG_NODEFRAG_BIT)
+#define XFS_DIFLAG_FILESTREAM (1 << XFS_DIFLAG_FILESTREAM_BIT)
#define XFS_DIFLAG_ANY \
(XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \
XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \
XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \
XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \
- XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG)
+ XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM)
#endif /* __XFS_DINODE_H__ */
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
index 8e8e527..29e0919 100644
--- a/fs/xfs/xfs_dir2.c
+++ b/fs/xfs/xfs_dir2.c
@@ -55,9 +55,9 @@
XFS_MAX_BLOCKSIZE);
mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog);
mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog;
- mp->m_dirdatablk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_DATA_FIRSTDB(mp));
- mp->m_dirleafblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
- mp->m_dirfreeblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_FREE_FIRSTDB(mp));
+ mp->m_dirdatablk = xfs_dir2_db_to_da(mp, XFS_DIR2_DATA_FIRSTDB(mp));
+ mp->m_dirleafblk = xfs_dir2_db_to_da(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
+ mp->m_dirfreeblk = xfs_dir2_db_to_da(mp, XFS_DIR2_FREE_FIRSTDB(mp));
mp->m_attr_node_ents =
(mp->m_sb.sb_blocksize - (uint)sizeof(xfs_da_node_hdr_t)) /
(uint)sizeof(xfs_da_node_entry_t);
@@ -554,7 +554,7 @@
*/
if (mapp != &map)
kmem_free(mapp, sizeof(*mapp) * count);
- *dbp = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)bno);
+ *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno);
/*
* Update file's size if this is the data space and it grew.
*/
@@ -706,7 +706,7 @@
dp = args->dp;
mp = dp->i_mount;
tp = args->trans;
- da = XFS_DIR2_DB_TO_DA(mp, db);
+ da = xfs_dir2_db_to_da(mp, db);
/*
* Unmap the fsblock(s).
*/
@@ -742,7 +742,7 @@
/*
* If the block isn't the last one in the directory, we're done.
*/
- if (dp->i_d.di_size > XFS_DIR2_DB_OFF_TO_BYTE(mp, db + 1, 0))
+ if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(mp, db + 1, 0))
return 0;
bno = da;
if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index 3accc1d..e4df1aa 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -115,13 +115,13 @@
xfs_da_brelse(tp, bp);
return XFS_ERROR(EFSCORRUPTED);
}
- len = XFS_DIR2_DATA_ENTSIZE(args->namelen);
+ len = xfs_dir2_data_entsize(args->namelen);
/*
* Set up pointers to parts of the block.
*/
bf = block->hdr.bestfree;
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* No stale entries? Need space for entry and new leaf.
*/
@@ -396,7 +396,7 @@
* Fill in the leaf entry.
*/
blp[mid].hashval = cpu_to_be32(args->hashval);
- blp[mid].address = cpu_to_be32(XFS_DIR2_BYTE_TO_DATAPTR(mp,
+ blp[mid].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
(char *)dep - (char *)block));
xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh);
/*
@@ -411,7 +411,7 @@
dep->inumber = cpu_to_be64(args->inumber);
dep->namelen = args->namelen;
memcpy(dep->name, args->name, args->namelen);
- tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
+ tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)block);
/*
* Clean up the bestfree array and log the header, tail, and entry.
@@ -455,7 +455,7 @@
/*
* If the block number in the offset is out of range, we're done.
*/
- if (XFS_DIR2_DATAPTR_TO_DB(mp, uio->uio_offset) > mp->m_dirdatablk) {
+ if (xfs_dir2_dataptr_to_db(mp, uio->uio_offset) > mp->m_dirdatablk) {
*eofp = 1;
return 0;
}
@@ -471,15 +471,15 @@
* Extract the byte offset we start at from the seek pointer.
* We'll skip entries before this.
*/
- wantoff = XFS_DIR2_DATAPTR_TO_OFF(mp, uio->uio_offset);
+ wantoff = xfs_dir2_dataptr_to_off(mp, uio->uio_offset);
block = bp->data;
xfs_dir2_data_check(dp, bp);
/*
* Set up values for the loop.
*/
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
+ btp = xfs_dir2_block_tail_p(mp, block);
ptr = (char *)block->u;
- endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
+ endptr = (char *)xfs_dir2_block_leaf_p(btp);
p.dbp = dbp;
p.put = put;
p.uio = uio;
@@ -502,7 +502,7 @@
/*
* Bump pointer for the next iteration.
*/
- ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
+ ptr += xfs_dir2_data_entsize(dep->namelen);
/*
* The entry is before the desired starting point, skip it.
*/
@@ -513,7 +513,7 @@
*/
p.namelen = dep->namelen;
- p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
ptr - (char *)block);
p.ino = be64_to_cpu(dep->inumber);
#if XFS_BIG_INUMS
@@ -531,7 +531,7 @@
*/
if (!p.done) {
uio->uio_offset =
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
(char *)dep - (char *)block);
xfs_da_brelse(tp, bp);
return error;
@@ -545,7 +545,7 @@
*eofp = 1;
uio->uio_offset =
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk + 1, 0);
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
xfs_da_brelse(tp, bp);
@@ -569,8 +569,8 @@
mp = tp->t_mountp;
block = bp->data;
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
xfs_da_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)block),
(uint)((char *)&blp[last + 1] - (char *)block - 1));
}
@@ -589,7 +589,7 @@
mp = tp->t_mountp;
block = bp->data;
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
+ btp = xfs_dir2_block_tail_p(mp, block);
xfs_da_log_buf(tp, bp, (uint)((char *)btp - (char *)block),
(uint)((char *)(btp + 1) - (char *)block - 1));
}
@@ -623,13 +623,13 @@
mp = dp->i_mount;
block = bp->data;
xfs_dir2_data_check(dp, bp);
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* Get the offset from the leaf entry, to point to the data.
*/
dep = (xfs_dir2_data_entry_t *)
- ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(blp[ent].address)));
+ ((char *)block + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));
/*
* Fill in inode number, release the block.
*/
@@ -675,8 +675,8 @@
ASSERT(bp != NULL);
block = bp->data;
xfs_dir2_data_check(dp, bp);
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* Loop doing a binary search for our hash value.
* Find our entry, ENOENT if it's not there.
@@ -713,7 +713,7 @@
* Get pointer to the entry from the leaf.
*/
dep = (xfs_dir2_data_entry_t *)
- ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr));
+ ((char *)block + xfs_dir2_dataptr_to_off(mp, addr));
/*
* Compare, if it's right give back buffer & entry number.
*/
@@ -768,20 +768,20 @@
tp = args->trans;
mp = dp->i_mount;
block = bp->data;
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* Point to the data entry using the leaf entry.
*/
dep = (xfs_dir2_data_entry_t *)
- ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(blp[ent].address)));
+ ((char *)block + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));
/*
* Mark the data entry's space free.
*/
needlog = needscan = 0;
xfs_dir2_data_make_free(tp, bp,
(xfs_dir2_data_aoff_t)((char *)dep - (char *)block),
- XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan);
+ xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan);
/*
* Fix up the block tail.
*/
@@ -843,13 +843,13 @@
dp = args->dp;
mp = dp->i_mount;
block = bp->data;
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* Point to the data entry we need to change.
*/
dep = (xfs_dir2_data_entry_t *)
- ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(blp[ent].address)));
+ ((char *)block + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));
ASSERT(be64_to_cpu(dep->inumber) != args->inumber);
/*
* Change the inode number to the new value.
@@ -912,7 +912,7 @@
mp = dp->i_mount;
leaf = lbp->data;
ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC);
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
/*
* If there are data blocks other than the first one, take this
* opportunity to remove trailing empty data blocks that may have
@@ -920,7 +920,7 @@
* These will show up in the leaf bests table.
*/
while (dp->i_d.di_size > mp->m_dirblksize) {
- bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
+ bestsp = xfs_dir2_leaf_bests_p(ltp);
if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) ==
mp->m_dirblksize - (uint)sizeof(block->hdr)) {
if ((error =
@@ -974,14 +974,14 @@
/*
* Initialize the block tail.
*/
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
+ btp = xfs_dir2_block_tail_p(mp, block);
btp->count = cpu_to_be32(be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale));
btp->stale = 0;
xfs_dir2_block_log_tail(tp, dbp);
/*
* Initialize the block leaf area. We compact out stale entries.
*/
- lep = XFS_DIR2_BLOCK_LEAF_P(btp);
+ lep = xfs_dir2_block_leaf_p(btp);
for (from = to = 0; from < be16_to_cpu(leaf->hdr.count); from++) {
if (be32_to_cpu(leaf->ents[from].address) == XFS_DIR2_NULL_DATAPTR)
continue;
@@ -1067,7 +1067,7 @@
ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
ASSERT(dp->i_df.if_u1.if_data != NULL);
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+ ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
/*
* Copy the directory into the stack buffer.
* Then pitch the incore inode data so we can make extents.
@@ -1119,10 +1119,10 @@
/*
* Fill in the tail.
*/
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
+ btp = xfs_dir2_block_tail_p(mp, block);
btp->count = cpu_to_be32(sfp->hdr.count + 2); /* ., .. */
btp->stale = 0;
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ blp = xfs_dir2_block_leaf_p(btp);
endoffset = (uint)((char *)blp - (char *)block);
/*
* Remove the freespace, we'll manage it.
@@ -1138,25 +1138,25 @@
dep->inumber = cpu_to_be64(dp->i_ino);
dep->namelen = 1;
dep->name[0] = '.';
- tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
+ tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)block);
xfs_dir2_data_log_entry(tp, bp, dep);
blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot);
- blp[0].address = cpu_to_be32(XFS_DIR2_BYTE_TO_DATAPTR(mp,
+ blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
(char *)dep - (char *)block));
/*
* Create entry for ..
*/
dep = (xfs_dir2_data_entry_t *)
((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET);
- dep->inumber = cpu_to_be64(XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
+ dep->inumber = cpu_to_be64(xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent));
dep->namelen = 2;
dep->name[0] = dep->name[1] = '.';
- tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
+ tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)block);
xfs_dir2_data_log_entry(tp, bp, dep);
blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
- blp[1].address = cpu_to_be32(XFS_DIR2_BYTE_TO_DATAPTR(mp,
+ blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
(char *)dep - (char *)block));
offset = XFS_DIR2_DATA_FIRST_OFFSET;
/*
@@ -1165,7 +1165,7 @@
if ((i = 0) == sfp->hdr.count)
sfep = NULL;
else
- sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ sfep = xfs_dir2_sf_firstentry(sfp);
/*
* Need to preserve the existing offset values in the sf directory.
* Insert holes (unused entries) where necessary.
@@ -1177,7 +1177,7 @@
if (sfep == NULL)
newoffset = endoffset;
else
- newoffset = XFS_DIR2_SF_GET_OFFSET(sfep);
+ newoffset = xfs_dir2_sf_get_offset(sfep);
/*
* There should be a hole here, make one.
*/
@@ -1186,7 +1186,7 @@
((char *)block + offset);
dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
dup->length = cpu_to_be16(newoffset - offset);
- *XFS_DIR2_DATA_UNUSED_TAG_P(dup) = cpu_to_be16(
+ *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16(
((char *)dup - (char *)block));
xfs_dir2_data_log_unused(tp, bp, dup);
(void)xfs_dir2_data_freeinsert((xfs_dir2_data_t *)block,
@@ -1198,22 +1198,22 @@
* Copy a real entry.
*/
dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset);
- dep->inumber = cpu_to_be64(XFS_DIR2_SF_GET_INUMBER(sfp,
- XFS_DIR2_SF_INUMBERP(sfep)));
+ dep->inumber = cpu_to_be64(xfs_dir2_sf_get_inumber(sfp,
+ xfs_dir2_sf_inumberp(sfep)));
dep->namelen = sfep->namelen;
memcpy(dep->name, sfep->name, dep->namelen);
- tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
+ tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)block);
xfs_dir2_data_log_entry(tp, bp, dep);
blp[2 + i].hashval = cpu_to_be32(xfs_da_hashname(
(char *)sfep->name, sfep->namelen));
- blp[2 + i].address = cpu_to_be32(XFS_DIR2_BYTE_TO_DATAPTR(mp,
+ blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
(char *)dep - (char *)block));
offset = (int)((char *)(tagp + 1) - (char *)block);
if (++i == sfp->hdr.count)
sfep = NULL;
else
- sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
+ sfep = xfs_dir2_sf_nextentry(sfp, sfep);
}
/* Done with the temporary buffer */
kmem_free(buf, buf_len);
diff --git a/fs/xfs/xfs_dir2_block.h b/fs/xfs/xfs_dir2_block.h
index 6722eff..e7c2606 100644
--- a/fs/xfs/xfs_dir2_block.h
+++ b/fs/xfs/xfs_dir2_block.h
@@ -60,7 +60,6 @@
/*
* Pointer to the leaf header embedded in a data block (1-block format)
*/
-#define XFS_DIR2_BLOCK_TAIL_P(mp,block) xfs_dir2_block_tail_p(mp,block)
static inline xfs_dir2_block_tail_t *
xfs_dir2_block_tail_p(struct xfs_mount *mp, xfs_dir2_block_t *block)
{
@@ -71,7 +70,6 @@
/*
* Pointer to the leaf entries embedded in a data block (1-block format)
*/
-#define XFS_DIR2_BLOCK_LEAF_P(btp) xfs_dir2_block_leaf_p(btp)
static inline struct xfs_dir2_leaf_entry *
xfs_dir2_block_leaf_p(xfs_dir2_block_tail_t *btp)
{
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c
index c211c37..7ebe295 100644
--- a/fs/xfs/xfs_dir2_data.c
+++ b/fs/xfs/xfs_dir2_data.c
@@ -72,8 +72,8 @@
bf = d->hdr.bestfree;
p = (char *)d->u;
if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
- lep = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, (xfs_dir2_block_t *)d);
+ lep = xfs_dir2_block_leaf_p(btp);
endp = (char *)lep;
} else
endp = (char *)d + mp->m_dirblksize;
@@ -107,7 +107,7 @@
*/
if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
ASSERT(lastfree == 0);
- ASSERT(be16_to_cpu(*XFS_DIR2_DATA_UNUSED_TAG_P(dup)) ==
+ ASSERT(be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) ==
(char *)dup - (char *)d);
dfp = xfs_dir2_data_freefind(d, dup);
if (dfp) {
@@ -131,12 +131,12 @@
dep = (xfs_dir2_data_entry_t *)p;
ASSERT(dep->namelen != 0);
ASSERT(xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)) == 0);
- ASSERT(be16_to_cpu(*XFS_DIR2_DATA_ENTRY_TAG_P(dep)) ==
+ ASSERT(be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)) ==
(char *)dep - (char *)d);
count++;
lastfree = 0;
if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
- addr = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
(xfs_dir2_data_aoff_t)
((char *)dep - (char *)d));
hash = xfs_da_hashname((char *)dep->name, dep->namelen);
@@ -147,7 +147,7 @@
}
ASSERT(i < be32_to_cpu(btp->count));
}
- p += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
+ p += xfs_dir2_data_entsize(dep->namelen);
}
/*
* Need to have seen all the entries and all the bestfree slots.
@@ -346,8 +346,8 @@
*/
p = (char *)d->u;
if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
- endp = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, (xfs_dir2_block_t *)d);
+ endp = (char *)xfs_dir2_block_leaf_p(btp);
} else
endp = (char *)d + mp->m_dirblksize;
/*
@@ -360,7 +360,7 @@
*/
if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
ASSERT((char *)dup - (char *)d ==
- be16_to_cpu(*XFS_DIR2_DATA_UNUSED_TAG_P(dup)));
+ be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
xfs_dir2_data_freeinsert(d, dup, loghead);
p += be16_to_cpu(dup->length);
}
@@ -370,8 +370,8 @@
else {
dep = (xfs_dir2_data_entry_t *)p;
ASSERT((char *)dep - (char *)d ==
- be16_to_cpu(*XFS_DIR2_DATA_ENTRY_TAG_P(dep)));
- p += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
+ be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)));
+ p += xfs_dir2_data_entsize(dep->namelen);
}
}
}
@@ -402,7 +402,7 @@
/*
* Get the buffer set up for the block.
*/
- error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, blkno), -1, &bp,
+ error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, blkno), -1, &bp,
XFS_DATA_FORK);
if (error) {
return error;
@@ -427,7 +427,7 @@
t=mp->m_dirblksize - (uint)sizeof(d->hdr);
d->hdr.bestfree[0].length = cpu_to_be16(t);
dup->length = cpu_to_be16(t);
- *XFS_DIR2_DATA_UNUSED_TAG_P(dup) = cpu_to_be16((char *)dup - (char *)d);
+ *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)d);
/*
* Log it and return it.
*/
@@ -452,7 +452,7 @@
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
xfs_da_log_buf(tp, bp, (uint)((char *)dep - (char *)d),
- (uint)((char *)(XFS_DIR2_DATA_ENTRY_TAG_P(dep) + 1) -
+ (uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) -
(char *)d - 1));
}
@@ -497,8 +497,8 @@
* Log the end (tag) of the unused entry.
*/
xfs_da_log_buf(tp, bp,
- (uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P(dup) - (char *)d),
- (uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P(dup) - (char *)d +
+ (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)d),
+ (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)d +
sizeof(xfs_dir2_data_off_t) - 1));
}
@@ -535,8 +535,8 @@
xfs_dir2_block_tail_t *btp; /* block tail */
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
- endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, (xfs_dir2_block_t *)d);
+ endptr = (char *)xfs_dir2_block_leaf_p(btp);
}
/*
* If this isn't the start of the block, then back up to
@@ -587,7 +587,7 @@
* Fix up the new big freespace.
*/
be16_add(&prevdup->length, len + be16_to_cpu(postdup->length));
- *XFS_DIR2_DATA_UNUSED_TAG_P(prevdup) =
+ *xfs_dir2_data_unused_tag_p(prevdup) =
cpu_to_be16((char *)prevdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, prevdup);
if (!needscan) {
@@ -621,7 +621,7 @@
else if (prevdup) {
dfp = xfs_dir2_data_freefind(d, prevdup);
be16_add(&prevdup->length, len);
- *XFS_DIR2_DATA_UNUSED_TAG_P(prevdup) =
+ *xfs_dir2_data_unused_tag_p(prevdup) =
cpu_to_be16((char *)prevdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, prevdup);
/*
@@ -649,7 +649,7 @@
newdup = (xfs_dir2_data_unused_t *)((char *)d + offset);
newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length));
- *XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+ *xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, newdup);
/*
@@ -676,7 +676,7 @@
newdup = (xfs_dir2_data_unused_t *)((char *)d + offset);
newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
newdup->length = cpu_to_be16(len);
- *XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+ *xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, newdup);
(void)xfs_dir2_data_freeinsert(d, newdup, needlogp);
@@ -712,7 +712,7 @@
ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
ASSERT(offset >= (char *)dup - (char *)d);
ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)d);
- ASSERT((char *)dup - (char *)d == be16_to_cpu(*XFS_DIR2_DATA_UNUSED_TAG_P(dup)));
+ ASSERT((char *)dup - (char *)d == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
/*
* Look up the entry in the bestfree table.
*/
@@ -745,7 +745,7 @@
newdup = (xfs_dir2_data_unused_t *)((char *)d + offset + len);
newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
newdup->length = cpu_to_be16(oldlen - len);
- *XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+ *xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, newdup);
/*
@@ -772,7 +772,7 @@
else if (matchback) {
newdup = dup;
newdup->length = cpu_to_be16(((char *)d + offset) - (char *)newdup);
- *XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+ *xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, newdup);
/*
@@ -799,13 +799,13 @@
else {
newdup = dup;
newdup->length = cpu_to_be16(((char *)d + offset) - (char *)newdup);
- *XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+ *xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, newdup);
newdup2 = (xfs_dir2_data_unused_t *)((char *)d + offset + len);
newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length));
- *XFS_DIR2_DATA_UNUSED_TAG_P(newdup2) =
+ *xfs_dir2_data_unused_tag_p(newdup2) =
cpu_to_be16((char *)newdup2 - (char *)d);
xfs_dir2_data_log_unused(tp, bp, newdup2);
/*
diff --git a/fs/xfs/xfs_dir2_data.h b/fs/xfs/xfs_dir2_data.h
index c94c909..b816e02 100644
--- a/fs/xfs/xfs_dir2_data.h
+++ b/fs/xfs/xfs_dir2_data.h
@@ -44,7 +44,7 @@
#define XFS_DIR2_DATA_SPACE 0
#define XFS_DIR2_DATA_OFFSET (XFS_DIR2_DATA_SPACE * XFS_DIR2_SPACE_SIZE)
#define XFS_DIR2_DATA_FIRSTDB(mp) \
- XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_DATA_OFFSET)
+ xfs_dir2_byte_to_db(mp, XFS_DIR2_DATA_OFFSET)
/*
* Offsets of . and .. in data space (always block 0)
@@ -52,9 +52,9 @@
#define XFS_DIR2_DATA_DOT_OFFSET \
((xfs_dir2_data_aoff_t)sizeof(xfs_dir2_data_hdr_t))
#define XFS_DIR2_DATA_DOTDOT_OFFSET \
- (XFS_DIR2_DATA_DOT_OFFSET + XFS_DIR2_DATA_ENTSIZE(1))
+ (XFS_DIR2_DATA_DOT_OFFSET + xfs_dir2_data_entsize(1))
#define XFS_DIR2_DATA_FIRST_OFFSET \
- (XFS_DIR2_DATA_DOTDOT_OFFSET + XFS_DIR2_DATA_ENTSIZE(2))
+ (XFS_DIR2_DATA_DOTDOT_OFFSET + xfs_dir2_data_entsize(2))
/*
* Structures.
@@ -123,7 +123,6 @@
/*
* Size of a data entry.
*/
-#define XFS_DIR2_DATA_ENTSIZE(n) xfs_dir2_data_entsize(n)
static inline int xfs_dir2_data_entsize(int n)
{
return (int)roundup(offsetof(xfs_dir2_data_entry_t, name[0]) + (n) + \
@@ -133,19 +132,16 @@
/*
* Pointer to an entry's tag word.
*/
-#define XFS_DIR2_DATA_ENTRY_TAG_P(dep) xfs_dir2_data_entry_tag_p(dep)
static inline __be16 *
xfs_dir2_data_entry_tag_p(xfs_dir2_data_entry_t *dep)
{
return (__be16 *)((char *)dep +
- XFS_DIR2_DATA_ENTSIZE(dep->namelen) - sizeof(__be16));
+ xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16));
}
/*
* Pointer to a freespace's tag word.
*/
-#define XFS_DIR2_DATA_UNUSED_TAG_P(dup) \
- xfs_dir2_data_unused_tag_p(dup)
static inline __be16 *
xfs_dir2_data_unused_tag_p(xfs_dir2_data_unused_t *dup)
{
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index db14ea7..1b73c9a 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -92,7 +92,7 @@
if ((error = xfs_da_grow_inode(args, &blkno))) {
return error;
}
- ldb = XFS_DIR2_DA_TO_DB(mp, blkno);
+ ldb = xfs_dir2_da_to_db(mp, blkno);
ASSERT(ldb == XFS_DIR2_LEAF_FIRSTDB(mp));
/*
* Initialize the leaf block, get a buffer for it.
@@ -104,8 +104,8 @@
leaf = lbp->data;
block = dbp->data;
xfs_dir2_data_check(dp, dbp);
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* Set the counts in the leaf header.
*/
@@ -137,9 +137,9 @@
/*
* Set up leaf tail and bests table.
*/
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp->bestcount = cpu_to_be32(1);
- bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
+ bestsp = xfs_dir2_leaf_bests_p(ltp);
bestsp[0] = block->hdr.bestfree[0].length;
/*
* Log the data header and leaf bests table.
@@ -209,9 +209,9 @@
*/
index = xfs_dir2_leaf_search_hash(args, lbp);
leaf = lbp->data;
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
- bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
- length = XFS_DIR2_DATA_ENTSIZE(args->namelen);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
+ bestsp = xfs_dir2_leaf_bests_p(ltp);
+ length = xfs_dir2_data_entsize(args->namelen);
/*
* See if there are any entries with the same hash value
* and space in their block for the new entry.
@@ -223,7 +223,7 @@
index++, lep++) {
if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
continue;
- i = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
+ i = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
ASSERT(i < be32_to_cpu(ltp->bestcount));
ASSERT(be16_to_cpu(bestsp[i]) != NULLDATAOFF);
if (be16_to_cpu(bestsp[i]) >= length) {
@@ -378,7 +378,7 @@
*/
else {
if ((error =
- xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, use_block),
+ xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, use_block),
-1, &dbp, XFS_DATA_FORK))) {
xfs_da_brelse(tp, lbp);
return error;
@@ -407,7 +407,7 @@
dep->inumber = cpu_to_be64(args->inumber);
dep->namelen = args->namelen;
memcpy(dep->name, args->name, dep->namelen);
- tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
+ tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)data);
/*
* Need to scan fix up the bestfree table.
@@ -529,7 +529,7 @@
* Fill in the new leaf entry.
*/
lep->hashval = cpu_to_be32(args->hashval);
- lep->address = cpu_to_be32(XFS_DIR2_DB_OFF_TO_DATAPTR(mp, use_block,
+ lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(mp, use_block,
be16_to_cpu(*tagp)));
/*
* Log the leaf fields and give up the buffers.
@@ -567,13 +567,13 @@
* Should factor in the size of the bests table as well.
* We can deduce a value for that from di_size.
*/
- ASSERT(be16_to_cpu(leaf->hdr.count) <= XFS_DIR2_MAX_LEAF_ENTS(mp));
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ASSERT(be16_to_cpu(leaf->hdr.count) <= xfs_dir2_max_leaf_ents(mp));
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
/*
* Leaves and bests don't overlap.
*/
ASSERT((char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] <=
- (char *)XFS_DIR2_LEAF_BESTS_P(ltp));
+ (char *)xfs_dir2_leaf_bests_p(ltp));
/*
* Check hash value order, count stale entries.
*/
@@ -815,12 +815,12 @@
* Inside the loop we keep the main offset value as a byte offset
* in the directory file.
*/
- curoff = XFS_DIR2_DATAPTR_TO_BYTE(mp, uio->uio_offset);
+ curoff = xfs_dir2_dataptr_to_byte(mp, uio->uio_offset);
/*
* Force this conversion through db so we truncate the offset
* down to get the start of the data block.
*/
- map_off = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_BYTE_TO_DB(mp, curoff));
+ map_off = xfs_dir2_db_to_da(mp, xfs_dir2_byte_to_db(mp, curoff));
/*
* Loop over directory entries until we reach the end offset.
* Get more blocks and readahead as necessary.
@@ -870,7 +870,7 @@
*/
if (1 + ra_want > map_blocks &&
map_off <
- XFS_DIR2_BYTE_TO_DA(mp, XFS_DIR2_LEAF_OFFSET)) {
+ xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) {
/*
* Get more bmaps, fill in after the ones
* we already have in the table.
@@ -878,7 +878,7 @@
nmap = map_size - map_valid;
error = xfs_bmapi(tp, dp,
map_off,
- XFS_DIR2_BYTE_TO_DA(mp,
+ xfs_dir2_byte_to_da(mp,
XFS_DIR2_LEAF_OFFSET) - map_off,
XFS_BMAPI_METADATA, NULL, 0,
&map[map_valid], &nmap, NULL, NULL);
@@ -903,7 +903,7 @@
map[map_valid + nmap - 1].br_blockcount;
else
map_off =
- XFS_DIR2_BYTE_TO_DA(mp,
+ xfs_dir2_byte_to_da(mp,
XFS_DIR2_LEAF_OFFSET);
/*
* Look for holes in the mapping, and
@@ -931,14 +931,14 @@
* No valid mappings, so no more data blocks.
*/
if (!map_valid) {
- curoff = XFS_DIR2_DA_TO_BYTE(mp, map_off);
+ curoff = xfs_dir2_da_to_byte(mp, map_off);
break;
}
/*
* Read the directory block starting at the first
* mapping.
*/
- curdb = XFS_DIR2_DA_TO_DB(mp, map->br_startoff);
+ curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
error = xfs_da_read_buf(tp, dp, map->br_startoff,
map->br_blockcount >= mp->m_dirblkfsbs ?
XFS_FSB_TO_DADDR(mp, map->br_startblock) :
@@ -1014,7 +1014,7 @@
/*
* Having done a read, we need to set a new offset.
*/
- newoff = XFS_DIR2_DB_OFF_TO_BYTE(mp, curdb, 0);
+ newoff = xfs_dir2_db_off_to_byte(mp, curdb, 0);
/*
* Start of the current block.
*/
@@ -1024,7 +1024,7 @@
* Make sure we're in the right block.
*/
else if (curoff > newoff)
- ASSERT(XFS_DIR2_BYTE_TO_DB(mp, curoff) ==
+ ASSERT(xfs_dir2_byte_to_db(mp, curoff) ==
curdb);
data = bp->data;
xfs_dir2_data_check(dp, bp);
@@ -1032,7 +1032,7 @@
* Find our position in the block.
*/
ptr = (char *)&data->u;
- byteoff = XFS_DIR2_BYTE_TO_OFF(mp, curoff);
+ byteoff = xfs_dir2_byte_to_off(mp, curoff);
/*
* Skip past the header.
*/
@@ -1054,15 +1054,15 @@
}
dep = (xfs_dir2_data_entry_t *)ptr;
length =
- XFS_DIR2_DATA_ENTSIZE(dep->namelen);
+ xfs_dir2_data_entsize(dep->namelen);
ptr += length;
}
/*
* Now set our real offset.
*/
curoff =
- XFS_DIR2_DB_OFF_TO_BYTE(mp,
- XFS_DIR2_BYTE_TO_DB(mp, curoff),
+ xfs_dir2_db_off_to_byte(mp,
+ xfs_dir2_byte_to_db(mp, curoff),
(char *)ptr - (char *)data);
if (ptr >= (char *)data + mp->m_dirblksize) {
continue;
@@ -1091,9 +1091,9 @@
p->namelen = dep->namelen;
- length = XFS_DIR2_DATA_ENTSIZE(p->namelen);
+ length = xfs_dir2_data_entsize(p->namelen);
- p->cook = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff + length);
+ p->cook = xfs_dir2_byte_to_dataptr(mp, curoff + length);
p->ino = be64_to_cpu(dep->inumber);
#if XFS_BIG_INUMS
@@ -1121,10 +1121,10 @@
* All done. Set output offset value to current offset.
*/
*eofp = eof;
- if (curoff > XFS_DIR2_DATAPTR_TO_BYTE(mp, XFS_DIR2_MAX_DATAPTR))
+ if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR))
uio->uio_offset = XFS_DIR2_MAX_DATAPTR;
else
- uio->uio_offset = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff);
+ uio->uio_offset = xfs_dir2_byte_to_dataptr(mp, curoff);
kmem_free(map, map_size * sizeof(*map));
kmem_free(p, sizeof(*p));
if (bp)
@@ -1159,7 +1159,7 @@
/*
* Get the buffer for the block.
*/
- error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, bno), -1, &bp,
+ error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, bno), -1, &bp,
XFS_DATA_FORK);
if (error) {
return error;
@@ -1181,7 +1181,7 @@
* the block.
*/
if (magic == XFS_DIR2_LEAF1_MAGIC) {
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp->bestcount = 0;
xfs_dir2_leaf_log_tail(tp, bp);
}
@@ -1206,9 +1206,9 @@
leaf = bp->data;
ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC);
- ltp = XFS_DIR2_LEAF_TAIL_P(tp->t_mountp, leaf);
- firstb = XFS_DIR2_LEAF_BESTS_P(ltp) + first;
- lastb = XFS_DIR2_LEAF_BESTS_P(ltp) + last;
+ ltp = xfs_dir2_leaf_tail_p(tp->t_mountp, leaf);
+ firstb = xfs_dir2_leaf_bests_p(ltp) + first;
+ lastb = xfs_dir2_leaf_bests_p(ltp) + last;
xfs_da_log_buf(tp, bp, (uint)((char *)firstb - (char *)leaf),
(uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1));
}
@@ -1268,7 +1268,7 @@
mp = tp->t_mountp;
leaf = bp->data;
ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC);
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
xfs_da_log_buf(tp, bp, (uint)((char *)ltp - (char *)leaf),
(uint)(mp->m_dirblksize - 1));
}
@@ -1312,7 +1312,7 @@
*/
dep = (xfs_dir2_data_entry_t *)
((char *)dbp->data +
- XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, be32_to_cpu(lep->address)));
+ xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address)));
/*
* Return the found inode number.
*/
@@ -1381,7 +1381,7 @@
/*
* Get the new data block number.
*/
- newdb = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
+ newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
/*
* If it's not the same as the old data block number,
* need to pitch the old one and read the new one.
@@ -1391,7 +1391,7 @@
xfs_da_brelse(tp, dbp);
if ((error =
xfs_da_read_buf(tp, dp,
- XFS_DIR2_DB_TO_DA(mp, newdb), -1, &dbp,
+ xfs_dir2_db_to_da(mp, newdb), -1, &dbp,
XFS_DATA_FORK))) {
xfs_da_brelse(tp, lbp);
return error;
@@ -1404,7 +1404,7 @@
*/
dep = (xfs_dir2_data_entry_t *)
((char *)dbp->data +
- XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(lep->address)));
+ xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
/*
* If it matches then return it.
*/
@@ -1469,20 +1469,20 @@
* Point to the leaf entry, use that to point to the data entry.
*/
lep = &leaf->ents[index];
- db = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
+ db = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
dep = (xfs_dir2_data_entry_t *)
- ((char *)data + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(lep->address)));
+ ((char *)data + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
needscan = needlog = 0;
oldbest = be16_to_cpu(data->hdr.bestfree[0].length);
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
- bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
+ bestsp = xfs_dir2_leaf_bests_p(ltp);
ASSERT(be16_to_cpu(bestsp[db]) == oldbest);
/*
* Mark the former data entry unused.
*/
xfs_dir2_data_make_free(tp, dbp,
(xfs_dir2_data_aoff_t)((char *)dep - (char *)data),
- XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan);
+ xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan);
/*
* We just mark the leaf entry stale by putting a null in it.
*/
@@ -1602,7 +1602,7 @@
*/
dep = (xfs_dir2_data_entry_t *)
((char *)dbp->data +
- XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, be32_to_cpu(lep->address)));
+ xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address)));
ASSERT(args->inumber != be64_to_cpu(dep->inumber));
/*
* Put the new inode number in, log it.
@@ -1698,7 +1698,7 @@
/*
* Read the offending data block. We need its buffer.
*/
- if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, db), -1, &dbp,
+ if ((error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, db), -1, &dbp,
XFS_DATA_FORK))) {
return error;
}
@@ -1712,7 +1712,7 @@
*/
leaf = lbp->data;
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ASSERT(be16_to_cpu(data->hdr.bestfree[0].length) ==
mp->m_dirblksize - (uint)sizeof(data->hdr));
ASSERT(db == be32_to_cpu(ltp->bestcount) - 1);
@@ -1727,7 +1727,7 @@
/*
* Eliminate the last bests entry from the table.
*/
- bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
+ bestsp = xfs_dir2_leaf_bests_p(ltp);
be32_add(<p->bestcount, -1);
memmove(&bestsp[1], &bestsp[0], be32_to_cpu(ltp->bestcount) * sizeof(*bestsp));
xfs_dir2_leaf_log_tail(tp, lbp);
@@ -1838,12 +1838,12 @@
/*
* Set up the leaf tail from the freespace block.
*/
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp->bestcount = free->hdr.nvalid;
/*
* Set up the leaf bests table.
*/
- memcpy(XFS_DIR2_LEAF_BESTS_P(ltp), free->bests,
+ memcpy(xfs_dir2_leaf_bests_p(ltp), free->bests,
be32_to_cpu(ltp->bestcount) * sizeof(leaf->bests[0]));
xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
xfs_dir2_leaf_log_tail(tp, lbp);
diff --git a/fs/xfs/xfs_dir2_leaf.h b/fs/xfs/xfs_dir2_leaf.h
index f57ca116..70c97f3 100644
--- a/fs/xfs/xfs_dir2_leaf.h
+++ b/fs/xfs/xfs_dir2_leaf.h
@@ -32,7 +32,7 @@
#define XFS_DIR2_LEAF_SPACE 1
#define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE)
#define XFS_DIR2_LEAF_FIRSTDB(mp) \
- XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_LEAF_OFFSET)
+ xfs_dir2_byte_to_db(mp, XFS_DIR2_LEAF_OFFSET)
/*
* Offset in data space of a data entry.
@@ -82,7 +82,6 @@
* DB blocks here are logical directory block numbers, not filesystem blocks.
*/
-#define XFS_DIR2_MAX_LEAF_ENTS(mp) xfs_dir2_max_leaf_ents(mp)
static inline int xfs_dir2_max_leaf_ents(struct xfs_mount *mp)
{
return (int)(((mp)->m_dirblksize - (uint)sizeof(xfs_dir2_leaf_hdr_t)) /
@@ -92,7 +91,6 @@
/*
* Get address of the bestcount field in the single-leaf block.
*/
-#define XFS_DIR2_LEAF_TAIL_P(mp,lp) xfs_dir2_leaf_tail_p(mp, lp)
static inline xfs_dir2_leaf_tail_t *
xfs_dir2_leaf_tail_p(struct xfs_mount *mp, xfs_dir2_leaf_t *lp)
{
@@ -104,7 +102,6 @@
/*
* Get address of the bests array in the single-leaf block.
*/
-#define XFS_DIR2_LEAF_BESTS_P(ltp) xfs_dir2_leaf_bests_p(ltp)
static inline __be16 *
xfs_dir2_leaf_bests_p(xfs_dir2_leaf_tail_t *ltp)
{
@@ -114,7 +111,6 @@
/*
* Convert dataptr to byte in file space
*/
-#define XFS_DIR2_DATAPTR_TO_BYTE(mp,dp) xfs_dir2_dataptr_to_byte(mp, dp)
static inline xfs_dir2_off_t
xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
{
@@ -124,7 +120,6 @@
/*
* Convert byte in file space to dataptr. It had better be aligned.
*/
-#define XFS_DIR2_BYTE_TO_DATAPTR(mp,by) xfs_dir2_byte_to_dataptr(mp,by)
static inline xfs_dir2_dataptr_t
xfs_dir2_byte_to_dataptr(struct xfs_mount *mp, xfs_dir2_off_t by)
{
@@ -134,7 +129,6 @@
/*
* Convert byte in space to (DB) block
*/
-#define XFS_DIR2_BYTE_TO_DB(mp,by) xfs_dir2_byte_to_db(mp, by)
static inline xfs_dir2_db_t
xfs_dir2_byte_to_db(struct xfs_mount *mp, xfs_dir2_off_t by)
{
@@ -145,17 +139,15 @@
/*
* Convert dataptr to a block number
*/
-#define XFS_DIR2_DATAPTR_TO_DB(mp,dp) xfs_dir2_dataptr_to_db(mp, dp)
static inline xfs_dir2_db_t
xfs_dir2_dataptr_to_db(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
{
- return XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_DATAPTR_TO_BYTE(mp, dp));
+ return xfs_dir2_byte_to_db(mp, xfs_dir2_dataptr_to_byte(mp, dp));
}
/*
* Convert byte in space to offset in a block
*/
-#define XFS_DIR2_BYTE_TO_OFF(mp,by) xfs_dir2_byte_to_off(mp, by)
static inline xfs_dir2_data_aoff_t
xfs_dir2_byte_to_off(struct xfs_mount *mp, xfs_dir2_off_t by)
{
@@ -166,18 +158,15 @@
/*
* Convert dataptr to a byte offset in a block
*/
-#define XFS_DIR2_DATAPTR_TO_OFF(mp,dp) xfs_dir2_dataptr_to_off(mp, dp)
static inline xfs_dir2_data_aoff_t
xfs_dir2_dataptr_to_off(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
{
- return XFS_DIR2_BYTE_TO_OFF(mp, XFS_DIR2_DATAPTR_TO_BYTE(mp, dp));
+ return xfs_dir2_byte_to_off(mp, xfs_dir2_dataptr_to_byte(mp, dp));
}
/*
* Convert block and offset to byte in space
*/
-#define XFS_DIR2_DB_OFF_TO_BYTE(mp,db,o) \
- xfs_dir2_db_off_to_byte(mp, db, o)
static inline xfs_dir2_off_t
xfs_dir2_db_off_to_byte(struct xfs_mount *mp, xfs_dir2_db_t db,
xfs_dir2_data_aoff_t o)
@@ -189,7 +178,6 @@
/*
* Convert block (DB) to block (dablk)
*/
-#define XFS_DIR2_DB_TO_DA(mp,db) xfs_dir2_db_to_da(mp, db)
static inline xfs_dablk_t
xfs_dir2_db_to_da(struct xfs_mount *mp, xfs_dir2_db_t db)
{
@@ -199,29 +187,25 @@
/*
* Convert byte in space to (DA) block
*/
-#define XFS_DIR2_BYTE_TO_DA(mp,by) xfs_dir2_byte_to_da(mp, by)
static inline xfs_dablk_t
xfs_dir2_byte_to_da(struct xfs_mount *mp, xfs_dir2_off_t by)
{
- return XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_BYTE_TO_DB(mp, by));
+ return xfs_dir2_db_to_da(mp, xfs_dir2_byte_to_db(mp, by));
}
/*
* Convert block and offset to dataptr
*/
-#define XFS_DIR2_DB_OFF_TO_DATAPTR(mp,db,o) \
- xfs_dir2_db_off_to_dataptr(mp, db, o)
static inline xfs_dir2_dataptr_t
xfs_dir2_db_off_to_dataptr(struct xfs_mount *mp, xfs_dir2_db_t db,
xfs_dir2_data_aoff_t o)
{
- return XFS_DIR2_BYTE_TO_DATAPTR(mp, XFS_DIR2_DB_OFF_TO_BYTE(mp, db, o));
+ return xfs_dir2_byte_to_dataptr(mp, xfs_dir2_db_off_to_byte(mp, db, o));
}
/*
* Convert block (dablk) to block (DB)
*/
-#define XFS_DIR2_DA_TO_DB(mp,da) xfs_dir2_da_to_db(mp, da)
static inline xfs_dir2_db_t
xfs_dir2_da_to_db(struct xfs_mount *mp, xfs_dablk_t da)
{
@@ -231,11 +215,10 @@
/*
* Convert block (dablk) to byte offset in space
*/
-#define XFS_DIR2_DA_TO_BYTE(mp,da) xfs_dir2_da_to_byte(mp, da)
static inline xfs_dir2_off_t
xfs_dir2_da_to_byte(struct xfs_mount *mp, xfs_dablk_t da)
{
- return XFS_DIR2_DB_OFF_TO_BYTE(mp, XFS_DIR2_DA_TO_DB(mp, da), 0);
+ return xfs_dir2_db_off_to_byte(mp, xfs_dir2_da_to_db(mp, da), 0);
}
/*
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index d083c38..91c61d9 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -136,14 +136,14 @@
/*
* Get the buffer for the new freespace block.
*/
- if ((error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fdb), -1, &fbp,
+ if ((error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, fdb), -1, &fbp,
XFS_DATA_FORK))) {
return error;
}
ASSERT(fbp != NULL);
free = fbp->data;
leaf = lbp->data;
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
/*
* Initialize the freespace block header.
*/
@@ -155,7 +155,7 @@
* Copy freespace entries from the leaf block to the new block.
* Count active entries.
*/
- for (i = n = 0, from = XFS_DIR2_LEAF_BESTS_P(ltp), to = free->bests;
+ for (i = n = 0, from = xfs_dir2_leaf_bests_p(ltp), to = free->bests;
i < be32_to_cpu(ltp->bestcount); i++, from++, to++) {
if ((off = be16_to_cpu(*from)) != NULLDATAOFF)
n++;
@@ -215,7 +215,7 @@
* a compact.
*/
- if (be16_to_cpu(leaf->hdr.count) == XFS_DIR2_MAX_LEAF_ENTS(mp)) {
+ if (be16_to_cpu(leaf->hdr.count) == xfs_dir2_max_leaf_ents(mp)) {
if (!leaf->hdr.stale)
return XFS_ERROR(ENOSPC);
compact = be16_to_cpu(leaf->hdr.stale) > 1;
@@ -327,7 +327,7 @@
* Insert the new entry, log everything.
*/
lep->hashval = cpu_to_be32(args->hashval);
- lep->address = cpu_to_be32(XFS_DIR2_DB_OFF_TO_DATAPTR(mp,
+ lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(mp,
args->blkno, args->index));
xfs_dir2_leaf_log_header(tp, bp);
xfs_dir2_leaf_log_ents(tp, bp, lfloglow, lfloghigh);
@@ -352,7 +352,7 @@
leaf = bp->data;
mp = dp->i_mount;
ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
- ASSERT(be16_to_cpu(leaf->hdr.count) <= XFS_DIR2_MAX_LEAF_ENTS(mp));
+ ASSERT(be16_to_cpu(leaf->hdr.count) <= xfs_dir2_max_leaf_ents(mp));
for (i = stale = 0; i < be16_to_cpu(leaf->hdr.count); i++) {
if (i + 1 < be16_to_cpu(leaf->hdr.count)) {
ASSERT(be32_to_cpu(leaf->ents[i].hashval) <=
@@ -440,7 +440,7 @@
if (args->addname) {
curfdb = curbp ? state->extrablk.blkno : -1;
curdb = -1;
- length = XFS_DIR2_DATA_ENTSIZE(args->namelen);
+ length = xfs_dir2_data_entsize(args->namelen);
if ((free = (curbp ? curbp->data : NULL)))
ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
}
@@ -465,7 +465,7 @@
/*
* Pull the data block number from the entry.
*/
- newdb = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
+ newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
/*
* For addname, we're looking for a place to put the new entry.
* We want to use a data block with an entry of equal
@@ -482,7 +482,7 @@
* Convert the data block to the free block
* holding its freespace information.
*/
- newfdb = XFS_DIR2_DB_TO_FDB(mp, newdb);
+ newfdb = xfs_dir2_db_to_fdb(mp, newdb);
/*
* If it's not the one we have in hand,
* read it in.
@@ -497,7 +497,7 @@
* Read the free block.
*/
if ((error = xfs_da_read_buf(tp, dp,
- XFS_DIR2_DB_TO_DA(mp,
+ xfs_dir2_db_to_da(mp,
newfdb),
-1, &curbp,
XFS_DATA_FORK))) {
@@ -517,7 +517,7 @@
/*
* Get the index for our entry.
*/
- fi = XFS_DIR2_DB_TO_FDINDEX(mp, curdb);
+ fi = xfs_dir2_db_to_fdindex(mp, curdb);
/*
* If it has room, return it.
*/
@@ -561,7 +561,7 @@
*/
if ((error =
xfs_da_read_buf(tp, dp,
- XFS_DIR2_DB_TO_DA(mp, newdb), -1,
+ xfs_dir2_db_to_da(mp, newdb), -1,
&curbp, XFS_DATA_FORK))) {
return error;
}
@@ -573,7 +573,7 @@
*/
dep = (xfs_dir2_data_entry_t *)
((char *)curbp->data +
- XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(lep->address)));
+ xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
/*
* Compare the entry, return it if it matches.
*/
@@ -876,9 +876,9 @@
/*
* Extract the data block and offset from the entry.
*/
- db = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
+ db = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
ASSERT(dblk->blkno == db);
- off = XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(lep->address));
+ off = xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address));
ASSERT(dblk->index == off);
/*
* Kill the leaf entry by marking it stale.
@@ -898,7 +898,7 @@
longest = be16_to_cpu(data->hdr.bestfree[0].length);
needlog = needscan = 0;
xfs_dir2_data_make_free(tp, dbp, off,
- XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan);
+ xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan);
/*
* Rescan the data block freespaces for bestfree.
* Log the data block header if needed.
@@ -924,8 +924,8 @@
* Convert the data block number to a free block,
* read in the free block.
*/
- fdb = XFS_DIR2_DB_TO_FDB(mp, db);
- if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fdb),
+ fdb = xfs_dir2_db_to_fdb(mp, db);
+ if ((error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, fdb),
-1, &fbp, XFS_DATA_FORK))) {
return error;
}
@@ -937,7 +937,7 @@
/*
* Calculate which entry we need to fix.
*/
- findex = XFS_DIR2_DB_TO_FDINDEX(mp, db);
+ findex = xfs_dir2_db_to_fdindex(mp, db);
longest = be16_to_cpu(data->hdr.bestfree[0].length);
/*
* If the data block is now empty we can get rid of it
@@ -1073,7 +1073,7 @@
/*
* Initialize the new leaf block.
*/
- error = xfs_dir2_leaf_init(args, XFS_DIR2_DA_TO_DB(mp, blkno),
+ error = xfs_dir2_leaf_init(args, xfs_dir2_da_to_db(mp, blkno),
&newblk->bp, XFS_DIR2_LEAFN_MAGIC);
if (error) {
return error;
@@ -1385,7 +1385,7 @@
dp = args->dp;
mp = dp->i_mount;
tp = args->trans;
- length = XFS_DIR2_DATA_ENTSIZE(args->namelen);
+ length = xfs_dir2_data_entsize(args->namelen);
/*
* If we came in with a freespace block that means that lookup
* found an entry with our hash value. This is the freespace
@@ -1438,7 +1438,7 @@
if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK)))
return error;
- lastfbno = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)fo);
+ lastfbno = xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo);
fbno = ifbno;
}
/*
@@ -1474,7 +1474,7 @@
* to avoid it.
*/
if ((error = xfs_da_read_buf(tp, dp,
- XFS_DIR2_DB_TO_DA(mp, fbno), -2, &fbp,
+ xfs_dir2_db_to_da(mp, fbno), -2, &fbp,
XFS_DATA_FORK))) {
return error;
}
@@ -1550,9 +1550,9 @@
* Get the freespace block corresponding to the data block
* that was just allocated.
*/
- fbno = XFS_DIR2_DB_TO_FDB(mp, dbno);
+ fbno = xfs_dir2_db_to_fdb(mp, dbno);
if (unlikely(error = xfs_da_read_buf(tp, dp,
- XFS_DIR2_DB_TO_DA(mp, fbno), -2, &fbp,
+ xfs_dir2_db_to_da(mp, fbno), -2, &fbp,
XFS_DATA_FORK))) {
xfs_da_buf_done(dbp);
return error;
@@ -1567,14 +1567,14 @@
return error;
}
- if (unlikely(XFS_DIR2_DB_TO_FDB(mp, dbno) != fbno)) {
+ if (unlikely(xfs_dir2_db_to_fdb(mp, dbno) != fbno)) {
cmn_err(CE_ALERT,
"xfs_dir2_node_addname_int: dir ino "
"%llu needed freesp block %lld for\n"
" data block %lld, got %lld\n"
" ifbno %llu lastfbno %d\n",
(unsigned long long)dp->i_ino,
- (long long)XFS_DIR2_DB_TO_FDB(mp, dbno),
+ (long long)xfs_dir2_db_to_fdb(mp, dbno),
(long long)dbno, (long long)fbno,
(unsigned long long)ifbno, lastfbno);
if (fblk) {
@@ -1598,7 +1598,7 @@
* Get a buffer for the new block.
*/
if ((error = xfs_da_get_buf(tp, dp,
- XFS_DIR2_DB_TO_DA(mp, fbno),
+ xfs_dir2_db_to_da(mp, fbno),
-1, &fbp, XFS_DATA_FORK))) {
return error;
}
@@ -1623,7 +1623,7 @@
/*
* Set the freespace block index from the data block number.
*/
- findex = XFS_DIR2_DB_TO_FDINDEX(mp, dbno);
+ findex = xfs_dir2_db_to_fdindex(mp, dbno);
/*
* If it's after the end of the current entries in the
* freespace block, extend that table.
@@ -1669,7 +1669,7 @@
* Read the data block in.
*/
if (unlikely(
- error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, dbno),
+ error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, dbno),
-1, &dbp, XFS_DATA_FORK))) {
if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)
xfs_da_buf_done(fbp);
@@ -1698,7 +1698,7 @@
dep->inumber = cpu_to_be64(args->inumber);
dep->namelen = args->namelen;
memcpy(dep->name, args->name, dep->namelen);
- tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
+ tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)data);
xfs_dir2_data_log_entry(tp, dbp, dep);
/*
@@ -1904,7 +1904,7 @@
ASSERT(be32_to_cpu(data->hdr.magic) == XFS_DIR2_DATA_MAGIC);
dep = (xfs_dir2_data_entry_t *)
((char *)data +
- XFS_DIR2_DATAPTR_TO_OFF(state->mp, be32_to_cpu(lep->address)));
+ xfs_dir2_dataptr_to_off(state->mp, be32_to_cpu(lep->address)));
ASSERT(inum != be64_to_cpu(dep->inumber));
/*
* Fill in the new inode number and log the entry.
@@ -1980,7 +1980,7 @@
* Blow the block away.
*/
if ((error =
- xfs_dir2_shrink_inode(args, XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)fo),
+ xfs_dir2_shrink_inode(args, xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo),
bp))) {
/*
* Can't fail with ENOSPC since that only happens with no
diff --git a/fs/xfs/xfs_dir2_node.h b/fs/xfs/xfs_dir2_node.h
index c7c870e..dde72db 100644
--- a/fs/xfs/xfs_dir2_node.h
+++ b/fs/xfs/xfs_dir2_node.h
@@ -36,7 +36,7 @@
#define XFS_DIR2_FREE_SPACE 2
#define XFS_DIR2_FREE_OFFSET (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE)
#define XFS_DIR2_FREE_FIRSTDB(mp) \
- XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_FREE_OFFSET)
+ xfs_dir2_byte_to_db(mp, XFS_DIR2_FREE_OFFSET)
#define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F */
@@ -60,7 +60,6 @@
/*
* Convert data space db to the corresponding free db.
*/
-#define XFS_DIR2_DB_TO_FDB(mp,db) xfs_dir2_db_to_fdb(mp, db)
static inline xfs_dir2_db_t
xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db)
{
@@ -70,7 +69,6 @@
/*
* Convert data space db to the corresponding index in a free db.
*/
-#define XFS_DIR2_DB_TO_FDINDEX(mp,db) xfs_dir2_db_to_fdindex(mp, db)
static inline int
xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db)
{
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c
index 0cd77b1..38fc4f2 100644
--- a/fs/xfs/xfs_dir2_sf.c
+++ b/fs/xfs/xfs_dir2_sf.c
@@ -89,8 +89,8 @@
mp = dp->i_mount;
count = i8count = namelen = 0;
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* Iterate over the block's data entries by using the leaf pointers.
@@ -102,7 +102,7 @@
* Calculate the pointer to the entry at hand.
*/
dep = (xfs_dir2_data_entry_t *)
- ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr));
+ ((char *)block + xfs_dir2_dataptr_to_off(mp, addr));
/*
* Detect . and .., so we can special-case them.
* . is not included in sf directories.
@@ -124,7 +124,7 @@
/*
* Calculate the new size, see if we should give up yet.
*/
- size = XFS_DIR2_SF_HDR_SIZE(i8count) + /* header */
+ size = xfs_dir2_sf_hdr_size(i8count) + /* header */
count + /* namelen */
count * (uint)sizeof(xfs_dir2_sf_off_t) + /* offset */
namelen + /* name */
@@ -139,7 +139,7 @@
*/
sfhp->count = count;
sfhp->i8count = i8count;
- XFS_DIR2_SF_PUT_INUMBER((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent);
+ xfs_dir2_sf_put_inumber((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent);
return size;
}
@@ -199,15 +199,15 @@
* Copy the header into the newly allocate local space.
*/
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- memcpy(sfp, sfhp, XFS_DIR2_SF_HDR_SIZE(sfhp->i8count));
+ memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count));
dp->i_d.di_size = size;
/*
* Set up to loop over the block's entries.
*/
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
+ btp = xfs_dir2_block_tail_p(mp, block);
ptr = (char *)block->u;
- endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
- sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ endptr = (char *)xfs_dir2_block_leaf_p(btp);
+ sfep = xfs_dir2_sf_firstentry(sfp);
/*
* Loop over the active and unused entries.
* Stop when we reach the leaf/tail portion of the block.
@@ -233,22 +233,22 @@
else if (dep->namelen == 2 &&
dep->name[0] == '.' && dep->name[1] == '.')
ASSERT(be64_to_cpu(dep->inumber) ==
- XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
+ xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent));
/*
* Normal entry, copy it into shortform.
*/
else {
sfep->namelen = dep->namelen;
- XFS_DIR2_SF_PUT_OFFSET(sfep,
+ xfs_dir2_sf_put_offset(sfep,
(xfs_dir2_data_aoff_t)
((char *)dep - (char *)block));
memcpy(sfep->name, dep->name, dep->namelen);
temp = be64_to_cpu(dep->inumber);
- XFS_DIR2_SF_PUT_INUMBER(sfp, &temp,
- XFS_DIR2_SF_INUMBERP(sfep));
- sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
+ xfs_dir2_sf_put_inumber(sfp, &temp,
+ xfs_dir2_sf_inumberp(sfep));
+ sfep = xfs_dir2_sf_nextentry(sfp, sfep);
}
- ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
+ ptr += xfs_dir2_data_entsize(dep->namelen);
}
ASSERT((char *)sfep - (char *)sfp == size);
xfs_dir2_sf_check(args);
@@ -294,11 +294,11 @@
ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
ASSERT(dp->i_df.if_u1.if_data != NULL);
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+ ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
/*
* Compute entry (and change in) size.
*/
- add_entsize = XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen);
+ add_entsize = xfs_dir2_sf_entsize_byname(sfp, args->namelen);
incr_isize = add_entsize;
objchange = 0;
#if XFS_BIG_INUMS
@@ -392,7 +392,7 @@
/*
* Grow the in-inode space.
*/
- xfs_idata_realloc(dp, XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen),
+ xfs_idata_realloc(dp, xfs_dir2_sf_entsize_byname(sfp, args->namelen),
XFS_DATA_FORK);
/*
* Need to set up again due to realloc of the inode data.
@@ -403,10 +403,10 @@
* Fill in the new entry.
*/
sfep->namelen = args->namelen;
- XFS_DIR2_SF_PUT_OFFSET(sfep, offset);
+ xfs_dir2_sf_put_offset(sfep, offset);
memcpy(sfep->name, args->name, sfep->namelen);
- XFS_DIR2_SF_PUT_INUMBER(sfp, &args->inumber,
- XFS_DIR2_SF_INUMBERP(sfep));
+ xfs_dir2_sf_put_inumber(sfp, &args->inumber,
+ xfs_dir2_sf_inumberp(sfep));
/*
* Update the header and inode.
*/
@@ -463,14 +463,14 @@
* If it's going to end up at the end then oldsfep will point there.
*/
for (offset = XFS_DIR2_DATA_FIRST_OFFSET,
- oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp),
- add_datasize = XFS_DIR2_DATA_ENTSIZE(args->namelen),
+ oldsfep = xfs_dir2_sf_firstentry(oldsfp),
+ add_datasize = xfs_dir2_data_entsize(args->namelen),
eof = (char *)oldsfep == &buf[old_isize];
!eof;
- offset = new_offset + XFS_DIR2_DATA_ENTSIZE(oldsfep->namelen),
- oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep),
+ offset = new_offset + xfs_dir2_data_entsize(oldsfep->namelen),
+ oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep),
eof = (char *)oldsfep == &buf[old_isize]) {
- new_offset = XFS_DIR2_SF_GET_OFFSET(oldsfep);
+ new_offset = xfs_dir2_sf_get_offset(oldsfep);
if (offset + add_datasize <= new_offset)
break;
}
@@ -495,10 +495,10 @@
* Fill in the new entry, and update the header counts.
*/
sfep->namelen = args->namelen;
- XFS_DIR2_SF_PUT_OFFSET(sfep, offset);
+ xfs_dir2_sf_put_offset(sfep, offset);
memcpy(sfep->name, args->name, sfep->namelen);
- XFS_DIR2_SF_PUT_INUMBER(sfp, &args->inumber,
- XFS_DIR2_SF_INUMBERP(sfep));
+ xfs_dir2_sf_put_inumber(sfp, &args->inumber,
+ xfs_dir2_sf_inumberp(sfep));
sfp->hdr.count++;
#if XFS_BIG_INUMS
if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
@@ -508,7 +508,7 @@
* If there's more left to copy, do that.
*/
if (!eof) {
- sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
+ sfep = xfs_dir2_sf_nextentry(sfp, sfep);
memcpy(sfep, oldsfep, old_isize - nbytes);
}
kmem_free(buf, old_isize);
@@ -544,9 +544,9 @@
mp = dp->i_mount;
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- size = XFS_DIR2_DATA_ENTSIZE(args->namelen);
+ size = xfs_dir2_data_entsize(args->namelen);
offset = XFS_DIR2_DATA_FIRST_OFFSET;
- sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ sfep = xfs_dir2_sf_firstentry(sfp);
holefit = 0;
/*
* Loop over sf entries.
@@ -555,10 +555,10 @@
*/
for (i = 0; i < sfp->hdr.count; i++) {
if (!holefit)
- holefit = offset + size <= XFS_DIR2_SF_GET_OFFSET(sfep);
- offset = XFS_DIR2_SF_GET_OFFSET(sfep) +
- XFS_DIR2_DATA_ENTSIZE(sfep->namelen);
- sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
+ holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
+ offset = xfs_dir2_sf_get_offset(sfep) +
+ xfs_dir2_data_entsize(sfep->namelen);
+ sfep = xfs_dir2_sf_nextentry(sfp, sfep);
}
/*
* Calculate data bytes used excluding the new entry, if this
@@ -617,18 +617,18 @@
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
offset = XFS_DIR2_DATA_FIRST_OFFSET;
- ino = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
+ ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
- ASSERT(XFS_DIR2_SF_GET_OFFSET(sfep) >= offset);
- ino = XFS_DIR2_SF_GET_INUMBER(sfp, XFS_DIR2_SF_INUMBERP(sfep));
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
+ ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
+ ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
offset =
- XFS_DIR2_SF_GET_OFFSET(sfep) +
- XFS_DIR2_DATA_ENTSIZE(sfep->namelen);
+ xfs_dir2_sf_get_offset(sfep) +
+ xfs_dir2_data_entsize(sfep->namelen);
}
ASSERT(i8count == sfp->hdr.i8count);
ASSERT(XFS_BIG_INUMS || i8count == 0);
@@ -671,7 +671,7 @@
ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
ASSERT(dp->i_df.if_bytes == 0);
i8count = pino > XFS_DIR2_MAX_SHORT_INUM;
- size = XFS_DIR2_SF_HDR_SIZE(i8count);
+ size = xfs_dir2_sf_hdr_size(i8count);
/*
* Make a buffer for the data.
*/
@@ -684,7 +684,7 @@
/*
* Now can put in the inode number, since i8count is set.
*/
- XFS_DIR2_SF_PUT_INUMBER(sfp, &pino, &sfp->hdr.parent);
+ xfs_dir2_sf_put_inumber(sfp, &pino, &sfp->hdr.parent);
sfp->hdr.count = 0;
dp->i_d.di_size = size;
xfs_dir2_sf_check(args);
@@ -727,12 +727,12 @@
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+ ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
/*
* If the block number in the offset is out of range, we're done.
*/
- if (XFS_DIR2_DATAPTR_TO_DB(mp, dir_offset) > mp->m_dirdatablk) {
+ if (xfs_dir2_dataptr_to_db(mp, dir_offset) > mp->m_dirdatablk) {
*eofp = 1;
return 0;
}
@@ -747,9 +747,9 @@
* Put . entry unless we're starting past it.
*/
if (dir_offset <=
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_DOT_OFFSET)) {
- p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, 0,
+ p.cook = xfs_dir2_db_off_to_dataptr(mp, 0,
XFS_DIR2_DATA_DOTDOT_OFFSET);
p.ino = dp->i_ino;
#if XFS_BIG_INUMS
@@ -762,7 +762,7 @@
if (!p.done) {
uio->uio_offset =
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_DOT_OFFSET);
return error;
}
@@ -772,11 +772,11 @@
* Put .. entry unless we're starting past it.
*/
if (dir_offset <=
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_DOTDOT_OFFSET)) {
- p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_FIRST_OFFSET);
- p.ino = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
+ p.ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
#if XFS_BIG_INUMS
p.ino += mp->m_inoadd;
#endif
@@ -787,7 +787,7 @@
if (!p.done) {
uio->uio_offset =
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_DOTDOT_OFFSET);
return error;
}
@@ -796,23 +796,23 @@
/*
* Loop while there are more entries and put'ing works.
*/
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
- off = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
- XFS_DIR2_SF_GET_OFFSET(sfep));
+ off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+ xfs_dir2_sf_get_offset(sfep));
if (dir_offset > off)
continue;
p.namelen = sfep->namelen;
- p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
- XFS_DIR2_SF_GET_OFFSET(sfep) +
- XFS_DIR2_DATA_ENTSIZE(p.namelen));
+ p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+ xfs_dir2_sf_get_offset(sfep) +
+ xfs_dir2_data_entsize(p.namelen));
- p.ino = XFS_DIR2_SF_GET_INUMBER(sfp, XFS_DIR2_SF_INUMBERP(sfep));
+ p.ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
#if XFS_BIG_INUMS
p.ino += mp->m_inoadd;
#endif
@@ -832,7 +832,7 @@
*eofp = 1;
uio->uio_offset =
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk + 1, 0);
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
return 0;
}
@@ -865,7 +865,7 @@
ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
ASSERT(dp->i_df.if_u1.if_data != NULL);
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+ ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
/*
* Special case for .
*/
@@ -878,21 +878,21 @@
*/
if (args->namelen == 2 &&
args->name[0] == '.' && args->name[1] == '.') {
- args->inumber = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
+ args->inumber = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
return XFS_ERROR(EEXIST);
}
/*
* Loop over all the entries trying to match ours.
*/
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
if (sfep->namelen == args->namelen &&
sfep->name[0] == args->name[0] &&
memcmp(args->name, sfep->name, args->namelen) == 0) {
args->inumber =
- XFS_DIR2_SF_GET_INUMBER(sfp,
- XFS_DIR2_SF_INUMBERP(sfep));
+ xfs_dir2_sf_get_inumber(sfp,
+ xfs_dir2_sf_inumberp(sfep));
return XFS_ERROR(EEXIST);
}
}
@@ -934,19 +934,19 @@
ASSERT(dp->i_df.if_bytes == oldsize);
ASSERT(dp->i_df.if_u1.if_data != NULL);
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- ASSERT(oldsize >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+ ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
/*
* Loop over the old directory entries.
* Find the one we're deleting.
*/
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
if (sfep->namelen == args->namelen &&
sfep->name[0] == args->name[0] &&
memcmp(sfep->name, args->name, args->namelen) == 0) {
- ASSERT(XFS_DIR2_SF_GET_INUMBER(sfp,
- XFS_DIR2_SF_INUMBERP(sfep)) ==
+ ASSERT(xfs_dir2_sf_get_inumber(sfp,
+ xfs_dir2_sf_inumberp(sfep)) ==
args->inumber);
break;
}
@@ -961,7 +961,7 @@
* Calculate sizes.
*/
byteoff = (int)((char *)sfep - (char *)sfp);
- entsize = XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen);
+ entsize = xfs_dir2_sf_entsize_byname(sfp, args->namelen);
newsize = oldsize - entsize;
/*
* Copy the part if any after the removed entry, sliding it down.
@@ -1027,7 +1027,7 @@
ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
ASSERT(dp->i_df.if_u1.if_data != NULL);
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+ ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
#if XFS_BIG_INUMS
/*
* New inode number is large, and need to convert to 8-byte inodes.
@@ -1067,28 +1067,28 @@
if (args->namelen == 2 &&
args->name[0] == '.' && args->name[1] == '.') {
#if XFS_BIG_INUMS || defined(DEBUG)
- ino = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
+ ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
ASSERT(args->inumber != ino);
#endif
- XFS_DIR2_SF_PUT_INUMBER(sfp, &args->inumber, &sfp->hdr.parent);
+ xfs_dir2_sf_put_inumber(sfp, &args->inumber, &sfp->hdr.parent);
}
/*
* Normal entry, look for the name.
*/
else {
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
if (sfep->namelen == args->namelen &&
sfep->name[0] == args->name[0] &&
memcmp(args->name, sfep->name, args->namelen) == 0) {
#if XFS_BIG_INUMS || defined(DEBUG)
- ino = XFS_DIR2_SF_GET_INUMBER(sfp,
- XFS_DIR2_SF_INUMBERP(sfep));
+ ino = xfs_dir2_sf_get_inumber(sfp,
+ xfs_dir2_sf_inumberp(sfep));
ASSERT(args->inumber != ino);
#endif
- XFS_DIR2_SF_PUT_INUMBER(sfp, &args->inumber,
- XFS_DIR2_SF_INUMBERP(sfep));
+ xfs_dir2_sf_put_inumber(sfp, &args->inumber,
+ xfs_dir2_sf_inumberp(sfep));
break;
}
}
@@ -1189,22 +1189,22 @@
*/
sfp->hdr.count = oldsfp->hdr.count;
sfp->hdr.i8count = 0;
- ino = XFS_DIR2_SF_GET_INUMBER(oldsfp, &oldsfp->hdr.parent);
- XFS_DIR2_SF_PUT_INUMBER(sfp, &ino, &sfp->hdr.parent);
+ ino = xfs_dir2_sf_get_inumber(oldsfp, &oldsfp->hdr.parent);
+ xfs_dir2_sf_put_inumber(sfp, &ino, &sfp->hdr.parent);
/*
* Copy the entries field by field.
*/
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp),
- oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
+ oldsfep = xfs_dir2_sf_firstentry(oldsfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep),
- oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) {
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep),
+ oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep)) {
sfep->namelen = oldsfep->namelen;
sfep->offset = oldsfep->offset;
memcpy(sfep->name, oldsfep->name, sfep->namelen);
- ino = XFS_DIR2_SF_GET_INUMBER(oldsfp,
- XFS_DIR2_SF_INUMBERP(oldsfep));
- XFS_DIR2_SF_PUT_INUMBER(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep));
+ ino = xfs_dir2_sf_get_inumber(oldsfp,
+ xfs_dir2_sf_inumberp(oldsfep));
+ xfs_dir2_sf_put_inumber(sfp, &ino, xfs_dir2_sf_inumberp(sfep));
}
/*
* Clean up the inode.
@@ -1266,22 +1266,22 @@
*/
sfp->hdr.count = oldsfp->hdr.count;
sfp->hdr.i8count = 1;
- ino = XFS_DIR2_SF_GET_INUMBER(oldsfp, &oldsfp->hdr.parent);
- XFS_DIR2_SF_PUT_INUMBER(sfp, &ino, &sfp->hdr.parent);
+ ino = xfs_dir2_sf_get_inumber(oldsfp, &oldsfp->hdr.parent);
+ xfs_dir2_sf_put_inumber(sfp, &ino, &sfp->hdr.parent);
/*
* Copy the entries field by field.
*/
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp),
- oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
+ oldsfep = xfs_dir2_sf_firstentry(oldsfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep),
- oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) {
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep),
+ oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep)) {
sfep->namelen = oldsfep->namelen;
sfep->offset = oldsfep->offset;
memcpy(sfep->name, oldsfep->name, sfep->namelen);
- ino = XFS_DIR2_SF_GET_INUMBER(oldsfp,
- XFS_DIR2_SF_INUMBERP(oldsfep));
- XFS_DIR2_SF_PUT_INUMBER(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep));
+ ino = xfs_dir2_sf_get_inumber(oldsfp,
+ xfs_dir2_sf_inumberp(oldsfep));
+ xfs_dir2_sf_put_inumber(sfp, &ino, xfs_dir2_sf_inumberp(sfep));
}
/*
* Clean up the inode.
diff --git a/fs/xfs/xfs_dir2_sf.h b/fs/xfs/xfs_dir2_sf.h
index 42f015b..11e5032 100644
--- a/fs/xfs/xfs_dir2_sf.h
+++ b/fs/xfs/xfs_dir2_sf.h
@@ -90,7 +90,6 @@
xfs_dir2_sf_entry_t list[1]; /* shortform entries */
} xfs_dir2_sf_t;
-#define XFS_DIR2_SF_HDR_SIZE(i8count) xfs_dir2_sf_hdr_size(i8count)
static inline int xfs_dir2_sf_hdr_size(int i8count)
{
return ((uint)sizeof(xfs_dir2_sf_hdr_t) - \
@@ -98,14 +97,11 @@
((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)));
}
-#define XFS_DIR2_SF_INUMBERP(sfep) xfs_dir2_sf_inumberp(sfep)
static inline xfs_dir2_inou_t *xfs_dir2_sf_inumberp(xfs_dir2_sf_entry_t *sfep)
{
return (xfs_dir2_inou_t *)&(sfep)->name[(sfep)->namelen];
}
-#define XFS_DIR2_SF_GET_INUMBER(sfp, from) \
- xfs_dir2_sf_get_inumber(sfp, from)
static inline xfs_intino_t
xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp, xfs_dir2_inou_t *from)
{
@@ -114,8 +110,6 @@
(xfs_intino_t)XFS_GET_DIR_INO8((from)->i8));
}
-#define XFS_DIR2_SF_PUT_INUMBER(sfp,from,to) \
- xfs_dir2_sf_put_inumber(sfp,from,to)
static inline void xfs_dir2_sf_put_inumber(xfs_dir2_sf_t *sfp, xfs_ino_t *from,
xfs_dir2_inou_t *to)
{
@@ -125,24 +119,18 @@
XFS_PUT_DIR_INO8(*(from), (to)->i8);
}
-#define XFS_DIR2_SF_GET_OFFSET(sfep) \
- xfs_dir2_sf_get_offset(sfep)
static inline xfs_dir2_data_aoff_t
xfs_dir2_sf_get_offset(xfs_dir2_sf_entry_t *sfep)
{
return INT_GET_UNALIGNED_16_BE(&(sfep)->offset.i);
}
-#define XFS_DIR2_SF_PUT_OFFSET(sfep,off) \
- xfs_dir2_sf_put_offset(sfep,off)
static inline void
xfs_dir2_sf_put_offset(xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t off)
{
INT_SET_UNALIGNED_16_BE(&(sfep)->offset.i, off);
}
-#define XFS_DIR2_SF_ENTSIZE_BYNAME(sfp,len) \
- xfs_dir2_sf_entsize_byname(sfp,len)
static inline int xfs_dir2_sf_entsize_byname(xfs_dir2_sf_t *sfp, int len)
{
return ((uint)sizeof(xfs_dir2_sf_entry_t) - 1 + (len) - \
@@ -150,8 +138,6 @@
((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)));
}
-#define XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep) \
- xfs_dir2_sf_entsize_byentry(sfp,sfep)
static inline int
xfs_dir2_sf_entsize_byentry(xfs_dir2_sf_t *sfp, xfs_dir2_sf_entry_t *sfep)
{
@@ -160,19 +146,17 @@
((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)));
}
-#define XFS_DIR2_SF_FIRSTENTRY(sfp) xfs_dir2_sf_firstentry(sfp)
static inline xfs_dir2_sf_entry_t *xfs_dir2_sf_firstentry(xfs_dir2_sf_t *sfp)
{
return ((xfs_dir2_sf_entry_t *) \
- ((char *)(sfp) + XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)));
+ ((char *)(sfp) + xfs_dir2_sf_hdr_size(sfp->hdr.i8count)));
}
-#define XFS_DIR2_SF_NEXTENTRY(sfp,sfep) xfs_dir2_sf_nextentry(sfp,sfep)
static inline xfs_dir2_sf_entry_t *
xfs_dir2_sf_nextentry(xfs_dir2_sf_t *sfp, xfs_dir2_sf_entry_t *sfep)
{
return ((xfs_dir2_sf_entry_t *) \
- ((char *)(sfep) + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep)));
+ ((char *)(sfep) + xfs_dir2_sf_entsize_byentry(sfp,sfep)));
}
/*
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c
new file mode 100644
index 0000000..ce22786
--- /dev/null
+++ b/fs/xfs/xfs_filestream.c
@@ -0,0 +1,771 @@
+/*
+ * Copyright (c) 2006-2007 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would 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; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "xfs.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_inum.h"
+#include "xfs_dir2.h"
+#include "xfs_dir2_sf.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_ag.h"
+#include "xfs_dmapi.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_mount.h"
+#include "xfs_bmap.h"
+#include "xfs_alloc.h"
+#include "xfs_utils.h"
+#include "xfs_mru_cache.h"
+#include "xfs_filestream.h"
+
+#ifdef XFS_FILESTREAMS_TRACE
+
+ktrace_t *xfs_filestreams_trace_buf;
+
+STATIC void
+xfs_filestreams_trace(
+ xfs_mount_t *mp, /* mount point */
+ int type, /* type of trace */
+ const char *func, /* source function */
+ int line, /* source line number */
+ __psunsigned_t arg0,
+ __psunsigned_t arg1,
+ __psunsigned_t arg2,
+ __psunsigned_t arg3,
+ __psunsigned_t arg4,
+ __psunsigned_t arg5)
+{
+ ktrace_enter(xfs_filestreams_trace_buf,
+ (void *)(__psint_t)(type | (line << 16)),
+ (void *)func,
+ (void *)(__psunsigned_t)current_pid(),
+ (void *)mp,
+ (void *)(__psunsigned_t)arg0,
+ (void *)(__psunsigned_t)arg1,
+ (void *)(__psunsigned_t)arg2,
+ (void *)(__psunsigned_t)arg3,
+ (void *)(__psunsigned_t)arg4,
+ (void *)(__psunsigned_t)arg5,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+}
+
+#define TRACE0(mp,t) TRACE6(mp,t,0,0,0,0,0,0)
+#define TRACE1(mp,t,a0) TRACE6(mp,t,a0,0,0,0,0,0)
+#define TRACE2(mp,t,a0,a1) TRACE6(mp,t,a0,a1,0,0,0,0)
+#define TRACE3(mp,t,a0,a1,a2) TRACE6(mp,t,a0,a1,a2,0,0,0)
+#define TRACE4(mp,t,a0,a1,a2,a3) TRACE6(mp,t,a0,a1,a2,a3,0,0)
+#define TRACE5(mp,t,a0,a1,a2,a3,a4) TRACE6(mp,t,a0,a1,a2,a3,a4,0)
+#define TRACE6(mp,t,a0,a1,a2,a3,a4,a5) \
+ xfs_filestreams_trace(mp, t, __FUNCTION__, __LINE__, \
+ (__psunsigned_t)a0, (__psunsigned_t)a1, \
+ (__psunsigned_t)a2, (__psunsigned_t)a3, \
+ (__psunsigned_t)a4, (__psunsigned_t)a5)
+
+#define TRACE_AG_SCAN(mp, ag, ag2) \
+ TRACE2(mp, XFS_FSTRM_KTRACE_AGSCAN, ag, ag2);
+#define TRACE_AG_PICK1(mp, max_ag, maxfree) \
+ TRACE2(mp, XFS_FSTRM_KTRACE_AGPICK1, max_ag, maxfree);
+#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag) \
+ TRACE6(mp, XFS_FSTRM_KTRACE_AGPICK2, ag, ag2, \
+ cnt, free, scan, flag)
+#define TRACE_UPDATE(mp, ip, ag, cnt, ag2, cnt2) \
+ TRACE5(mp, XFS_FSTRM_KTRACE_UPDATE, ip, ag, cnt, ag2, cnt2)
+#define TRACE_FREE(mp, ip, pip, ag, cnt) \
+ TRACE4(mp, XFS_FSTRM_KTRACE_FREE, ip, pip, ag, cnt)
+#define TRACE_LOOKUP(mp, ip, pip, ag, cnt) \
+ TRACE4(mp, XFS_FSTRM_KTRACE_ITEM_LOOKUP, ip, pip, ag, cnt)
+#define TRACE_ASSOCIATE(mp, ip, pip, ag, cnt) \
+ TRACE4(mp, XFS_FSTRM_KTRACE_ASSOCIATE, ip, pip, ag, cnt)
+#define TRACE_MOVEAG(mp, ip, pip, oag, ocnt, nag, ncnt) \
+ TRACE6(mp, XFS_FSTRM_KTRACE_MOVEAG, ip, pip, oag, ocnt, nag, ncnt)
+#define TRACE_ORPHAN(mp, ip, ag) \
+ TRACE2(mp, XFS_FSTRM_KTRACE_ORPHAN, ip, ag);
+
+
+#else
+#define TRACE_AG_SCAN(mp, ag, ag2)
+#define TRACE_AG_PICK1(mp, max_ag, maxfree)
+#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag)
+#define TRACE_UPDATE(mp, ip, ag, cnt, ag2, cnt2)
+#define TRACE_FREE(mp, ip, pip, ag, cnt)
+#define TRACE_LOOKUP(mp, ip, pip, ag, cnt)
+#define TRACE_ASSOCIATE(mp, ip, pip, ag, cnt)
+#define TRACE_MOVEAG(mp, ip, pip, oag, ocnt, nag, ncnt)
+#define TRACE_ORPHAN(mp, ip, ag)
+#endif
+
+static kmem_zone_t *item_zone;
+
+/*
+ * Structure for associating a file or a directory with an allocation group.
+ * The parent directory pointer is only needed for files, but since there will
+ * generally be vastly more files than directories in the cache, using the same
+ * data structure simplifies the code with very little memory overhead.
+ */
+typedef struct fstrm_item
+{
+ xfs_agnumber_t ag; /* AG currently in use for the file/directory. */
+ xfs_inode_t *ip; /* inode self-pointer. */
+ xfs_inode_t *pip; /* Parent directory inode pointer. */
+} fstrm_item_t;
+
+
+/*
+ * Scan the AGs starting at startag looking for an AG that isn't in use and has
+ * at least minlen blocks free.
+ */
+static int
+_xfs_filestream_pick_ag(
+ xfs_mount_t *mp,
+ xfs_agnumber_t startag,
+ xfs_agnumber_t *agp,
+ int flags,
+ xfs_extlen_t minlen)
+{
+ int err, trylock, nscan;
+ xfs_extlen_t delta, longest, need, free, minfree, maxfree = 0;
+ xfs_agnumber_t ag, max_ag = NULLAGNUMBER;
+ struct xfs_perag *pag;
+
+ /* 2% of an AG's blocks must be free for it to be chosen. */
+ minfree = mp->m_sb.sb_agblocks / 50;
+
+ ag = startag;
+ *agp = NULLAGNUMBER;
+
+ /* For the first pass, don't sleep trying to init the per-AG. */
+ trylock = XFS_ALLOC_FLAG_TRYLOCK;
+
+ for (nscan = 0; 1; nscan++) {
+
+ TRACE_AG_SCAN(mp, ag, xfs_filestream_peek_ag(mp, ag));
+
+ pag = mp->m_perag + ag;
+
+ if (!pag->pagf_init) {
+ err = xfs_alloc_pagf_init(mp, NULL, ag, trylock);
+ if (err && !trylock)
+ return err;
+ }
+
+ /* Might fail sometimes during the 1st pass with trylock set. */
+ if (!pag->pagf_init)
+ goto next_ag;
+
+ /* Keep track of the AG with the most free blocks. */
+ if (pag->pagf_freeblks > maxfree) {
+ maxfree = pag->pagf_freeblks;
+ max_ag = ag;
+ }
+
+ /*
+ * The AG reference count does two things: it enforces mutual
+ * exclusion when examining the suitability of an AG in this
+ * loop, and it guards against two filestreams being established
+ * in the same AG as each other.
+ */
+ if (xfs_filestream_get_ag(mp, ag) > 1) {
+ xfs_filestream_put_ag(mp, ag);
+ goto next_ag;
+ }
+
+ need = XFS_MIN_FREELIST_PAG(pag, mp);
+ delta = need > pag->pagf_flcount ? need - pag->pagf_flcount : 0;
+ longest = (pag->pagf_longest > delta) ?
+ (pag->pagf_longest - delta) :
+ (pag->pagf_flcount > 0 || pag->pagf_longest > 0);
+
+ if (((minlen && longest >= minlen) ||
+ (!minlen && pag->pagf_freeblks >= minfree)) &&
+ (!pag->pagf_metadata || !(flags & XFS_PICK_USERDATA) ||
+ (flags & XFS_PICK_LOWSPACE))) {
+
+ /* Break out, retaining the reference on the AG. */
+ free = pag->pagf_freeblks;
+ *agp = ag;
+ break;
+ }
+
+ /* Drop the reference on this AG, it's not usable. */
+ xfs_filestream_put_ag(mp, ag);
+next_ag:
+ /* Move to the next AG, wrapping to AG 0 if necessary. */
+ if (++ag >= mp->m_sb.sb_agcount)
+ ag = 0;
+
+ /* If a full pass of the AGs hasn't been done yet, continue. */
+ if (ag != startag)
+ continue;
+
+ /* Allow sleeping in xfs_alloc_pagf_init() on the 2nd pass. */
+ if (trylock != 0) {
+ trylock = 0;
+ continue;
+ }
+
+ /* Finally, if lowspace wasn't set, set it for the 3rd pass. */
+ if (!(flags & XFS_PICK_LOWSPACE)) {
+ flags |= XFS_PICK_LOWSPACE;
+ continue;
+ }
+
+ /*
+ * Take the AG with the most free space, regardless of whether
+ * it's already in use by another filestream.
+ */
+ if (max_ag != NULLAGNUMBER) {
+ xfs_filestream_get_ag(mp, max_ag);
+ TRACE_AG_PICK1(mp, max_ag, maxfree);
+ free = maxfree;
+ *agp = max_ag;
+ break;
+ }
+
+ /* take AG 0 if none matched */
+ TRACE_AG_PICK1(mp, max_ag, maxfree);
+ *agp = 0;
+ return 0;
+ }
+
+ TRACE_AG_PICK2(mp, startag, *agp, xfs_filestream_peek_ag(mp, *agp),
+ free, nscan, flags);
+
+ return 0;
+}
+
+/*
+ * Set the allocation group number for a file or a directory, updating inode
+ * references and per-AG references as appropriate. Must be called with the
+ * m_peraglock held in read mode.
+ */
+static int
+_xfs_filestream_update_ag(
+ xfs_inode_t *ip,
+ xfs_inode_t *pip,
+ xfs_agnumber_t ag)
+{
+ int err = 0;
+ xfs_mount_t *mp;
+ xfs_mru_cache_t *cache;
+ fstrm_item_t *item;
+ xfs_agnumber_t old_ag;
+ xfs_inode_t *old_pip;
+
+ /*
+ * Either ip is a regular file and pip is a directory, or ip is a
+ * directory and pip is NULL.
+ */
+ ASSERT(ip && (((ip->i_d.di_mode & S_IFREG) && pip &&
+ (pip->i_d.di_mode & S_IFDIR)) ||
+ ((ip->i_d.di_mode & S_IFDIR) && !pip)));
+
+ mp = ip->i_mount;
+ cache = mp->m_filestream;
+
+ item = xfs_mru_cache_lookup(cache, ip->i_ino);
+ if (item) {
+ ASSERT(item->ip == ip);
+ old_ag = item->ag;
+ item->ag = ag;
+ old_pip = item->pip;
+ item->pip = pip;
+ xfs_mru_cache_done(cache);
+
+ /*
+ * If the AG has changed, drop the old ref and take a new one,
+ * effectively transferring the reference from old to new AG.
+ */
+ if (ag != old_ag) {
+ xfs_filestream_put_ag(mp, old_ag);
+ xfs_filestream_get_ag(mp, ag);
+ }
+
+ /*
+ * If ip is a file and its pip has changed, drop the old ref and
+ * take a new one.
+ */
+ if (pip && pip != old_pip) {
+ IRELE(old_pip);
+ IHOLD(pip);
+ }
+
+ TRACE_UPDATE(mp, ip, old_ag, xfs_filestream_peek_ag(mp, old_ag),
+ ag, xfs_filestream_peek_ag(mp, ag));
+ return 0;
+ }
+
+ item = kmem_zone_zalloc(item_zone, KM_MAYFAIL);
+ if (!item)
+ return ENOMEM;
+
+ item->ag = ag;
+ item->ip = ip;
+ item->pip = pip;
+
+ err = xfs_mru_cache_insert(cache, ip->i_ino, item);
+ if (err) {
+ kmem_zone_free(item_zone, item);
+ return err;
+ }
+
+ /* Take a reference on the AG. */
+ xfs_filestream_get_ag(mp, ag);
+
+ /*
+ * Take a reference on the inode itself regardless of whether it's a
+ * regular file or a directory.
+ */
+ IHOLD(ip);
+
+ /*
+ * In the case of a regular file, take a reference on the parent inode
+ * as well to ensure it remains in-core.
+ */
+ if (pip)
+ IHOLD(pip);
+
+ TRACE_UPDATE(mp, ip, ag, xfs_filestream_peek_ag(mp, ag),
+ ag, xfs_filestream_peek_ag(mp, ag));
+
+ return 0;
+}
+
+/* xfs_fstrm_free_func(): callback for freeing cached stream items. */
+void
+xfs_fstrm_free_func(
+ xfs_ino_t ino,
+ fstrm_item_t *item)
+{
+ xfs_inode_t *ip = item->ip;
+ int ref;
+
+ ASSERT(ip->i_ino == ino);
+
+ xfs_iflags_clear(ip, XFS_IFILESTREAM);
+
+ /* Drop the reference taken on the AG when the item was added. */
+ ref = xfs_filestream_put_ag(ip->i_mount, item->ag);
+
+ ASSERT(ref >= 0);
+ TRACE_FREE(ip->i_mount, ip, item->pip, item->ag,
+ xfs_filestream_peek_ag(ip->i_mount, item->ag));
+
+ /*
+ * _xfs_filestream_update_ag() always takes a reference on the inode
+ * itself, whether it's a file or a directory. Release it here.
+ * This can result in the inode being freed and so we must
+ * not hold any inode locks when freeing filesstreams objects
+ * otherwise we can deadlock here.
+ */
+ IRELE(ip);
+
+ /*
+ * In the case of a regular file, _xfs_filestream_update_ag() also
+ * takes a ref on the parent inode to keep it in-core. Release that
+ * too.
+ */
+ if (item->pip)
+ IRELE(item->pip);
+
+ /* Finally, free the memory allocated for the item. */
+ kmem_zone_free(item_zone, item);
+}
+
+/*
+ * xfs_filestream_init() is called at xfs initialisation time to set up the
+ * memory zone that will be used for filestream data structure allocation.
+ */
+int
+xfs_filestream_init(void)
+{
+ item_zone = kmem_zone_init(sizeof(fstrm_item_t), "fstrm_item");
+#ifdef XFS_FILESTREAMS_TRACE
+ xfs_filestreams_trace_buf = ktrace_alloc(XFS_FSTRM_KTRACE_SIZE, KM_SLEEP);
+#endif
+ return item_zone ? 0 : -ENOMEM;
+}
+
+/*
+ * xfs_filestream_uninit() is called at xfs termination time to destroy the
+ * memory zone that was used for filestream data structure allocation.
+ */
+void
+xfs_filestream_uninit(void)
+{
+#ifdef XFS_FILESTREAMS_TRACE
+ ktrace_free(xfs_filestreams_trace_buf);
+#endif
+ kmem_zone_destroy(item_zone);
+}
+
+/*
+ * xfs_filestream_mount() is called when a file system is mounted with the
+ * filestream option. It is responsible for allocating the data structures
+ * needed to track the new file system's file streams.
+ */
+int
+xfs_filestream_mount(
+ xfs_mount_t *mp)
+{
+ int err;
+ unsigned int lifetime, grp_count;
+
+ /*
+ * The filestream timer tunable is currently fixed within the range of
+ * one second to four minutes, with five seconds being the default. The
+ * group count is somewhat arbitrary, but it'd be nice to adhere to the
+ * timer tunable to within about 10 percent. This requires at least 10
+ * groups.
+ */
+ lifetime = xfs_fstrm_centisecs * 10;
+ grp_count = 10;
+
+ err = xfs_mru_cache_create(&mp->m_filestream, lifetime, grp_count,
+ (xfs_mru_cache_free_func_t)xfs_fstrm_free_func);
+
+ return err;
+}
+
+/*
+ * xfs_filestream_unmount() is called when a file system that was mounted with
+ * the filestream option is unmounted. It drains the data structures created
+ * to track the file system's file streams and frees all the memory that was
+ * allocated.
+ */
+void
+xfs_filestream_unmount(
+ xfs_mount_t *mp)
+{
+ xfs_mru_cache_destroy(mp->m_filestream);
+}
+
+/*
+ * If the mount point's m_perag array is going to be reallocated, all
+ * outstanding cache entries must be flushed to avoid accessing reference count
+ * addresses that have been freed. The call to xfs_filestream_flush() must be
+ * made inside the block that holds the m_peraglock in write mode to do the
+ * reallocation.
+ */
+void
+xfs_filestream_flush(
+ xfs_mount_t *mp)
+{
+ /* point in time flush, so keep the reaper running */
+ xfs_mru_cache_flush(mp->m_filestream, 1);
+}
+
+/*
+ * Return the AG of the filestream the file or directory belongs to, or
+ * NULLAGNUMBER otherwise.
+ */
+xfs_agnumber_t
+xfs_filestream_lookup_ag(
+ xfs_inode_t *ip)
+{
+ xfs_mru_cache_t *cache;
+ fstrm_item_t *item;
+ xfs_agnumber_t ag;
+ int ref;
+
+ if (!(ip->i_d.di_mode & (S_IFREG | S_IFDIR))) {
+ ASSERT(0);
+ return NULLAGNUMBER;
+ }
+
+ cache = ip->i_mount->m_filestream;
+ item = xfs_mru_cache_lookup(cache, ip->i_ino);
+ if (!item) {
+ TRACE_LOOKUP(ip->i_mount, ip, NULL, NULLAGNUMBER, 0);
+ return NULLAGNUMBER;
+ }
+
+ ASSERT(ip == item->ip);
+ ag = item->ag;
+ ref = xfs_filestream_peek_ag(ip->i_mount, ag);
+ xfs_mru_cache_done(cache);
+
+ TRACE_LOOKUP(ip->i_mount, ip, item->pip, ag, ref);
+ return ag;
+}
+
+/*
+ * xfs_filestream_associate() should only be called to associate a regular file
+ * with its parent directory. Calling it with a child directory isn't
+ * appropriate because filestreams don't apply to entire directory hierarchies.
+ * Creating a file in a child directory of an existing filestream directory
+ * starts a new filestream with its own allocation group association.
+ *
+ * Returns < 0 on error, 0 if successful association occurred, > 0 if
+ * we failed to get an association because of locking issues.
+ */
+int
+xfs_filestream_associate(
+ xfs_inode_t *pip,
+ xfs_inode_t *ip)
+{
+ xfs_mount_t *mp;
+ xfs_mru_cache_t *cache;
+ fstrm_item_t *item;
+ xfs_agnumber_t ag, rotorstep, startag;
+ int err = 0;
+
+ ASSERT(pip->i_d.di_mode & S_IFDIR);
+ ASSERT(ip->i_d.di_mode & S_IFREG);
+ if (!(pip->i_d.di_mode & S_IFDIR) || !(ip->i_d.di_mode & S_IFREG))
+ return -EINVAL;
+
+ mp = pip->i_mount;
+ cache = mp->m_filestream;
+ down_read(&mp->m_peraglock);
+
+ /*
+ * We have a problem, Houston.
+ *
+ * Taking the iolock here violates inode locking order - we already
+ * hold the ilock. Hence if we block getting this lock we may never
+ * wake. Unfortunately, that means if we can't get the lock, we're
+ * screwed in terms of getting a stream association - we can't spin
+ * waiting for the lock because someone else is waiting on the lock we
+ * hold and we cannot drop that as we are in a transaction here.
+ *
+ * Lucky for us, this inversion is rarely a problem because it's a
+ * directory inode that we are trying to lock here and that means the
+ * only place that matters is xfs_sync_inodes() and SYNC_DELWRI is
+ * used. i.e. freeze, remount-ro, quotasync or unmount.
+ *
+ * So, if we can't get the iolock without sleeping then just give up
+ */
+ if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL)) {
+ up_read(&mp->m_peraglock);
+ return 1;
+ }
+
+ /* If the parent directory is already in the cache, use its AG. */
+ item = xfs_mru_cache_lookup(cache, pip->i_ino);
+ if (item) {
+ ASSERT(item->ip == pip);
+ ag = item->ag;
+ xfs_mru_cache_done(cache);
+
+ TRACE_LOOKUP(mp, pip, pip, ag, xfs_filestream_peek_ag(mp, ag));
+ err = _xfs_filestream_update_ag(ip, pip, ag);
+
+ goto exit;
+ }
+
+ /*
+ * Set the starting AG using the rotor for inode32, otherwise
+ * use the directory inode's AG.
+ */
+ if (mp->m_flags & XFS_MOUNT_32BITINODES) {
+ rotorstep = xfs_rotorstep;
+ startag = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount;
+ mp->m_agfrotor = (mp->m_agfrotor + 1) %
+ (mp->m_sb.sb_agcount * rotorstep);
+ } else
+ startag = XFS_INO_TO_AGNO(mp, pip->i_ino);
+
+ /* Pick a new AG for the parent inode starting at startag. */
+ err = _xfs_filestream_pick_ag(mp, startag, &ag, 0, 0);
+ if (err || ag == NULLAGNUMBER)
+ goto exit_did_pick;
+
+ /* Associate the parent inode with the AG. */
+ err = _xfs_filestream_update_ag(pip, NULL, ag);
+ if (err)
+ goto exit_did_pick;
+
+ /* Associate the file inode with the AG. */
+ err = _xfs_filestream_update_ag(ip, pip, ag);
+ if (err)
+ goto exit_did_pick;
+
+ TRACE_ASSOCIATE(mp, ip, pip, ag, xfs_filestream_peek_ag(mp, ag));
+
+exit_did_pick:
+ /*
+ * If _xfs_filestream_pick_ag() returned a valid AG, remove the
+ * reference it took on it, since the file and directory will have taken
+ * their own now if they were successfully cached.
+ */
+ if (ag != NULLAGNUMBER)
+ xfs_filestream_put_ag(mp, ag);
+
+exit:
+ xfs_iunlock(pip, XFS_IOLOCK_EXCL);
+ up_read(&mp->m_peraglock);
+ return -err;
+}
+
+/*
+ * Pick a new allocation group for the current file and its file stream. This
+ * function is called by xfs_bmap_filestreams() with the mount point's per-ag
+ * lock held.
+ */
+int
+xfs_filestream_new_ag(
+ xfs_bmalloca_t *ap,
+ xfs_agnumber_t *agp)
+{
+ int flags, err;
+ xfs_inode_t *ip, *pip = NULL;
+ xfs_mount_t *mp;
+ xfs_mru_cache_t *cache;
+ xfs_extlen_t minlen;
+ fstrm_item_t *dir, *file;
+ xfs_agnumber_t ag = NULLAGNUMBER;
+
+ ip = ap->ip;
+ mp = ip->i_mount;
+ cache = mp->m_filestream;
+ minlen = ap->alen;
+ *agp = NULLAGNUMBER;
+
+ /*
+ * Look for the file in the cache, removing it if it's found. Doing
+ * this allows it to be held across the dir lookup that follows.
+ */
+ file = xfs_mru_cache_remove(cache, ip->i_ino);
+ if (file) {
+ ASSERT(ip == file->ip);
+
+ /* Save the file's parent inode and old AG number for later. */
+ pip = file->pip;
+ ag = file->ag;
+
+ /* Look for the file's directory in the cache. */
+ dir = xfs_mru_cache_lookup(cache, pip->i_ino);
+ if (dir) {
+ ASSERT(pip == dir->ip);
+
+ /*
+ * If the directory has already moved on to a new AG,
+ * use that AG as the new AG for the file. Don't
+ * forget to twiddle the AG refcounts to match the
+ * movement.
+ */
+ if (dir->ag != file->ag) {
+ xfs_filestream_put_ag(mp, file->ag);
+ xfs_filestream_get_ag(mp, dir->ag);
+ *agp = file->ag = dir->ag;
+ }
+
+ xfs_mru_cache_done(cache);
+ }
+
+ /*
+ * Put the file back in the cache. If this fails, the free
+ * function needs to be called to tidy up in the same way as if
+ * the item had simply expired from the cache.
+ */
+ err = xfs_mru_cache_insert(cache, ip->i_ino, file);
+ if (err) {
+ xfs_fstrm_free_func(ip->i_ino, file);
+ return err;
+ }
+
+ /*
+ * If the file's AG was moved to the directory's new AG, there's
+ * nothing more to be done.
+ */
+ if (*agp != NULLAGNUMBER) {
+ TRACE_MOVEAG(mp, ip, pip,
+ ag, xfs_filestream_peek_ag(mp, ag),
+ *agp, xfs_filestream_peek_ag(mp, *agp));
+ return 0;
+ }
+ }
+
+ /*
+ * If the file's parent directory is known, take its iolock in exclusive
+ * mode to prevent two sibling files from racing each other to migrate
+ * themselves and their parent to different AGs.
+ */
+ if (pip)
+ xfs_ilock(pip, XFS_IOLOCK_EXCL);
+
+ /*
+ * A new AG needs to be found for the file. If the file's parent
+ * directory is also known, it will be moved to the new AG as well to
+ * ensure that files created inside it in future use the new AG.
+ */
+ ag = (ag == NULLAGNUMBER) ? 0 : (ag + 1) % mp->m_sb.sb_agcount;
+ flags = (ap->userdata ? XFS_PICK_USERDATA : 0) |
+ (ap->low ? XFS_PICK_LOWSPACE : 0);
+
+ err = _xfs_filestream_pick_ag(mp, ag, agp, flags, minlen);
+ if (err || *agp == NULLAGNUMBER)
+ goto exit;
+
+ /*
+ * If the file wasn't found in the file cache, then its parent directory
+ * inode isn't known. For this to have happened, the file must either
+ * be pre-existing, or it was created long enough ago that its cache
+ * entry has expired. This isn't the sort of usage that the filestreams
+ * allocator is trying to optimise, so there's no point trying to track
+ * its new AG somehow in the filestream data structures.
+ */
+ if (!pip) {
+ TRACE_ORPHAN(mp, ip, *agp);
+ goto exit;
+ }
+
+ /* Associate the parent inode with the AG. */
+ err = _xfs_filestream_update_ag(pip, NULL, *agp);
+ if (err)
+ goto exit;
+
+ /* Associate the file inode with the AG. */
+ err = _xfs_filestream_update_ag(ip, pip, *agp);
+ if (err)
+ goto exit;
+
+ TRACE_MOVEAG(mp, ip, pip, NULLAGNUMBER, 0,
+ *agp, xfs_filestream_peek_ag(mp, *agp));
+
+exit:
+ /*
+ * If _xfs_filestream_pick_ag() returned a valid AG, remove the
+ * reference it took on it, since the file and directory will have taken
+ * their own now if they were successfully cached.
+ */
+ if (*agp != NULLAGNUMBER)
+ xfs_filestream_put_ag(mp, *agp);
+ else
+ *agp = 0;
+
+ if (pip)
+ xfs_iunlock(pip, XFS_IOLOCK_EXCL);
+
+ return err;
+}
+
+/*
+ * Remove an association between an inode and a filestream object.
+ * Typically this is done on last close of an unlinked file.
+ */
+void
+xfs_filestream_deassociate(
+ xfs_inode_t *ip)
+{
+ xfs_mru_cache_t *cache = ip->i_mount->m_filestream;
+
+ xfs_mru_cache_delete(cache, ip->i_ino);
+}
diff --git a/fs/xfs/xfs_filestream.h b/fs/xfs/xfs_filestream.h
new file mode 100644
index 0000000..f655f7d
--- /dev/null
+++ b/fs/xfs/xfs_filestream.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2006-2007 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would 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; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __XFS_FILESTREAM_H__
+#define __XFS_FILESTREAM_H__
+
+#ifdef __KERNEL__
+
+struct xfs_mount;
+struct xfs_inode;
+struct xfs_perag;
+struct xfs_bmalloca;
+
+#ifdef XFS_FILESTREAMS_TRACE
+#define XFS_FSTRM_KTRACE_INFO 1
+#define XFS_FSTRM_KTRACE_AGSCAN 2
+#define XFS_FSTRM_KTRACE_AGPICK1 3
+#define XFS_FSTRM_KTRACE_AGPICK2 4
+#define XFS_FSTRM_KTRACE_UPDATE 5
+#define XFS_FSTRM_KTRACE_FREE 6
+#define XFS_FSTRM_KTRACE_ITEM_LOOKUP 7
+#define XFS_FSTRM_KTRACE_ASSOCIATE 8
+#define XFS_FSTRM_KTRACE_MOVEAG 9
+#define XFS_FSTRM_KTRACE_ORPHAN 10
+
+#define XFS_FSTRM_KTRACE_SIZE 16384
+extern ktrace_t *xfs_filestreams_trace_buf;
+
+#endif
+
+/*
+ * Allocation group filestream associations are tracked with per-ag atomic
+ * counters. These counters allow _xfs_filestream_pick_ag() to tell whether a
+ * particular AG already has active filestreams associated with it. The mount
+ * point's m_peraglock is used to protect these counters from per-ag array
+ * re-allocation during a growfs operation. When xfs_growfs_data_private() is
+ * about to reallocate the array, it calls xfs_filestream_flush() with the
+ * m_peraglock held in write mode.
+ *
+ * Since xfs_mru_cache_flush() guarantees that all the free functions for all
+ * the cache elements have finished executing before it returns, it's safe for
+ * the free functions to use the atomic counters without m_peraglock protection.
+ * This allows the implementation of xfs_fstrm_free_func() to be agnostic about
+ * whether it was called with the m_peraglock held in read mode, write mode or
+ * not held at all. The race condition this addresses is the following:
+ *
+ * - The work queue scheduler fires and pulls a filestream directory cache
+ * element off the LRU end of the cache for deletion, then gets pre-empted.
+ * - A growfs operation grabs the m_peraglock in write mode, flushes all the
+ * remaining items from the cache and reallocates the mount point's per-ag
+ * array, resetting all the counters to zero.
+ * - The work queue thread resumes and calls the free function for the element
+ * it started cleaning up earlier. In the process it decrements the
+ * filestreams counter for an AG that now has no references.
+ *
+ * With a shrinkfs feature, the above scenario could panic the system.
+ *
+ * All other uses of the following macros should be protected by either the
+ * m_peraglock held in read mode, or the cache's internal locking exposed by the
+ * interval between a call to xfs_mru_cache_lookup() and a call to
+ * xfs_mru_cache_done(). In addition, the m_peraglock must be held in read mode
+ * when new elements are added to the cache.
+ *
+ * Combined, these locking rules ensure that no associations will ever exist in
+ * the cache that reference per-ag array elements that have since been
+ * reallocated.
+ */
+STATIC_INLINE int
+xfs_filestream_peek_ag(
+ xfs_mount_t *mp,
+ xfs_agnumber_t agno)
+{
+ return atomic_read(&mp->m_perag[agno].pagf_fstrms);
+}
+
+STATIC_INLINE int
+xfs_filestream_get_ag(
+ xfs_mount_t *mp,
+ xfs_agnumber_t agno)
+{
+ return atomic_inc_return(&mp->m_perag[agno].pagf_fstrms);
+}
+
+STATIC_INLINE int
+xfs_filestream_put_ag(
+ xfs_mount_t *mp,
+ xfs_agnumber_t agno)
+{
+ return atomic_dec_return(&mp->m_perag[agno].pagf_fstrms);
+}
+
+/* allocation selection flags */
+typedef enum xfs_fstrm_alloc {
+ XFS_PICK_USERDATA = 1,
+ XFS_PICK_LOWSPACE = 2,
+} xfs_fstrm_alloc_t;
+
+/* prototypes for filestream.c */
+int xfs_filestream_init(void);
+void xfs_filestream_uninit(void);
+int xfs_filestream_mount(struct xfs_mount *mp);
+void xfs_filestream_unmount(struct xfs_mount *mp);
+void xfs_filestream_flush(struct xfs_mount *mp);
+xfs_agnumber_t xfs_filestream_lookup_ag(struct xfs_inode *ip);
+int xfs_filestream_associate(struct xfs_inode *dip, struct xfs_inode *ip);
+void xfs_filestream_deassociate(struct xfs_inode *ip);
+int xfs_filestream_new_ag(struct xfs_bmalloca *ap, xfs_agnumber_t *agp);
+
+
+/* filestreams for the inode? */
+STATIC_INLINE int
+xfs_inode_is_filestream(
+ struct xfs_inode *ip)
+{
+ return (ip->i_mount->m_flags & XFS_MOUNT_FILESTREAMS) ||
+ xfs_iflags_test(ip, XFS_IFILESTREAM) ||
+ (ip->i_d.di_flags & XFS_DIFLAG_FILESTREAM);
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* __XFS_FILESTREAM_H__ */
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
index 1335449..ec3c9c2 100644
--- a/fs/xfs/xfs_fs.h
+++ b/fs/xfs/xfs_fs.h
@@ -66,6 +66,7 @@
#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
+#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
/*
@@ -238,6 +239,7 @@
#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */
#define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */
#define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */
+#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */
/*
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index b599e6b..432e823 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -44,6 +44,7 @@
#include "xfs_trans_space.h"
#include "xfs_rtalloc.h"
#include "xfs_rw.h"
+#include "xfs_filestream.h"
/*
* File system operations
@@ -94,6 +95,8 @@
XFS_FSOP_GEOM_FLAGS_DIRV2 : 0) |
(XFS_SB_VERSION_HASSECTOR(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_SECTOR : 0) |
+ (xfs_sb_version_haslazysbcount(&mp->m_sb) ?
+ XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) |
(XFS_SB_VERSION_HASATTR2(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_ATTR2 : 0);
geo->logsectsize = XFS_SB_VERSION_HASSECTOR(&mp->m_sb) ?
@@ -140,6 +143,8 @@
pct = in->imaxpct;
if (nb < mp->m_sb.sb_dblocks || pct < 0 || pct > 100)
return XFS_ERROR(EINVAL);
+ if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))
+ return error;
dpct = pct - mp->m_sb.sb_imax_pct;
error = xfs_read_buf(mp, mp->m_ddev_targp,
XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
@@ -161,6 +166,7 @@
new = nb - mp->m_sb.sb_dblocks;
oagcount = mp->m_sb.sb_agcount;
if (nagcount > oagcount) {
+ xfs_filestream_flush(mp);
down_write(&mp->m_peraglock);
mp->m_perag = kmem_realloc(mp->m_perag,
sizeof(xfs_perag_t) * nagcount,
@@ -173,6 +179,7 @@
up_write(&mp->m_peraglock);
}
tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);
+ tp->t_flags |= XFS_TRANS_RESERVE;
if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp),
XFS_GROWDATA_LOG_RES(mp), 0, 0, 0))) {
xfs_trans_cancel(tp, 0);
@@ -328,6 +335,7 @@
be32_add(&agf->agf_length, new);
ASSERT(be32_to_cpu(agf->agf_length) ==
be32_to_cpu(agi->agi_length));
+ xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH);
/*
* Free the new space.
*/
@@ -494,8 +502,9 @@
unsigned long s;
/* If inval is null, report current values and return */
-
if (inval == (__uint64_t *)NULL) {
+ if (!outval)
+ return EINVAL;
outval->resblks = mp->m_resblks;
outval->resblks_avail = mp->m_resblks_avail;
return 0;
@@ -558,8 +567,10 @@
}
}
out:
- outval->resblks = mp->m_resblks;
- outval->resblks_avail = mp->m_resblks_avail;
+ if (outval) {
+ outval->resblks = mp->m_resblks;
+ outval->resblks_avail = mp->m_resblks_avail;
+ }
XFS_SB_UNLOCK(mp, s);
if (fdblks_delta) {
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
index b5feb3e..f943368 100644
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -123,6 +123,7 @@
int blks_per_cluster; /* fs blocks per inode cluster */
xfs_btree_cur_t *cur; /* inode btree cursor */
xfs_daddr_t d; /* disk addr of buffer */
+ xfs_agnumber_t agno;
int error;
xfs_buf_t *fbuf; /* new free inodes' buffer */
xfs_dinode_t *free; /* new free inode structure */
@@ -302,15 +303,15 @@
}
be32_add(&agi->agi_count, newlen);
be32_add(&agi->agi_freecount, newlen);
+ agno = be32_to_cpu(agi->agi_seqno);
down_read(&args.mp->m_peraglock);
- args.mp->m_perag[be32_to_cpu(agi->agi_seqno)].pagi_freecount += newlen;
+ args.mp->m_perag[agno].pagi_freecount += newlen;
up_read(&args.mp->m_peraglock);
agi->agi_newino = cpu_to_be32(newino);
/*
* Insert records describing the new inode chunk into the btree.
*/
- cur = xfs_btree_init_cursor(args.mp, tp, agbp,
- be32_to_cpu(agi->agi_seqno),
+ cur = xfs_btree_init_cursor(args.mp, tp, agbp, agno,
XFS_BTNUM_INO, (xfs_inode_t *)0, 0);
for (thisino = newino;
thisino < newino + newlen;
@@ -1387,6 +1388,7 @@
pag = &mp->m_perag[agno];
if (!pag->pagi_init) {
pag->pagi_freecount = be32_to_cpu(agi->agi_freecount);
+ pag->pagi_count = be32_to_cpu(agi->agi_count);
pag->pagi_init = 1;
} else {
/*
@@ -1410,3 +1412,23 @@
*bpp = bp;
return 0;
}
+
+/*
+ * Read in the agi to initialise the per-ag data in the mount structure
+ */
+int
+xfs_ialloc_pagi_init(
+ xfs_mount_t *mp, /* file system mount structure */
+ xfs_trans_t *tp, /* transaction pointer */
+ xfs_agnumber_t agno) /* allocation group number */
+{
+ xfs_buf_t *bp = NULL;
+ int error;
+
+ error = xfs_ialloc_read_agi(mp, tp, agno, &bp);
+ if (error)
+ return error;
+ if (bp)
+ xfs_trans_brelse(tp, bp);
+ return 0;
+}
diff --git a/fs/xfs/xfs_ialloc.h b/fs/xfs/xfs_ialloc.h
index 7f5debe..97f4040 100644
--- a/fs/xfs/xfs_ialloc.h
+++ b/fs/xfs/xfs_ialloc.h
@@ -149,6 +149,16 @@
xfs_agnumber_t agno, /* allocation group number */
struct xfs_buf **bpp); /* allocation group hdr buf */
+/*
+ * Read in the allocation group header to initialise the per-ag data
+ * in the mount structure
+ */
+int
+xfs_ialloc_pagi_init(
+ struct xfs_mount *mp, /* file system mount structure */
+ struct xfs_trans *tp, /* transaction pointer */
+ xfs_agnumber_t agno); /* allocation group number */
+
#endif /* __KERNEL__ */
#endif /* __XFS_IALLOC_H__ */
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 3ca5d43..cdc4c28 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -48,7 +48,9 @@
#include "xfs_dir2_trace.h"
#include "xfs_quota.h"
#include "xfs_acl.h"
+#include "xfs_filestream.h"
+#include <linux/log2.h>
kmem_zone_t *xfs_ifork_zone;
kmem_zone_t *xfs_inode_zone;
@@ -643,8 +645,7 @@
ep->l1 = INT_GET(get_unaligned((__uint64_t*)&dp->l1),
ARCH_CONVERT);
}
- xfs_bmap_trace_exlist("xfs_iformat_extents", ip, nex,
- whichfork);
+ XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork);
if (whichfork != XFS_DATA_FORK ||
XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE)
if (unlikely(xfs_check_nostate_extents(
@@ -817,6 +818,8 @@
flags |= XFS_XFLAG_EXTSZINHERIT;
if (di_flags & XFS_DIFLAG_NODEFRAG)
flags |= XFS_XFLAG_NODEFRAG;
+ if (di_flags & XFS_DIFLAG_FILESTREAM)
+ flags |= XFS_XFLAG_FILESTREAM;
}
return flags;
@@ -1074,6 +1077,11 @@
* also returns the [locked] bp pointing to the head of the freelist
* as ialloc_context. The caller should hold this buffer across
* the commit and pass it back into this routine on the second call.
+ *
+ * If we are allocating quota inodes, we do not have a parent inode
+ * to attach to or associate with (i.e. pip == NULL) because they
+ * are not linked into the directory structure - they are attached
+ * directly to the superblock - and so have no parent.
*/
int
xfs_ialloc(
@@ -1099,7 +1107,7 @@
* Call the space management code to pick
* the on-disk inode to be allocated.
*/
- error = xfs_dialloc(tp, pip->i_ino, mode, okalloc,
+ error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc,
ialloc_context, call_again, &ino);
if (error != 0) {
return error;
@@ -1150,10 +1158,10 @@
/*
* Project ids won't be stored on disk if we are using a version 1 inode.
*/
- if ( (prid != 0) && (ip->i_d.di_version == XFS_DINODE_VERSION_1))
+ if ((prid != 0) && (ip->i_d.di_version == XFS_DINODE_VERSION_1))
xfs_bump_ino_vers2(tp, ip);
- if (XFS_INHERIT_GID(pip, vp->v_vfsp)) {
+ if (pip && XFS_INHERIT_GID(pip, vp->v_vfsp)) {
ip->i_d.di_gid = pip->i_d.di_gid;
if ((pip->i_d.di_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR) {
ip->i_d.di_mode |= S_ISGID;
@@ -1195,8 +1203,16 @@
flags |= XFS_ILOG_DEV;
break;
case S_IFREG:
+ if (pip && xfs_inode_is_filestream(pip)) {
+ error = xfs_filestream_associate(pip, ip);
+ if (error < 0)
+ return -error;
+ if (!error)
+ xfs_iflags_set(ip, XFS_IFILESTREAM);
+ }
+ /* fall through */
case S_IFDIR:
- if (unlikely(pip->i_d.di_flags & XFS_DIFLAG_ANY)) {
+ if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) {
uint di_flags = 0;
if ((mode & S_IFMT) == S_IFDIR) {
@@ -1233,6 +1249,8 @@
if ((pip->i_d.di_flags & XFS_DIFLAG_NODEFRAG) &&
xfs_inherit_nodefrag)
di_flags |= XFS_DIFLAG_NODEFRAG;
+ if (pip->i_d.di_flags & XFS_DIFLAG_FILESTREAM)
+ di_flags |= XFS_DIFLAG_FILESTREAM;
ip->i_d.di_flags |= di_flags;
}
/* FALLTHROUGH */
@@ -2875,9 +2893,6 @@
int copied;
xfs_bmbt_rec_t *dest_ep;
xfs_bmbt_rec_t *ep;
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_iextents_copy";
-#endif
int i;
xfs_ifork_t *ifp;
int nrecs;
@@ -2888,7 +2903,7 @@
ASSERT(ifp->if_bytes > 0);
nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
- xfs_bmap_trace_exlist(fname, ip, nrecs, whichfork);
+ XFS_BMAP_TRACE_EXLIST(ip, nrecs, whichfork);
ASSERT(nrecs > 0);
/*
@@ -4184,7 +4199,7 @@
ifp->if_bytes = new_size;
return;
}
- if ((new_size & (new_size - 1)) != 0) {
+ if (!is_power_of_2(new_size)){
rnew_size = xfs_iroundup(new_size);
}
if (rnew_size != ifp->if_real_bytes) {
@@ -4207,7 +4222,7 @@
*/
else {
new_size += ifp->if_bytes;
- if ((new_size & (new_size - 1)) != 0) {
+ if (!is_power_of_2(new_size)) {
rnew_size = xfs_iroundup(new_size);
}
xfs_iext_inline_to_direct(ifp, rnew_size);
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index f75afec..012dfd4 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -379,6 +379,7 @@
#define XFS_ISTALE 0x0010 /* inode has been staled */
#define XFS_IRECLAIMABLE 0x0020 /* inode can be reclaimed */
#define XFS_INEW 0x0040
+#define XFS_IFILESTREAM 0x0080 /* inode is in a filestream directory */
/*
* Flags for inode locking.
@@ -414,19 +415,22 @@
* gets a lockdep subclass of 1 and the second lock will have a lockdep
* subclass of 0.
*
- * XFS_I[O]LOCK_INUMORDER - for locking several inodes at the some time
+ * XFS_LOCK_INUMORDER - for locking several inodes at the some time
* with xfs_lock_inodes(). This flag is used as the starting subclass
* and each subsequent lock acquired will increment the subclass by one.
* So the first lock acquired will have a lockdep subclass of 2, the
- * second lock will have a lockdep subclass of 3, and so on.
+ * second lock will have a lockdep subclass of 3, and so on. It is
+ * the responsibility of the class builder to shift this to the correct
+ * portion of the lock_mode lockdep mask.
*/
+#define XFS_LOCK_PARENT 1
+#define XFS_LOCK_INUMORDER 2
+
#define XFS_IOLOCK_SHIFT 16
-#define XFS_IOLOCK_PARENT (1 << XFS_IOLOCK_SHIFT)
-#define XFS_IOLOCK_INUMORDER (2 << XFS_IOLOCK_SHIFT)
+#define XFS_IOLOCK_PARENT (XFS_LOCK_PARENT << XFS_IOLOCK_SHIFT)
#define XFS_ILOCK_SHIFT 24
-#define XFS_ILOCK_PARENT (1 << XFS_ILOCK_SHIFT)
-#define XFS_ILOCK_INUMORDER (2 << XFS_ILOCK_SHIFT)
+#define XFS_ILOCK_PARENT (XFS_LOCK_PARENT << XFS_ILOCK_SHIFT)
#define XFS_IOLOCK_DEP_MASK 0x00ff0000
#define XFS_ILOCK_DEP_MASK 0xff000000
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 3f2b9f2..bf57b75 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -451,19 +451,14 @@
return XFS_ERROR(error);
rt = XFS_IS_REALTIME_INODE(ip);
- if (unlikely(rt)) {
- if (!(extsz = ip->i_d.di_extsize))
- extsz = mp->m_sb.sb_rextsize;
- } else {
- extsz = ip->i_d.di_extsize;
- }
+ extsz = xfs_get_extsz_hint(ip);
isize = ip->i_size;
if (io->io_new_size > isize)
isize = io->io_new_size;
- offset_fsb = XFS_B_TO_FSBT(mp, offset);
- last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
+ offset_fsb = XFS_B_TO_FSBT(mp, offset);
+ last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
if ((offset + count) > isize) {
error = xfs_iomap_eof_align_last_fsb(mp, io, isize, extsz,
&last_fsb);
@@ -489,13 +484,13 @@
if (unlikely(rt)) {
resrtextents = qblocks = resaligned;
resrtextents /= mp->m_sb.sb_rextsize;
- resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
- quota_flag = XFS_QMOPT_RES_RTBLKS;
- } else {
- resrtextents = 0;
+ resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
+ quota_flag = XFS_QMOPT_RES_RTBLKS;
+ } else {
+ resrtextents = 0;
resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned);
- quota_flag = XFS_QMOPT_RES_REGBLKS;
- }
+ quota_flag = XFS_QMOPT_RES_REGBLKS;
+ }
/*
* Allocate and setup the transaction
@@ -666,13 +661,7 @@
if (error)
return XFS_ERROR(error);
- if (XFS_IS_REALTIME_INODE(ip)) {
- if (!(extsz = ip->i_d.di_extsize))
- extsz = mp->m_sb.sb_rextsize;
- } else {
- extsz = ip->i_d.di_extsize;
- }
-
+ extsz = xfs_get_extsz_hint(ip);
offset_fsb = XFS_B_TO_FSBT(mp, offset);
retry:
@@ -788,18 +777,12 @@
nimaps = 0;
while (nimaps == 0) {
tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
+ tp->t_flags |= XFS_TRANS_RESERVE;
nres = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK);
error = xfs_trans_reserve(tp, nres,
XFS_WRITE_LOG_RES(mp),
0, XFS_TRANS_PERM_LOG_RES,
XFS_WRITE_LOG_COUNT);
- if (error == ENOSPC) {
- error = xfs_trans_reserve(tp, 0,
- XFS_WRITE_LOG_RES(mp),
- 0,
- XFS_TRANS_PERM_LOG_RES,
- XFS_WRITE_LOG_COUNT);
- }
if (error) {
xfs_trans_cancel(tp, 0);
return XFS_ERROR(error);
@@ -917,8 +900,8 @@
* from unwritten to real. Do allocations in a loop until
* we have covered the range passed in.
*/
-
tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
+ tp->t_flags |= XFS_TRANS_RESERVE;
error = xfs_trans_reserve(tp, resblks,
XFS_WRITE_LOG_RES(mp), 0,
XFS_TRANS_PERM_LOG_RES,
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index e725ddd..4c2454b 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -202,6 +202,16 @@
return 0;
}
+STATIC int
+xfs_bulkstat_one_fmt(
+ void __user *ubuffer,
+ const xfs_bstat_t *buffer)
+{
+ if (copy_to_user(ubuffer, buffer, sizeof(*buffer)))
+ return -EFAULT;
+ return sizeof(*buffer);
+}
+
/*
* Return stat information for one inode.
* Return 0 if ok, else errno.
@@ -221,6 +231,7 @@
xfs_bstat_t *buf; /* return buffer */
int error = 0; /* error value */
xfs_dinode_t *dip; /* dinode inode pointer */
+ bulkstat_one_fmt_pf formatter = private_data ? : xfs_bulkstat_one_fmt;
dip = (xfs_dinode_t *)dibuff;
*stat = BULKSTAT_RV_NOTHING;
@@ -243,14 +254,15 @@
xfs_bulkstat_one_dinode(mp, ino, dip, buf);
}
- if (copy_to_user(buffer, buf, sizeof(*buf))) {
+ error = formatter(buffer, buf);
+ if (error < 0) {
error = EFAULT;
goto out_free;
}
*stat = BULKSTAT_RV_DIDONE;
if (ubused)
- *ubused = sizeof(*buf);
+ *ubused = error;
out_free:
kmem_free(buf, sizeof(*buf));
@@ -748,6 +760,19 @@
return 0;
}
+int
+xfs_inumbers_fmt(
+ void __user *ubuffer, /* buffer to write to */
+ const xfs_inogrp_t *buffer, /* buffer to read from */
+ long count, /* # of elements to read */
+ long *written) /* # of bytes written */
+{
+ if (copy_to_user(ubuffer, buffer, count * sizeof(*buffer)))
+ return -EFAULT;
+ *written = count * sizeof(*buffer);
+ return 0;
+}
+
/*
* Return inode number table for the filesystem.
*/
@@ -756,7 +781,8 @@
xfs_mount_t *mp, /* mount point for filesystem */
xfs_ino_t *lastino, /* last inode returned */
int *count, /* size of buffer/count returned */
- xfs_inogrp_t __user *ubuffer)/* buffer with inode descriptions */
+ void __user *ubuffer,/* buffer with inode descriptions */
+ inumbers_fmt_pf formatter)
{
xfs_buf_t *agbp;
xfs_agino_t agino;
@@ -835,12 +861,12 @@
bufidx++;
left--;
if (bufidx == bcount) {
- if (copy_to_user(ubuffer, buffer,
- bufidx * sizeof(*buffer))) {
+ long written;
+ if (formatter(ubuffer, buffer, bufidx, &written)) {
error = XFS_ERROR(EFAULT);
break;
}
- ubuffer += bufidx;
+ ubuffer += written;
*count += bufidx;
bufidx = 0;
}
@@ -862,8 +888,8 @@
}
if (!error) {
if (bufidx) {
- if (copy_to_user(ubuffer, buffer,
- bufidx * sizeof(*buffer)))
+ long written;
+ if (formatter(ubuffer, buffer, bufidx, &written))
error = XFS_ERROR(EFAULT);
else
*count += bufidx;
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
index f25a288..a1f18fc 100644
--- a/fs/xfs/xfs_itable.h
+++ b/fs/xfs/xfs_itable.h
@@ -69,6 +69,10 @@
char __user *buffer,
int *done);
+typedef int (*bulkstat_one_fmt_pf)( /* used size in bytes or negative error */
+ void __user *ubuffer, /* buffer to write to */
+ const xfs_bstat_t *buffer); /* buffer to read from */
+
int
xfs_bulkstat_one(
xfs_mount_t *mp,
@@ -86,11 +90,25 @@
xfs_mount_t *mp,
xfs_ino_t ino);
+typedef int (*inumbers_fmt_pf)(
+ void __user *ubuffer, /* buffer to write to */
+ const xfs_inogrp_t *buffer, /* buffer to read from */
+ long count, /* # of elements to read */
+ long *written); /* # of bytes written */
+
+int
+xfs_inumbers_fmt(
+ void __user *ubuffer, /* buffer to write to */
+ const xfs_inogrp_t *buffer, /* buffer to read from */
+ long count, /* # of elements to read */
+ long *written); /* # of bytes written */
+
int /* error status */
xfs_inumbers(
xfs_mount_t *mp, /* mount point for filesystem */
xfs_ino_t *last, /* last inode returned */
int *count, /* size of buffer/count returned */
- xfs_inogrp_t __user *buffer);/* buffer with inode info */
+ void __user *buffer, /* buffer with inode info */
+ inumbers_fmt_pf formatter);
#endif /* __XFS_ITABLE_H__ */
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index c48bf61..9d4c4fb 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -817,10 +817,8 @@
SPLDECL(s);
int needed = 0, gen;
xlog_t *log = mp->m_log;
- bhv_vfs_t *vfsp = XFS_MTOVFS(mp);
- if (vfs_test_for_freeze(vfsp) || XFS_FORCED_SHUTDOWN(mp) ||
- (vfsp->vfs_flag & VFS_RDONLY))
+ if (!xfs_fs_writable(mp))
return 0;
s = LOG_LOCK(log);
@@ -967,14 +965,16 @@
} else if (iclog->ic_state & XLOG_STATE_IOERROR) {
aborted = XFS_LI_ABORTED;
}
+
+ /* log I/O is always issued ASYNC */
+ ASSERT(XFS_BUF_ISASYNC(bp));
xlog_state_done_syncing(iclog, aborted);
- if (!(XFS_BUF_ISASYNC(bp))) {
- /*
- * Corresponding psema() will be done in bwrite(). If we don't
- * vsema() here, panic.
- */
- XFS_BUF_V_IODONESEMA(bp);
- }
+ /*
+ * do not reference the buffer (bp) here as we could race
+ * with it being freed after writing the unmount record to the
+ * log.
+ */
+
} /* xlog_iodone */
/*
@@ -1199,11 +1199,18 @@
*iclogp = (xlog_in_core_t *)
kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP);
iclog = *iclogp;
- iclog->hic_data = (xlog_in_core_2_t *)
- kmem_zalloc(iclogsize, KM_SLEEP | KM_LARGE);
-
iclog->ic_prev = prev_iclog;
prev_iclog = iclog;
+
+ bp = xfs_buf_get_noaddr(log->l_iclog_size, mp->m_logdev_targp);
+ if (!XFS_BUF_CPSEMA(bp))
+ ASSERT(0);
+ XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone);
+ XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb);
+ XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1);
+ iclog->ic_bp = bp;
+ iclog->hic_data = bp->b_addr;
+
log->l_iclog_bak[i] = (xfs_caddr_t)&(iclog->ic_header);
head = &iclog->ic_header;
@@ -1216,11 +1223,6 @@
INT_SET(head->h_fmt, ARCH_CONVERT, XLOG_FMT);
memcpy(&head->h_fs_uuid, &mp->m_sb.sb_uuid, sizeof(uuid_t));
- bp = xfs_buf_get_empty(log->l_iclog_size, mp->m_logdev_targp);
- XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone);
- XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb);
- XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1);
- iclog->ic_bp = bp;
iclog->ic_size = XFS_BUF_SIZE(bp) - log->l_iclog_hsize;
iclog->ic_state = XLOG_STATE_ACTIVE;
@@ -1432,7 +1434,7 @@
} else {
iclog->ic_bwritecnt = 1;
}
- XFS_BUF_SET_PTR(bp, (xfs_caddr_t) &(iclog->ic_header), count);
+ XFS_BUF_SET_COUNT(bp, count);
XFS_BUF_SET_FSPRIVATE(bp, iclog); /* save for later */
XFS_BUF_ZEROFLAGS(bp);
XFS_BUF_BUSY(bp);
@@ -1528,7 +1530,6 @@
}
#endif
next_iclog = iclog->ic_next;
- kmem_free(iclog->hic_data, log->l_iclog_size);
kmem_free(iclog, sizeof(xlog_in_core_t));
iclog = next_iclog;
}
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 080fabf..fddbb09 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -927,6 +927,14 @@
ASSIGN_ANY_LSN_HOST(log->l_last_sync_lsn, log->l_curr_cycle,
after_umount_blk);
*tail_blk = after_umount_blk;
+
+ /*
+ * Note that the unmount was clean. If the unmount
+ * was not clean, we need to know this to rebuild the
+ * superblock counters from the perag headers if we
+ * have a filesystem using non-persistent counters.
+ */
+ log->l_mp->m_flags |= XFS_MOUNT_WAS_CLEAN;
}
}
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index a96bde6..a66b398 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -202,6 +202,27 @@
kmem_free(mp, sizeof(xfs_mount_t));
}
+/*
+ * Check size of device based on the (data/realtime) block count.
+ * Note: this check is used by the growfs code as well as mount.
+ */
+int
+xfs_sb_validate_fsb_count(
+ xfs_sb_t *sbp,
+ __uint64_t nblocks)
+{
+ ASSERT(PAGE_SHIFT >= sbp->sb_blocklog);
+ ASSERT(sbp->sb_blocklog >= BBSHIFT);
+
+#if XFS_BIG_BLKNOS /* Limited by ULONG_MAX of page cache index */
+ if (nblocks >> (PAGE_CACHE_SHIFT - sbp->sb_blocklog) > ULONG_MAX)
+ return E2BIG;
+#else /* Limited by UINT_MAX of sectors */
+ if (nblocks << (sbp->sb_blocklog - BBSHIFT) > UINT_MAX)
+ return E2BIG;
+#endif
+ return 0;
+}
/*
* Check the validity of the SB found.
@@ -284,18 +305,8 @@
return XFS_ERROR(EFSCORRUPTED);
}
- ASSERT(PAGE_SHIFT >= sbp->sb_blocklog);
- ASSERT(sbp->sb_blocklog >= BBSHIFT);
-
-#if XFS_BIG_BLKNOS /* Limited by ULONG_MAX of page cache index */
- if (unlikely(
- (sbp->sb_dblocks >> (PAGE_SHIFT - sbp->sb_blocklog)) > ULONG_MAX ||
- (sbp->sb_rblocks >> (PAGE_SHIFT - sbp->sb_blocklog)) > ULONG_MAX)) {
-#else /* Limited by UINT_MAX of sectors */
- if (unlikely(
- (sbp->sb_dblocks << (sbp->sb_blocklog - BBSHIFT)) > UINT_MAX ||
- (sbp->sb_rblocks << (sbp->sb_blocklog - BBSHIFT)) > UINT_MAX)) {
-#endif
+ if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) ||
+ xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) {
xfs_fs_mount_cmn_err(flags,
"file system too large to be mounted on this system.");
return XFS_ERROR(E2BIG);
@@ -632,6 +643,64 @@
sbp->sb_inopblock);
mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog;
}
+
+/*
+ * xfs_initialize_perag_data
+ *
+ * Read in each per-ag structure so we can count up the number of
+ * allocated inodes, free inodes and used filesystem blocks as this
+ * information is no longer persistent in the superblock. Once we have
+ * this information, write it into the in-core superblock structure.
+ */
+STATIC int
+xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount)
+{
+ xfs_agnumber_t index;
+ xfs_perag_t *pag;
+ xfs_sb_t *sbp = &mp->m_sb;
+ uint64_t ifree = 0;
+ uint64_t ialloc = 0;
+ uint64_t bfree = 0;
+ uint64_t bfreelst = 0;
+ uint64_t btree = 0;
+ int error;
+ int s;
+
+ for (index = 0; index < agcount; index++) {
+ /*
+ * read the agf, then the agi. This gets us
+ * all the inforamtion we need and populates the
+ * per-ag structures for us.
+ */
+ error = xfs_alloc_pagf_init(mp, NULL, index, 0);
+ if (error)
+ return error;
+
+ error = xfs_ialloc_pagi_init(mp, NULL, index);
+ if (error)
+ return error;
+ pag = &mp->m_perag[index];
+ ifree += pag->pagi_freecount;
+ ialloc += pag->pagi_count;
+ bfree += pag->pagf_freeblks;
+ bfreelst += pag->pagf_flcount;
+ btree += pag->pagf_btreeblks;
+ }
+ /*
+ * Overwrite incore superblock counters with just-read data
+ */
+ s = XFS_SB_LOCK(mp);
+ sbp->sb_ifree = ifree;
+ sbp->sb_icount = ialloc;
+ sbp->sb_fdblocks = bfree + bfreelst + btree;
+ XFS_SB_UNLOCK(mp, s);
+
+ /* Fixup the per-cpu counters as well. */
+ xfs_icsb_reinit_counters(mp);
+
+ return 0;
+}
+
/*
* xfs_mountfs
*
@@ -656,7 +725,7 @@
bhv_vnode_t *rvp = NULL;
int readio_log, writeio_log;
xfs_daddr_t d;
- __uint64_t ret64;
+ __uint64_t resblks;
__int64_t update_flags;
uint quotamount, quotaflags;
int agno;
@@ -773,6 +842,7 @@
*/
if ((mfsi_flags & XFS_MFSI_SECOND) == 0 &&
(mp->m_flags & XFS_MOUNT_NOUUID) == 0) {
+ __uint64_t ret64;
if (xfs_uuid_mount(mp)) {
error = XFS_ERROR(EINVAL);
goto error1;
@@ -976,6 +1046,34 @@
}
/*
+ * Now the log is mounted, we know if it was an unclean shutdown or
+ * not. If it was, with the first phase of recovery has completed, we
+ * have consistent AG blocks on disk. We have not recovered EFIs yet,
+ * but they are recovered transactionally in the second recovery phase
+ * later.
+ *
+ * Hence we can safely re-initialise incore superblock counters from
+ * the per-ag data. These may not be correct if the filesystem was not
+ * cleanly unmounted, so we need to wait for recovery to finish before
+ * doing this.
+ *
+ * If the filesystem was cleanly unmounted, then we can trust the
+ * values in the superblock to be correct and we don't need to do
+ * anything here.
+ *
+ * If we are currently making the filesystem, the initialisation will
+ * fail as the perag data is in an undefined state.
+ */
+
+ if (xfs_sb_version_haslazysbcount(&mp->m_sb) &&
+ !XFS_LAST_UNMOUNT_WAS_CLEAN(mp) &&
+ !mp->m_sb.sb_inprogress) {
+ error = xfs_initialize_perag_data(mp, sbp->sb_agcount);
+ if (error) {
+ goto error2;
+ }
+ }
+ /*
* Get and sanity-check the root inode.
* Save the pointer to it in the mount structure.
*/
@@ -1044,6 +1142,23 @@
if ((error = XFS_QM_MOUNT(mp, quotamount, quotaflags, mfsi_flags)))
goto error4;
+ /*
+ * Now we are mounted, reserve a small amount of unused space for
+ * privileged transactions. This is needed so that transaction
+ * space required for critical operations can dip into this pool
+ * when at ENOSPC. This is needed for operations like create with
+ * attr, unwritten extent conversion at ENOSPC, etc. Data allocations
+ * are not allowed to use this reserved space.
+ *
+ * We default to 5% or 1024 fsbs of space reserved, whichever is smaller.
+ * This may drive us straight to ENOSPC on mount, but that implies
+ * we were already there on the last unmount.
+ */
+ resblks = mp->m_sb.sb_dblocks;
+ do_div(resblks, 20);
+ resblks = min_t(__uint64_t, resblks, 1024);
+ xfs_reserve_blocks(mp, &resblks, NULL);
+
return 0;
error4:
@@ -1083,7 +1198,19 @@
#if defined(DEBUG) || defined(INDUCE_IO_ERROR)
int64_t fsid;
#endif
+ __uint64_t resblks;
+ /*
+ * We can potentially deadlock here if we have an inode cluster
+ * that has been freed has it's buffer still pinned in memory because
+ * the transaction is still sitting in a iclog. The stale inodes
+ * on that buffer will have their flush locks held until the
+ * transaction hits the disk and the callbacks run. the inode
+ * flush takes the flush lock unconditionally and with nothing to
+ * push out the iclog we will never get that unlocked. hence we
+ * need to force the log first.
+ */
+ xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
xfs_iflush_all(mp);
XFS_QM_DQPURGEALL(mp, XFS_QMOPT_QUOTALL | XFS_QMOPT_UMOUNTING);
@@ -1100,10 +1227,26 @@
xfs_binval(mp->m_rtdev_targp);
}
+ /*
+ * Unreserve any blocks we have so that when we unmount we don't account
+ * the reserved free space as used. This is really only necessary for
+ * lazy superblock counting because it trusts the incore superblock
+ * counters to be aboslutely correct on clean unmount.
+ *
+ * We don't bother correcting this elsewhere for lazy superblock
+ * counting because on mount of an unclean filesystem we reconstruct the
+ * correct counter value and this is irrelevant.
+ *
+ * For non-lazy counter filesystems, this doesn't matter at all because
+ * we only every apply deltas to the superblock and hence the incore
+ * value does not matter....
+ */
+ resblks = 0;
+ xfs_reserve_blocks(mp, &resblks, NULL);
+
+ xfs_log_sbcount(mp, 1);
xfs_unmountfs_writesb(mp);
-
xfs_unmountfs_wait(mp); /* wait for async bufs */
-
xfs_log_unmount(mp); /* Done! No more fs ops. */
xfs_freesb(mp);
@@ -1150,6 +1293,62 @@
}
int
+xfs_fs_writable(xfs_mount_t *mp)
+{
+ bhv_vfs_t *vfsp = XFS_MTOVFS(mp);
+
+ return !(vfs_test_for_freeze(vfsp) || XFS_FORCED_SHUTDOWN(mp) ||
+ (vfsp->vfs_flag & VFS_RDONLY));
+}
+
+/*
+ * xfs_log_sbcount
+ *
+ * Called either periodically to keep the on disk superblock values
+ * roughly up to date or from unmount to make sure the values are
+ * correct on a clean unmount.
+ *
+ * Note this code can be called during the process of freezing, so
+ * we may need to use the transaction allocator which does not not
+ * block when the transaction subsystem is in its frozen state.
+ */
+int
+xfs_log_sbcount(
+ xfs_mount_t *mp,
+ uint sync)
+{
+ xfs_trans_t *tp;
+ int error;
+
+ if (!xfs_fs_writable(mp))
+ return 0;
+
+ xfs_icsb_sync_counters(mp);
+
+ /*
+ * we don't need to do this if we are updating the superblock
+ * counters on every modification.
+ */
+ if (!xfs_sb_version_haslazysbcount(&mp->m_sb))
+ return 0;
+
+ tp = _xfs_trans_alloc(mp, XFS_TRANS_SB_COUNT);
+ error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
+ XFS_DEFAULT_LOG_COUNT);
+ if (error) {
+ xfs_trans_cancel(tp, 0);
+ return error;
+ }
+
+ xfs_mod_sb(tp, XFS_SB_IFREE | XFS_SB_ICOUNT | XFS_SB_FDBLOCKS);
+ if (sync)
+ xfs_trans_set_sync(tp);
+ xfs_trans_commit(tp, 0);
+
+ return 0;
+}
+
+int
xfs_unmountfs_writesb(xfs_mount_t *mp)
{
xfs_buf_t *sbp;
@@ -1160,16 +1359,15 @@
* skip superblock write if fs is read-only, or
* if we are doing a forced umount.
*/
- sbp = xfs_getsb(mp, 0);
if (!(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY ||
XFS_FORCED_SHUTDOWN(mp))) {
- xfs_icsb_sync_counters(mp);
+ sbp = xfs_getsb(mp, 0);
+ sb = XFS_BUF_TO_SBP(sbp);
/*
* mark shared-readonly if desired
*/
- sb = XFS_BUF_TO_SBP(sbp);
if (mp->m_mk_sharedro) {
if (!(sb->sb_flags & XFS_SBF_READONLY))
sb->sb_flags |= XFS_SBF_READONLY;
@@ -1178,6 +1376,7 @@
xfs_fs_cmn_err(CE_NOTE, mp,
"Unmounting, marking shared read-only");
}
+
XFS_BUF_UNDONE(sbp);
XFS_BUF_UNREAD(sbp);
XFS_BUF_UNDELAYWRITE(sbp);
@@ -1192,8 +1391,8 @@
mp, sbp, XFS_BUF_ADDR(sbp));
if (error && mp->m_mk_sharedro)
xfs_fs_cmn_err(CE_ALERT, mp, "Superblock write error detected while unmounting. Filesystem may not be marked shared readonly");
+ xfs_buf_relse(sbp);
}
- xfs_buf_relse(sbp);
return error;
}
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 82304b9..76ad747 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -66,6 +66,7 @@
struct xfs_bmap_free;
struct xfs_extdelta;
struct xfs_swapext;
+struct xfs_mru_cache;
extern struct bhv_vfsops xfs_vfsops;
extern struct bhv_vnodeops xfs_vnodeops;
@@ -424,17 +425,18 @@
struct notifier_block m_icsb_notifier; /* hotplug cpu notifier */
struct mutex m_icsb_mutex; /* balancer sync lock */
#endif
+ struct xfs_mru_cache *m_filestream; /* per-mount filestream data */
} xfs_mount_t;
/*
* Flags for m_flags.
*/
-#define XFS_MOUNT_WSYNC (1ULL << 0) /* for nfs - all metadata ops
+#define XFS_MOUNT_WSYNC (1ULL << 0) /* for nfs - all metadata ops
must be synchronous except
for space allocations */
-#define XFS_MOUNT_INO64 (1ULL << 1)
+#define XFS_MOUNT_INO64 (1ULL << 1)
/* (1ULL << 2) -- currently unused */
- /* (1ULL << 3) -- currently unused */
+#define XFS_MOUNT_WAS_CLEAN (1ULL << 3)
#define XFS_MOUNT_FS_SHUTDOWN (1ULL << 4) /* atomic stop of all filesystem
operations, typically for
disk errors in metadata */
@@ -463,6 +465,8 @@
* I/O size in stat() */
#define XFS_MOUNT_NO_PERCPU_SB (1ULL << 23) /* don't use per-cpu superblock
counters */
+#define XFS_MOUNT_FILESTREAMS (1ULL << 24) /* enable the filestreams
+ allocator */
/*
@@ -511,6 +515,8 @@
#define XFS_MAXIOFFSET(mp) ((mp)->m_maxioffset)
+#define XFS_LAST_UNMOUNT_WAS_CLEAN(mp) \
+ ((mp)->m_flags & XFS_MOUNT_WAS_CLEAN)
#define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN)
#define xfs_force_shutdown(m,f) \
bhv_vfs_force_shutdown((XFS_MTOVFS(m)), f, __FILE__, __LINE__)
@@ -602,6 +608,7 @@
extern xfs_mount_t *xfs_mount_init(void);
extern void xfs_mod_sb(xfs_trans_t *, __int64_t);
+extern int xfs_log_sbcount(xfs_mount_t *, uint);
extern void xfs_mount_free(xfs_mount_t *mp, int remove_bhv);
extern int xfs_mountfs(struct bhv_vfs *, xfs_mount_t *mp, int);
extern void xfs_mountfs_check_barriers(xfs_mount_t *mp);
@@ -618,12 +625,14 @@
extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
extern int xfs_readsb(xfs_mount_t *, int);
extern void xfs_freesb(xfs_mount_t *);
+extern int xfs_fs_writable(xfs_mount_t *);
extern void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int);
extern int xfs_syncsub(xfs_mount_t *, int, int *);
extern int xfs_sync_inodes(xfs_mount_t *, int, int *);
extern xfs_agnumber_t xfs_initialize_perag(struct bhv_vfs *, xfs_mount_t *,
xfs_agnumber_t);
extern void xfs_xlatesb(void *, struct xfs_sb *, int, __int64_t);
+extern int xfs_sb_validate_fsb_count(struct xfs_sb *, __uint64_t);
extern struct xfs_dmops xfs_dmcore_stub;
extern struct xfs_qmops xfs_qmcore_stub;
diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c
new file mode 100644
index 0000000..7deb9e3
--- /dev/null
+++ b/fs/xfs/xfs_mru_cache.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 2006-2007 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would 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; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "xfs.h"
+#include "xfs_mru_cache.h"
+
+/*
+ * The MRU Cache data structure consists of a data store, an array of lists and
+ * a lock to protect its internal state. At initialisation time, the client
+ * supplies an element lifetime in milliseconds and a group count, as well as a
+ * function pointer to call when deleting elements. A data structure for
+ * queueing up work in the form of timed callbacks is also included.
+ *
+ * The group count controls how many lists are created, and thereby how finely
+ * the elements are grouped in time. When reaping occurs, all the elements in
+ * all the lists whose time has expired are deleted.
+ *
+ * To give an example of how this works in practice, consider a client that
+ * initialises an MRU Cache with a lifetime of ten seconds and a group count of
+ * five. Five internal lists will be created, each representing a two second
+ * period in time. When the first element is added, time zero for the data
+ * structure is initialised to the current time.
+ *
+ * All the elements added in the first two seconds are appended to the first
+ * list. Elements added in the third second go into the second list, and so on.
+ * If an element is accessed at any point, it is removed from its list and
+ * inserted at the head of the current most-recently-used list.
+ *
+ * The reaper function will have nothing to do until at least twelve seconds
+ * have elapsed since the first element was added. The reason for this is that
+ * if it were called at t=11s, there could be elements in the first list that
+ * have only been inactive for nine seconds, so it still does nothing. If it is
+ * called anywhere between t=12 and t=14 seconds, it will delete all the
+ * elements that remain in the first list. It's therefore possible for elements
+ * to remain in the data store even after they've been inactive for up to
+ * (t + t/g) seconds, where t is the inactive element lifetime and g is the
+ * number of groups.
+ *
+ * The above example assumes that the reaper function gets called at least once
+ * every (t/g) seconds. If it is called less frequently, unused elements will
+ * accumulate in the reap list until the reaper function is eventually called.
+ * The current implementation uses work queue callbacks to carefully time the
+ * reaper function calls, so this should happen rarely, if at all.
+ *
+ * From a design perspective, the primary reason for the choice of a list array
+ * representing discrete time intervals is that it's only practical to reap
+ * expired elements in groups of some appreciable size. This automatically
+ * introduces a granularity to element lifetimes, so there's no point storing an
+ * individual timeout with each element that specifies a more precise reap time.
+ * The bonus is a saving of sizeof(long) bytes of memory per element stored.
+ *
+ * The elements could have been stored in just one list, but an array of
+ * counters or pointers would need to be maintained to allow them to be divided
+ * up into discrete time groups. More critically, the process of touching or
+ * removing an element would involve walking large portions of the entire list,
+ * which would have a detrimental effect on performance. The additional memory
+ * requirement for the array of list heads is minimal.
+ *
+ * When an element is touched or deleted, it needs to be removed from its
+ * current list. Doubly linked lists are used to make the list maintenance
+ * portion of these operations O(1). Since reaper timing can be imprecise,
+ * inserts and lookups can occur when there are no free lists available. When
+ * this happens, all the elements on the LRU list need to be migrated to the end
+ * of the reap list. To keep the list maintenance portion of these operations
+ * O(1) also, list tails need to be accessible without walking the entire list.
+ * This is the reason why doubly linked list heads are used.
+ */
+
+/*
+ * An MRU Cache is a dynamic data structure that stores its elements in a way
+ * that allows efficient lookups, but also groups them into discrete time
+ * intervals based on insertion time. This allows elements to be efficiently
+ * and automatically reaped after a fixed period of inactivity.
+ *
+ * When a client data pointer is stored in the MRU Cache it needs to be added to
+ * both the data store and to one of the lists. It must also be possible to
+ * access each of these entries via the other, i.e. to:
+ *
+ * a) Walk a list, removing the corresponding data store entry for each item.
+ * b) Look up a data store entry, then access its list entry directly.
+ *
+ * To achieve both of these goals, each entry must contain both a list entry and
+ * a key, in addition to the user's data pointer. Note that it's not a good
+ * idea to have the client embed one of these structures at the top of their own
+ * data structure, because inserting the same item more than once would most
+ * likely result in a loop in one of the lists. That's a sure-fire recipe for
+ * an infinite loop in the code.
+ */
+typedef struct xfs_mru_cache_elem
+{
+ struct list_head list_node;
+ unsigned long key;
+ void *value;
+} xfs_mru_cache_elem_t;
+
+static kmem_zone_t *xfs_mru_elem_zone;
+static struct workqueue_struct *xfs_mru_reap_wq;
+
+/*
+ * When inserting, destroying or reaping, it's first necessary to update the
+ * lists relative to a particular time. In the case of destroying, that time
+ * will be well in the future to ensure that all items are moved to the reap
+ * list. In all other cases though, the time will be the current time.
+ *
+ * This function enters a loop, moving the contents of the LRU list to the reap
+ * list again and again until either a) the lists are all empty, or b) time zero
+ * has been advanced sufficiently to be within the immediate element lifetime.
+ *
+ * Case a) above is detected by counting how many groups are migrated and
+ * stopping when they've all been moved. Case b) is detected by monitoring the
+ * time_zero field, which is updated as each group is migrated.
+ *
+ * The return value is the earliest time that more migration could be needed, or
+ * zero if there's no need to schedule more work because the lists are empty.
+ */
+STATIC unsigned long
+_xfs_mru_cache_migrate(
+ xfs_mru_cache_t *mru,
+ unsigned long now)
+{
+ unsigned int grp;
+ unsigned int migrated = 0;
+ struct list_head *lru_list;
+
+ /* Nothing to do if the data store is empty. */
+ if (!mru->time_zero)
+ return 0;
+
+ /* While time zero is older than the time spanned by all the lists. */
+ while (mru->time_zero <= now - mru->grp_count * mru->grp_time) {
+
+ /*
+ * If the LRU list isn't empty, migrate its elements to the tail
+ * of the reap list.
+ */
+ lru_list = mru->lists + mru->lru_grp;
+ if (!list_empty(lru_list))
+ list_splice_init(lru_list, mru->reap_list.prev);
+
+ /*
+ * Advance the LRU group number, freeing the old LRU list to
+ * become the new MRU list; advance time zero accordingly.
+ */
+ mru->lru_grp = (mru->lru_grp + 1) % mru->grp_count;
+ mru->time_zero += mru->grp_time;
+
+ /*
+ * If reaping is so far behind that all the elements on all the
+ * lists have been migrated to the reap list, it's now empty.
+ */
+ if (++migrated == mru->grp_count) {
+ mru->lru_grp = 0;
+ mru->time_zero = 0;
+ return 0;
+ }
+ }
+
+ /* Find the first non-empty list from the LRU end. */
+ for (grp = 0; grp < mru->grp_count; grp++) {
+
+ /* Check the grp'th list from the LRU end. */
+ lru_list = mru->lists + ((mru->lru_grp + grp) % mru->grp_count);
+ if (!list_empty(lru_list))
+ return mru->time_zero +
+ (mru->grp_count + grp) * mru->grp_time;
+ }
+
+ /* All the lists must be empty. */
+ mru->lru_grp = 0;
+ mru->time_zero = 0;
+ return 0;
+}
+
+/*
+ * When inserting or doing a lookup, an element needs to be inserted into the
+ * MRU list. The lists must be migrated first to ensure that they're
+ * up-to-date, otherwise the new element could be given a shorter lifetime in
+ * the cache than it should.
+ */
+STATIC void
+_xfs_mru_cache_list_insert(
+ xfs_mru_cache_t *mru,
+ xfs_mru_cache_elem_t *elem)
+{
+ unsigned int grp = 0;
+ unsigned long now = jiffies;
+
+ /*
+ * If the data store is empty, initialise time zero, leave grp set to
+ * zero and start the work queue timer if necessary. Otherwise, set grp
+ * to the number of group times that have elapsed since time zero.
+ */
+ if (!_xfs_mru_cache_migrate(mru, now)) {
+ mru->time_zero = now;
+ if (!mru->next_reap)
+ mru->next_reap = mru->grp_count * mru->grp_time;
+ } else {
+ grp = (now - mru->time_zero) / mru->grp_time;
+ grp = (mru->lru_grp + grp) % mru->grp_count;
+ }
+
+ /* Insert the element at the tail of the corresponding list. */
+ list_add_tail(&elem->list_node, mru->lists + grp);
+}
+
+/*
+ * When destroying or reaping, all the elements that were migrated to the reap
+ * list need to be deleted. For each element this involves removing it from the
+ * data store, removing it from the reap list, calling the client's free
+ * function and deleting the element from the element zone.
+ */
+STATIC void
+_xfs_mru_cache_clear_reap_list(
+ xfs_mru_cache_t *mru)
+{
+ xfs_mru_cache_elem_t *elem, *next;
+ struct list_head tmp;
+
+ INIT_LIST_HEAD(&tmp);
+ list_for_each_entry_safe(elem, next, &mru->reap_list, list_node) {
+
+ /* Remove the element from the data store. */
+ radix_tree_delete(&mru->store, elem->key);
+
+ /*
+ * remove to temp list so it can be freed without
+ * needing to hold the lock
+ */
+ list_move(&elem->list_node, &tmp);
+ }
+ mutex_spinunlock(&mru->lock, 0);
+
+ list_for_each_entry_safe(elem, next, &tmp, list_node) {
+
+ /* Remove the element from the reap list. */
+ list_del_init(&elem->list_node);
+
+ /* Call the client's free function with the key and value pointer. */
+ mru->free_func(elem->key, elem->value);
+
+ /* Free the element structure. */
+ kmem_zone_free(xfs_mru_elem_zone, elem);
+ }
+
+ mutex_spinlock(&mru->lock);
+}
+
+/*
+ * We fire the reap timer every group expiry interval so
+ * we always have a reaper ready to run. This makes shutdown
+ * and flushing of the reaper easy to do. Hence we need to
+ * keep when the next reap must occur so we can determine
+ * at each interval whether there is anything we need to do.
+ */
+STATIC void
+_xfs_mru_cache_reap(
+ struct work_struct *work)
+{
+ xfs_mru_cache_t *mru = container_of(work, xfs_mru_cache_t, work.work);
+ unsigned long now;
+
+ ASSERT(mru && mru->lists);
+ if (!mru || !mru->lists)
+ return;
+
+ mutex_spinlock(&mru->lock);
+ now = jiffies;
+ if (mru->reap_all ||
+ (mru->next_reap && time_after(now, mru->next_reap))) {
+ if (mru->reap_all)
+ now += mru->grp_count * mru->grp_time * 2;
+ mru->next_reap = _xfs_mru_cache_migrate(mru, now);
+ _xfs_mru_cache_clear_reap_list(mru);
+ }
+
+ /*
+ * the process that triggered the reap_all is responsible
+ * for restating the periodic reap if it is required.
+ */
+ if (!mru->reap_all)
+ queue_delayed_work(xfs_mru_reap_wq, &mru->work, mru->grp_time);
+ mru->reap_all = 0;
+ mutex_spinunlock(&mru->lock, 0);
+}
+
+int
+xfs_mru_cache_init(void)
+{
+ xfs_mru_elem_zone = kmem_zone_init(sizeof(xfs_mru_cache_elem_t),
+ "xfs_mru_cache_elem");
+ if (!xfs_mru_elem_zone)
+ return ENOMEM;
+
+ xfs_mru_reap_wq = create_singlethread_workqueue("xfs_mru_cache");
+ if (!xfs_mru_reap_wq) {
+ kmem_zone_destroy(xfs_mru_elem_zone);
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+void
+xfs_mru_cache_uninit(void)
+{
+ destroy_workqueue(xfs_mru_reap_wq);
+ kmem_zone_destroy(xfs_mru_elem_zone);
+}
+
+/*
+ * To initialise a struct xfs_mru_cache pointer, call xfs_mru_cache_create()
+ * with the address of the pointer, a lifetime value in milliseconds, a group
+ * count and a free function to use when deleting elements. This function
+ * returns 0 if the initialisation was successful.
+ */
+int
+xfs_mru_cache_create(
+ xfs_mru_cache_t **mrup,
+ unsigned int lifetime_ms,
+ unsigned int grp_count,
+ xfs_mru_cache_free_func_t free_func)
+{
+ xfs_mru_cache_t *mru = NULL;
+ int err = 0, grp;
+ unsigned int grp_time;
+
+ if (mrup)
+ *mrup = NULL;
+
+ if (!mrup || !grp_count || !lifetime_ms || !free_func)
+ return EINVAL;
+
+ if (!(grp_time = msecs_to_jiffies(lifetime_ms) / grp_count))
+ return EINVAL;
+
+ if (!(mru = kmem_zalloc(sizeof(*mru), KM_SLEEP)))
+ return ENOMEM;
+
+ /* An extra list is needed to avoid reaping up to a grp_time early. */
+ mru->grp_count = grp_count + 1;
+ mru->lists = kmem_alloc(mru->grp_count * sizeof(*mru->lists), KM_SLEEP);
+
+ if (!mru->lists) {
+ err = ENOMEM;
+ goto exit;
+ }
+
+ for (grp = 0; grp < mru->grp_count; grp++)
+ INIT_LIST_HEAD(mru->lists + grp);
+
+ /*
+ * We use GFP_KERNEL radix tree preload and do inserts under a
+ * spinlock so GFP_ATOMIC is appropriate for the radix tree itself.
+ */
+ INIT_RADIX_TREE(&mru->store, GFP_ATOMIC);
+ INIT_LIST_HEAD(&mru->reap_list);
+ spinlock_init(&mru->lock, "xfs_mru_cache");
+ INIT_DELAYED_WORK(&mru->work, _xfs_mru_cache_reap);
+
+ mru->grp_time = grp_time;
+ mru->free_func = free_func;
+
+ /* start up the reaper event */
+ mru->next_reap = 0;
+ mru->reap_all = 0;
+ queue_delayed_work(xfs_mru_reap_wq, &mru->work, mru->grp_time);
+
+ *mrup = mru;
+
+exit:
+ if (err && mru && mru->lists)
+ kmem_free(mru->lists, mru->grp_count * sizeof(*mru->lists));
+ if (err && mru)
+ kmem_free(mru, sizeof(*mru));
+
+ return err;
+}
+
+/*
+ * Call xfs_mru_cache_flush() to flush out all cached entries, calling their
+ * free functions as they're deleted. When this function returns, the caller is
+ * guaranteed that all the free functions for all the elements have finished
+ * executing.
+ *
+ * While we are flushing, we stop the periodic reaper event from triggering.
+ * Normally, we want to restart this periodic event, but if we are shutting
+ * down the cache we do not want it restarted. hence the restart parameter
+ * where 0 = do not restart reaper and 1 = restart reaper.
+ */
+void
+xfs_mru_cache_flush(
+ xfs_mru_cache_t *mru,
+ int restart)
+{
+ if (!mru || !mru->lists)
+ return;
+
+ cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work);
+
+ mutex_spinlock(&mru->lock);
+ mru->reap_all = 1;
+ mutex_spinunlock(&mru->lock, 0);
+
+ queue_work(xfs_mru_reap_wq, &mru->work.work);
+ flush_workqueue(xfs_mru_reap_wq);
+
+ mutex_spinlock(&mru->lock);
+ WARN_ON_ONCE(mru->reap_all != 0);
+ mru->reap_all = 0;
+ if (restart)
+ queue_delayed_work(xfs_mru_reap_wq, &mru->work, mru->grp_time);
+ mutex_spinunlock(&mru->lock, 0);
+}
+
+void
+xfs_mru_cache_destroy(
+ xfs_mru_cache_t *mru)
+{
+ if (!mru || !mru->lists)
+ return;
+
+ /* we don't want the reaper to restart here */
+ xfs_mru_cache_flush(mru, 0);
+
+ kmem_free(mru->lists, mru->grp_count * sizeof(*mru->lists));
+ kmem_free(mru, sizeof(*mru));
+}
+
+/*
+ * To insert an element, call xfs_mru_cache_insert() with the data store, the
+ * element's key and the client data pointer. This function returns 0 on
+ * success or ENOMEM if memory for the data element couldn't be allocated.
+ */
+int
+xfs_mru_cache_insert(
+ xfs_mru_cache_t *mru,
+ unsigned long key,
+ void *value)
+{
+ xfs_mru_cache_elem_t *elem;
+
+ ASSERT(mru && mru->lists);
+ if (!mru || !mru->lists)
+ return EINVAL;
+
+ elem = kmem_zone_zalloc(xfs_mru_elem_zone, KM_SLEEP);
+ if (!elem)
+ return ENOMEM;
+
+ if (radix_tree_preload(GFP_KERNEL)) {
+ kmem_zone_free(xfs_mru_elem_zone, elem);
+ return ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&elem->list_node);
+ elem->key = key;
+ elem->value = value;
+
+ mutex_spinlock(&mru->lock);
+
+ radix_tree_insert(&mru->store, key, elem);
+ radix_tree_preload_end();
+ _xfs_mru_cache_list_insert(mru, elem);
+
+ mutex_spinunlock(&mru->lock, 0);
+
+ return 0;
+}
+
+/*
+ * To remove an element without calling the free function, call
+ * xfs_mru_cache_remove() with the data store and the element's key. On success
+ * the client data pointer for the removed element is returned, otherwise this
+ * function will return a NULL pointer.
+ */
+void *
+xfs_mru_cache_remove(
+ xfs_mru_cache_t *mru,
+ unsigned long key)
+{
+ xfs_mru_cache_elem_t *elem;
+ void *value = NULL;
+
+ ASSERT(mru && mru->lists);
+ if (!mru || !mru->lists)
+ return NULL;
+
+ mutex_spinlock(&mru->lock);
+ elem = radix_tree_delete(&mru->store, key);
+ if (elem) {
+ value = elem->value;
+ list_del(&elem->list_node);
+ }
+
+ mutex_spinunlock(&mru->lock, 0);
+
+ if (elem)
+ kmem_zone_free(xfs_mru_elem_zone, elem);
+
+ return value;
+}
+
+/*
+ * To remove and element and call the free function, call xfs_mru_cache_delete()
+ * with the data store and the element's key.
+ */
+void
+xfs_mru_cache_delete(
+ xfs_mru_cache_t *mru,
+ unsigned long key)
+{
+ void *value = xfs_mru_cache_remove(mru, key);
+
+ if (value)
+ mru->free_func(key, value);
+}
+
+/*
+ * To look up an element using its key, call xfs_mru_cache_lookup() with the
+ * data store and the element's key. If found, the element will be moved to the
+ * head of the MRU list to indicate that it's been touched.
+ *
+ * The internal data structures are protected by a spinlock that is STILL HELD
+ * when this function returns. Call xfs_mru_cache_done() to release it. Note
+ * that it is not safe to call any function that might sleep in the interim.
+ *
+ * The implementation could have used reference counting to avoid this
+ * restriction, but since most clients simply want to get, set or test a member
+ * of the returned data structure, the extra per-element memory isn't warranted.
+ *
+ * If the element isn't found, this function returns NULL and the spinlock is
+ * released. xfs_mru_cache_done() should NOT be called when this occurs.
+ */
+void *
+xfs_mru_cache_lookup(
+ xfs_mru_cache_t *mru,
+ unsigned long key)
+{
+ xfs_mru_cache_elem_t *elem;
+
+ ASSERT(mru && mru->lists);
+ if (!mru || !mru->lists)
+ return NULL;
+
+ mutex_spinlock(&mru->lock);
+ elem = radix_tree_lookup(&mru->store, key);
+ if (elem) {
+ list_del(&elem->list_node);
+ _xfs_mru_cache_list_insert(mru, elem);
+ }
+ else
+ mutex_spinunlock(&mru->lock, 0);
+
+ return elem ? elem->value : NULL;
+}
+
+/*
+ * To look up an element using its key, but leave its location in the internal
+ * lists alone, call xfs_mru_cache_peek(). If the element isn't found, this
+ * function returns NULL.
+ *
+ * See the comments above the declaration of the xfs_mru_cache_lookup() function
+ * for important locking information pertaining to this call.
+ */
+void *
+xfs_mru_cache_peek(
+ xfs_mru_cache_t *mru,
+ unsigned long key)
+{
+ xfs_mru_cache_elem_t *elem;
+
+ ASSERT(mru && mru->lists);
+ if (!mru || !mru->lists)
+ return NULL;
+
+ mutex_spinlock(&mru->lock);
+ elem = radix_tree_lookup(&mru->store, key);
+ if (!elem)
+ mutex_spinunlock(&mru->lock, 0);
+
+ return elem ? elem->value : NULL;
+}
+
+/*
+ * To release the internal data structure spinlock after having performed an
+ * xfs_mru_cache_lookup() or an xfs_mru_cache_peek(), call xfs_mru_cache_done()
+ * with the data store pointer.
+ */
+void
+xfs_mru_cache_done(
+ xfs_mru_cache_t *mru)
+{
+ mutex_spinunlock(&mru->lock, 0);
+}
diff --git a/fs/xfs/xfs_mru_cache.h b/fs/xfs/xfs_mru_cache.h
new file mode 100644
index 0000000..624fd10
--- /dev/null
+++ b/fs/xfs/xfs_mru_cache.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2006-2007 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would 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; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __XFS_MRU_CACHE_H__
+#define __XFS_MRU_CACHE_H__
+
+
+/* Function pointer type for callback to free a client's data pointer. */
+typedef void (*xfs_mru_cache_free_func_t)(unsigned long, void*);
+
+typedef struct xfs_mru_cache
+{
+ struct radix_tree_root store; /* Core storage data structure. */
+ struct list_head *lists; /* Array of lists, one per grp. */
+ struct list_head reap_list; /* Elements overdue for reaping. */
+ spinlock_t lock; /* Lock to protect this struct. */
+ unsigned int grp_count; /* Number of discrete groups. */
+ unsigned int grp_time; /* Time period spanned by grps. */
+ unsigned int lru_grp; /* Group containing time zero. */
+ unsigned long time_zero; /* Time first element was added. */
+ unsigned long next_reap; /* Time that the reaper should
+ next do something. */
+ unsigned int reap_all; /* if set, reap all lists */
+ xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */
+ struct delayed_work work; /* Workqueue data for reaping. */
+} xfs_mru_cache_t;
+
+int xfs_mru_cache_init(void);
+void xfs_mru_cache_uninit(void);
+int xfs_mru_cache_create(struct xfs_mru_cache **mrup, unsigned int lifetime_ms,
+ unsigned int grp_count,
+ xfs_mru_cache_free_func_t free_func);
+void xfs_mru_cache_flush(xfs_mru_cache_t *mru, int restart);
+void xfs_mru_cache_destroy(struct xfs_mru_cache *mru);
+int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key,
+ void *value);
+void * xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key);
+void xfs_mru_cache_delete(struct xfs_mru_cache *mru, unsigned long key);
+void *xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key);
+void *xfs_mru_cache_peek(struct xfs_mru_cache *mru, unsigned long key);
+void xfs_mru_cache_done(struct xfs_mru_cache *mru);
+
+#endif /* __XFS_MRU_CACHE_H__ */
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index b3a5f07..47082c0 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -1882,11 +1882,13 @@
(nrblocks = in->newblocks) <= sbp->sb_rblocks ||
(sbp->sb_rblocks && (in->extsize != sbp->sb_rextsize)))
return XFS_ERROR(EINVAL);
+ if ((error = xfs_sb_validate_fsb_count(sbp, nrblocks)))
+ return error;
/*
* Read in the last block of the device, make sure it exists.
*/
error = xfs_read_buf(mp, mp->m_rtdev_targp,
- XFS_FSB_TO_BB(mp, in->newblocks - 1),
+ XFS_FSB_TO_BB(mp, nrblocks - 1),
XFS_FSB_TO_BB(mp, 1), 0, &bp);
if (error)
return error;
diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h
index 188b296..fcf28db 100644
--- a/fs/xfs/xfs_rw.h
+++ b/fs/xfs/xfs_rw.h
@@ -72,6 +72,34 @@
}
/*
+ * Flags for xfs_free_eofblocks
+ */
+#define XFS_FREE_EOF_LOCK (1<<0)
+#define XFS_FREE_EOF_NOLOCK (1<<1)
+
+
+/*
+ * helper function to extract extent size hint from inode
+ */
+STATIC_INLINE xfs_extlen_t
+xfs_get_extsz_hint(
+ xfs_inode_t *ip)
+{
+ xfs_extlen_t extsz;
+
+ if (unlikely(ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) {
+ extsz = (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)
+ ? ip->i_d.di_extsize
+ : ip->i_mount->m_sb.sb_rextsize;
+ ASSERT(extsz);
+ } else {
+ extsz = (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)
+ ? ip->i_d.di_extsize : 0;
+ }
+ return extsz;
+}
+
+/*
* Prototypes for functions in xfs_rw.c.
*/
extern int xfs_write_clear_setuid(struct xfs_inode *ip);
@@ -91,10 +119,12 @@
extern int xfs_rwlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock);
extern void xfs_rwunlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock);
extern int xfs_setattr(bhv_desc_t *, bhv_vattr_t *vap, int flags,
- cred_t *credp);
+ cred_t *credp);
extern int xfs_change_file_space(bhv_desc_t *bdp, int cmd, xfs_flock64_t *bf,
- xfs_off_t offset, cred_t *credp, int flags);
+ xfs_off_t offset, cred_t *credp, int flags);
extern int xfs_set_dmattrs(bhv_desc_t *bdp, u_int evmask, u_int16_t state,
- cred_t *credp);
+ cred_t *credp);
+extern int xfs_free_eofblocks(struct xfs_mount *mp, struct xfs_inode *ip,
+ int flags);
#endif /* __XFS_RW_H__ */
diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h
index 467854b..ef42537 100644
--- a/fs/xfs/xfs_sb.h
+++ b/fs/xfs/xfs_sb.h
@@ -74,12 +74,13 @@
*/
#define XFS_SB_VERSION2_REALFBITS 0x00ffffff /* Mask: features */
#define XFS_SB_VERSION2_RESERVED1BIT 0x00000001
-#define XFS_SB_VERSION2_RESERVED2BIT 0x00000002
+#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */
#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004
#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */
#define XFS_SB_VERSION2_OKREALFBITS \
- (XFS_SB_VERSION2_ATTR2BIT)
+ (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
+ XFS_SB_VERSION2_ATTR2BIT)
#define XFS_SB_VERSION2_OKSASHFBITS \
(0)
#define XFS_SB_VERSION2_OKREALBITS \
@@ -181,6 +182,9 @@
#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN)
#define XFS_SB_UNIT XFS_SB_MVAL(UNIT)
#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH)
+#define XFS_SB_ICOUNT XFS_SB_MVAL(ICOUNT)
+#define XFS_SB_IFREE XFS_SB_MVAL(IFREE)
+#define XFS_SB_FDBLOCKS XFS_SB_MVAL(FDBLOCKS)
#define XFS_SB_FEATURES2 XFS_SB_MVAL(FEATURES2)
#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT)
#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1)
@@ -188,7 +192,7 @@
(XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
- XFS_SB_FEATURES2)
+ XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2)
/*
@@ -414,6 +418,12 @@
* ((sbp)->sb_features2 & XFS_SB_VERSION2_FUNBIT)
*/
+static inline int xfs_sb_version_haslazysbcount(xfs_sb_t *sbp)
+{
+ return (XFS_SB_VERSION_HASMOREBITS(sbp) && \
+ ((sbp)->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT));
+}
+
#define XFS_SB_VERSION_HASATTR2(sbp) xfs_sb_version_hasattr2(sbp)
static inline int xfs_sb_version_hasattr2(xfs_sb_t *sbp)
{
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index cc2d609..356d662 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -427,6 +427,14 @@
*
* Mark the transaction structure to indicate that the superblock
* needs to be updated before committing.
+ *
+ * Because we may not be keeping track of allocated/free inodes and
+ * used filesystem blocks in the superblock, we do not mark the
+ * superblock dirty in this transaction if we modify these fields.
+ * We still need to update the transaction deltas so that they get
+ * applied to the incore superblock, but we don't want them to
+ * cause the superblock to get locked and logged if these are the
+ * only fields in the superblock that the transaction modifies.
*/
void
xfs_trans_mod_sb(
@@ -434,13 +442,19 @@
uint field,
int64_t delta)
{
+ uint32_t flags = (XFS_TRANS_DIRTY|XFS_TRANS_SB_DIRTY);
+ xfs_mount_t *mp = tp->t_mountp;
switch (field) {
case XFS_TRANS_SB_ICOUNT:
tp->t_icount_delta += delta;
+ if (xfs_sb_version_haslazysbcount(&mp->m_sb))
+ flags &= ~XFS_TRANS_SB_DIRTY;
break;
case XFS_TRANS_SB_IFREE:
tp->t_ifree_delta += delta;
+ if (xfs_sb_version_haslazysbcount(&mp->m_sb))
+ flags &= ~XFS_TRANS_SB_DIRTY;
break;
case XFS_TRANS_SB_FDBLOCKS:
/*
@@ -453,6 +467,8 @@
ASSERT(tp->t_blk_res_used <= tp->t_blk_res);
}
tp->t_fdblocks_delta += delta;
+ if (xfs_sb_version_haslazysbcount(&mp->m_sb))
+ flags &= ~XFS_TRANS_SB_DIRTY;
break;
case XFS_TRANS_SB_RES_FDBLOCKS:
/*
@@ -462,6 +478,8 @@
*/
ASSERT(delta < 0);
tp->t_res_fdblocks_delta += delta;
+ if (xfs_sb_version_haslazysbcount(&mp->m_sb))
+ flags &= ~XFS_TRANS_SB_DIRTY;
break;
case XFS_TRANS_SB_FREXTENTS:
/*
@@ -515,7 +533,7 @@
return;
}
- tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY);
+ tp->t_flags |= flags;
}
/*
@@ -544,18 +562,23 @@
(tp->t_ag_freeblks_delta + tp->t_ag_flist_delta +
tp->t_ag_btree_delta));
- if (tp->t_icount_delta != 0) {
- INT_MOD(sbp->sb_icount, ARCH_CONVERT, tp->t_icount_delta);
- }
- if (tp->t_ifree_delta != 0) {
- INT_MOD(sbp->sb_ifree, ARCH_CONVERT, tp->t_ifree_delta);
- }
+ /*
+ * Only update the superblock counters if we are logging them
+ */
+ if (!xfs_sb_version_haslazysbcount(&(tp->t_mountp->m_sb))) {
+ if (tp->t_icount_delta != 0) {
+ INT_MOD(sbp->sb_icount, ARCH_CONVERT, tp->t_icount_delta);
+ }
+ if (tp->t_ifree_delta != 0) {
+ INT_MOD(sbp->sb_ifree, ARCH_CONVERT, tp->t_ifree_delta);
+ }
- if (tp->t_fdblocks_delta != 0) {
- INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_fdblocks_delta);
- }
- if (tp->t_res_fdblocks_delta != 0) {
- INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_res_fdblocks_delta);
+ if (tp->t_fdblocks_delta != 0) {
+ INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_fdblocks_delta);
+ }
+ if (tp->t_res_fdblocks_delta != 0) {
+ INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_res_fdblocks_delta);
+ }
}
if (tp->t_frextents_delta != 0) {
@@ -615,11 +638,23 @@
}
/*
- * xfs_trans_unreserve_and_mod_sb() is called to release unused
- * reservations and apply superblock counter changes to the in-core
- * superblock.
+ * xfs_trans_unreserve_and_mod_sb() is called to release unused reservations
+ * and apply superblock counter changes to the in-core superblock. The
+ * t_res_fdblocks_delta and t_res_frextents_delta fields are explicitly NOT
+ * applied to the in-core superblock. The idea is that that has already been
+ * done.
*
* This is done efficiently with a single call to xfs_mod_incore_sb_batch().
+ * However, we have to ensure that we only modify each superblock field only
+ * once because the application of the delta values may not be atomic. That can
+ * lead to ENOSPC races occurring if we have two separate modifcations of the
+ * free space counter to put back the entire reservation and then take away
+ * what we used.
+ *
+ * If we are not logging superblock counters, then the inode allocated/free and
+ * used block counts are not updated in the on disk superblock. In this case,
+ * XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we
+ * still need to update the incore superblock with the changes.
*/
STATIC void
xfs_trans_unreserve_and_mod_sb(
@@ -627,40 +662,49 @@
{
xfs_mod_sb_t msb[14]; /* If you add cases, add entries */
xfs_mod_sb_t *msbp;
+ xfs_mount_t *mp = tp->t_mountp;
/* REFERENCED */
int error;
int rsvd;
+ int64_t blkdelta = 0;
+ int64_t rtxdelta = 0;
msbp = msb;
rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
- /*
- * Release any reserved blocks. Any that were allocated
- * will be taken back again by fdblocks_delta below.
- */
- if (tp->t_blk_res > 0) {
+ /* calculate free blocks delta */
+ if (tp->t_blk_res > 0)
+ blkdelta = tp->t_blk_res;
+
+ if ((tp->t_fdblocks_delta != 0) &&
+ (xfs_sb_version_haslazysbcount(&mp->m_sb) ||
+ (tp->t_flags & XFS_TRANS_SB_DIRTY)))
+ blkdelta += tp->t_fdblocks_delta;
+
+ if (blkdelta != 0) {
msbp->msb_field = XFS_SBS_FDBLOCKS;
- msbp->msb_delta = tp->t_blk_res;
+ msbp->msb_delta = blkdelta;
msbp++;
}
- /*
- * Release any reserved real time extents . Any that were
- * allocated will be taken back again by frextents_delta below.
- */
- if (tp->t_rtx_res > 0) {
+ /* calculate free realtime extents delta */
+ if (tp->t_rtx_res > 0)
+ rtxdelta = tp->t_rtx_res;
+
+ if ((tp->t_frextents_delta != 0) &&
+ (tp->t_flags & XFS_TRANS_SB_DIRTY))
+ rtxdelta += tp->t_frextents_delta;
+
+ if (rtxdelta != 0) {
msbp->msb_field = XFS_SBS_FREXTENTS;
- msbp->msb_delta = tp->t_rtx_res;
+ msbp->msb_delta = rtxdelta;
msbp++;
}
- /*
- * Apply any superblock modifications to the in-core version.
- * The t_res_fdblocks_delta and t_res_frextents_delta fields are
- * explicitly NOT applied to the in-core superblock.
- * The idea is that that has already been done.
- */
- if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
+ /* apply remaining deltas */
+
+ if (xfs_sb_version_haslazysbcount(&mp->m_sb) ||
+ (tp->t_flags & XFS_TRANS_SB_DIRTY)) {
if (tp->t_icount_delta != 0) {
msbp->msb_field = XFS_SBS_ICOUNT;
msbp->msb_delta = tp->t_icount_delta;
@@ -671,16 +715,9 @@
msbp->msb_delta = tp->t_ifree_delta;
msbp++;
}
- if (tp->t_fdblocks_delta != 0) {
- msbp->msb_field = XFS_SBS_FDBLOCKS;
- msbp->msb_delta = tp->t_fdblocks_delta;
- msbp++;
- }
- if (tp->t_frextents_delta != 0) {
- msbp->msb_field = XFS_SBS_FREXTENTS;
- msbp->msb_delta = tp->t_frextents_delta;
- msbp++;
- }
+ }
+
+ if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
if (tp->t_dblocks_delta != 0) {
msbp->msb_field = XFS_SBS_DBLOCKS;
msbp->msb_delta = tp->t_dblocks_delta;
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 7dfcc45..0e26e72 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -94,7 +94,8 @@
#define XFS_TRANS_GROWFSRT_ZERO 38
#define XFS_TRANS_GROWFSRT_FREE 39
#define XFS_TRANS_SWAPEXT 40
-#define XFS_TRANS_TYPE_MAX 40
+#define XFS_TRANS_SB_COUNT 41
+#define XFS_TRANS_TYPE_MAX 41
/* new transaction types need to be reflected in xfs_logprint(8) */
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
index 65c5612..11f5ea2 100644
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -51,6 +51,8 @@
#include "xfs_acl.h"
#include "xfs_attr.h"
#include "xfs_clnt.h"
+#include "xfs_mru_cache.h"
+#include "xfs_filestream.h"
#include "xfs_fsops.h"
STATIC int xfs_sync(bhv_desc_t *, int, cred_t *);
@@ -81,6 +83,8 @@
xfs_dabuf_zone = kmem_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf");
xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork");
xfs_acl_zone_init(xfs_acl_zone, "xfs_acl");
+ xfs_mru_cache_init();
+ xfs_filestream_init();
/*
* The size of the zone allocated buf log item is the maximum
@@ -164,6 +168,8 @@
xfs_cleanup_procfs();
xfs_sysctl_unregister();
xfs_refcache_destroy();
+ xfs_filestream_uninit();
+ xfs_mru_cache_uninit();
xfs_acl_zone_destroy(xfs_acl_zone);
#ifdef XFS_DIR2_TRACE
@@ -320,6 +326,9 @@
else
mp->m_flags &= ~XFS_MOUNT_BARRIER;
+ if (ap->flags2 & XFSMNT2_FILESTREAMS)
+ mp->m_flags |= XFS_MOUNT_FILESTREAMS;
+
return 0;
}
@@ -518,6 +527,9 @@
if (mp->m_flags & XFS_MOUNT_BARRIER)
xfs_mountfs_check_barriers(mp);
+ if ((error = xfs_filestream_mount(mp)))
+ goto error2;
+
error = XFS_IOINIT(vfsp, args, flags);
if (error)
goto error2;
@@ -575,6 +587,13 @@
*/
xfs_refcache_purge_mp(mp);
+ /*
+ * Blow away any referenced inode in the filestreams cache.
+ * This can and will cause log traffic as inodes go inactive
+ * here.
+ */
+ xfs_filestream_unmount(mp);
+
XFS_bflush(mp->m_ddev_targp);
error = xfs_unmount_flush(mp, 0);
if (error)
@@ -640,7 +659,7 @@
* we can write the unmount record.
*/
do {
- xfs_syncsub(mp, SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT, NULL);
+ xfs_syncsub(mp, SYNC_INODE_QUIESCE, NULL);
pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
if (!pincount) {
delay(50);
@@ -651,6 +670,30 @@
return 0;
}
+/*
+ * Second stage of a quiesce. The data is already synced, now we have to take
+ * care of the metadata. New transactions are already blocked, so we need to
+ * wait for any remaining transactions to drain out before proceding.
+ */
+STATIC void
+xfs_attr_quiesce(
+ xfs_mount_t *mp)
+{
+ /* wait for all modifications to complete */
+ while (atomic_read(&mp->m_active_trans) > 0)
+ delay(100);
+
+ /* flush inodes and push all remaining buffers out to disk */
+ xfs_quiesce_fs(mp);
+
+ ASSERT_ALWAYS(atomic_read(&mp->m_active_trans) == 0);
+
+ /* Push the superblock and write an unmount record */
+ xfs_log_sbcount(mp, 1);
+ xfs_log_unmount_write(mp);
+ xfs_unmountfs_writesb(mp);
+}
+
STATIC int
xfs_mntupdate(
bhv_desc_t *bdp,
@@ -670,10 +713,9 @@
mp->m_flags &= ~XFS_MOUNT_BARRIER;
}
} else if (!(vfsp->vfs_flag & VFS_RDONLY)) { /* rw -> ro */
- bhv_vfs_sync(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL);
- xfs_quiesce_fs(mp);
- xfs_log_unmount_write(mp);
- xfs_unmountfs_writesb(mp);
+ xfs_filestream_flush(mp);
+ bhv_vfs_sync(vfsp, SYNC_DATA_QUIESCE, NULL);
+ xfs_attr_quiesce(mp);
vfsp->vfs_flag |= VFS_RDONLY;
}
return 0;
@@ -887,6 +929,9 @@
{
xfs_mount_t *mp = XFS_BHVTOM(bdp);
+ if (flags & SYNC_IOWAIT)
+ xfs_filestream_flush(mp);
+
return xfs_syncsub(mp, flags, NULL);
}
@@ -1128,58 +1173,41 @@
* in the inode list.
*/
- if ((flags & SYNC_CLOSE) && (vp != NULL)) {
- /*
- * This is the shutdown case. We just need to
- * flush and invalidate all the pages associated
- * with the inode. Drop the inode lock since
- * we can't hold it across calls to the buffer
- * cache.
- *
- * We don't set the VREMAPPING bit in the vnode
- * here, because we don't hold the vnode lock
- * exclusively. It doesn't really matter, though,
- * because we only come here when we're shutting
- * down anyway.
- */
+ /*
+ * If we have to flush data or wait for I/O completion
+ * we need to drop the ilock that we currently hold.
+ * If we need to drop the lock, insert a marker if we
+ * have not already done so.
+ */
+ if ((flags & (SYNC_CLOSE|SYNC_IOWAIT)) ||
+ ((flags & SYNC_DELWRI) && VN_DIRTY(vp))) {
+ if (mount_locked) {
+ IPOINTER_INSERT(ip, mp);
+ }
xfs_iunlock(ip, XFS_ILOCK_SHARED);
- if (XFS_FORCED_SHUTDOWN(mp)) {
- bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF);
- } else {
- error = bhv_vop_flushinval_pages(vp, 0, -1, FI_REMAPF);
- }
-
- xfs_ilock(ip, XFS_ILOCK_SHARED);
-
- } else if ((flags & SYNC_DELWRI) && (vp != NULL)) {
- if (VN_DIRTY(vp)) {
- /* We need to have dropped the lock here,
- * so insert a marker if we have not already
- * done so.
- */
- if (mount_locked) {
- IPOINTER_INSERT(ip, mp);
- }
-
- /*
- * Drop the inode lock since we can't hold it
- * across calls to the buffer cache.
- */
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
+ if (flags & SYNC_CLOSE) {
+ /* Shutdown case. Flush and invalidate. */
+ if (XFS_FORCED_SHUTDOWN(mp))
+ bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF);
+ else
+ error = bhv_vop_flushinval_pages(vp, 0,
+ -1, FI_REMAPF);
+ } else if ((flags & SYNC_DELWRI) && VN_DIRTY(vp)) {
error = bhv_vop_flush_pages(vp, (xfs_off_t)0,
-1, fflag, FI_NONE);
- xfs_ilock(ip, XFS_ILOCK_SHARED);
}
+ /*
+ * When freezing, we need to wait ensure all I/O (including direct
+ * I/O) is complete to ensure no further data modification can take
+ * place after this point
+ */
+ if (flags & SYNC_IOWAIT)
+ vn_iowait(vp);
+
+ xfs_ilock(ip, XFS_ILOCK_SHARED);
}
- /*
- * When freezing, we need to wait ensure all I/O (including direct
- * I/O) is complete to ensure no further data modification can take
- * place after this point
- */
- if (flags & SYNC_IOWAIT)
- vn_iowait(vp);
if (flags & SYNC_BDFLUSH) {
if ((flags & SYNC_ATTR) &&
@@ -1514,6 +1542,15 @@
}
/*
+ * If asked, update the disk superblock with incore counter values if we
+ * are using non-persistent counters so that they don't get too far out
+ * of sync if we crash or get a forced shutdown. We don't want to force
+ * this to disk, just get a transaction into the iclogs....
+ */
+ if (flags & SYNC_SUPER)
+ xfs_log_sbcount(mp, 0);
+
+ /*
* Now check to see if the log needs a "dummy" transaction.
*/
@@ -1645,6 +1682,7 @@
* in stat(). */
#define MNTOPT_ATTR2 "attr2" /* do use attr2 attribute format */
#define MNTOPT_NOATTR2 "noattr2" /* do not use attr2 attribute format */
+#define MNTOPT_FILESTREAM "filestreams" /* use filestreams allocator */
STATIC unsigned long
suffix_strtoul(char *s, char **endp, unsigned int base)
@@ -1831,6 +1869,8 @@
args->flags |= XFSMNT_ATTR2;
} else if (!strcmp(this_char, MNTOPT_NOATTR2)) {
args->flags &= ~XFSMNT_ATTR2;
+ } else if (!strcmp(this_char, MNTOPT_FILESTREAM)) {
+ args->flags2 |= XFSMNT2_FILESTREAMS;
} else if (!strcmp(this_char, "osyncisdsync")) {
/* no-op, this is now the default */
cmn_err(CE_WARN,
@@ -1959,9 +1999,9 @@
}
/*
- * Second stage of a freeze. The data is already frozen, now we have to take
- * care of the metadata. New transactions are already blocked, so we need to
- * wait for any remaining transactions to drain out before proceding.
+ * Second stage of a freeze. The data is already frozen so we only
+ * need to take care of themetadata. Once that's done write a dummy
+ * record to dirty the log in case of a crash while frozen.
*/
STATIC void
xfs_freeze(
@@ -1969,18 +2009,7 @@
{
xfs_mount_t *mp = XFS_BHVTOM(bdp);
- /* wait for all modifications to complete */
- while (atomic_read(&mp->m_active_trans) > 0)
- delay(100);
-
- /* flush inodes and push all remaining buffers out to disk */
- xfs_quiesce_fs(mp);
-
- ASSERT_ALWAYS(atomic_read(&mp->m_active_trans) == 0);
-
- /* Push the superblock and write an unmount record */
- xfs_log_unmount_write(mp);
- xfs_unmountfs_writesb(mp);
+ xfs_attr_quiesce(mp);
xfs_fs_log_dummy(mp);
}
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 70bc82f..79b5227 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -51,6 +51,7 @@
#include "xfs_refcache.h"
#include "xfs_trans_space.h"
#include "xfs_log_priv.h"
+#include "xfs_filestream.h"
STATIC int
xfs_open(
@@ -77,36 +78,6 @@
return 0;
}
-STATIC int
-xfs_close(
- bhv_desc_t *bdp,
- int flags,
- lastclose_t lastclose,
- cred_t *credp)
-{
- bhv_vnode_t *vp = BHV_TO_VNODE(bdp);
- xfs_inode_t *ip = XFS_BHVTOI(bdp);
-
- if (XFS_FORCED_SHUTDOWN(ip->i_mount))
- return XFS_ERROR(EIO);
-
- if (lastclose != L_TRUE || !VN_ISREG(vp))
- return 0;
-
- /*
- * If we previously truncated this file and removed old data in
- * the process, we want to initiate "early" writeout on the last
- * close. This is an attempt to combat the notorious NULL files
- * problem which is particularly noticable from a truncate down,
- * buffered (re-)write (delalloc), followed by a crash. What we
- * are effectively doing here is significantly reducing the time
- * window where we'd otherwise be exposed to that problem.
- */
- if (VUNTRUNCATE(vp) && VN_DIRTY(vp) && ip->i_delayed_blks > 0)
- return bhv_vop_flush_pages(vp, 0, -1, XFS_B_ASYNC, FI_NONE);
- return 0;
-}
-
/*
* xfs_getattr
*/
@@ -183,9 +154,8 @@
* realtime extent size or the realtime volume's
* extent size.
*/
- vap->va_blocksize = ip->i_d.di_extsize ?
- (ip->i_d.di_extsize << mp->m_sb.sb_blocklog) :
- (mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog);
+ vap->va_blocksize =
+ xfs_get_extsz_hint(ip) << mp->m_sb.sb_blocklog;
}
break;
}
@@ -814,6 +784,8 @@
di_flags |= XFS_DIFLAG_PROJINHERIT;
if (vap->va_xflags & XFS_XFLAG_NODEFRAG)
di_flags |= XFS_DIFLAG_NODEFRAG;
+ if (vap->va_xflags & XFS_XFLAG_FILESTREAM)
+ di_flags |= XFS_DIFLAG_FILESTREAM;
if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
if (vap->va_xflags & XFS_XFLAG_RTINHERIT)
di_flags |= XFS_DIFLAG_RTINHERIT;
@@ -1201,13 +1173,15 @@
}
/*
- * This is called by xfs_inactive to free any blocks beyond eof,
- * when the link count isn't zero.
+ * This is called by xfs_inactive to free any blocks beyond eof
+ * when the link count isn't zero and by xfs_dm_punch_hole() when
+ * punching a hole to EOF.
*/
-STATIC int
-xfs_inactive_free_eofblocks(
+int
+xfs_free_eofblocks(
xfs_mount_t *mp,
- xfs_inode_t *ip)
+ xfs_inode_t *ip,
+ int flags)
{
xfs_trans_t *tp;
int error;
@@ -1216,6 +1190,7 @@
xfs_filblks_t map_len;
int nimaps;
xfs_bmbt_irec_t imap;
+ int use_iolock = (flags & XFS_FREE_EOF_LOCK);
/*
* Figure out if there are any blocks beyond the end
@@ -1256,11 +1231,14 @@
* cache and we can't
* do that within a transaction.
*/
- xfs_ilock(ip, XFS_IOLOCK_EXCL);
+ if (use_iolock)
+ xfs_ilock(ip, XFS_IOLOCK_EXCL);
error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
ip->i_size);
if (error) {
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+ xfs_trans_cancel(tp, 0);
+ if (use_iolock)
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return error;
}
@@ -1297,7 +1275,8 @@
error = xfs_trans_commit(tp,
XFS_TRANS_RELEASE_LOG_RES);
}
- xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
+ xfs_iunlock(ip, (use_iolock ? (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)
+ : XFS_ILOCK_EXCL));
}
return error;
}
@@ -1560,6 +1539,31 @@
if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
return 0;
+ if (!XFS_FORCED_SHUTDOWN(mp)) {
+ /*
+ * If we are using filestreams, and we have an unlinked
+ * file that we are processing the last close on, then nothing
+ * will be able to reopen and write to this file. Purge this
+ * inode from the filestreams cache so that it doesn't delay
+ * teardown of the inode.
+ */
+ if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip))
+ xfs_filestream_deassociate(ip);
+
+ /*
+ * If we previously truncated this file and removed old data
+ * in the process, we want to initiate "early" writeout on
+ * the last close. This is an attempt to combat the notorious
+ * NULL files problem which is particularly noticable from a
+ * truncate down, buffered (re-)write (delalloc), followed by
+ * a crash. What we are effectively doing here is
+ * significantly reducing the time window where we'd otherwise
+ * be exposed to that problem.
+ */
+ if (VUNTRUNCATE(vp) && VN_DIRTY(vp) && ip->i_delayed_blks > 0)
+ bhv_vop_flush_pages(vp, 0, -1, XFS_B_ASYNC, FI_NONE);
+ }
+
#ifdef HAVE_REFCACHE
/* If we are in the NFS reference cache then don't do this now */
if (ip->i_refcache)
@@ -1573,7 +1577,8 @@
(ip->i_df.if_flags & XFS_IFEXTENTS)) &&
(!(ip->i_d.di_flags &
(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {
- if ((error = xfs_inactive_free_eofblocks(mp, ip)))
+ error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK);
+ if (error)
return error;
/* Update linux inode block count after free above */
vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,
@@ -1654,7 +1659,8 @@
(!(ip->i_d.di_flags &
(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
(ip->i_delayed_blks != 0)))) {
- if ((error = xfs_inactive_free_eofblocks(mp, ip)))
+ error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK);
+ if (error)
return VN_INACTIVE_CACHE;
/* Update linux inode block count after free above */
vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,
@@ -1680,6 +1686,7 @@
error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0);
if (error) {
+ xfs_trans_cancel(tp, 0);
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return VN_INACTIVE_CACHE;
}
@@ -2217,9 +2224,9 @@
xfs_lock_inumorder(int lock_mode, int subclass)
{
if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
- lock_mode |= (subclass + XFS_IOLOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
+ lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL))
- lock_mode |= (subclass + XFS_ILOCK_INUMORDER) << XFS_ILOCK_SHIFT;
+ lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_ILOCK_SHIFT;
return lock_mode;
}
@@ -2546,6 +2553,15 @@
*/
xfs_refcache_purge_ip(ip);
+ /*
+ * If we are using filestreams, kill the stream association.
+ * If the file is still open it may get a new one but that
+ * will get killed on last close in xfs_close() so we don't
+ * have to worry about that.
+ */
+ if (link_zero && xfs_inode_is_filestream(ip))
+ xfs_filestream_deassociate(ip);
+
vn_trace_exit(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address);
/*
@@ -4047,22 +4063,16 @@
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
- rt = XFS_IS_REALTIME_INODE(ip);
- if (unlikely(rt)) {
- if (!(extsz = ip->i_d.di_extsize))
- extsz = mp->m_sb.sb_rextsize;
- } else {
- extsz = ip->i_d.di_extsize;
- }
-
if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
return error;
if (len <= 0)
return XFS_ERROR(EINVAL);
+ rt = XFS_IS_REALTIME_INODE(ip);
+ extsz = xfs_get_extsz_hint(ip);
+
count = len;
- error = 0;
imapp = &imaps[0];
nimaps = 1;
bmapi_flag = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0);
@@ -4678,7 +4688,6 @@
bhv_vnodeops_t xfs_vnodeops = {
BHV_IDENTITY_INIT(VN_BHV_XFS,VNODE_POSITION_XFS),
.vop_open = xfs_open,
- .vop_close = xfs_close,
.vop_read = xfs_read,
#ifdef HAVE_SPLICE
.vop_splice_read = xfs_splice_read,
diff --git a/include/asm-frv/uaccess.h b/include/asm-frv/uaccess.h
index 3d90e10..53650c9 100644
--- a/include/asm-frv/uaccess.h
+++ b/include/asm-frv/uaccess.h
@@ -277,6 +277,8 @@
#endif
+#define __clear_user clear_user
+
static inline unsigned long __must_check
__copy_to_user(void __user *to, const void *from, unsigned long n)
{
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 0de7e2a..357e8cf 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -295,28 +295,8 @@
};
struct cipher_tfm {
- void *cit_iv;
- unsigned int cit_ivsize;
- u32 cit_mode;
int (*cit_setkey)(struct crypto_tfm *tfm,
const u8 *key, unsigned int keylen);
- int (*cit_encrypt)(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes);
- int (*cit_encrypt_iv)(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv);
- int (*cit_decrypt)(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes);
- int (*cit_decrypt_iv)(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv);
- void (*cit_xor_block)(u8 *dst, const u8 *src);
void (*cit_encrypt_one)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
void (*cit_decrypt_one)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
};
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index f2d248f..3a63224 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -265,6 +265,7 @@
u32 ethtool_op_get_tx_csum(struct net_device *dev);
int ethtool_op_set_tx_csum(struct net_device *dev, u32 data);
int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data);
+int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data);
u32 ethtool_op_get_sg(struct net_device *dev);
int ethtool_op_set_sg(struct net_device *dev, u32 data);
u32 ethtool_op_get_tso(struct net_device *dev);
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index ecd61e8..272f8c8 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -227,6 +227,17 @@
#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
#define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
+/* 802.11g ERP information element */
+#define WLAN_ERP_NON_ERP_PRESENT (1<<0)
+#define WLAN_ERP_USE_PROTECTION (1<<1)
+#define WLAN_ERP_BARKER_PREAMBLE (1<<2)
+
+/* WLAN_ERP_BARKER_PREAMBLE values */
+enum {
+ WLAN_ERP_PREAMBLE_SHORT = 0,
+ WLAN_ERP_PREAMBLE_LONG = 1,
+};
+
/* Status codes */
enum ieee80211_statuscode {
WLAN_STATUS_SUCCESS = 0,
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
new file mode 100644
index 0000000..0d9d7ea
--- /dev/null
+++ b/include/linux/if_macvlan.h
@@ -0,0 +1,9 @@
+#ifndef _LINUX_IF_MACVLAN_H
+#define _LINUX_IF_MACVLAN_H
+
+#ifdef __KERNEL__
+
+extern struct sk_buff *(*macvlan_handle_frame_hook)(struct sk_buff *);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_IF_MACVLAN_H */
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 61a57dc..f8443fd 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -127,13 +127,6 @@
* like DHCP that use packet-filtering and don't understand
* 802.1Q
*/
- struct dev_mc_list *old_mc_list; /* old multi-cast list for the VLAN interface..
- * we save this so we can tell what changes were
- * made, in order to feed the right changes down
- * to the real hardware...
- */
- int old_allmulti; /* similar to above. */
- int old_promiscuity; /* similar to above. */
struct net_device *real_dev; /* the underlying device/interface */
unsigned char real_dev_addr[ETH_ALEN];
struct proc_dir_entry *dent; /* Holds the proc data */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 79cc3da..322b5ea 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -190,6 +190,7 @@
struct dev_addr_list *next;
u8 da_addr[MAX_ADDR_LEN];
u8 da_addrlen;
+ u8 da_synced;
int da_users;
int da_gusers;
};
@@ -516,6 +517,9 @@
void *saddr,
unsigned len);
int (*rebuild_header)(struct sk_buff *skb);
+#define HAVE_CHANGE_RX_FLAGS
+ void (*change_rx_flags)(struct net_device *dev,
+ int flags);
#define HAVE_SET_RX_MODE
void (*set_rx_mode)(struct net_device *dev);
#define HAVE_MULTICAST
@@ -560,6 +564,8 @@
/* bridge stuff */
struct net_bridge_port *br_port;
+ /* macvlan */
+ struct macvlan_port *macvlan_port;
/* class/net/name entry */
struct device dev;
@@ -1100,6 +1106,8 @@
extern int dev_unicast_add(struct net_device *dev, void *addr, int alen);
extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
+extern int dev_mc_sync(struct net_device *to, struct net_device *from);
+extern void dev_mc_unsync(struct net_device *to, struct net_device *from);
extern void dev_mc_discard(struct net_device *dev);
extern int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all);
extern int __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly);
diff --git a/include/linux/netfilter/xt_connlimit.h b/include/linux/netfilter/xt_connlimit.h
new file mode 100644
index 0000000..90ae8b4
--- /dev/null
+++ b/include/linux/netfilter/xt_connlimit.h
@@ -0,0 +1,17 @@
+#ifndef _XT_CONNLIMIT_H
+#define _XT_CONNLIMIT_H
+
+struct xt_connlimit_data;
+
+struct xt_connlimit_info {
+ union {
+ u_int32_t v4_mask;
+ u_int32_t v6_mask[4];
+ };
+ unsigned int limit, inverse;
+
+ /* this needs to be at the end */
+ struct xt_connlimit_data *data __attribute__((aligned(8)));
+};
+
+#endif /* _XT_CONNLIMIT_H */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9391e4a..ce25643 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1639,7 +1639,7 @@
* if skb->ip_summed is CHECKSUM_UNNECESSARY which indicates that the
* hardware has already verified the correctness of the checksum.
*/
-static inline unsigned int skb_checksum_complete(struct sk_buff *skb)
+static inline __sum16 skb_checksum_complete(struct sk_buff *skb)
{
return skb_csum_unnecessary(skb) ?
0 : __skb_checksum_complete(skb);
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
new file mode 100644
index 0000000..88884d3
--- /dev/null
+++ b/include/net/9p/9p.h
@@ -0,0 +1,417 @@
+/*
+ * include/net/9p/9p.h
+ *
+ * 9P protocol definitions.
+ *
+ * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
+ * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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; if not, write to:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#ifndef NET_9P_H
+#define NET_9P_H
+
+#ifdef CONFIG_NET_9P_DEBUG
+
+#define P9_DEBUG_ERROR (1<<0)
+#define P9_DEBUG_9P (1<<2)
+#define P9_DEBUG_VFS (1<<3)
+#define P9_DEBUG_CONV (1<<4)
+#define P9_DEBUG_MUX (1<<5)
+#define P9_DEBUG_TRANS (1<<6)
+#define P9_DEBUG_SLABS (1<<7)
+#define P9_DEBUG_FCALL (1<<8)
+
+extern unsigned int p9_debug_level;
+
+#define P9_DPRINTK(level, format, arg...) \
+do { \
+ if ((p9_debug_level & level) == level) \
+ printk(KERN_NOTICE "-- %s (%d): " \
+ format , __FUNCTION__, current->pid , ## arg); \
+} while (0)
+
+#define PRINT_FCALL_ERROR(s, fcall) P9_DPRINTK(P9_DEBUG_ERROR, \
+ "%s: %.*s\n", s, fcall?fcall->params.rerror.error.len:0, \
+ fcall?fcall->params.rerror.error.str:"");
+
+#else
+#define P9_DPRINTK(level, format, arg...) do { } while (0)
+#define PRINT_FCALL_ERROR(s, fcall) do { } while (0)
+#endif
+
+#define P9_EPRINTK(level, format, arg...) \
+do { \
+ printk(level "9p: %s (%d): " \
+ format , __FUNCTION__, current->pid , ## arg); \
+} while (0)
+
+
+/* Message Types */
+enum {
+ P9_TVERSION = 100,
+ P9_RVERSION,
+ P9_TAUTH = 102,
+ P9_RAUTH,
+ P9_TATTACH = 104,
+ P9_RATTACH,
+ P9_TERROR = 106,
+ P9_RERROR,
+ P9_TFLUSH = 108,
+ P9_RFLUSH,
+ P9_TWALK = 110,
+ P9_RWALK,
+ P9_TOPEN = 112,
+ P9_ROPEN,
+ P9_TCREATE = 114,
+ P9_RCREATE,
+ P9_TREAD = 116,
+ P9_RREAD,
+ P9_TWRITE = 118,
+ P9_RWRITE,
+ P9_TCLUNK = 120,
+ P9_RCLUNK,
+ P9_TREMOVE = 122,
+ P9_RREMOVE,
+ P9_TSTAT = 124,
+ P9_RSTAT,
+ P9_TWSTAT = 126,
+ P9_RWSTAT,
+};
+
+/* open modes */
+enum {
+ P9_OREAD = 0x00,
+ P9_OWRITE = 0x01,
+ P9_ORDWR = 0x02,
+ P9_OEXEC = 0x03,
+ P9_OEXCL = 0x04,
+ P9_OTRUNC = 0x10,
+ P9_OREXEC = 0x20,
+ P9_ORCLOSE = 0x40,
+ P9_OAPPEND = 0x80,
+};
+
+/* permissions */
+enum {
+ P9_DMDIR = 0x80000000,
+ P9_DMAPPEND = 0x40000000,
+ P9_DMEXCL = 0x20000000,
+ P9_DMMOUNT = 0x10000000,
+ P9_DMAUTH = 0x08000000,
+ P9_DMTMP = 0x04000000,
+ P9_DMSYMLINK = 0x02000000,
+ P9_DMLINK = 0x01000000,
+ /* 9P2000.u extensions */
+ P9_DMDEVICE = 0x00800000,
+ P9_DMNAMEDPIPE = 0x00200000,
+ P9_DMSOCKET = 0x00100000,
+ P9_DMSETUID = 0x00080000,
+ P9_DMSETGID = 0x00040000,
+};
+
+/* qid.types */
+enum {
+ P9_QTDIR = 0x80,
+ P9_QTAPPEND = 0x40,
+ P9_QTEXCL = 0x20,
+ P9_QTMOUNT = 0x10,
+ P9_QTAUTH = 0x08,
+ P9_QTTMP = 0x04,
+ P9_QTSYMLINK = 0x02,
+ P9_QTLINK = 0x01,
+ P9_QTFILE = 0x00,
+};
+
+#define P9_NOTAG (u16)(~0)
+#define P9_NOFID (u32)(~0)
+#define P9_MAXWELEM 16
+
+/* ample room for Twrite/Rread header */
+#define P9_IOHDRSZ 24
+
+struct p9_str {
+ u16 len;
+ char *str;
+};
+
+/* qids are the unique ID for a file (like an inode */
+struct p9_qid {
+ u8 type;
+ u32 version;
+ u64 path;
+};
+
+/* Plan 9 file metadata (stat) structure */
+struct p9_stat {
+ u16 size;
+ u16 type;
+ u32 dev;
+ struct p9_qid qid;
+ u32 mode;
+ u32 atime;
+ u32 mtime;
+ u64 length;
+ struct p9_str name;
+ struct p9_str uid;
+ struct p9_str gid;
+ struct p9_str muid;
+ struct p9_str extension; /* 9p2000.u extensions */
+ u32 n_uid; /* 9p2000.u extensions */
+ u32 n_gid; /* 9p2000.u extensions */
+ u32 n_muid; /* 9p2000.u extensions */
+};
+
+/* file metadata (stat) structure used to create Twstat message
+ The is similar to p9_stat, but the strings don't point to
+ the same memory block and should be freed separately
+*/
+struct p9_wstat {
+ u16 size;
+ u16 type;
+ u32 dev;
+ struct p9_qid qid;
+ u32 mode;
+ u32 atime;
+ u32 mtime;
+ u64 length;
+ char *name;
+ char *uid;
+ char *gid;
+ char *muid;
+ char *extension; /* 9p2000.u extensions */
+ u32 n_uid; /* 9p2000.u extensions */
+ u32 n_gid; /* 9p2000.u extensions */
+ u32 n_muid; /* 9p2000.u extensions */
+};
+
+/* Structures for Protocol Operations */
+struct p9_tversion {
+ u32 msize;
+ struct p9_str version;
+};
+
+struct p9_rversion {
+ u32 msize;
+ struct p9_str version;
+};
+
+struct p9_tauth {
+ u32 afid;
+ struct p9_str uname;
+ struct p9_str aname;
+};
+
+struct p9_rauth {
+ struct p9_qid qid;
+};
+
+struct p9_rerror {
+ struct p9_str error;
+ u32 errno; /* 9p2000.u extension */
+};
+
+struct p9_tflush {
+ u16 oldtag;
+};
+
+struct p9_rflush {
+};
+
+struct p9_tattach {
+ u32 fid;
+ u32 afid;
+ struct p9_str uname;
+ struct p9_str aname;
+};
+
+struct p9_rattach {
+ struct p9_qid qid;
+};
+
+struct p9_twalk {
+ u32 fid;
+ u32 newfid;
+ u16 nwname;
+ struct p9_str wnames[16];
+};
+
+struct p9_rwalk {
+ u16 nwqid;
+ struct p9_qid wqids[16];
+};
+
+struct p9_topen {
+ u32 fid;
+ u8 mode;
+};
+
+struct p9_ropen {
+ struct p9_qid qid;
+ u32 iounit;
+};
+
+struct p9_tcreate {
+ u32 fid;
+ struct p9_str name;
+ u32 perm;
+ u8 mode;
+ struct p9_str extension;
+};
+
+struct p9_rcreate {
+ struct p9_qid qid;
+ u32 iounit;
+};
+
+struct p9_tread {
+ u32 fid;
+ u64 offset;
+ u32 count;
+};
+
+struct p9_rread {
+ u32 count;
+ u8 *data;
+};
+
+struct p9_twrite {
+ u32 fid;
+ u64 offset;
+ u32 count;
+ u8 *data;
+};
+
+struct p9_rwrite {
+ u32 count;
+};
+
+struct p9_tclunk {
+ u32 fid;
+};
+
+struct p9_rclunk {
+};
+
+struct p9_tremove {
+ u32 fid;
+};
+
+struct p9_rremove {
+};
+
+struct p9_tstat {
+ u32 fid;
+};
+
+struct p9_rstat {
+ struct p9_stat stat;
+};
+
+struct p9_twstat {
+ u32 fid;
+ struct p9_stat stat;
+};
+
+struct p9_rwstat {
+};
+
+/*
+ * fcall is the primary packet structure
+ *
+ */
+
+struct p9_fcall {
+ u32 size;
+ u8 id;
+ u16 tag;
+ void *sdata;
+
+ union {
+ struct p9_tversion tversion;
+ struct p9_rversion rversion;
+ struct p9_tauth tauth;
+ struct p9_rauth rauth;
+ struct p9_rerror rerror;
+ struct p9_tflush tflush;
+ struct p9_rflush rflush;
+ struct p9_tattach tattach;
+ struct p9_rattach rattach;
+ struct p9_twalk twalk;
+ struct p9_rwalk rwalk;
+ struct p9_topen topen;
+ struct p9_ropen ropen;
+ struct p9_tcreate tcreate;
+ struct p9_rcreate rcreate;
+ struct p9_tread tread;
+ struct p9_rread rread;
+ struct p9_twrite twrite;
+ struct p9_rwrite rwrite;
+ struct p9_tclunk tclunk;
+ struct p9_rclunk rclunk;
+ struct p9_tremove tremove;
+ struct p9_rremove rremove;
+ struct p9_tstat tstat;
+ struct p9_rstat rstat;
+ struct p9_twstat twstat;
+ struct p9_rwstat rwstat;
+ } params;
+};
+
+struct p9_idpool;
+
+int p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat,
+ int dotu);
+int p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *fc, int dotu);
+void p9_set_tag(struct p9_fcall *fc, u16 tag);
+struct p9_fcall *p9_create_tversion(u32 msize, char *version);
+struct p9_fcall *p9_create_tattach(u32 fid, u32 afid, char *uname,
+ char *aname);
+struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname);
+struct p9_fcall *p9_create_tflush(u16 oldtag);
+struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname,
+ char **wnames);
+struct p9_fcall *p9_create_topen(u32 fid, u8 mode);
+struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
+ char *extension, int dotu);
+struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count);
+struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count,
+ const char *data);
+struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count,
+ const char __user *data);
+struct p9_fcall *p9_create_tclunk(u32 fid);
+struct p9_fcall *p9_create_tremove(u32 fid);
+struct p9_fcall *p9_create_tstat(u32 fid);
+struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat,
+ int dotu);
+
+int p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int dotu);
+int p9_errstr2errno(char *errstr, int len);
+
+struct p9_idpool *p9_idpool_create(void);
+void p9_idpool_destroy(struct p9_idpool *);
+int p9_idpool_get(struct p9_idpool *p);
+void p9_idpool_put(int id, struct p9_idpool *p);
+int p9_idpool_check(int id, struct p9_idpool *p);
+
+int p9_error_init(void);
+int p9_errstr2errno(char *, int);
+int __init p9_sysctl_register(void);
+void __exit p9_sysctl_unregister(void);
+#endif /* NET_9P_H */
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
new file mode 100644
index 0000000..d65ed7c
--- /dev/null
+++ b/include/net/9p/client.h
@@ -0,0 +1,80 @@
+/*
+ * include/net/9p/client.h
+ *
+ * 9P Client Definitions
+ *
+ * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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; if not, write to:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#ifndef NET_9P_CLIENT_H
+#define NET_9P_CLIENT_H
+
+struct p9_client {
+ spinlock_t lock; /* protect client structure */
+ int msize;
+ unsigned char dotu;
+ struct p9_transport *trans;
+ struct p9_conn *conn;
+
+ struct p9_idpool *fidpool;
+ struct list_head fidlist;
+};
+
+struct p9_fid {
+ struct p9_client *clnt;
+ u32 fid;
+ int mode;
+ struct p9_qid qid;
+ u32 iounit;
+ uid_t uid;
+ void *aux;
+
+ int rdir_fpos;
+ int rdir_pos;
+ struct p9_fcall *rdir_fcall;
+ struct list_head flist;
+ struct list_head dlist; /* list of all fids attached to a dentry */
+};
+
+struct p9_client *p9_client_create(struct p9_transport *trans, int msize,
+ int dotu);
+void p9_client_destroy(struct p9_client *clnt);
+void p9_client_disconnect(struct p9_client *clnt);
+struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
+ char *uname, char *aname);
+struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, char *aname);
+struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
+ int clone);
+int p9_client_open(struct p9_fid *fid, int mode);
+int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
+ char *extension);
+int p9_client_clunk(struct p9_fid *fid);
+int p9_client_remove(struct p9_fid *fid);
+int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count);
+int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count);
+int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count);
+int p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset,
+ u32 count);
+int p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
+ u32 count);
+struct p9_stat *p9_client_stat(struct p9_fid *fid);
+int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst);
+struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset);
+
+#endif /* NET_9P_CLIENT_H */
diff --git a/include/net/9p/conn.h b/include/net/9p/conn.h
new file mode 100644
index 0000000..583b6a2
--- /dev/null
+++ b/include/net/9p/conn.h
@@ -0,0 +1,57 @@
+/*
+ * include/net/9p/conn.h
+ *
+ * Connection Definitions
+ *
+ * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
+ * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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; if not, write to:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#ifndef NET_9P_CONN_H
+#define NET_9P_CONN_H
+
+#undef P9_NONBLOCK
+
+struct p9_conn;
+struct p9_req;
+
+/**
+ * p9_mux_req_callback - callback function that is called when the
+ * response of a request is received. The callback is called from
+ * a workqueue and shouldn't block.
+ *
+ * @req - request
+ * @a - the pointer that was specified when the request was send to be
+ * passed to the callback
+ */
+typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a);
+
+struct p9_conn *p9_conn_create(struct p9_transport *trans, int msize,
+ unsigned char *dotu);
+void p9_conn_destroy(struct p9_conn *);
+int p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc, struct p9_fcall **rc);
+
+#ifdef P9_NONBLOCK
+int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
+ p9_conn_req_callback cb, void *a);
+#endif /* P9_NONBLOCK */
+
+void p9_conn_cancel(struct p9_conn *m, int err);
+
+#endif /* NET_9P_CONN_H */
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h
new file mode 100644
index 0000000..462d422
--- /dev/null
+++ b/include/net/9p/transport.h
@@ -0,0 +1,49 @@
+/*
+ * include/net/9p/transport.h
+ *
+ * Transport Definition
+ *
+ * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
+ * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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; if not, write to:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#ifndef NET_9P_TRANSPORT_H
+#define NET_9P_TRANSPORT_H
+
+enum p9_transport_status {
+ Connected,
+ Disconnected,
+ Hung,
+};
+
+struct p9_transport {
+ enum p9_transport_status status;
+ void *priv;
+
+ int (*write) (struct p9_transport *, void *, int);
+ int (*read) (struct p9_transport *, void *, int);
+ void (*close) (struct p9_transport *);
+ unsigned int (*poll)(struct p9_transport *, struct poll_table_struct *);
+};
+
+struct p9_transport *p9_trans_create_tcp(const char *addr, int port);
+struct p9_transport *p9_trans_create_unix(const char *addr);
+struct p9_transport *p9_trans_create_fd(int rfd, int wfd);
+
+#endif /* NET_9P_TRANSPORT_H */
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 2f0273f..68b4eaf 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -121,34 +121,4 @@
extern int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
extern int tcf_action_copy_stats (struct sk_buff *,struct tc_action *, int);
#endif /* CONFIG_NET_CLS_ACT */
-
-extern int tcf_police(struct sk_buff *skb, struct tcf_police *p);
-extern void tcf_police_destroy(struct tcf_police *p);
-extern struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est);
-extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p);
-extern int tcf_police_dump_stats(struct sk_buff *skb, struct tcf_police *p);
-
-static inline int
-tcf_police_release(struct tcf_police *p, int bind)
-{
- int ret = 0;
-#ifdef CONFIG_NET_CLS_ACT
- if (p) {
- if (bind)
- p->tcf_bindcnt--;
-
- p->tcf_refcnt--;
- if (p->tcf_refcnt <= 0 && !p->tcf_bindcnt) {
- tcf_police_destroy(p);
- ret = 1;
- }
- }
-#else
- if (p && --p->tcf_refcnt == 0)
- tcf_police_destroy(p);
-
-#endif /* CONFIG_NET_CLS_ACT */
- return ret;
-}
-
#endif
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 88171f8..7edaef6 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -11,6 +11,44 @@
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
*/
+
+/* Radiotap header iteration
+ * implemented in net/wireless/radiotap.c
+ * docs in Documentation/networking/radiotap-headers.txt
+ */
+/**
+ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
+ * @rtheader: pointer to the radiotap header we are walking through
+ * @max_length: length of radiotap header in cpu byte ordering
+ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
+ * @this_arg: pointer to current radiotap arg
+ * @arg_index: internal next argument index
+ * @arg: internal next argument pointer
+ * @next_bitmap: internal pointer to next present u32
+ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ */
+
+struct ieee80211_radiotap_iterator {
+ struct ieee80211_radiotap_header *rtheader;
+ int max_length;
+ int this_arg_index;
+ u8 *this_arg;
+
+ int arg_index;
+ u8 *arg;
+ __le32 *next_bitmap;
+ u32 bitmap_shifter;
+};
+
+extern int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length);
+
+extern int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator);
+
+
/* from net/wireless.h */
struct wiphy;
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index 09a2532..47d52b2 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -209,9 +209,6 @@
extern struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
const int state);
-extern void __inet_twsk_kill(struct inet_timewait_sock *tw,
- struct inet_hashinfo *hashinfo);
-
extern void __inet_twsk_hashdance(struct inet_timewait_sock *tw,
struct sock *sk,
struct inet_hashinfo *hashinfo);
diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h
index f9bd11b..b6c468c 100644
--- a/include/net/iucv/af_iucv.h
+++ b/include/net/iucv/af_iucv.h
@@ -60,6 +60,7 @@
char dst_user_id[8];
char dst_name[8];
struct list_head accept_q;
+ spinlock_t accept_q_lock;
struct sock *parent;
struct iucv_path *path;
struct sk_buff_head send_skb_q;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index a7f122b..c34fd9a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -347,9 +347,16 @@
* @mac_addr: pointer to MAC address of the interface. This pointer is valid
* until the interface is removed (i.e. it cannot be used after
* remove_interface() callback was called for this interface).
+ * This pointer will be %NULL for monitor interfaces, be careful.
*
* This structure is used in add_interface() and remove_interface()
* callbacks of &struct ieee80211_hw.
+ *
+ * When you allow multiple interfaces to be added to your PHY, take care
+ * that the hardware can actually handle multiple MAC addresses. However,
+ * also take care that when there's no interface left with mac_addr != %NULL
+ * you remove the MAC address from the device to avoid acknowledging packets
+ * in pure monitor mode.
*/
struct ieee80211_if_init_conf {
int if_id;
@@ -574,10 +581,11 @@
* to returning zero. By returning non-zero addition of the interface
* is inhibited. Unless monitor_during_oper is set, it is guaranteed
* that monitor interfaces and normal interfaces are mutually
- * exclusive. The open() handler is called after add_interface()
- * if this is the first device added. At least one of the open()
- * open() and add_interface() callbacks has to be assigned. If
- * add_interface() is NULL, one STA interface is permitted only. */
+ * exclusive. If assigned, the open() handler is called after
+ * add_interface() if this is the first device added. The
+ * add_interface() callback has to be assigned because it is the only
+ * way to obtain the requested MAC address for any interface.
+ */
int (*add_interface)(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
@@ -921,12 +929,6 @@
ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
struct ieee80211_tx_control *control);
-/* Low level drivers that have their own MLME and MAC indicate
- * the aid for an associating station with this call */
-int ieee80211_set_aid_for_sta(struct ieee80211_hw *hw,
- u8 *peer_address, u16 aid);
-
-
/* Given an sk_buff with a raw 802.11 header at the data pointer this function
* returns the 802.11 header length in bytes (not including encryption
* headers). If the data in the sk_buff is too short to contain a valid 802.11
diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
index 3ed4e14..7a67160 100644
--- a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
+++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
@@ -12,6 +12,8 @@
/* Returns new sk_buff, or NULL */
struct sk_buff *nf_ct_ipv4_ct_gather_frags(struct sk_buff *skb);
+extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
+
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp;
diff --git a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
index b4b6049..5a89659 100644
--- a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
+++ b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
@@ -7,7 +7,7 @@
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6;
-extern int nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start,
+extern int nf_ct_ipv6_skip_exthdr(const struct sk_buff *skb, int start,
u8 *nexthdrp, int len);
extern int nf_ct_frag6_init(void);
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index d4f02eb..810020e 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -186,6 +186,10 @@
extern void nf_conntrack_flush(void);
+extern int nf_ct_get_tuplepr(const struct sk_buff *skb,
+ unsigned int nhoff,
+ u_int16_t l3num,
+ struct nf_conntrack_tuple *tuple);
extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
const struct nf_conntrack_tuple *orig);
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index 890752d..3c58a2c 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -58,11 +58,11 @@
/*
* Called before tracking.
- * *dataoff: offset of protocol header (TCP, UDP,...) in *pskb
+ * *dataoff: offset of protocol header (TCP, UDP,...) in skb
* *protonum: protocol number
*/
- int (*prepare)(struct sk_buff **pskb, unsigned int hooknum,
- unsigned int *dataoff, u_int8_t *protonum);
+ int (*get_l4proto)(const struct sk_buff *skb, unsigned int nhoff,
+ unsigned int *dataoff, u_int8_t *protonum);
int (*tuple_to_nfattr)(struct sk_buff *skb,
const struct nf_conntrack_tuple *t);
@@ -89,8 +89,6 @@
extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p);
/* Existing built-in protocols */
-extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
-extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_generic;
static inline struct nf_conntrack_l3proto *
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 6c29920..7968b1d 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -65,8 +65,6 @@
{
#ifdef CONFIG_NET_CLS_ACT
struct tc_action *action;
-#elif defined CONFIG_NET_CLS_POLICE
- struct tcf_police *police;
#endif
};
@@ -91,8 +89,6 @@
{
#ifdef CONFIG_NET_CLS_ACT
return !!exts->action;
-#elif defined CONFIG_NET_CLS_POLICE
- return !!exts->police;
#else
return 0;
#endif
@@ -129,11 +125,7 @@
#ifdef CONFIG_NET_CLS_ACT
if (exts->action)
return tcf_action_exec(skb, exts->action, res);
-#elif defined CONFIG_NET_CLS_POLICE
- if (exts->police)
- return tcf_police(skb, exts->police);
#endif
-
return 0;
}
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index 5754d53..9e22526 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -89,8 +89,10 @@
__qdisc_run(dev);
}
+extern int tc_classify_compat(struct sk_buff *skb, struct tcf_proto *tp,
+ struct tcf_result *res);
extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
- struct tcf_result *res);
+ struct tcf_result *res);
/* Calculate maximal size of packet seen by hard_start_xmit
routine of this device.
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 1b8e351..8a67f24 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -290,7 +290,7 @@
{
sch->qstats.drops++;
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (sch->reshape_fail == NULL || sch->reshape_fail(skb, sch))
goto drop;
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 55ebf03..50e907f 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -48,6 +48,7 @@
ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT = UEVENT_BASE + 14,
ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15,
+ ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16,
/* up events */
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
@@ -71,6 +72,8 @@
/* messages u -> k */
struct msg_create_session {
uint32_t initial_cmdsn;
+ uint16_t cmds_max;
+ uint16_t queue_depth;
} c_session;
struct msg_destroy_session {
uint32_t sid;
@@ -136,6 +139,11 @@
*/
uint32_t enable;
} tgt_dscvr;
+ struct msg_set_host_param {
+ uint32_t host_no;
+ uint32_t param; /* enum iscsi_host_param */
+ uint32_t len;
+ } set_host_param;
} u;
union {
/* messages k -> u */
@@ -223,6 +231,11 @@
ISCSI_PARAM_CONN_PORT,
ISCSI_PARAM_CONN_ADDRESS,
+ ISCSI_PARAM_USERNAME,
+ ISCSI_PARAM_USERNAME_IN,
+ ISCSI_PARAM_PASSWORD,
+ ISCSI_PARAM_PASSWORD_IN,
+
/* must always be last */
ISCSI_PARAM_MAX,
};
@@ -249,6 +262,24 @@
#define ISCSI_SESS_RECOVERY_TMO (1 << ISCSI_PARAM_SESS_RECOVERY_TMO)
#define ISCSI_CONN_PORT (1 << ISCSI_PARAM_CONN_PORT)
#define ISCSI_CONN_ADDRESS (1 << ISCSI_PARAM_CONN_ADDRESS)
+#define ISCSI_USERNAME (1 << ISCSI_PARAM_USERNAME)
+#define ISCSI_USERNAME_IN (1 << ISCSI_PARAM_USERNAME_IN)
+#define ISCSI_PASSWORD (1 << ISCSI_PARAM_PASSWORD)
+#define ISCSI_PASSWORD_IN (1 << ISCSI_PARAM_PASSWORD_IN)
+
+/* iSCSI HBA params */
+enum iscsi_host_param {
+ ISCSI_HOST_PARAM_HWADDRESS,
+ ISCSI_HOST_PARAM_INITIATOR_NAME,
+ ISCSI_HOST_PARAM_NETDEV_NAME,
+ ISCSI_HOST_PARAM_IPADDRESS,
+ ISCSI_HOST_PARAM_MAX,
+};
+
+#define ISCSI_HOST_HWADDRESS (1 << ISCSI_HOST_PARAM_HWADDRESS)
+#define ISCSI_HOST_INITIATOR_NAME (1 << ISCSI_HOST_PARAM_INITIATOR_NAME)
+#define ISCSI_HOST_NETDEV_NAME (1 << ISCSI_HOST_PARAM_NETDEV_NAME)
+#define ISCSI_HOST_IPADDRESS (1 << ISCSI_HOST_PARAM_IPADDRESS)
#define iscsi_ptr(_handle) ((void*)(unsigned long)_handle)
#define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr)
@@ -272,6 +303,9 @@
#define CAP_MULTI_CONN 0x40
#define CAP_TEXT_NEGO 0x80
#define CAP_MARKERS 0x100
+#define CAP_FW_DB 0x200
+#define CAP_SENDTARGETS_OFFLOAD 0x400
+#define CAP_DATA_PATH_OFFLOAD 0x800
/*
* These flags describes reason of stop_conn() call
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index ea0816d..3f631b0 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -48,9 +48,8 @@
#define debug_scsi(fmt...)
#endif
-#define ISCSI_XMIT_CMDS_MAX 128 /* must be power of 2 */
-#define ISCSI_MGMT_CMDS_MAX 32 /* must be power of 2 */
-#define ISCSI_CONN_MAX 1
+#define ISCSI_DEF_XMIT_CMDS_MAX 128 /* must be power of 2 */
+#define ISCSI_MGMT_CMDS_MAX 16 /* must be power of 2 */
#define ISCSI_MGMT_ITT_OFFSET 0xa00
@@ -73,6 +72,8 @@
#define ISCSI_AGE_SHIFT 28
#define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT)
+#define ISCSI_ADDRESS_BUF_LEN 64
+
struct iscsi_mgmt_task {
/*
* Becuae LLDs allocate their hdr differently, this is a pointer to
@@ -80,7 +81,7 @@
*/
struct iscsi_hdr *hdr;
char *data; /* mgmt payload */
- int data_count; /* counts data to be sent */
+ unsigned data_count; /* counts data to be sent */
uint32_t itt; /* this ITT */
void *dd_data; /* driver/transport data */
struct list_head running;
@@ -90,6 +91,7 @@
ISCSI_TASK_COMPLETED,
ISCSI_TASK_PENDING,
ISCSI_TASK_RUNNING,
+ ISCSI_TASK_ABORTING,
};
struct iscsi_cmd_task {
@@ -99,16 +101,14 @@
*/
struct iscsi_cmd *hdr;
int itt; /* this ITT */
- int datasn; /* DataSN */
uint32_t unsol_datasn;
- int imm_count; /* imm-data (bytes) */
- int unsol_count; /* unsolicited (bytes)*/
+ unsigned imm_count; /* imm-data (bytes) */
+ unsigned unsol_count; /* unsolicited (bytes)*/
/* offset in unsolicited stream (bytes); */
- int unsol_offset;
- int data_count; /* remaining Data-Out */
+ unsigned unsol_offset;
+ unsigned data_count; /* remaining Data-Out */
struct scsi_cmnd *sc; /* associated SCSI cmd*/
- int total_length;
struct iscsi_conn *conn; /* used connection */
struct iscsi_mgmt_task *mtask; /* tmf mtask in progr */
@@ -152,18 +152,11 @@
struct iscsi_cmd_task *ctask; /* xmit ctask in progress */
/* xmit */
- struct kfifo *immqueue; /* immediate xmit queue */
struct kfifo *mgmtqueue; /* mgmt (control) xmit queue */
struct list_head mgmt_run_list; /* list of control tasks */
struct list_head xmitqueue; /* data-path cmd queue */
struct list_head run_list; /* list of cmds in progress */
struct work_struct xmitwork; /* per-conn. xmit workqueue */
- /*
- * serializes connection xmit, access to kfifos:
- * xmitqueue, immqueue, mgmtqueue
- */
- struct mutex xmitmutex;
-
unsigned long suspend_tx; /* suspend Tx */
unsigned long suspend_rx; /* suspend Rx */
@@ -174,8 +167,8 @@
int tmabort_state; /* see TMABORT_INITIAL, etc.*/
/* negotiated params */
- int max_recv_dlength; /* initiator_max_recv_dsl*/
- int max_xmit_dlength; /* target_max_recv_dsl */
+ unsigned max_recv_dlength; /* initiator_max_recv_dsl*/
+ unsigned max_xmit_dlength; /* target_max_recv_dsl */
int hdrdgst_en;
int datadgst_en;
int ifmarker_en;
@@ -183,6 +176,12 @@
/* values userspace uses to id a conn */
int persistent_port;
char *persistent_address;
+ /* remote portal currently connected to */
+ int portal_port;
+ char portal_address[ISCSI_ADDRESS_BUF_LEN];
+ /* local address */
+ int local_port;
+ char local_address[ISCSI_ADDRESS_BUF_LEN];
/* MIB-statistics */
uint64_t txdata_octets;
@@ -213,18 +212,25 @@
/* configuration */
int initial_r2t_en;
- int max_r2t;
+ unsigned max_r2t;
int imm_data_en;
- int first_burst;
- int max_burst;
+ unsigned first_burst;
+ unsigned max_burst;
int time2wait;
int time2retain;
int pdu_inorder_en;
int dataseq_inorder_en;
int erl;
int tpgt;
+ char *username;
+ char *username_in;
+ char *password;
+ char *password_in;
char *targetname;
-
+ char *initiatorname;
+ /* hw address or netdev iscsi connection is bound to */
+ char *hwaddress;
+ char *netdev;
/* control data */
struct iscsi_transport *tt;
struct Scsi_Host *host;
@@ -255,12 +261,22 @@
extern int iscsi_queuecommand(struct scsi_cmnd *sc,
void (*done)(struct scsi_cmnd *));
+
+/*
+ * iSCSI host helpers.
+ */
+extern int iscsi_host_set_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf,
+ int buflen);
+extern int iscsi_host_get_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf);
+
/*
* session management
*/
extern struct iscsi_cls_session *
iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *,
- int, int, uint32_t, uint32_t *);
+ uint16_t, uint16_t, int, int, uint32_t, uint32_t *);
extern void iscsi_session_teardown(struct iscsi_cls_session *);
extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *);
extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
@@ -289,8 +305,7 @@
/*
* pdu and task processing
*/
-extern int iscsi_check_assign_cmdsn(struct iscsi_session *,
- struct iscsi_nopin *);
+extern void iscsi_update_cmdsn(struct iscsi_session *, struct iscsi_nopin *);
extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *,
struct iscsi_data *hdr);
extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *,
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index a2e0c10..53e1705 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -135,4 +135,24 @@
extern struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *, gfp_t);
extern void scsi_free_sgtable(struct scatterlist *, int);
+extern int scsi_dma_map(struct scsi_cmnd *cmd);
+extern void scsi_dma_unmap(struct scsi_cmnd *cmd);
+
+#define scsi_sg_count(cmd) ((cmd)->use_sg)
+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
+
+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
+{
+ cmd->resid = resid;
+}
+
+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
+{
+ return cmd->resid;
+}
+
+#define scsi_for_each_sg(cmd, sg, nseg, __i) \
+ for (__i = 0, sg = scsi_sglist(cmd); __i < (nseg); __i++, (sg)++)
+
#endif /* _SCSI_SCSI_CMND_H */
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 2f3c5b8b..d5057bc 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -209,7 +209,6 @@
extern int scsi_add_device(struct Scsi_Host *host, uint channel,
uint target, uint lun);
extern void scsi_remove_device(struct scsi_device *);
-extern int scsi_device_cancel(struct scsi_device *, int);
extern int scsi_device_get(struct scsi_device *);
extern void scsi_device_put(struct scsi_device *);
@@ -287,6 +286,7 @@
extern void scsi_target_unblock(struct device *);
extern void scsi_remove_target(struct device *);
extern void int_to_scsilun(unsigned int, struct scsi_lun *);
+extern int scsilun_to_int(struct scsi_lun *);
extern const char *scsi_device_state_name(enum scsi_device_state);
extern int scsi_is_sdev_device(const struct device *);
extern int scsi_is_target_device(const struct device *);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 68f461b..ba07cf7c 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -339,12 +339,6 @@
enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
/*
- * suspend support
- */
- int (*resume)(struct scsi_device *);
- int (*suspend)(struct scsi_device *, pm_message_t state);
-
- /*
* Name of proc directory
*/
char *proc_name;
@@ -677,6 +671,10 @@
#define shost_printk(prefix, shost, fmt, a...) \
dev_printk(prefix, &(shost)->shost_gendev, fmt, ##a)
+static inline void *shost_priv(struct Scsi_Host *shost)
+{
+ return (void *)shost->hostdata;
+}
int scsi_is_host_device(const struct device *);
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index 1e79730..a0d80bc 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -1,4 +1,4 @@
-/*
+/*
* FiberChannel transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
@@ -19,7 +19,7 @@
*
* ========
*
- * Copyright (C) 2004-2005 James Smart, Emulex Corporation
+ * Copyright (C) 2004-2007 James Smart, Emulex Corporation
* Rewrite for host, target, device, and remote port attributes,
* statistics, and service functions...
*
@@ -62,8 +62,10 @@
FC_PORTTYPE_NLPORT, /* (Public) Loop w/ FLPort */
FC_PORTTYPE_LPORT, /* (Private) Loop w/o FLPort */
FC_PORTTYPE_PTP, /* Point to Point w/ another NPort */
+ FC_PORTTYPE_NPIV, /* VPORT based on NPIV */
};
+
/*
* fc_port_state: If you alter this, you also need to alter scsi_transport_fc.c
* (for the ascii descriptions).
@@ -83,7 +85,26 @@
};
-/*
+/*
+ * fc_vport_state: If you alter this, you also need to alter
+ * scsi_transport_fc.c (for the ascii descriptions).
+ */
+enum fc_vport_state {
+ FC_VPORT_UNKNOWN,
+ FC_VPORT_ACTIVE,
+ FC_VPORT_DISABLED,
+ FC_VPORT_LINKDOWN,
+ FC_VPORT_INITIALIZING,
+ FC_VPORT_NO_FABRIC_SUPP,
+ FC_VPORT_NO_FABRIC_RSCS,
+ FC_VPORT_FABRIC_LOGOUT,
+ FC_VPORT_FABRIC_REJ_WWN,
+ FC_VPORT_FAILED,
+};
+
+
+
+/*
* FC Classes of Service
* Note: values are not enumerated, as they can be "or'd" together
* for reporting (e.g. report supported_classes). If you alter this list,
@@ -96,7 +117,7 @@
#define FC_COS_CLASS4 0x10
#define FC_COS_CLASS6 0x40
-/*
+/*
* FC Port Speeds
* Note: values are not enumerated, as they can be "or'd" together
* for reporting (e.g. report supported_speeds). If you alter this list,
@@ -124,16 +145,114 @@
};
/*
- * FC Remote Port Roles
+ * FC Port Roles
* Note: values are not enumerated, as they can be "or'd" together
* for reporting (e.g. report roles). If you alter this list,
* you also need to alter scsi_transport_fc.c (for the ascii descriptions).
*/
-#define FC_RPORT_ROLE_UNKNOWN 0x00
-#define FC_RPORT_ROLE_FCP_TARGET 0x01
-#define FC_RPORT_ROLE_FCP_INITIATOR 0x02
-#define FC_RPORT_ROLE_IP_PORT 0x04
+#define FC_PORT_ROLE_UNKNOWN 0x00
+#define FC_PORT_ROLE_FCP_TARGET 0x01
+#define FC_PORT_ROLE_FCP_INITIATOR 0x02
+#define FC_PORT_ROLE_IP_PORT 0x04
+/* The following are for compatibility */
+#define FC_RPORT_ROLE_UNKNOWN FC_PORT_ROLE_UNKNOWN
+#define FC_RPORT_ROLE_FCP_TARGET FC_PORT_ROLE_FCP_TARGET
+#define FC_RPORT_ROLE_FCP_INITIATOR FC_PORT_ROLE_FCP_INITIATOR
+#define FC_RPORT_ROLE_IP_PORT FC_PORT_ROLE_IP_PORT
+
+
+/* Macro for use in defining Virtual Port attributes */
+#define FC_VPORT_ATTR(_name,_mode,_show,_store) \
+struct class_device_attribute class_device_attr_vport_##_name = \
+ __ATTR(_name,_mode,_show,_store)
+
+
+/*
+ * FC Virtual Port Attributes
+ *
+ * This structure exists for each FC port is a virtual FC port. Virtual
+ * ports share the physical link with the Physical port. Each virtual
+ * ports has a unique presense on the SAN, and may be instantiated via
+ * NPIV, Virtual Fabrics, or via additional ALPAs. As the vport is a
+ * unique presense, each vport has it's own view of the fabric,
+ * authentication priviledge, and priorities.
+ *
+ * A virtual port may support 1 or more FC4 roles. Typically it is a
+ * FCP Initiator. It could be a FCP Target, or exist sole for an IP over FC
+ * roles. FC port attributes for the vport will be reported on any
+ * fc_host class object allocated for an FCP Initiator.
+ *
+ * --
+ *
+ * Fixed attributes are not expected to change. The driver is
+ * expected to set these values after receiving the fc_vport structure
+ * via the vport_create() call from the transport.
+ * The transport fully manages all get functions w/o driver interaction.
+ *
+ * Dynamic attributes are expected to change. The driver participates
+ * in all get/set operations via functions provided by the driver.
+ *
+ * Private attributes are transport-managed values. They are fully
+ * managed by the transport w/o driver interaction.
+ */
+
+#define FC_VPORT_SYMBOLIC_NAMELEN 64
+struct fc_vport {
+ /* Fixed Attributes */
+
+ /* Dynamic Attributes */
+
+ /* Private (Transport-managed) Attributes */
+ enum fc_vport_state vport_state;
+ enum fc_vport_state vport_last_state;
+ u64 node_name;
+ u64 port_name;
+ u32 roles;
+ u32 vport_id; /* Admin Identifier for the vport */
+ enum fc_port_type vport_type;
+ char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
+
+ /* exported data */
+ void *dd_data; /* Used for driver-specific storage */
+
+ /* internal data */
+ struct Scsi_Host *shost; /* Physical Port Parent */
+ unsigned int channel;
+ u32 number;
+ u8 flags;
+ struct list_head peers;
+ struct device dev;
+ struct work_struct vport_delete_work;
+} __attribute__((aligned(sizeof(unsigned long))));
+
+/* bit field values for struct fc_vport "flags" field: */
+#define FC_VPORT_CREATING 0x01
+#define FC_VPORT_DELETING 0x02
+#define FC_VPORT_DELETED 0x04
+#define FC_VPORT_DEL 0x06 /* Any DELETE state */
+
+#define dev_to_vport(d) \
+ container_of(d, struct fc_vport, dev)
+#define transport_class_to_vport(classdev) \
+ dev_to_vport(classdev->dev)
+#define vport_to_shost(v) \
+ (v->shost)
+#define vport_to_shost_channel(v) \
+ (v->channel)
+#define vport_to_parent(v) \
+ (v->dev.parent)
+
+
+/* Error return codes for vport_create() callback */
+#define VPCERR_UNSUPPORTED -ENOSYS /* no driver/adapter
+ support */
+#define VPCERR_BAD_WWN -ENOTUNIQ /* driver validation
+ of WWNs failed */
+#define VPCERR_NO_FABRIC_SUPP -EOPNOTSUPP /* Fabric connection
+ is loop or the
+ Fabric Port does
+ not support NPIV */
/*
* fc_rport_identifiers: This set of data contains all elements
@@ -149,6 +268,7 @@
u32 roles;
};
+
/* Macro for use in defining Remote Port attributes */
#define FC_RPORT_ATTR(_name,_mode,_show,_store) \
struct class_device_attribute class_device_attr_rport_##_name = \
@@ -278,7 +398,7 @@
u64 prim_seq_protocol_err_count;
u64 invalid_tx_word_count;
u64 invalid_crc_count;
-
+
/* fc4 statistics (only FCP supported currently) */
u64 fcp_input_requests;
u64 fcp_output_requests;
@@ -343,6 +463,7 @@
u8 supported_fc4s[FC_FC4_LIST_SIZE];
u32 supported_speeds;
u32 maxframe_size;
+ u16 max_npiv_vports;
char serial_number[FC_SERIAL_NUMBER_SIZE];
/* Dynamic Attributes */
@@ -361,8 +482,11 @@
/* internal data */
struct list_head rports;
struct list_head rport_bindings;
+ struct list_head vports;
u32 next_rport_number;
u32 next_target_id;
+ u32 next_vport_number;
+ u16 npiv_vports_inuse;
/* work queues for rport state manipulation */
char work_q_name[KOBJ_NAME_LEN];
@@ -388,6 +512,8 @@
(((struct fc_host_attrs *)(x)->shost_data)->supported_speeds)
#define fc_host_maxframe_size(x) \
(((struct fc_host_attrs *)(x)->shost_data)->maxframe_size)
+#define fc_host_max_npiv_vports(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->max_npiv_vports)
#define fc_host_serial_number(x) \
(((struct fc_host_attrs *)(x)->shost_data)->serial_number)
#define fc_host_port_id(x) \
@@ -412,10 +538,16 @@
(((struct fc_host_attrs *)(x)->shost_data)->rports)
#define fc_host_rport_bindings(x) \
(((struct fc_host_attrs *)(x)->shost_data)->rport_bindings)
+#define fc_host_vports(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->vports)
#define fc_host_next_rport_number(x) \
(((struct fc_host_attrs *)(x)->shost_data)->next_rport_number)
#define fc_host_next_target_id(x) \
(((struct fc_host_attrs *)(x)->shost_data)->next_target_id)
+#define fc_host_next_vport_number(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->next_vport_number)
+#define fc_host_npiv_vports_inuse(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->npiv_vports_inuse)
#define fc_host_work_q_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->work_q_name)
#define fc_host_work_q(x) \
@@ -452,14 +584,20 @@
void (*dev_loss_tmo_callbk)(struct fc_rport *);
void (*terminate_rport_io)(struct fc_rport *);
+ void (*set_vport_symbolic_name)(struct fc_vport *);
+ int (*vport_create)(struct fc_vport *, bool);
+ int (*vport_disable)(struct fc_vport *, bool);
+ int (*vport_delete)(struct fc_vport *);
+
/* allocation lengths for host-specific data */
u32 dd_fcrport_size;
+ u32 dd_fcvport_size;
- /*
+ /*
* The driver sets these to tell the transport class it
* wants the attributes displayed in sysfs. If the show_ flag
* is not set, the attribute will be private to the transport
- * class
+ * class
*/
/* remote port fixed attributes */
@@ -512,7 +650,7 @@
switch (rport->port_state) {
case FC_PORTSTATE_ONLINE:
- if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+ if (rport->roles & FC_PORT_ROLE_FCP_TARGET)
result = 0;
else if (rport->flags & FC_RPORT_DEVLOSS_PENDING)
result = DID_IMM_RETRY << 16;
@@ -549,6 +687,27 @@
wwn[7] = inm & 0xff;
}
+/**
+ * fc_vport_set_state() - called to set a vport's state. Saves the old state,
+ * excepting the transitory states of initializing and sending the ELS
+ * traffic to instantiate the vport on the link.
+ *
+ * Assumes the driver has surrounded this with the proper locking to ensure
+ * a coherent state change.
+ *
+ * @vport: virtual port whose state is changing
+ * @new_state: new state
+ **/
+static inline void
+fc_vport_set_state(struct fc_vport *vport, enum fc_vport_state new_state)
+{
+ if ((new_state != FC_VPORT_UNKNOWN) &&
+ (new_state != FC_VPORT_INITIALIZING))
+ vport->vport_last_state = vport->vport_state;
+ vport->vport_state = new_state;
+}
+
+
struct scsi_transport_template *fc_attach_transport(
struct fc_function_template *);
void fc_release_transport(struct scsi_transport_template *);
@@ -567,5 +726,6 @@
* be sure to read the Vendor Type and ID formatting requirements
* specified in scsi_netlink.h
*/
+int fc_vport_terminate(struct fc_vport *vport);
#endif /* SCSI_TRANSPORT_FC_H */
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index d5c218d..706c0cd 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -79,7 +79,8 @@
char *name;
unsigned int caps;
/* LLD sets this to indicate what values it can export to sysfs */
- unsigned int param_mask;
+ uint64_t param_mask;
+ uint64_t host_param_mask;
struct scsi_host_template *host_template;
/* LLD connection data size */
int conndata_size;
@@ -89,7 +90,8 @@
unsigned int max_conn;
unsigned int max_cmd_len;
struct iscsi_cls_session *(*create_session) (struct iscsi_transport *it,
- struct scsi_transport_template *t, uint32_t sn, uint32_t *hn);
+ struct scsi_transport_template *t, uint16_t, uint16_t,
+ uint32_t sn, uint32_t *hn);
void (*destroy_session) (struct iscsi_cls_session *session);
struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
uint32_t cid);
@@ -105,14 +107,18 @@
enum iscsi_param param, char *buf);
int (*get_session_param) (struct iscsi_cls_session *session,
enum iscsi_param param, char *buf);
+ int (*get_host_param) (struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf);
+ int (*set_host_param) (struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf,
+ int buflen);
int (*send_pdu) (struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
char *data, uint32_t data_size);
void (*get_stats) (struct iscsi_cls_conn *conn,
struct iscsi_stats *stats);
void (*init_cmd_task) (struct iscsi_cmd_task *ctask);
void (*init_mgmt_task) (struct iscsi_conn *conn,
- struct iscsi_mgmt_task *mtask,
- char *data, uint32_t data_size);
+ struct iscsi_mgmt_task *mtask);
int (*xmit_cmd_task) (struct iscsi_conn *conn,
struct iscsi_cmd_task *ctask);
void (*cleanup_cmd_task) (struct iscsi_conn *conn,
@@ -124,7 +130,7 @@
uint64_t *ep_handle);
int (*ep_poll) (uint64_t ep_handle, int timeout_ms);
void (*ep_disconnect) (uint64_t ep_handle);
- int (*tgt_dscvr) (enum iscsi_tgt_dscvr type, uint32_t host_no,
+ int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
uint32_t enable, struct sockaddr *dst_addr);
};
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 402eb4e..9927cca 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -151,6 +151,7 @@
out:
return ret;
}
+EXPORT_SYMBOL(radix_tree_preload);
static inline void tag_set(struct radix_tree_node *node, unsigned int tag,
int offset)
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index abb9900..cda936b 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -373,10 +373,11 @@
new_dev->open = vlan_dev_open;
new_dev->stop = vlan_dev_stop;
new_dev->set_multicast_list = vlan_dev_set_multicast_list;
+ new_dev->change_rx_flags = vlan_change_rx_flags;
new_dev->destructor = free_netdev;
new_dev->do_ioctl = vlan_dev_ioctl;
- memset(new_dev->broadcast, 0, sizeof(ETH_ALEN));
+ memset(new_dev->broadcast, 0, ETH_ALEN);
}
static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev)
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 62ce1c5..7df5b29 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -69,6 +69,7 @@
u32 flag, short flag_val);
void vlan_dev_get_realdev_name(const struct net_device *dev, char *result);
void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result);
+void vlan_change_rx_flags(struct net_device *dev, int change);
void vlan_dev_set_multicast_list(struct net_device *vlan_dev);
int vlan_check_real_dev(struct net_device *real_dev, unsigned short vlan_id);
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index d4a62d1..4d2aa4d 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -612,90 +612,6 @@
*result = VLAN_DEV_INFO(dev)->vlan_id;
}
-static inline int vlan_dmi_equals(struct dev_mc_list *dmi1,
- struct dev_mc_list *dmi2)
-{
- return ((dmi1->dmi_addrlen == dmi2->dmi_addrlen) &&
- (memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0));
-}
-
-/** dmi is a single entry into a dev_mc_list, a single node. mc_list is
- * an entire list, and we'll iterate through it.
- */
-static int vlan_should_add_mc(struct dev_mc_list *dmi, struct dev_mc_list *mc_list)
-{
- struct dev_mc_list *idmi;
-
- for (idmi = mc_list; idmi != NULL; ) {
- if (vlan_dmi_equals(dmi, idmi)) {
- if (dmi->dmi_users > idmi->dmi_users)
- return 1;
- else
- return 0;
- } else {
- idmi = idmi->next;
- }
- }
-
- return 1;
-}
-
-static inline void vlan_destroy_mc_list(struct dev_mc_list *mc_list)
-{
- struct dev_mc_list *dmi = mc_list;
- struct dev_mc_list *next;
-
- while(dmi) {
- next = dmi->next;
- kfree(dmi);
- dmi = next;
- }
-}
-
-static void vlan_copy_mc_list(struct dev_mc_list *mc_list, struct vlan_dev_info *vlan_info)
-{
- struct dev_mc_list *dmi, *new_dmi;
-
- vlan_destroy_mc_list(vlan_info->old_mc_list);
- vlan_info->old_mc_list = NULL;
-
- for (dmi = mc_list; dmi != NULL; dmi = dmi->next) {
- new_dmi = kmalloc(sizeof(*new_dmi), GFP_ATOMIC);
- if (new_dmi == NULL) {
- printk(KERN_ERR "vlan: cannot allocate memory. "
- "Multicast may not work properly from now.\n");
- return;
- }
-
- /* Copy whole structure, then make new 'next' pointer */
- *new_dmi = *dmi;
- new_dmi->next = vlan_info->old_mc_list;
- vlan_info->old_mc_list = new_dmi;
- }
-}
-
-static void vlan_flush_mc_list(struct net_device *dev)
-{
- struct dev_mc_list *dmi = dev->mc_list;
-
- while (dmi) {
- printk(KERN_DEBUG "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from vlan interface\n",
- dev->name,
- dmi->dmi_addr[0],
- dmi->dmi_addr[1],
- dmi->dmi_addr[2],
- dmi->dmi_addr[3],
- dmi->dmi_addr[4],
- dmi->dmi_addr[5]);
- dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
- dmi = dev->mc_list;
- }
-
- /* dev->mc_list is NULL by the time we get here. */
- vlan_destroy_mc_list(VLAN_DEV_INFO(dev)->old_mc_list);
- VLAN_DEV_INFO(dev)->old_mc_list = NULL;
-}
-
int vlan_dev_open(struct net_device *dev)
{
struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
@@ -712,6 +628,11 @@
}
memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN);
+ if (dev->flags & IFF_ALLMULTI)
+ dev_set_allmulti(real_dev, 1);
+ if (dev->flags & IFF_PROMISC)
+ dev_set_promiscuity(real_dev, 1);
+
return 0;
}
@@ -719,7 +640,11 @@
{
struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev;
- vlan_flush_mc_list(dev);
+ dev_mc_unsync(real_dev, dev);
+ if (dev->flags & IFF_ALLMULTI)
+ dev_set_allmulti(real_dev, -1);
+ if (dev->flags & IFF_PROMISC)
+ dev_set_promiscuity(real_dev, -1);
if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len);
@@ -754,68 +679,18 @@
return err;
}
+void vlan_change_rx_flags(struct net_device *dev, int change)
+{
+ struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev;
+
+ if (change & IFF_ALLMULTI)
+ dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1);
+ if (change & IFF_PROMISC)
+ dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1);
+}
+
/** Taken from Gleb + Lennert's VLAN code, and modified... */
void vlan_dev_set_multicast_list(struct net_device *vlan_dev)
{
- struct dev_mc_list *dmi;
- struct net_device *real_dev;
- int inc;
-
- if (vlan_dev && (vlan_dev->priv_flags & IFF_802_1Q_VLAN)) {
- /* Then it's a real vlan device, as far as we can tell.. */
- real_dev = VLAN_DEV_INFO(vlan_dev)->real_dev;
-
- /* compare the current promiscuity to the last promisc we had.. */
- inc = vlan_dev->promiscuity - VLAN_DEV_INFO(vlan_dev)->old_promiscuity;
- if (inc) {
- printk(KERN_INFO "%s: dev_set_promiscuity(master, %d)\n",
- vlan_dev->name, inc);
- dev_set_promiscuity(real_dev, inc); /* found in dev.c */
- VLAN_DEV_INFO(vlan_dev)->old_promiscuity = vlan_dev->promiscuity;
- }
-
- inc = vlan_dev->allmulti - VLAN_DEV_INFO(vlan_dev)->old_allmulti;
- if (inc) {
- printk(KERN_INFO "%s: dev_set_allmulti(master, %d)\n",
- vlan_dev->name, inc);
- dev_set_allmulti(real_dev, inc); /* dev.c */
- VLAN_DEV_INFO(vlan_dev)->old_allmulti = vlan_dev->allmulti;
- }
-
- /* looking for addresses to add to master's list */
- for (dmi = vlan_dev->mc_list; dmi != NULL; dmi = dmi->next) {
- if (vlan_should_add_mc(dmi, VLAN_DEV_INFO(vlan_dev)->old_mc_list)) {
- dev_mc_add(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
- printk(KERN_DEBUG "%s: add %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address to master interface\n",
- vlan_dev->name,
- dmi->dmi_addr[0],
- dmi->dmi_addr[1],
- dmi->dmi_addr[2],
- dmi->dmi_addr[3],
- dmi->dmi_addr[4],
- dmi->dmi_addr[5]);
- }
- }
-
- /* looking for addresses to delete from master's list */
- for (dmi = VLAN_DEV_INFO(vlan_dev)->old_mc_list; dmi != NULL; dmi = dmi->next) {
- if (vlan_should_add_mc(dmi, vlan_dev->mc_list)) {
- /* if we think we should add it to the new list, then we should really
- * delete it from the real list on the underlying device.
- */
- dev_mc_delete(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
- printk(KERN_DEBUG "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n",
- vlan_dev->name,
- dmi->dmi_addr[0],
- dmi->dmi_addr[1],
- dmi->dmi_addr[2],
- dmi->dmi_addr[3],
- dmi->dmi_addr[4],
- dmi->dmi_addr[5]);
- }
- }
-
- /* save multicast list */
- vlan_copy_mc_list(vlan_dev->mc_list, VLAN_DEV_INFO(vlan_dev));
- }
+ dev_mc_sync(VLAN_DEV_INFO(vlan_dev)->real_dev, vlan_dev);
}
diff --git a/net/9p/Kconfig b/net/9p/Kconfig
new file mode 100644
index 0000000..66821cd
--- /dev/null
+++ b/net/9p/Kconfig
@@ -0,0 +1,21 @@
+#
+# 9P protocol configuration
+#
+
+menuconfig NET_9P
+ depends on NET && EXPERIMENTAL
+ tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)"
+ help
+ If you say Y here, you will get experimental support for
+ Plan 9 resource sharing via the 9P2000 protocol.
+
+ See <http://v9fs.sf.net> for more information.
+
+ If unsure, say N.
+
+config NET_9P_DEBUG
+ bool "Debug information"
+ depends on NET_9P
+ help
+ Say Y if you want the 9P subsistem to log debug information.
+
diff --git a/net/9p/Makefile b/net/9p/Makefile
new file mode 100644
index 0000000..85b3a78
--- /dev/null
+++ b/net/9p/Makefile
@@ -0,0 +1,13 @@
+obj-$(CONFIG_NET_9P) := 9pnet.o
+
+9pnet-objs := \
+ mod.o \
+ trans_fd.o \
+ mux.o \
+ client.o \
+ conv.o \
+ error.o \
+ fcprint.o \
+ util.o \
+
+9pnet-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/net/9p/client.c b/net/9p/client.c
new file mode 100644
index 0000000..cb17075
--- /dev/null
+++ b/net/9p/client.c
@@ -0,0 +1,965 @@
+/*
+ * net/9p/clnt.c
+ *
+ * 9P Client
+ *
+ * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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; if not, write to:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <net/9p/9p.h>
+#include <net/9p/transport.h>
+#include <net/9p/conn.h>
+#include <net/9p/client.h>
+
+static struct p9_fid *p9_fid_create(struct p9_client *clnt);
+static void p9_fid_destroy(struct p9_fid *fid);
+static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
+
+struct p9_client *p9_client_create(struct p9_transport *trans, int msize,
+ int dotu)
+{
+ int err, n;
+ struct p9_client *clnt;
+ struct p9_fcall *tc, *rc;
+ struct p9_str *version;
+
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
+ if (!clnt)
+ return ERR_PTR(-ENOMEM);
+
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n",
+ clnt, trans, msize, dotu);
+ spin_lock_init(&clnt->lock);
+ clnt->trans = trans;
+ clnt->msize = msize;
+ clnt->dotu = dotu;
+ INIT_LIST_HEAD(&clnt->fidlist);
+ clnt->fidpool = p9_idpool_create();
+ if (!clnt->fidpool) {
+ err = PTR_ERR(clnt->fidpool);
+ clnt->fidpool = NULL;
+ goto error;
+ }
+
+ clnt->conn = p9_conn_create(clnt->trans, clnt->msize, &clnt->dotu);
+ if (IS_ERR(clnt->conn)) {
+ err = PTR_ERR(clnt->conn);
+ clnt->conn = NULL;
+ goto error;
+ }
+
+ tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000");
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ version = &rc->params.rversion.version;
+ if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8))
+ clnt->dotu = 1;
+ else if (version->len == 6 && !memcmp(version->str, "9P2000", 6))
+ clnt->dotu = 0;
+ else {
+ err = -EREMOTEIO;
+ goto error;
+ }
+
+ n = rc->params.rversion.msize;
+ if (n < clnt->msize)
+ clnt->msize = n;
+
+ kfree(tc);
+ kfree(rc);
+ return clnt;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ p9_client_destroy(clnt);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_create);
+
+void p9_client_destroy(struct p9_client *clnt)
+{
+ struct p9_fid *fid, *fidptr;
+
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
+ if (clnt->conn) {
+ p9_conn_destroy(clnt->conn);
+ clnt->conn = NULL;
+ }
+
+ if (clnt->trans) {
+ clnt->trans->close(clnt->trans);
+ kfree(clnt->trans);
+ clnt->trans = NULL;
+ }
+
+ list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
+ p9_fid_destroy(fid);
+
+ if (clnt->fidpool)
+ p9_idpool_destroy(clnt->fidpool);
+
+ kfree(clnt);
+}
+EXPORT_SYMBOL(p9_client_destroy);
+
+void p9_client_disconnect(struct p9_client *clnt)
+{
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
+ clnt->trans->status = Disconnected;
+ p9_conn_cancel(clnt->conn, -EIO);
+}
+EXPORT_SYMBOL(p9_client_disconnect);
+
+struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
+ char *uname, char *aname)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_fid *fid;
+
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n",
+ clnt, afid?afid->fid:-1, uname, aname);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+
+ fid = p9_fid_create(clnt);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ fid = NULL;
+ goto error;
+ }
+
+ tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid));
+ kfree(tc);
+ kfree(rc);
+ return fid;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ if (fid)
+ p9_fid_destroy(fid);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_attach);
+
+struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, char *aname)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_fid *fid;
+
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname,
+ aname);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+
+ fid = p9_fid_create(clnt);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ fid = NULL;
+ goto error;
+ }
+
+ tc = p9_create_tauth(fid->fid, uname, aname);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid));
+ kfree(tc);
+ kfree(rc);
+ return fid;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ if (fid)
+ p9_fid_destroy(fid);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_auth);
+
+struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
+ int clone)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+ struct p9_fid *fid;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n",
+ oldfid->fid, nwname, wnames?wnames[0]:NULL);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = oldfid->clnt;
+ if (clone) {
+ fid = p9_fid_create(clnt);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ fid = NULL;
+ goto error;
+ }
+
+ fid->uid = oldfid->uid;
+ } else
+ fid = oldfid;
+
+ tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err) {
+ if (rc && rc->id == P9_RWALK)
+ goto clunk_fid;
+ else
+ goto error;
+ }
+
+ if (rc->params.rwalk.nwqid != nwname) {
+ err = -ENOENT;
+ goto clunk_fid;
+ }
+
+ if (nwname)
+ memmove(&fid->qid,
+ &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1],
+ sizeof(struct p9_qid));
+ else
+ fid->qid = oldfid->qid;
+
+ kfree(tc);
+ kfree(rc);
+ return fid;
+
+clunk_fid:
+ kfree(tc);
+ kfree(rc);
+ rc = NULL;
+ tc = p9_create_tclunk(fid->fid);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ p9_conn_rpc(clnt->conn, tc, &rc);
+
+error:
+ kfree(tc);
+ kfree(rc);
+ if (fid && (fid != oldfid))
+ p9_fid_destroy(fid);
+
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_walk);
+
+int p9_client_open(struct p9_fid *fid, int mode)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+
+ if (fid->mode != -1)
+ return -EINVAL;
+
+ tc = p9_create_topen(fid->fid, mode);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto done;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto done;
+
+ fid->mode = mode;
+ fid->iounit = rc->params.ropen.iounit;
+
+done:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_open);
+
+int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
+ char *extension)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid,
+ name, perm, mode);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+
+ if (fid->mode != -1)
+ return -EINVAL;
+
+ tc = p9_create_tcreate(fid->fid, name, perm, mode, extension,
+ clnt->dotu);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto done;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto done;
+
+ fid->mode = mode;
+ fid->iounit = rc->params.ropen.iounit;
+
+done:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_fcreate);
+
+int p9_client_clunk(struct p9_fid *fid)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+
+ tc = p9_create_tclunk(fid->fid);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto done;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto done;
+
+ p9_fid_destroy(fid);
+
+done:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_clunk);
+
+int p9_client_remove(struct p9_fid *fid)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+
+ tc = p9_create_tremove(fid->fid);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto done;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto done;
+
+ p9_fid_destroy(fid);
+
+done:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_remove);
+
+int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count)
+{
+ int err, n, rsize, total;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid,
+ (long long unsigned) offset, count);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+ total = 0;
+
+ rsize = fid->iounit;
+ if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
+ rsize = clnt->msize - P9_IOHDRSZ;
+
+ do {
+ if (count < rsize)
+ rsize = count;
+
+ tc = p9_create_tread(fid->fid, offset, rsize);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ n = rc->params.rread.count;
+ if (n > count)
+ n = count;
+
+ memmove(data, rc->params.rread.data, n);
+ count -= n;
+ data += n;
+ offset += n;
+ total += n;
+ kfree(tc);
+ tc = NULL;
+ kfree(rc);
+ rc = NULL;
+ } while (count > 0 && n == rsize);
+
+ return total;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_read);
+
+int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count)
+{
+ int err, n, rsize, total;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
+ (long long unsigned) offset, count);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+ total = 0;
+
+ rsize = fid->iounit;
+ if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
+ rsize = clnt->msize - P9_IOHDRSZ;
+
+ do {
+ if (count < rsize)
+ rsize = count;
+
+ tc = p9_create_twrite(fid->fid, offset, rsize, data);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ n = rc->params.rread.count;
+ count -= n;
+ data += n;
+ offset += n;
+ total += n;
+ kfree(tc);
+ tc = NULL;
+ kfree(rc);
+ rc = NULL;
+ } while (count > 0);
+
+ return total;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_write);
+
+int
+p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count)
+{
+ int err, n, rsize, total;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
+ (long long unsigned) offset, count);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+ total = 0;
+
+ rsize = fid->iounit;
+ if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
+ rsize = clnt->msize - P9_IOHDRSZ;
+
+ do {
+ if (count < rsize)
+ rsize = count;
+
+ tc = p9_create_tread(fid->fid, offset, rsize);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ n = rc->params.rread.count;
+ if (n > count)
+ n = count;
+
+ err = copy_to_user(data, rc->params.rread.data, n);
+ if (err) {
+ err = -EFAULT;
+ goto error;
+ }
+
+ count -= n;
+ data += n;
+ offset += n;
+ total += n;
+ kfree(tc);
+ tc = NULL;
+ kfree(rc);
+ rc = NULL;
+ } while (count > 0 && n == rsize);
+
+ return total;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_uread);
+
+int
+p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
+ u32 count)
+{
+ int err, n, rsize, total;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
+ (long long unsigned) offset, count);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+ total = 0;
+
+ rsize = fid->iounit;
+ if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
+ rsize = clnt->msize - P9_IOHDRSZ;
+
+ do {
+ if (count < rsize)
+ rsize = count;
+
+ tc = p9_create_twrite_u(fid->fid, offset, rsize, data);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ n = rc->params.rread.count;
+ count -= n;
+ data += n;
+ offset += n;
+ total += n;
+ kfree(tc);
+ tc = NULL;
+ kfree(rc);
+ rc = NULL;
+ } while (count > 0);
+
+ return total;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_uwrite);
+
+int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count)
+{
+ int n, total;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
+ (long long unsigned) offset, count);
+ n = 0;
+ total = 0;
+ while (count) {
+ n = p9_client_read(fid, data, offset, count);
+ if (n <= 0)
+ break;
+
+ data += n;
+ offset += n;
+ count -= n;
+ total += n;
+ }
+
+ if (n < 0)
+ total = n;
+
+ return total;
+}
+EXPORT_SYMBOL(p9_client_readn);
+
+struct p9_stat *p9_client_stat(struct p9_fid *fid)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+ struct p9_stat *ret;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ ret = NULL;
+ clnt = fid->clnt;
+
+ tc = p9_create_tstat(fid->fid);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu);
+ if (IS_ERR(ret)) {
+ err = PTR_ERR(ret);
+ ret = NULL;
+ goto error;
+ }
+
+ kfree(tc);
+ kfree(rc);
+ return ret;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ kfree(ret);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_stat);
+
+int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+
+ tc = p9_create_twstat(fid->fid, wst, clnt->dotu);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto done;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+
+done:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_wstat);
+
+struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset)
+{
+ int err, n, m;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+ struct p9_stat st, *ret;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid,
+ (long long unsigned) offset);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ ret = NULL;
+ clnt = fid->clnt;
+
+ /* if the offset is below or above the current response, free it */
+ if (offset < fid->rdir_fpos || (fid->rdir_fcall &&
+ offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) {
+ fid->rdir_pos = 0;
+ if (fid->rdir_fcall)
+ fid->rdir_fpos += fid->rdir_fcall->params.rread.count;
+
+ kfree(fid->rdir_fcall);
+ fid->rdir_fcall = NULL;
+ if (offset < fid->rdir_fpos)
+ fid->rdir_fpos = 0;
+ }
+
+ if (!fid->rdir_fcall) {
+ n = fid->iounit;
+ if (!n || n > clnt->msize-P9_IOHDRSZ)
+ n = clnt->msize - P9_IOHDRSZ;
+
+ while (1) {
+ if (fid->rdir_fcall) {
+ fid->rdir_fpos +=
+ fid->rdir_fcall->params.rread.count;
+ kfree(fid->rdir_fcall);
+ fid->rdir_fcall = NULL;
+ }
+
+ tc = p9_create_tread(fid->fid, fid->rdir_fpos, n);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ n = rc->params.rread.count;
+ if (n == 0)
+ goto done;
+
+ fid->rdir_fcall = rc;
+ rc = NULL;
+ if (offset >= fid->rdir_fpos &&
+ offset < fid->rdir_fpos+n)
+ break;
+ }
+
+ fid->rdir_pos = 0;
+ }
+
+ m = offset - fid->rdir_fpos;
+ if (m < 0)
+ goto done;
+
+ n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m,
+ fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu);
+
+ if (!n) {
+ err = -EIO;
+ goto error;
+ }
+
+ fid->rdir_pos += n;
+ st.size = n;
+ ret = p9_clone_stat(&st, clnt->dotu);
+ if (IS_ERR(ret)) {
+ err = PTR_ERR(ret);
+ ret = NULL;
+ goto error;
+ }
+
+done:
+ kfree(tc);
+ kfree(rc);
+ return ret;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ kfree(ret);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_dirread);
+
+static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu)
+{
+ int n;
+ char *p;
+ struct p9_stat *ret;
+
+ n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len +
+ st->muid.len;
+
+ if (dotu)
+ n += st->extension.len;
+
+ ret = kmalloc(n, GFP_KERNEL);
+ if (!ret)
+ return ERR_PTR(-ENOMEM);
+
+ memmove(ret, st, sizeof(struct p9_stat));
+ p = ((char *) ret) + sizeof(struct p9_stat);
+ memmove(p, st->name.str, st->name.len);
+ p += st->name.len;
+ memmove(p, st->uid.str, st->uid.len);
+ p += st->uid.len;
+ memmove(p, st->gid.str, st->gid.len);
+ p += st->gid.len;
+ memmove(p, st->muid.str, st->muid.len);
+ p += st->muid.len;
+
+ if (dotu) {
+ memmove(p, st->extension.str, st->extension.len);
+ p += st->extension.len;
+ }
+
+ return ret;
+}
+
+static struct p9_fid *p9_fid_create(struct p9_client *clnt)
+{
+ int err;
+ struct p9_fid *fid;
+
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
+ fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
+ if (!fid)
+ return ERR_PTR(-ENOMEM);
+
+ fid->fid = p9_idpool_get(clnt->fidpool);
+ if (fid->fid < 0) {
+ err = -ENOSPC;
+ goto error;
+ }
+
+ memset(&fid->qid, 0, sizeof(struct p9_qid));
+ fid->mode = -1;
+ fid->rdir_fpos = 0;
+ fid->rdir_pos = 0;
+ fid->rdir_fcall = NULL;
+ fid->uid = current->fsuid;
+ fid->clnt = clnt;
+ fid->aux = NULL;
+
+ spin_lock(&clnt->lock);
+ list_add(&fid->flist, &clnt->fidlist);
+ spin_unlock(&clnt->lock);
+
+ return fid;
+
+error:
+ kfree(fid);
+ return ERR_PTR(err);
+}
+
+static void p9_fid_destroy(struct p9_fid *fid)
+{
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
+ clnt = fid->clnt;
+ p9_idpool_put(fid->fid, clnt->fidpool);
+ spin_lock(&clnt->lock);
+ list_del(&fid->flist);
+ spin_unlock(&clnt->lock);
+ kfree(fid->rdir_fcall);
+ kfree(fid);
+}
diff --git a/net/9p/conv.c b/net/9p/conv.c
new file mode 100644
index 0000000..3745117
--- /dev/null
+++ b/net/9p/conv.c
@@ -0,0 +1,903 @@
+/*
+ * net/9p/conv.c
+ *
+ * 9P protocol conversion functions
+ *
+ * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net>
+ * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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; if not, write to:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/idr.h>
+#include <linux/uaccess.h>
+#include <net/9p/9p.h>
+
+/*
+ * Buffer to help with string parsing
+ */
+struct cbuf {
+ unsigned char *sp;
+ unsigned char *p;
+ unsigned char *ep;
+};
+
+static inline void buf_init(struct cbuf *buf, void *data, int datalen)
+{
+ buf->sp = buf->p = data;
+ buf->ep = data + datalen;
+}
+
+static inline int buf_check_overflow(struct cbuf *buf)
+{
+ return buf->p > buf->ep;
+}
+
+static int buf_check_size(struct cbuf *buf, int len)
+{
+ if (buf->p + len > buf->ep) {
+ if (buf->p < buf->ep) {
+ P9_EPRINTK(KERN_ERR,
+ "buffer overflow: want %d has %d\n", len,
+ (int)(buf->ep - buf->p));
+ dump_stack();
+ buf->p = buf->ep + 1;
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+static void *buf_alloc(struct cbuf *buf, int len)
+{
+ void *ret = NULL;
+
+ if (buf_check_size(buf, len)) {
+ ret = buf->p;
+ buf->p += len;
+ }
+
+ return ret;
+}
+
+static void buf_put_int8(struct cbuf *buf, u8 val)
+{
+ if (buf_check_size(buf, 1)) {
+ buf->p[0] = val;
+ buf->p++;
+ }
+}
+
+static void buf_put_int16(struct cbuf *buf, u16 val)
+{
+ if (buf_check_size(buf, 2)) {
+ *(__le16 *) buf->p = cpu_to_le16(val);
+ buf->p += 2;
+ }
+}
+
+static void buf_put_int32(struct cbuf *buf, u32 val)
+{
+ if (buf_check_size(buf, 4)) {
+ *(__le32 *)buf->p = cpu_to_le32(val);
+ buf->p += 4;
+ }
+}
+
+static void buf_put_int64(struct cbuf *buf, u64 val)
+{
+ if (buf_check_size(buf, 8)) {
+ *(__le64 *)buf->p = cpu_to_le64(val);
+ buf->p += 8;
+ }
+}
+
+static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
+{
+ char *ret;
+
+ ret = NULL;
+ if (buf_check_size(buf, slen + 2)) {
+ buf_put_int16(buf, slen);
+ ret = buf->p;
+ memcpy(buf->p, s, slen);
+ buf->p += slen;
+ }
+
+ return ret;
+}
+
+static inline void buf_put_string(struct cbuf *buf, const char *s)
+{
+ buf_put_stringn(buf, s, strlen(s));
+}
+
+static u8 buf_get_int8(struct cbuf *buf)
+{
+ u8 ret = 0;
+
+ if (buf_check_size(buf, 1)) {
+ ret = buf->p[0];
+ buf->p++;
+ }
+
+ return ret;
+}
+
+static u16 buf_get_int16(struct cbuf *buf)
+{
+ u16 ret = 0;
+
+ if (buf_check_size(buf, 2)) {
+ ret = le16_to_cpu(*(__le16 *)buf->p);
+ buf->p += 2;
+ }
+
+ return ret;
+}
+
+static u32 buf_get_int32(struct cbuf *buf)
+{
+ u32 ret = 0;
+
+ if (buf_check_size(buf, 4)) {
+ ret = le32_to_cpu(*(__le32 *)buf->p);
+ buf->p += 4;
+ }
+
+ return ret;
+}
+
+static u64 buf_get_int64(struct cbuf *buf)
+{
+ u64 ret = 0;
+
+ if (buf_check_size(buf, 8)) {
+ ret = le64_to_cpu(*(__le64 *)buf->p);
+ buf->p += 8;
+ }
+
+ return ret;
+}
+
+static void buf_get_str(struct cbuf *buf, struct p9_str *vstr)
+{
+ vstr->len = buf_get_int16(buf);
+ if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
+ vstr->str = buf->p;
+ buf->p += vstr->len;
+ } else {
+ vstr->len = 0;
+ vstr->str = NULL;
+ }
+}
+
+static void buf_get_qid(struct cbuf *bufp, struct p9_qid *qid)
+{
+ qid->type = buf_get_int8(bufp);
+ qid->version = buf_get_int32(bufp);
+ qid->path = buf_get_int64(bufp);
+}
+
+/**
+ * p9_size_wstat - calculate the size of a variable length stat struct
+ * @stat: metadata (stat) structure
+ * @dotu: non-zero if 9P2000.u
+ *
+ */
+
+static int p9_size_wstat(struct p9_wstat *wstat, int dotu)
+{
+ int size = 0;
+
+ if (wstat == NULL) {
+ P9_EPRINTK(KERN_ERR, "p9_size_stat: got a NULL stat pointer\n");
+ return 0;
+ }
+
+ size = /* 2 + *//* size[2] */
+ 2 + /* type[2] */
+ 4 + /* dev[4] */
+ 1 + /* qid.type[1] */
+ 4 + /* qid.vers[4] */
+ 8 + /* qid.path[8] */
+ 4 + /* mode[4] */
+ 4 + /* atime[4] */
+ 4 + /* mtime[4] */
+ 8 + /* length[8] */
+ 8; /* minimum sum of string lengths */
+
+ if (wstat->name)
+ size += strlen(wstat->name);
+ if (wstat->uid)
+ size += strlen(wstat->uid);
+ if (wstat->gid)
+ size += strlen(wstat->gid);
+ if (wstat->muid)
+ size += strlen(wstat->muid);
+
+ if (dotu) {
+ size += 4 + /* n_uid[4] */
+ 4 + /* n_gid[4] */
+ 4 + /* n_muid[4] */
+ 2; /* string length of extension[4] */
+ if (wstat->extension)
+ size += strlen(wstat->extension);
+ }
+
+ return size;
+}
+
+/**
+ * buf_get_stat - safely decode a recieved metadata (stat) structure
+ * @bufp: buffer to deserialize
+ * @stat: metadata (stat) structure
+ * @dotu: non-zero if 9P2000.u
+ *
+ */
+
+static void
+buf_get_stat(struct cbuf *bufp, struct p9_stat *stat, int dotu)
+{
+ stat->size = buf_get_int16(bufp);
+ stat->type = buf_get_int16(bufp);
+ stat->dev = buf_get_int32(bufp);
+ stat->qid.type = buf_get_int8(bufp);
+ stat->qid.version = buf_get_int32(bufp);
+ stat->qid.path = buf_get_int64(bufp);
+ stat->mode = buf_get_int32(bufp);
+ stat->atime = buf_get_int32(bufp);
+ stat->mtime = buf_get_int32(bufp);
+ stat->length = buf_get_int64(bufp);
+ buf_get_str(bufp, &stat->name);
+ buf_get_str(bufp, &stat->uid);
+ buf_get_str(bufp, &stat->gid);
+ buf_get_str(bufp, &stat->muid);
+
+ if (dotu) {
+ buf_get_str(bufp, &stat->extension);
+ stat->n_uid = buf_get_int32(bufp);
+ stat->n_gid = buf_get_int32(bufp);
+ stat->n_muid = buf_get_int32(bufp);
+ }
+}
+
+/**
+ * p9_deserialize_stat - decode a received metadata structure
+ * @buf: buffer to deserialize
+ * @buflen: length of received buffer
+ * @stat: metadata structure to decode into
+ * @dotu: non-zero if 9P2000.u
+ *
+ * Note: stat will point to the buf region.
+ */
+
+int
+p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat,
+ int dotu)
+{
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+ unsigned char *p;
+
+ buf_init(bufp, buf, buflen);
+ p = bufp->p;
+ buf_get_stat(bufp, stat, dotu);
+
+ if (buf_check_overflow(bufp))
+ return 0;
+ else
+ return bufp->p - p;
+}
+EXPORT_SYMBOL(p9_deserialize_stat);
+
+/**
+ * deserialize_fcall - unmarshal a response
+ * @buf: recieved buffer
+ * @buflen: length of received buffer
+ * @rcall: fcall structure to populate
+ * @rcalllen: length of fcall structure to populate
+ * @dotu: non-zero if 9P2000.u
+ *
+ */
+
+int
+p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *rcall,
+ int dotu)
+{
+
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+ int i = 0;
+
+ buf_init(bufp, buf, buflen);
+
+ rcall->size = buf_get_int32(bufp);
+ rcall->id = buf_get_int8(bufp);
+ rcall->tag = buf_get_int16(bufp);
+
+ P9_DPRINTK(P9_DEBUG_CONV, "size %d id %d tag %d\n", rcall->size,
+ rcall->id, rcall->tag);
+
+ switch (rcall->id) {
+ default:
+ P9_EPRINTK(KERN_ERR, "unknown message type: %d\n", rcall->id);
+ return -EPROTO;
+ case P9_RVERSION:
+ rcall->params.rversion.msize = buf_get_int32(bufp);
+ buf_get_str(bufp, &rcall->params.rversion.version);
+ break;
+ case P9_RFLUSH:
+ break;
+ case P9_RATTACH:
+ rcall->params.rattach.qid.type = buf_get_int8(bufp);
+ rcall->params.rattach.qid.version = buf_get_int32(bufp);
+ rcall->params.rattach.qid.path = buf_get_int64(bufp);
+ break;
+ case P9_RWALK:
+ rcall->params.rwalk.nwqid = buf_get_int16(bufp);
+ if (rcall->params.rwalk.nwqid > P9_MAXWELEM) {
+ P9_EPRINTK(KERN_ERR,
+ "Rwalk with more than %d qids: %d\n",
+ P9_MAXWELEM, rcall->params.rwalk.nwqid);
+ return -EPROTO;
+ }
+
+ for (i = 0; i < rcall->params.rwalk.nwqid; i++)
+ buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
+ break;
+ case P9_ROPEN:
+ buf_get_qid(bufp, &rcall->params.ropen.qid);
+ rcall->params.ropen.iounit = buf_get_int32(bufp);
+ break;
+ case P9_RCREATE:
+ buf_get_qid(bufp, &rcall->params.rcreate.qid);
+ rcall->params.rcreate.iounit = buf_get_int32(bufp);
+ break;
+ case P9_RREAD:
+ rcall->params.rread.count = buf_get_int32(bufp);
+ rcall->params.rread.data = bufp->p;
+ buf_check_size(bufp, rcall->params.rread.count);
+ break;
+ case P9_RWRITE:
+ rcall->params.rwrite.count = buf_get_int32(bufp);
+ break;
+ case P9_RCLUNK:
+ break;
+ case P9_RREMOVE:
+ break;
+ case P9_RSTAT:
+ buf_get_int16(bufp);
+ buf_get_stat(bufp, &rcall->params.rstat.stat, dotu);
+ break;
+ case P9_RWSTAT:
+ break;
+ case P9_RERROR:
+ buf_get_str(bufp, &rcall->params.rerror.error);
+ if (dotu)
+ rcall->params.rerror.errno = buf_get_int16(bufp);
+ break;
+ }
+
+ if (buf_check_overflow(bufp)) {
+ P9_DPRINTK(P9_DEBUG_ERROR, "buffer overflow\n");
+ return -EIO;
+ }
+
+ return bufp->p - bufp->sp;
+}
+EXPORT_SYMBOL(p9_deserialize_fcall);
+
+static inline void p9_put_int8(struct cbuf *bufp, u8 val, u8 * p)
+{
+ *p = val;
+ buf_put_int8(bufp, val);
+}
+
+static inline void p9_put_int16(struct cbuf *bufp, u16 val, u16 * p)
+{
+ *p = val;
+ buf_put_int16(bufp, val);
+}
+
+static inline void p9_put_int32(struct cbuf *bufp, u32 val, u32 * p)
+{
+ *p = val;
+ buf_put_int32(bufp, val);
+}
+
+static inline void p9_put_int64(struct cbuf *bufp, u64 val, u64 * p)
+{
+ *p = val;
+ buf_put_int64(bufp, val);
+}
+
+static void
+p9_put_str(struct cbuf *bufp, char *data, struct p9_str *str)
+{
+ int len;
+ char *s;
+
+ if (data)
+ len = strlen(data);
+ else
+ len = 0;
+
+ s = buf_put_stringn(bufp, data, len);
+ if (str) {
+ str->len = len;
+ str->str = s;
+ }
+}
+
+static int
+p9_put_data(struct cbuf *bufp, const char *data, int count,
+ unsigned char **pdata)
+{
+ *pdata = buf_alloc(bufp, count);
+ memmove(*pdata, data, count);
+ return count;
+}
+
+static int
+p9_put_user_data(struct cbuf *bufp, const char __user *data, int count,
+ unsigned char **pdata)
+{
+ *pdata = buf_alloc(bufp, count);
+ return copy_from_user(*pdata, data, count);
+}
+
+static void
+p9_put_wstat(struct cbuf *bufp, struct p9_wstat *wstat,
+ struct p9_stat *stat, int statsz, int dotu)
+{
+ p9_put_int16(bufp, statsz, &stat->size);
+ p9_put_int16(bufp, wstat->type, &stat->type);
+ p9_put_int32(bufp, wstat->dev, &stat->dev);
+ p9_put_int8(bufp, wstat->qid.type, &stat->qid.type);
+ p9_put_int32(bufp, wstat->qid.version, &stat->qid.version);
+ p9_put_int64(bufp, wstat->qid.path, &stat->qid.path);
+ p9_put_int32(bufp, wstat->mode, &stat->mode);
+ p9_put_int32(bufp, wstat->atime, &stat->atime);
+ p9_put_int32(bufp, wstat->mtime, &stat->mtime);
+ p9_put_int64(bufp, wstat->length, &stat->length);
+
+ p9_put_str(bufp, wstat->name, &stat->name);
+ p9_put_str(bufp, wstat->uid, &stat->uid);
+ p9_put_str(bufp, wstat->gid, &stat->gid);
+ p9_put_str(bufp, wstat->muid, &stat->muid);
+
+ if (dotu) {
+ p9_put_str(bufp, wstat->extension, &stat->extension);
+ p9_put_int32(bufp, wstat->n_uid, &stat->n_uid);
+ p9_put_int32(bufp, wstat->n_gid, &stat->n_gid);
+ p9_put_int32(bufp, wstat->n_muid, &stat->n_muid);
+ }
+}
+
+static struct p9_fcall *
+p9_create_common(struct cbuf *bufp, u32 size, u8 id)
+{
+ struct p9_fcall *fc;
+
+ size += 4 + 1 + 2; /* size[4] id[1] tag[2] */
+ fc = kmalloc(sizeof(struct p9_fcall) + size, GFP_KERNEL);
+ if (!fc)
+ return ERR_PTR(-ENOMEM);
+
+ fc->sdata = (char *)fc + sizeof(*fc);
+
+ buf_init(bufp, (char *)fc->sdata, size);
+ p9_put_int32(bufp, size, &fc->size);
+ p9_put_int8(bufp, id, &fc->id);
+ p9_put_int16(bufp, P9_NOTAG, &fc->tag);
+
+ return fc;
+}
+
+void p9_set_tag(struct p9_fcall *fc, u16 tag)
+{
+ fc->tag = tag;
+ *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
+}
+EXPORT_SYMBOL(p9_set_tag);
+
+struct p9_fcall *p9_create_tversion(u32 msize, char *version)
+{
+ int size;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ size = 4 + 2 + strlen(version); /* msize[4] version[s] */
+ fc = p9_create_common(bufp, size, P9_TVERSION);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, msize, &fc->params.tversion.msize);
+ p9_put_str(bufp, version, &fc->params.tversion.version);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_tversion);
+
+struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname)
+{
+ int size;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ /* afid[4] uname[s] aname[s] */
+ size = 4 + 2 + strlen(uname) + 2 + strlen(aname);
+ fc = p9_create_common(bufp, size, P9_TAUTH);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, afid, &fc->params.tauth.afid);
+ p9_put_str(bufp, uname, &fc->params.tauth.uname);
+ p9_put_str(bufp, aname, &fc->params.tauth.aname);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_tauth);
+
+struct p9_fcall *
+p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
+{
+ int size;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ /* fid[4] afid[4] uname[s] aname[s] */
+ size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname);
+ fc = p9_create_common(bufp, size, P9_TATTACH);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, fid, &fc->params.tattach.fid);
+ p9_put_int32(bufp, afid, &fc->params.tattach.afid);
+ p9_put_str(bufp, uname, &fc->params.tattach.uname);
+ p9_put_str(bufp, aname, &fc->params.tattach.aname);
+
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_tattach);
+
+struct p9_fcall *p9_create_tflush(u16 oldtag)
+{
+ int size;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ size = 2; /* oldtag[2] */
+ fc = p9_create_common(bufp, size, P9_TFLUSH);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_tflush);
+
+struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname,
+ char **wnames)
+{
+ int i, size;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ if (nwname > P9_MAXWELEM) {
+ P9_DPRINTK(P9_DEBUG_ERROR, "nwname > %d\n", P9_MAXWELEM);
+ return NULL;
+ }
+
+ size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */
+ for (i = 0; i < nwname; i++) {
+ size += 2 + strlen(wnames[i]); /* wname[s] */
+ }
+
+ fc = p9_create_common(bufp, size, P9_TWALK);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, fid, &fc->params.twalk.fid);
+ p9_put_int32(bufp, newfid, &fc->params.twalk.newfid);
+ p9_put_int16(bufp, nwname, &fc->params.twalk.nwname);
+ for (i = 0; i < nwname; i++) {
+ p9_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
+ }
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_twalk);
+
+struct p9_fcall *p9_create_topen(u32 fid, u8 mode)
+{
+ int size;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ size = 4 + 1; /* fid[4] mode[1] */
+ fc = p9_create_common(bufp, size, P9_TOPEN);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, fid, &fc->params.topen.fid);
+ p9_put_int8(bufp, mode, &fc->params.topen.mode);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_topen);
+
+struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
+ char *extension, int dotu)
+{
+ int size;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ /* fid[4] name[s] perm[4] mode[1] */
+ size = 4 + 2 + strlen(name) + 4 + 1;
+ if (dotu) {
+ size += 2 + /* extension[s] */
+ (extension == NULL ? 0 : strlen(extension));
+ }
+
+ fc = p9_create_common(bufp, size, P9_TCREATE);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, fid, &fc->params.tcreate.fid);
+ p9_put_str(bufp, name, &fc->params.tcreate.name);
+ p9_put_int32(bufp, perm, &fc->params.tcreate.perm);
+ p9_put_int8(bufp, mode, &fc->params.tcreate.mode);
+ if (dotu)
+ p9_put_str(bufp, extension, &fc->params.tcreate.extension);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_tcreate);
+
+struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count)
+{
+ int size;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */
+ fc = p9_create_common(bufp, size, P9_TREAD);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, fid, &fc->params.tread.fid);
+ p9_put_int64(bufp, offset, &fc->params.tread.offset);
+ p9_put_int32(bufp, count, &fc->params.tread.count);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_tread);
+
+struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count,
+ const char *data)
+{
+ int size, err;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ /* fid[4] offset[8] count[4] data[count] */
+ size = 4 + 8 + 4 + count;
+ fc = p9_create_common(bufp, size, P9_TWRITE);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, fid, &fc->params.twrite.fid);
+ p9_put_int64(bufp, offset, &fc->params.twrite.offset);
+ p9_put_int32(bufp, count, &fc->params.twrite.count);
+ err = p9_put_data(bufp, data, count, &fc->params.twrite.data);
+ if (err) {
+ kfree(fc);
+ fc = ERR_PTR(err);
+ }
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_twrite);
+
+struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count,
+ const char __user *data)
+{
+ int size, err;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ /* fid[4] offset[8] count[4] data[count] */
+ size = 4 + 8 + 4 + count;
+ fc = p9_create_common(bufp, size, P9_TWRITE);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, fid, &fc->params.twrite.fid);
+ p9_put_int64(bufp, offset, &fc->params.twrite.offset);
+ p9_put_int32(bufp, count, &fc->params.twrite.count);
+ err = p9_put_user_data(bufp, data, count, &fc->params.twrite.data);
+ if (err) {
+ kfree(fc);
+ fc = ERR_PTR(err);
+ }
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_twrite_u);
+
+struct p9_fcall *p9_create_tclunk(u32 fid)
+{
+ int size;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ size = 4; /* fid[4] */
+ fc = p9_create_common(bufp, size, P9_TCLUNK);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, fid, &fc->params.tclunk.fid);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_tclunk);
+
+struct p9_fcall *p9_create_tremove(u32 fid)
+{
+ int size;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ size = 4; /* fid[4] */
+ fc = p9_create_common(bufp, size, P9_TREMOVE);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, fid, &fc->params.tremove.fid);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_tremove);
+
+struct p9_fcall *p9_create_tstat(u32 fid)
+{
+ int size;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ size = 4; /* fid[4] */
+ fc = p9_create_common(bufp, size, P9_TSTAT);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, fid, &fc->params.tstat.fid);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_tstat);
+
+struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat,
+ int dotu)
+{
+ int size, statsz;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ statsz = p9_size_wstat(wstat, dotu);
+ size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */
+ fc = p9_create_common(bufp, size, P9_TWSTAT);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, fid, &fc->params.twstat.fid);
+ buf_put_int16(bufp, statsz + 2);
+ p9_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, dotu);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_twstat);
diff --git a/fs/9p/error.h b/net/9p/error.c
similarity index 78%
rename from fs/9p/error.h
rename to net/9p/error.c
index 5f3ca52..ab2458b 100644
--- a/fs/9p/error.h
+++ b/net/9p/error.c
@@ -1,12 +1,11 @@
/*
- * linux/fs/9p/error.h
+ * linux/fs/9p/error.c
*
- * Huge Nasty Error Table
+ * Error string handling
*
- * Plan 9 uses error strings, Unix uses error numbers. This table tries to
- * match UNIX strings and Plan 9 strings to unix error numbers. It is used
- * to preload the dynamic error table which can also track user-specific error
- * strings.
+ * Plan 9 uses error strings, Unix uses error numbers. These functions
+ * try to help manage that and provide for dynamically adding error
+ * mappings.
*
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
@@ -28,8 +27,11 @@
*
*/
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/jhash.h>
#include <linux/errno.h>
-#include <asm/errno.h>
+#include <net/9p/9p.h>
struct errormap {
char *name;
@@ -174,4 +176,65 @@
{NULL, -1}
};
-extern int v9fs_error_init(void);
+/**
+ * p9_error_init - preload
+ * @errstr: error string
+ *
+ */
+
+int p9_error_init(void)
+{
+ struct errormap *c;
+ int bucket;
+
+ /* initialize hash table */
+ for (bucket = 0; bucket < ERRHASHSZ; bucket++)
+ INIT_HLIST_HEAD(&hash_errmap[bucket]);
+
+ /* load initial error map into hash table */
+ for (c = errmap; c->name != NULL; c++) {
+ c->namelen = strlen(c->name);
+ bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ;
+ INIT_HLIST_NODE(&c->list);
+ hlist_add_head(&c->list, &hash_errmap[bucket]);
+ }
+
+ return 1;
+}
+EXPORT_SYMBOL(p9_error_init);
+
+/**
+ * errstr2errno - convert error string to error number
+ * @errstr: error string
+ *
+ */
+
+int p9_errstr2errno(char *errstr, int len)
+{
+ int errno;
+ struct hlist_node *p;
+ struct errormap *c;
+ int bucket;
+
+ errno = 0;
+ p = NULL;
+ c = NULL;
+ bucket = jhash(errstr, len, 0) % ERRHASHSZ;
+ hlist_for_each_entry(c, p, &hash_errmap[bucket], list) {
+ if (c->namelen == len && !memcmp(c->name, errstr, len)) {
+ errno = c->val;
+ break;
+ }
+ }
+
+ if (errno == 0) {
+ /* TODO: if error isn't found, add it dynamically */
+ errstr[len] = 0;
+ printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__,
+ errstr);
+ errno = 1;
+ }
+
+ return -errno;
+}
+EXPORT_SYMBOL(p9_errstr2errno);
diff --git a/fs/9p/fcprint.c b/net/9p/fcprint.c
similarity index 64%
rename from fs/9p/fcprint.c
rename to net/9p/fcprint.c
index 34b9611..b1ae8ec 100644
--- a/fs/9p/fcprint.c
+++ b/net/9p/fcprint.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/9p/fcprint.c
+ * net/9p/fcprint.c
*
* Print 9P call.
*
@@ -25,61 +25,59 @@
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/idr.h>
+#include <net/9p/9p.h>
-#include "debug.h"
-#include "v9fs.h"
-#include "9p.h"
-#include "mux.h"
+#ifdef CONFIG_NET_9P_DEBUG
static int
-v9fs_printqid(char *buf, int buflen, struct v9fs_qid *q)
+p9_printqid(char *buf, int buflen, struct p9_qid *q)
{
int n;
char b[10];
n = 0;
- if (q->type & V9FS_QTDIR)
+ if (q->type & P9_QTDIR)
b[n++] = 'd';
- if (q->type & V9FS_QTAPPEND)
+ if (q->type & P9_QTAPPEND)
b[n++] = 'a';
- if (q->type & V9FS_QTAUTH)
+ if (q->type & P9_QTAUTH)
b[n++] = 'A';
- if (q->type & V9FS_QTEXCL)
+ if (q->type & P9_QTEXCL)
b[n++] = 'l';
- if (q->type & V9FS_QTTMP)
+ if (q->type & P9_QTTMP)
b[n++] = 't';
- if (q->type & V9FS_QTSYMLINK)
+ if (q->type & P9_QTSYMLINK)
b[n++] = 'L';
b[n] = '\0';
- return scnprintf(buf, buflen, "(%.16llx %x %s)", (long long int) q->path,
- q->version, b);
+ return scnprintf(buf, buflen, "(%.16llx %x %s)",
+ (long long int) q->path, q->version, b);
}
static int
-v9fs_printperm(char *buf, int buflen, int perm)
+p9_printperm(char *buf, int buflen, int perm)
{
int n;
char b[15];
n = 0;
- if (perm & V9FS_DMDIR)
+ if (perm & P9_DMDIR)
b[n++] = 'd';
- if (perm & V9FS_DMAPPEND)
+ if (perm & P9_DMAPPEND)
b[n++] = 'a';
- if (perm & V9FS_DMAUTH)
+ if (perm & P9_DMAUTH)
b[n++] = 'A';
- if (perm & V9FS_DMEXCL)
+ if (perm & P9_DMEXCL)
b[n++] = 'l';
- if (perm & V9FS_DMTMP)
+ if (perm & P9_DMTMP)
b[n++] = 't';
- if (perm & V9FS_DMDEVICE)
+ if (perm & P9_DMDEVICE)
b[n++] = 'D';
- if (perm & V9FS_DMSOCKET)
+ if (perm & P9_DMSOCKET)
b[n++] = 'S';
- if (perm & V9FS_DMNAMEDPIPE)
+ if (perm & P9_DMNAMEDPIPE)
b[n++] = 'P';
- if (perm & V9FS_DMSYMLINK)
+ if (perm & P9_DMSYMLINK)
b[n++] = 'L';
b[n] = '\0';
@@ -87,7 +85,7 @@
}
static int
-v9fs_printstat(char *buf, int buflen, struct v9fs_stat *st, int extended)
+p9_printstat(char *buf, int buflen, struct p9_stat *st, int extended)
{
int n;
@@ -105,9 +103,9 @@
n += scnprintf(buf+n, buflen-n, "(%d)", st->n_muid);
n += scnprintf(buf+n, buflen-n, " q ");
- n += v9fs_printqid(buf+n, buflen-n, &st->qid);
+ n += p9_printqid(buf+n, buflen-n, &st->qid);
n += scnprintf(buf+n, buflen-n, " m ");
- n += v9fs_printperm(buf+n, buflen-n, st->mode);
+ n += p9_printperm(buf+n, buflen-n, st->mode);
n += scnprintf(buf+n, buflen-n, " at %d mt %d l %lld",
st->atime, st->mtime, (long long int) st->length);
@@ -119,7 +117,7 @@
}
static int
-v9fs_dumpdata(char *buf, int buflen, u8 *data, int datalen)
+p9_dumpdata(char *buf, int buflen, u8 *data, int datalen)
{
int i, n;
@@ -139,13 +137,13 @@
}
static int
-v9fs_printdata(char *buf, int buflen, u8 *data, int datalen)
+p9_printdata(char *buf, int buflen, u8 *data, int datalen)
{
- return v9fs_dumpdata(buf, buflen, data, datalen<16?datalen:16);
+ return p9_dumpdata(buf, buflen, data, datalen < 16?datalen:16);
}
int
-v9fs_printfcall(char *buf, int buflen, struct v9fs_fcall *fc, int extended)
+p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
{
int i, ret, type, tag;
@@ -157,21 +155,23 @@
ret = 0;
switch (type) {
- case TVERSION:
+ case P9_TVERSION:
ret += scnprintf(buf+ret, buflen-ret,
- "Tversion tag %u msize %u version '%.*s'", tag,
- fc->params.tversion.msize, fc->params.tversion.version.len,
- fc->params.tversion.version.str);
+ "Tversion tag %u msize %u version '%.*s'", tag,
+ fc->params.tversion.msize,
+ fc->params.tversion.version.len,
+ fc->params.tversion.version.str);
break;
- case RVERSION:
+ case P9_RVERSION:
ret += scnprintf(buf+ret, buflen-ret,
- "Rversion tag %u msize %u version '%.*s'", tag,
- fc->params.rversion.msize, fc->params.rversion.version.len,
- fc->params.rversion.version.str);
+ "Rversion tag %u msize %u version '%.*s'", tag,
+ fc->params.rversion.msize,
+ fc->params.rversion.version.len,
+ fc->params.rversion.version.str);
break;
- case TAUTH:
+ case P9_TAUTH:
ret += scnprintf(buf+ret, buflen-ret,
"Tauth tag %u afid %d uname '%.*s' aname '%.*s'", tag,
fc->params.tauth.afid, fc->params.tauth.uname.len,
@@ -179,93 +179,97 @@
fc->params.tauth.aname.str);
break;
- case RAUTH:
+ case P9_RAUTH:
ret += scnprintf(buf+ret, buflen-ret, "Rauth tag %u qid ", tag);
- v9fs_printqid(buf+ret, buflen-ret, &fc->params.rauth.qid);
+ p9_printqid(buf+ret, buflen-ret, &fc->params.rauth.qid);
break;
- case TATTACH:
+ case P9_TATTACH:
ret += scnprintf(buf+ret, buflen-ret,
- "Tattach tag %u fid %d afid %d uname '%.*s' aname '%.*s'",
- tag, fc->params.tattach.fid, fc->params.tattach.afid,
- fc->params.tattach.uname.len, fc->params.tattach.uname.str,
- fc->params.tattach.aname.len, fc->params.tattach.aname.str);
+ "Tattach tag %u fid %d afid %d uname '%.*s' aname '%.*s'", tag,
+ fc->params.tattach.fid, fc->params.tattach.afid,
+ fc->params.tattach.uname.len, fc->params.tattach.uname.str,
+ fc->params.tattach.aname.len, fc->params.tattach.aname.str);
break;
- case RATTACH:
- ret += scnprintf(buf+ret, buflen-ret, "Rattach tag %u qid ", tag);
- v9fs_printqid(buf+ret, buflen-ret, &fc->params.rattach.qid);
+ case P9_RATTACH:
+ ret += scnprintf(buf+ret, buflen-ret, "Rattach tag %u qid ",
+ tag);
+ p9_printqid(buf+ret, buflen-ret, &fc->params.rattach.qid);
break;
- case RERROR:
- ret += scnprintf(buf+ret, buflen-ret, "Rerror tag %u ename '%.*s'",
- tag, fc->params.rerror.error.len,
- fc->params.rerror.error.str);
+ case P9_RERROR:
+ ret += scnprintf(buf+ret, buflen-ret,
+ "Rerror tag %u ename '%.*s'", tag,
+ fc->params.rerror.error.len,
+ fc->params.rerror.error.str);
if (extended)
ret += scnprintf(buf+ret, buflen-ret, " ecode %d\n",
fc->params.rerror.errno);
break;
- case TFLUSH:
+ case P9_TFLUSH:
ret += scnprintf(buf+ret, buflen-ret, "Tflush tag %u oldtag %u",
tag, fc->params.tflush.oldtag);
break;
- case RFLUSH:
+ case P9_RFLUSH:
ret += scnprintf(buf+ret, buflen-ret, "Rflush tag %u", tag);
break;
- case TWALK:
+ case P9_TWALK:
ret += scnprintf(buf+ret, buflen-ret,
"Twalk tag %u fid %d newfid %d nwname %d", tag,
fc->params.twalk.fid, fc->params.twalk.newfid,
fc->params.twalk.nwname);
- for(i = 0; i < fc->params.twalk.nwname; i++)
- ret += scnprintf(buf+ret, buflen-ret," '%.*s'",
+ for (i = 0; i < fc->params.twalk.nwname; i++)
+ ret += scnprintf(buf+ret, buflen-ret, " '%.*s'",
fc->params.twalk.wnames[i].len,
fc->params.twalk.wnames[i].str);
break;
- case RWALK:
+ case P9_RWALK:
ret += scnprintf(buf+ret, buflen-ret, "Rwalk tag %u nwqid %d",
tag, fc->params.rwalk.nwqid);
- for(i = 0; i < fc->params.rwalk.nwqid; i++)
- ret += v9fs_printqid(buf+ret, buflen-ret,
+ for (i = 0; i < fc->params.rwalk.nwqid; i++)
+ ret += p9_printqid(buf+ret, buflen-ret,
&fc->params.rwalk.wqids[i]);
break;
- case TOPEN:
+ case P9_TOPEN:
ret += scnprintf(buf+ret, buflen-ret,
"Topen tag %u fid %d mode %d", tag,
fc->params.topen.fid, fc->params.topen.mode);
break;
- case ROPEN:
+ case P9_ROPEN:
ret += scnprintf(buf+ret, buflen-ret, "Ropen tag %u", tag);
- ret += v9fs_printqid(buf+ret, buflen-ret, &fc->params.ropen.qid);
- ret += scnprintf(buf+ret, buflen-ret," iounit %d",
+ ret += p9_printqid(buf+ret, buflen-ret, &fc->params.ropen.qid);
+ ret += scnprintf(buf+ret, buflen-ret, " iounit %d",
fc->params.ropen.iounit);
break;
- case TCREATE:
+ case P9_TCREATE:
ret += scnprintf(buf+ret, buflen-ret,
"Tcreate tag %u fid %d name '%.*s' perm ", tag,
fc->params.tcreate.fid, fc->params.tcreate.name.len,
fc->params.tcreate.name.str);
- ret += v9fs_printperm(buf+ret, buflen-ret, fc->params.tcreate.perm);
+ ret += p9_printperm(buf+ret, buflen-ret,
+ fc->params.tcreate.perm);
ret += scnprintf(buf+ret, buflen-ret, " mode %d",
fc->params.tcreate.mode);
break;
- case RCREATE:
+ case P9_RCREATE:
ret += scnprintf(buf+ret, buflen-ret, "Rcreate tag %u", tag);
- ret += v9fs_printqid(buf+ret, buflen-ret, &fc->params.rcreate.qid);
+ ret += p9_printqid(buf+ret, buflen-ret,
+ &fc->params.rcreate.qid);
ret += scnprintf(buf+ret, buflen-ret, " iounit %d",
fc->params.rcreate.iounit);
break;
- case TREAD:
+ case P9_TREAD:
ret += scnprintf(buf+ret, buflen-ret,
"Tread tag %u fid %d offset %lld count %u", tag,
fc->params.tread.fid,
@@ -273,66 +277,66 @@
fc->params.tread.count);
break;
- case RREAD:
+ case P9_RREAD:
ret += scnprintf(buf+ret, buflen-ret,
"Rread tag %u count %u data ", tag,
fc->params.rread.count);
- ret += v9fs_printdata(buf+ret, buflen-ret, fc->params.rread.data,
+ ret += p9_printdata(buf+ret, buflen-ret, fc->params.rread.data,
fc->params.rread.count);
break;
- case TWRITE:
+ case P9_TWRITE:
ret += scnprintf(buf+ret, buflen-ret,
"Twrite tag %u fid %d offset %lld count %u data ",
tag, fc->params.twrite.fid,
(long long int) fc->params.twrite.offset,
fc->params.twrite.count);
- ret += v9fs_printdata(buf+ret, buflen-ret, fc->params.twrite.data,
+ ret += p9_printdata(buf+ret, buflen-ret, fc->params.twrite.data,
fc->params.twrite.count);
break;
- case RWRITE:
+ case P9_RWRITE:
ret += scnprintf(buf+ret, buflen-ret, "Rwrite tag %u count %u",
tag, fc->params.rwrite.count);
break;
- case TCLUNK:
+ case P9_TCLUNK:
ret += scnprintf(buf+ret, buflen-ret, "Tclunk tag %u fid %d",
tag, fc->params.tclunk.fid);
break;
- case RCLUNK:
+ case P9_RCLUNK:
ret += scnprintf(buf+ret, buflen-ret, "Rclunk tag %u", tag);
break;
- case TREMOVE:
+ case P9_TREMOVE:
ret += scnprintf(buf+ret, buflen-ret, "Tremove tag %u fid %d",
tag, fc->params.tremove.fid);
break;
- case RREMOVE:
+ case P9_RREMOVE:
ret += scnprintf(buf+ret, buflen-ret, "Rremove tag %u", tag);
break;
- case TSTAT:
+ case P9_TSTAT:
ret += scnprintf(buf+ret, buflen-ret, "Tstat tag %u fid %d",
tag, fc->params.tstat.fid);
break;
- case RSTAT:
+ case P9_RSTAT:
ret += scnprintf(buf+ret, buflen-ret, "Rstat tag %u ", tag);
- ret += v9fs_printstat(buf+ret, buflen-ret, &fc->params.rstat.stat,
+ ret += p9_printstat(buf+ret, buflen-ret, &fc->params.rstat.stat,
extended);
break;
- case TWSTAT:
+ case P9_TWSTAT:
ret += scnprintf(buf+ret, buflen-ret, "Twstat tag %u fid %d ",
tag, fc->params.twstat.fid);
- ret += v9fs_printstat(buf+ret, buflen-ret, &fc->params.twstat.stat,
- extended);
+ ret += p9_printstat(buf+ret, buflen-ret,
+ &fc->params.twstat.stat, extended);
break;
- case RWSTAT:
+ case P9_RWSTAT:
ret += scnprintf(buf+ret, buflen-ret, "Rwstat tag %u", tag);
break;
@@ -343,3 +347,12 @@
return ret;
}
+
+#else
+int
+p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
+{
+ return 0;
+}
+EXPORT_SYMBOL(p9_printfcall);
+#endif /* CONFIG_NET_9P_DEBUG */
diff --git a/net/9p/mod.c b/net/9p/mod.c
new file mode 100644
index 0000000..4f9e1d2
--- /dev/null
+++ b/net/9p/mod.c
@@ -0,0 +1,85 @@
+/*
+ * net/9p/9p.c
+ *
+ * 9P entry point
+ *
+ * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
+ * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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; if not, write to:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <net/9p/9p.h>
+
+#ifdef CONFIG_NET_9P_DEBUG
+unsigned int p9_debug_level = 0; /* feature-rific global debug level */
+EXPORT_SYMBOL(p9_debug_level);
+module_param_named(debug, p9_debug_level, uint, 0);
+MODULE_PARM_DESC(debug, "9P debugging level");
+#endif
+
+extern int p9_mux_global_init(void);
+extern void p9_mux_global_exit(void);
+extern int p9_sysctl_register(void);
+extern void p9_sysctl_unregister(void);
+
+/**
+ * v9fs_init - Initialize module
+ *
+ */
+static int __init init_p9(void)
+{
+ int ret;
+
+ p9_error_init();
+ printk(KERN_INFO "Installing 9P2000 support\n");
+ ret = p9_mux_global_init();
+ if (ret) {
+ printk(KERN_WARNING "9p: starting mux failed\n");
+ return ret;
+ }
+
+ ret = p9_sysctl_register();
+ if (ret) {
+ printk(KERN_WARNING "9p: registering sysctl failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * v9fs_init - shutdown module
+ *
+ */
+
+static void __exit exit_p9(void)
+{
+ p9_sysctl_unregister();
+ p9_mux_global_exit();
+}
+
+module_init(init_p9)
+module_exit(exit_p9)
+
+MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
+MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
+MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
+MODULE_LICENSE("GPL");
diff --git a/net/9p/mux.c b/net/9p/mux.c
new file mode 100644
index 0000000..acb0388
--- /dev/null
+++ b/net/9p/mux.c
@@ -0,0 +1,1054 @@
+/*
+ * net/9p/mux.c
+ *
+ * Protocol Multiplexer
+ *
+ * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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; if not, write to:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/kthread.h>
+#include <linux/idr.h>
+#include <linux/mutex.h>
+#include <net/9p/9p.h>
+#include <net/9p/transport.h>
+#include <net/9p/conn.h>
+
+#define ERREQFLUSH 1
+#define SCHED_TIMEOUT 10
+#define MAXPOLLWADDR 2
+
+enum {
+ Rworksched = 1, /* read work scheduled or running */
+ Rpending = 2, /* can read */
+ Wworksched = 4, /* write work scheduled or running */
+ Wpending = 8, /* can write */
+};
+
+enum {
+ None,
+ Flushing,
+ Flushed,
+};
+
+struct p9_mux_poll_task;
+
+struct p9_req {
+ spinlock_t lock; /* protect request structure */
+ int tag;
+ struct p9_fcall *tcall;
+ struct p9_fcall *rcall;
+ int err;
+ p9_conn_req_callback cb;
+ void *cba;
+ int flush;
+ struct list_head req_list;
+};
+
+struct p9_conn {
+ spinlock_t lock; /* protect lock structure */
+ struct list_head mux_list;
+ struct p9_mux_poll_task *poll_task;
+ int msize;
+ unsigned char *extended;
+ struct p9_transport *trans;
+ struct p9_idpool *tagpool;
+ int err;
+ wait_queue_head_t equeue;
+ struct list_head req_list;
+ struct list_head unsent_req_list;
+ struct p9_fcall *rcall;
+ int rpos;
+ char *rbuf;
+ int wpos;
+ int wsize;
+ char *wbuf;
+ wait_queue_t poll_wait[MAXPOLLWADDR];
+ wait_queue_head_t *poll_waddr[MAXPOLLWADDR];
+ poll_table pt;
+ struct work_struct rq;
+ struct work_struct wq;
+ unsigned long wsched;
+};
+
+struct p9_mux_poll_task {
+ struct task_struct *task;
+ struct list_head mux_list;
+ int muxnum;
+};
+
+struct p9_mux_rpc {
+ struct p9_conn *m;
+ int err;
+ struct p9_fcall *tcall;
+ struct p9_fcall *rcall;
+ wait_queue_head_t wqueue;
+};
+
+static int p9_poll_proc(void *);
+static void p9_read_work(struct work_struct *work);
+static void p9_write_work(struct work_struct *work);
+static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
+ poll_table * p);
+static u16 p9_mux_get_tag(struct p9_conn *);
+static void p9_mux_put_tag(struct p9_conn *, u16);
+
+static DEFINE_MUTEX(p9_mux_task_lock);
+static struct workqueue_struct *p9_mux_wq;
+
+static int p9_mux_num;
+static int p9_mux_poll_task_num;
+static struct p9_mux_poll_task p9_mux_poll_tasks[100];
+
+int p9_mux_global_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
+ p9_mux_poll_tasks[i].task = NULL;
+
+ p9_mux_wq = create_workqueue("v9fs");
+ if (!p9_mux_wq) {
+ printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void p9_mux_global_exit(void)
+{
+ destroy_workqueue(p9_mux_wq);
+}
+
+/**
+ * p9_mux_calc_poll_procs - calculates the number of polling procs
+ * based on the number of mounted v9fs filesystems.
+ *
+ * The current implementation returns sqrt of the number of mounts.
+ */
+static int p9_mux_calc_poll_procs(int muxnum)
+{
+ int n;
+
+ if (p9_mux_poll_task_num)
+ n = muxnum / p9_mux_poll_task_num +
+ (muxnum % p9_mux_poll_task_num ? 1 : 0);
+ else
+ n = 1;
+
+ if (n > ARRAY_SIZE(p9_mux_poll_tasks))
+ n = ARRAY_SIZE(p9_mux_poll_tasks);
+
+ return n;
+}
+
+static int p9_mux_poll_start(struct p9_conn *m)
+{
+ int i, n;
+ struct p9_mux_poll_task *vpt, *vptlast;
+ struct task_struct *pproc;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, p9_mux_num,
+ p9_mux_poll_task_num);
+ mutex_lock(&p9_mux_task_lock);
+
+ n = p9_mux_calc_poll_procs(p9_mux_num + 1);
+ if (n > p9_mux_poll_task_num) {
+ for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
+ if (p9_mux_poll_tasks[i].task == NULL) {
+ vpt = &p9_mux_poll_tasks[i];
+ P9_DPRINTK(P9_DEBUG_MUX, "create proc %p\n",
+ vpt);
+ pproc = kthread_create(p9_poll_proc, vpt,
+ "v9fs-poll");
+
+ if (!IS_ERR(pproc)) {
+ vpt->task = pproc;
+ INIT_LIST_HEAD(&vpt->mux_list);
+ vpt->muxnum = 0;
+ p9_mux_poll_task_num++;
+ wake_up_process(vpt->task);
+ }
+ break;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(p9_mux_poll_tasks))
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "warning: no free poll slots\n");
+ }
+
+ n = (p9_mux_num + 1) / p9_mux_poll_task_num +
+ ((p9_mux_num + 1) % p9_mux_poll_task_num ? 1 : 0);
+
+ vptlast = NULL;
+ for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
+ vpt = &p9_mux_poll_tasks[i];
+ if (vpt->task != NULL) {
+ vptlast = vpt;
+ if (vpt->muxnum < n) {
+ P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
+ list_add(&m->mux_list, &vpt->mux_list);
+ vpt->muxnum++;
+ m->poll_task = vpt;
+ memset(&m->poll_waddr, 0,
+ sizeof(m->poll_waddr));
+ init_poll_funcptr(&m->pt, p9_pollwait);
+ break;
+ }
+ }
+ }
+
+ if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) {
+ if (vptlast == NULL)
+ return -ENOMEM;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
+ list_add(&m->mux_list, &vptlast->mux_list);
+ vptlast->muxnum++;
+ m->poll_task = vptlast;
+ memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
+ init_poll_funcptr(&m->pt, p9_pollwait);
+ }
+
+ p9_mux_num++;
+ mutex_unlock(&p9_mux_task_lock);
+
+ return 0;
+}
+
+static void p9_mux_poll_stop(struct p9_conn *m)
+{
+ int i;
+ struct p9_mux_poll_task *vpt;
+
+ mutex_lock(&p9_mux_task_lock);
+ vpt = m->poll_task;
+ list_del(&m->mux_list);
+ for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
+ if (m->poll_waddr[i] != NULL) {
+ remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]);
+ m->poll_waddr[i] = NULL;
+ }
+ }
+ vpt->muxnum--;
+ if (!vpt->muxnum) {
+ P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt);
+ kthread_stop(vpt->task);
+ vpt->task = NULL;
+ p9_mux_poll_task_num--;
+ }
+ p9_mux_num--;
+ mutex_unlock(&p9_mux_task_lock);
+}
+
+/**
+ * p9_conn_create - allocate and initialize the per-session mux data
+ * Creates the polling task if this is the first session.
+ *
+ * @trans - transport structure
+ * @msize - maximum message size
+ * @extended - pointer to the extended flag
+ */
+struct p9_conn *p9_conn_create(struct p9_transport *trans, int msize,
+ unsigned char *extended)
+{
+ int i, n;
+ struct p9_conn *m, *mtmp;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans, msize);
+ m = kmalloc(sizeof(struct p9_conn), GFP_KERNEL);
+ if (!m)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&m->lock);
+ INIT_LIST_HEAD(&m->mux_list);
+ m->msize = msize;
+ m->extended = extended;
+ m->trans = trans;
+ m->tagpool = p9_idpool_create();
+ if (!m->tagpool) {
+ kfree(m);
+ return ERR_PTR(PTR_ERR(m->tagpool));
+ }
+
+ m->err = 0;
+ init_waitqueue_head(&m->equeue);
+ INIT_LIST_HEAD(&m->req_list);
+ INIT_LIST_HEAD(&m->unsent_req_list);
+ m->rcall = NULL;
+ m->rpos = 0;
+ m->rbuf = NULL;
+ m->wpos = m->wsize = 0;
+ m->wbuf = NULL;
+ INIT_WORK(&m->rq, p9_read_work);
+ INIT_WORK(&m->wq, p9_write_work);
+ m->wsched = 0;
+ memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
+ m->poll_task = NULL;
+ n = p9_mux_poll_start(m);
+ if (n)
+ return ERR_PTR(n);
+
+ n = trans->poll(trans, &m->pt);
+ if (n & POLLIN) {
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
+ set_bit(Rpending, &m->wsched);
+ }
+
+ if (n & POLLOUT) {
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
+ set_bit(Wpending, &m->wsched);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
+ if (IS_ERR(m->poll_waddr[i])) {
+ p9_mux_poll_stop(m);
+ mtmp = (void *)m->poll_waddr; /* the error code */
+ kfree(m);
+ m = mtmp;
+ break;
+ }
+ }
+
+ return m;
+}
+EXPORT_SYMBOL(p9_conn_create);
+
+/**
+ * p9_mux_destroy - cancels all pending requests and frees mux resources
+ */
+void p9_conn_destroy(struct p9_conn *m)
+{
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m,
+ m->mux_list.prev, m->mux_list.next);
+ p9_conn_cancel(m, -ECONNRESET);
+
+ if (!list_empty(&m->req_list)) {
+ /* wait until all processes waiting on this session exit */
+ P9_DPRINTK(P9_DEBUG_MUX,
+ "mux %p waiting for empty request queue\n", m);
+ wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p request queue empty: %d\n", m,
+ list_empty(&m->req_list));
+ }
+
+ p9_mux_poll_stop(m);
+ m->trans = NULL;
+ p9_idpool_destroy(m->tagpool);
+ kfree(m);
+}
+EXPORT_SYMBOL(p9_conn_destroy);
+
+/**
+ * p9_pollwait - called by files poll operation to add v9fs-poll task
+ * to files wait queue
+ */
+static void
+p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
+ poll_table * p)
+{
+ int i;
+ struct p9_conn *m;
+
+ m = container_of(p, struct p9_conn, pt);
+ for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++)
+ if (m->poll_waddr[i] == NULL)
+ break;
+
+ if (i >= ARRAY_SIZE(m->poll_waddr)) {
+ P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
+ return;
+ }
+
+ m->poll_waddr[i] = wait_address;
+
+ if (!wait_address) {
+ P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n");
+ m->poll_waddr[i] = ERR_PTR(-EIO);
+ return;
+ }
+
+ init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task);
+ add_wait_queue(wait_address, &m->poll_wait[i]);
+}
+
+/**
+ * p9_poll_mux - polls a mux and schedules read or write works if necessary
+ */
+static void p9_poll_mux(struct p9_conn *m)
+{
+ int n;
+
+ if (m->err < 0)
+ return;
+
+ n = m->trans->poll(m->trans, NULL);
+ if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
+ P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n);
+ if (n >= 0)
+ n = -ECONNRESET;
+ p9_conn_cancel(m, n);
+ }
+
+ if (n & POLLIN) {
+ set_bit(Rpending, &m->wsched);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
+ if (!test_and_set_bit(Rworksched, &m->wsched)) {
+ P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
+ queue_work(p9_mux_wq, &m->rq);
+ }
+ }
+
+ if (n & POLLOUT) {
+ set_bit(Wpending, &m->wsched);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
+ if ((m->wsize || !list_empty(&m->unsent_req_list))
+ && !test_and_set_bit(Wworksched, &m->wsched)) {
+ P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
+ queue_work(p9_mux_wq, &m->wq);
+ }
+ }
+}
+
+/**
+ * p9_poll_proc - polls all v9fs transports for new events and queues
+ * the appropriate work to the work queue
+ */
+static int p9_poll_proc(void *a)
+{
+ struct p9_conn *m, *mtmp;
+ struct p9_mux_poll_task *vpt;
+
+ vpt = a;
+ P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt);
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) {
+ p9_poll_mux(m);
+ }
+
+ P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n");
+ schedule_timeout(SCHED_TIMEOUT * HZ);
+ }
+
+ __set_current_state(TASK_RUNNING);
+ P9_DPRINTK(P9_DEBUG_MUX, "finish\n");
+ return 0;
+}
+
+/**
+ * p9_write_work - called when a transport can send some data
+ */
+static void p9_write_work(struct work_struct *work)
+{
+ int n, err;
+ struct p9_conn *m;
+ struct p9_req *req;
+
+ m = container_of(work, struct p9_conn, wq);
+
+ if (m->err < 0) {
+ clear_bit(Wworksched, &m->wsched);
+ return;
+ }
+
+ if (!m->wsize) {
+ if (list_empty(&m->unsent_req_list)) {
+ clear_bit(Wworksched, &m->wsched);
+ return;
+ }
+
+ spin_lock(&m->lock);
+again:
+ req = list_entry(m->unsent_req_list.next, struct p9_req,
+ req_list);
+ list_move_tail(&req->req_list, &m->req_list);
+ if (req->err == ERREQFLUSH)
+ goto again;
+
+ m->wbuf = req->tcall->sdata;
+ m->wsize = req->tcall->size;
+ m->wpos = 0;
+ spin_unlock(&m->lock);
+ }
+
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos,
+ m->wsize);
+ clear_bit(Wpending, &m->wsched);
+ err = m->trans->write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err);
+ if (err == -EAGAIN) {
+ clear_bit(Wworksched, &m->wsched);
+ return;
+ }
+
+ if (err < 0)
+ goto error;
+ else if (err == 0) {
+ err = -EREMOTEIO;
+ goto error;
+ }
+
+ m->wpos += err;
+ if (m->wpos == m->wsize)
+ m->wpos = m->wsize = 0;
+
+ if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
+ if (test_and_clear_bit(Wpending, &m->wsched))
+ n = POLLOUT;
+ else
+ n = m->trans->poll(m->trans, NULL);
+
+ if (n & POLLOUT) {
+ P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
+ queue_work(p9_mux_wq, &m->wq);
+ } else
+ clear_bit(Wworksched, &m->wsched);
+ } else
+ clear_bit(Wworksched, &m->wsched);
+
+ return;
+
+error:
+ p9_conn_cancel(m, err);
+ clear_bit(Wworksched, &m->wsched);
+}
+
+static void process_request(struct p9_conn *m, struct p9_req *req)
+{
+ int ecode;
+ struct p9_str *ename;
+
+ if (!req->err && req->rcall->id == P9_RERROR) {
+ ecode = req->rcall->params.rerror.errno;
+ ename = &req->rcall->params.rerror.error;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,
+ ename->str);
+
+ if (*m->extended)
+ req->err = -ecode;
+
+ if (!req->err) {
+ req->err = p9_errstr2errno(ename->str, ename->len);
+
+ if (!req->err) { /* string match failed */
+ PRINT_FCALL_ERROR("unknown error", req->rcall);
+ }
+
+ if (!req->err)
+ req->err = -ESERVERFAULT;
+ }
+ } else if (req->tcall && req->rcall->id != req->tcall->id + 1) {
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "fcall mismatch: expected %d, got %d\n",
+ req->tcall->id + 1, req->rcall->id);
+ if (!req->err)
+ req->err = -EIO;
+ }
+}
+
+/**
+ * p9_read_work - called when there is some data to be read from a transport
+ */
+static void p9_read_work(struct work_struct *work)
+{
+ int n, err;
+ struct p9_conn *m;
+ struct p9_req *req, *rptr, *rreq;
+ struct p9_fcall *rcall;
+ char *rbuf;
+
+ m = container_of(work, struct p9_conn, rq);
+
+ if (m->err < 0)
+ return;
+
+ rcall = NULL;
+ P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
+
+ if (!m->rcall) {
+ m->rcall =
+ kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL);
+ if (!m->rcall) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
+ m->rpos = 0;
+ }
+
+ clear_bit(Rpending, &m->wsched);
+ err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err);
+ if (err == -EAGAIN) {
+ clear_bit(Rworksched, &m->wsched);
+ return;
+ }
+
+ if (err <= 0)
+ goto error;
+
+ m->rpos += err;
+ while (m->rpos > 4) {
+ n = le32_to_cpu(*(__le32 *) m->rbuf);
+ if (n >= m->msize) {
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "requested packet size too big: %d\n", n);
+ err = -EIO;
+ goto error;
+ }
+
+ if (m->rpos < n)
+ break;
+
+ err =
+ p9_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended);
+ if (err < 0) {
+ goto error;
+ }
+
+#ifdef CONFIG_NET_9P_DEBUG
+ if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
+ char buf[150];
+
+ p9_printfcall(buf, sizeof(buf), m->rcall,
+ *m->extended);
+ printk(KERN_NOTICE ">>> %p %s\n", m, buf);
+ }
+#endif
+
+ rcall = m->rcall;
+ rbuf = m->rbuf;
+ if (m->rpos > n) {
+ m->rcall = kmalloc(sizeof(struct p9_fcall) + m->msize,
+ GFP_KERNEL);
+ if (!m->rcall) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
+ memmove(m->rbuf, rbuf + n, m->rpos - n);
+ m->rpos -= n;
+ } else {
+ m->rcall = NULL;
+ m->rbuf = NULL;
+ m->rpos = 0;
+ }
+
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m,
+ rcall->id, rcall->tag);
+
+ req = NULL;
+ spin_lock(&m->lock);
+ list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
+ if (rreq->tag == rcall->tag) {
+ req = rreq;
+ if (req->flush != Flushing)
+ list_del(&req->req_list);
+ break;
+ }
+ }
+ spin_unlock(&m->lock);
+
+ if (req) {
+ req->rcall = rcall;
+ process_request(m, req);
+
+ if (req->flush != Flushing) {
+ if (req->cb)
+ (*req->cb) (req, req->cba);
+ else
+ kfree(req->rcall);
+
+ wake_up(&m->equeue);
+ }
+ } else {
+ if (err >= 0 && rcall->id != P9_RFLUSH)
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "unexpected response mux %p id %d tag %d\n",
+ m, rcall->id, rcall->tag);
+ kfree(rcall);
+ }
+ }
+
+ if (!list_empty(&m->req_list)) {
+ if (test_and_clear_bit(Rpending, &m->wsched))
+ n = POLLIN;
+ else
+ n = m->trans->poll(m->trans, NULL);
+
+ if (n & POLLIN) {
+ P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
+ queue_work(p9_mux_wq, &m->rq);
+ } else
+ clear_bit(Rworksched, &m->wsched);
+ } else
+ clear_bit(Rworksched, &m->wsched);
+
+ return;
+
+error:
+ p9_conn_cancel(m, err);
+ clear_bit(Rworksched, &m->wsched);
+}
+
+/**
+ * p9_send_request - send 9P request
+ * The function can sleep until the request is scheduled for sending.
+ * The function can be interrupted. Return from the function is not
+ * a guarantee that the request is sent successfully. Can return errors
+ * that can be retrieved by PTR_ERR macros.
+ *
+ * @m: mux data
+ * @tc: request to be sent
+ * @cb: callback function to call when response is received
+ * @cba: parameter to pass to the callback function
+ */
+static struct p9_req *p9_send_request(struct p9_conn *m,
+ struct p9_fcall *tc,
+ p9_conn_req_callback cb, void *cba)
+{
+ int n;
+ struct p9_req *req;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
+ tc, tc->id);
+ if (m->err < 0)
+ return ERR_PTR(m->err);
+
+ req = kmalloc(sizeof(struct p9_req), GFP_KERNEL);
+ if (!req)
+ return ERR_PTR(-ENOMEM);
+
+ if (tc->id == P9_TVERSION)
+ n = P9_NOTAG;
+ else
+ n = p9_mux_get_tag(m);
+
+ if (n < 0)
+ return ERR_PTR(-ENOMEM);
+
+ p9_set_tag(tc, n);
+
+#ifdef CONFIG_NET_9P_DEBUG
+ if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
+ char buf[150];
+
+ p9_printfcall(buf, sizeof(buf), tc, *m->extended);
+ printk(KERN_NOTICE "<<< %p %s\n", m, buf);
+ }
+#endif
+
+ spin_lock_init(&req->lock);
+ req->tag = n;
+ req->tcall = tc;
+ req->rcall = NULL;
+ req->err = 0;
+ req->cb = cb;
+ req->cba = cba;
+ req->flush = None;
+
+ spin_lock(&m->lock);
+ list_add_tail(&req->req_list, &m->unsent_req_list);
+ spin_unlock(&m->lock);
+
+ if (test_and_clear_bit(Wpending, &m->wsched))
+ n = POLLOUT;
+ else
+ n = m->trans->poll(m->trans, NULL);
+
+ if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
+ queue_work(p9_mux_wq, &m->wq);
+
+ return req;
+}
+
+static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req)
+{
+ p9_mux_put_tag(m, req->tag);
+ kfree(req);
+}
+
+static void p9_mux_flush_cb(struct p9_req *freq, void *a)
+{
+ p9_conn_req_callback cb;
+ int tag;
+ struct p9_conn *m;
+ struct p9_req *req, *rreq, *rptr;
+
+ m = a;
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,
+ freq->tcall, freq->rcall, freq->err,
+ freq->tcall->params.tflush.oldtag);
+
+ spin_lock(&m->lock);
+ cb = NULL;
+ tag = freq->tcall->params.tflush.oldtag;
+ req = NULL;
+ list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
+ if (rreq->tag == tag) {
+ req = rreq;
+ list_del(&req->req_list);
+ break;
+ }
+ }
+ spin_unlock(&m->lock);
+
+ if (req) {
+ spin_lock(&req->lock);
+ req->flush = Flushed;
+ spin_unlock(&req->lock);
+
+ if (req->cb)
+ (*req->cb) (req, req->cba);
+ else
+ kfree(req->rcall);
+
+ wake_up(&m->equeue);
+ }
+
+ kfree(freq->tcall);
+ kfree(freq->rcall);
+ p9_mux_free_request(m, freq);
+}
+
+static int
+p9_mux_flush_request(struct p9_conn *m, struct p9_req *req)
+{
+ struct p9_fcall *fc;
+ struct p9_req *rreq, *rptr;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
+
+ /* if a response was received for a request, do nothing */
+ spin_lock(&req->lock);
+ if (req->rcall || req->err) {
+ spin_unlock(&req->lock);
+ P9_DPRINTK(P9_DEBUG_MUX,
+ "mux %p req %p response already received\n", m, req);
+ return 0;
+ }
+
+ req->flush = Flushing;
+ spin_unlock(&req->lock);
+
+ spin_lock(&m->lock);
+ /* if the request is not sent yet, just remove it from the list */
+ list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) {
+ if (rreq->tag == req->tag) {
+ P9_DPRINTK(P9_DEBUG_MUX,
+ "mux %p req %p request is not sent yet\n", m, req);
+ list_del(&rreq->req_list);
+ req->flush = Flushed;
+ spin_unlock(&m->lock);
+ if (req->cb)
+ (*req->cb) (req, req->cba);
+ return 0;
+ }
+ }
+ spin_unlock(&m->lock);
+
+ clear_thread_flag(TIF_SIGPENDING);
+ fc = p9_create_tflush(req->tag);
+ p9_send_request(m, fc, p9_mux_flush_cb, m);
+ return 1;
+}
+
+static void
+p9_conn_rpc_cb(struct p9_req *req, void *a)
+{
+ struct p9_mux_rpc *r;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "req %p r %p\n", req, a);
+ r = a;
+ r->rcall = req->rcall;
+ r->err = req->err;
+
+ if (req->flush != None && !req->err)
+ r->err = -ERESTARTSYS;
+
+ wake_up(&r->wqueue);
+}
+
+/**
+ * p9_mux_rpc - sends 9P request and waits until a response is available.
+ * The function can be interrupted.
+ * @m: mux data
+ * @tc: request to be sent
+ * @rc: pointer where a pointer to the response is stored
+ */
+int
+p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc,
+ struct p9_fcall **rc)
+{
+ int err, sigpending;
+ unsigned long flags;
+ struct p9_req *req;
+ struct p9_mux_rpc r;
+
+ r.err = 0;
+ r.tcall = tc;
+ r.rcall = NULL;
+ r.m = m;
+ init_waitqueue_head(&r.wqueue);
+
+ if (rc)
+ *rc = NULL;
+
+ sigpending = 0;
+ if (signal_pending(current)) {
+ sigpending = 1;
+ clear_thread_flag(TIF_SIGPENDING);
+ }
+
+ req = p9_send_request(m, tc, p9_conn_rpc_cb, &r);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
+ return err;
+ }
+
+ err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0);
+ if (r.err < 0)
+ err = r.err;
+
+ if (err == -ERESTARTSYS && m->trans->status == Connected
+ && m->err == 0) {
+ if (p9_mux_flush_request(m, req)) {
+ /* wait until we get response of the flush message */
+ do {
+ clear_thread_flag(TIF_SIGPENDING);
+ err = wait_event_interruptible(r.wqueue,
+ r.rcall || r.err);
+ } while (!r.rcall && !r.err && err == -ERESTARTSYS &&
+ m->trans->status == Connected && !m->err);
+
+ err = -ERESTARTSYS;
+ }
+ sigpending = 1;
+ }
+
+ if (sigpending) {
+ spin_lock_irqsave(¤t->sighand->siglock, flags);
+ recalc_sigpending();
+ spin_unlock_irqrestore(¤t->sighand->siglock, flags);
+ }
+
+ if (rc)
+ *rc = r.rcall;
+ else
+ kfree(r.rcall);
+
+ p9_mux_free_request(m, req);
+ if (err > 0)
+ err = -EIO;
+
+ return err;
+}
+EXPORT_SYMBOL(p9_conn_rpc);
+
+#ifdef P9_NONBLOCK
+/**
+ * p9_conn_rpcnb - sends 9P request without waiting for response.
+ * @m: mux data
+ * @tc: request to be sent
+ * @cb: callback function to be called when response arrives
+ * @cba: value to pass to the callback function
+ */
+int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
+ p9_conn_req_callback cb, void *a)
+{
+ int err;
+ struct p9_req *req;
+
+ req = p9_send_request(m, tc, cb, a);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
+ return PTR_ERR(req);
+ }
+
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag);
+ return 0;
+}
+EXPORT_SYMBOL(p9_conn_rpcnb);
+#endif /* P9_NONBLOCK */
+
+/**
+ * p9_conn_cancel - cancel all pending requests with error
+ * @m: mux data
+ * @err: error code
+ */
+void p9_conn_cancel(struct p9_conn *m, int err)
+{
+ struct p9_req *req, *rtmp;
+ LIST_HEAD(cancel_list);
+
+ P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
+ m->err = err;
+ spin_lock(&m->lock);
+ list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
+ list_move(&req->req_list, &cancel_list);
+ }
+ list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
+ list_move(&req->req_list, &cancel_list);
+ }
+ spin_unlock(&m->lock);
+
+ list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
+ list_del(&req->req_list);
+ if (!req->err)
+ req->err = err;
+
+ if (req->cb)
+ (*req->cb) (req, req->cba);
+ else
+ kfree(req->rcall);
+ }
+
+ wake_up(&m->equeue);
+}
+EXPORT_SYMBOL(p9_conn_cancel);
+
+static u16 p9_mux_get_tag(struct p9_conn *m)
+{
+ int tag;
+
+ tag = p9_idpool_get(m->tagpool);
+ if (tag < 0)
+ return P9_NOTAG;
+ else
+ return (u16) tag;
+}
+
+static void p9_mux_put_tag(struct p9_conn *m, u16 tag)
+{
+ if (tag != P9_NOTAG && p9_idpool_check(tag, m->tagpool))
+ p9_idpool_put(tag, m->tagpool);
+}
diff --git a/net/9p/sysctl.c b/net/9p/sysctl.c
new file mode 100644
index 0000000..e7fe706
--- /dev/null
+++ b/net/9p/sysctl.c
@@ -0,0 +1,86 @@
+/*
+ * net/9p/sysctl.c
+ *
+ * 9P sysctl interface
+ *
+ * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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; if not, write to:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+#include <linux/init.h>
+#include <net/9p/9p.h>
+
+enum {
+ P9_SYSCTL_NET = 487,
+ P9_SYSCTL_DEBUG = 1,
+};
+
+static ctl_table p9_table[] = {
+#ifdef CONFIG_NET_9P_DEBUG
+ {
+ .ctl_name = P9_SYSCTL_DEBUG,
+ .procname = "debug",
+ .data = &p9_debug_level,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec
+ },
+#endif
+ { .ctl_name = 0 },
+};
+
+static ctl_table p9_net_table[] = {
+ {
+ .ctl_name = P9_SYSCTL_NET,
+ .procname = "9p",
+ .maxlen = 0,
+ .mode = 0555,
+ .child = p9_table,
+ },
+ { .ctl_name = 0 },
+};
+
+static ctl_table p9_ctl_table[] = {
+ {
+ .ctl_name = CTL_NET,
+ .procname = "net",
+ .maxlen = 0,
+ .mode = 0555,
+ .child = p9_net_table,
+ },
+ { .ctl_name = 0 },
+};
+
+static struct ctl_table_header *p9_table_header;
+
+int __init p9_sysctl_register(void)
+{
+ p9_table_header = register_sysctl_table(p9_ctl_table);
+ if (!p9_table_header)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void __exit p9_sysctl_unregister(void)
+{
+ unregister_sysctl_table(p9_table_header);
+}
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
new file mode 100644
index 0000000..fd636e9
--- /dev/null
+++ b/net/9p/trans_fd.c
@@ -0,0 +1,363 @@
+/*
+ * linux/fs/9p/trans_fd.c
+ *
+ * Fd transport layer. Includes deprecated socket layer.
+ *
+ * Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
+ * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
+ * Copyright (C) 2004-2005 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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; if not, write to:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#include <linux/in.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/ipv6.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/un.h>
+#include <linux/uaccess.h>
+#include <linux/inet.h>
+#include <linux/idr.h>
+#include <linux/file.h>
+#include <net/9p/9p.h>
+#include <net/9p/transport.h>
+
+#define P9_PORT 564
+
+struct p9_trans_fd {
+ struct file *rd;
+ struct file *wr;
+};
+
+static int p9_socket_open(struct p9_transport *trans, struct socket *csocket);
+static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd);
+static int p9_fd_read(struct p9_transport *trans, void *v, int len);
+static int p9_fd_write(struct p9_transport *trans, void *v, int len);
+static unsigned int p9_fd_poll(struct p9_transport *trans,
+ struct poll_table_struct *pt);
+static void p9_fd_close(struct p9_transport *trans);
+
+struct p9_transport *p9_trans_create_tcp(const char *addr, int port)
+{
+ int err;
+ struct p9_transport *trans;
+ struct socket *csocket;
+ struct sockaddr_in sin_server;
+
+ csocket = NULL;
+ trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
+ if (!trans)
+ return ERR_PTR(-ENOMEM);
+
+ trans->write = p9_fd_write;
+ trans->read = p9_fd_read;
+ trans->close = p9_fd_close;
+ trans->poll = p9_fd_poll;
+
+ sin_server.sin_family = AF_INET;
+ sin_server.sin_addr.s_addr = in_aton(addr);
+ sin_server.sin_port = htons(port);
+ sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
+
+ if (!csocket) {
+ P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
+ err = -EIO;
+ goto error;
+ }
+
+ err = csocket->ops->connect(csocket,
+ (struct sockaddr *)&sin_server,
+ sizeof(struct sockaddr_in), 0);
+ if (err < 0) {
+ P9_EPRINTK(KERN_ERR,
+ "p9_trans_tcp: problem connecting socket to %s\n",
+ addr);
+ goto error;
+ }
+
+ err = p9_socket_open(trans, csocket);
+ if (err < 0)
+ goto error;
+
+ return trans;
+
+error:
+ if (csocket)
+ sock_release(csocket);
+
+ kfree(trans);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_trans_create_tcp);
+
+struct p9_transport *p9_trans_create_unix(const char *addr)
+{
+ int err;
+ struct socket *csocket;
+ struct sockaddr_un sun_server;
+ struct p9_transport *trans;
+
+ csocket = NULL;
+ trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
+ if (!trans)
+ return ERR_PTR(-ENOMEM);
+
+ trans->write = p9_fd_write;
+ trans->read = p9_fd_read;
+ trans->close = p9_fd_close;
+ trans->poll = p9_fd_poll;
+
+ if (strlen(addr) > UNIX_PATH_MAX) {
+ P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
+ addr);
+ err = -ENAMETOOLONG;
+ goto error;
+ }
+
+ sun_server.sun_family = PF_UNIX;
+ strcpy(sun_server.sun_path, addr);
+ sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
+ err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
+ sizeof(struct sockaddr_un) - 1, 0);
+ if (err < 0) {
+ P9_EPRINTK(KERN_ERR,
+ "p9_trans_unix: problem connecting socket: %s: %d\n",
+ addr, err);
+ goto error;
+ }
+
+ err = p9_socket_open(trans, csocket);
+ if (err < 0)
+ goto error;
+
+ return trans;
+
+error:
+ if (csocket)
+ sock_release(csocket);
+
+ kfree(trans);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_trans_create_unix);
+
+struct p9_transport *p9_trans_create_fd(int rfd, int wfd)
+{
+ int err;
+ struct p9_transport *trans;
+
+ if (rfd == ~0 || wfd == ~0) {
+ printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
+ return ERR_PTR(-ENOPROTOOPT);
+ }
+
+ trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
+ if (!trans)
+ return ERR_PTR(-ENOMEM);
+
+ trans->write = p9_fd_write;
+ trans->read = p9_fd_read;
+ trans->close = p9_fd_close;
+ trans->poll = p9_fd_poll;
+
+ err = p9_fd_open(trans, rfd, wfd);
+ if (err < 0)
+ goto error;
+
+ return trans;
+
+error:
+ kfree(trans);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_trans_create_fd);
+
+static int p9_socket_open(struct p9_transport *trans, struct socket *csocket)
+{
+ int fd, ret;
+
+ csocket->sk->sk_allocation = GFP_NOIO;
+ fd = sock_map_fd(csocket);
+ if (fd < 0) {
+ P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
+ return fd;
+ }
+
+ ret = p9_fd_open(trans, fd, fd);
+ if (ret < 0) {
+ P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n");
+ sockfd_put(csocket);
+ return ret;
+ }
+
+ ((struct p9_trans_fd *)trans->priv)->rd->f_flags |= O_NONBLOCK;
+
+ return 0;
+}
+
+static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd)
+{
+ struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
+ GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ ts->rd = fget(rfd);
+ ts->wr = fget(wfd);
+ if (!ts->rd || !ts->wr) {
+ if (ts->rd)
+ fput(ts->rd);
+ if (ts->wr)
+ fput(ts->wr);
+ kfree(ts);
+ return -EIO;
+ }
+
+ trans->priv = ts;
+ trans->status = Connected;
+
+ return 0;
+}
+
+/**
+ * p9_fd_read- read from a fd
+ * @v9ses: session information
+ * @v: buffer to receive data into
+ * @len: size of receive buffer
+ *
+ */
+static int p9_fd_read(struct p9_transport *trans, void *v, int len)
+{
+ int ret;
+ struct p9_trans_fd *ts = NULL;
+
+ if (trans && trans->status != Disconnected)
+ ts = trans->priv;
+
+ if (!ts)
+ return -EREMOTEIO;
+
+ if (!(ts->rd->f_flags & O_NONBLOCK))
+ P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n");
+
+ ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
+ if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
+ trans->status = Disconnected;
+ return ret;
+}
+
+/**
+ * p9_fd_write - write to a socket
+ * @v9ses: session information
+ * @v: buffer to send data from
+ * @len: size of send buffer
+ *
+ */
+static int p9_fd_write(struct p9_transport *trans, void *v, int len)
+{
+ int ret;
+ mm_segment_t oldfs;
+ struct p9_trans_fd *ts = NULL;
+
+ if (trans && trans->status != Disconnected)
+ ts = trans->priv;
+
+ if (!ts)
+ return -EREMOTEIO;
+
+ if (!(ts->wr->f_flags & O_NONBLOCK))
+ P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n");
+
+ oldfs = get_fs();
+ set_fs(get_ds());
+ /* The cast to a user pointer is valid due to the set_fs() */
+ ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
+ set_fs(oldfs);
+
+ if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
+ trans->status = Disconnected;
+ return ret;
+}
+
+static unsigned int
+p9_fd_poll(struct p9_transport *trans, struct poll_table_struct *pt)
+{
+ int ret, n;
+ struct p9_trans_fd *ts = NULL;
+ mm_segment_t oldfs;
+
+ if (trans && trans->status == Connected)
+ ts = trans->priv;
+
+ if (!ts)
+ return -EREMOTEIO;
+
+ if (!ts->rd->f_op || !ts->rd->f_op->poll)
+ return -EIO;
+
+ if (!ts->wr->f_op || !ts->wr->f_op->poll)
+ return -EIO;
+
+ oldfs = get_fs();
+ set_fs(get_ds());
+
+ ret = ts->rd->f_op->poll(ts->rd, pt);
+ if (ret < 0)
+ goto end;
+
+ if (ts->rd != ts->wr) {
+ n = ts->wr->f_op->poll(ts->wr, pt);
+ if (n < 0) {
+ ret = n;
+ goto end;
+ }
+ ret = (ret & ~POLLOUT) | (n & ~POLLIN);
+ }
+
+end:
+ set_fs(oldfs);
+ return ret;
+}
+
+/**
+ * p9_sock_close - shutdown socket
+ * @trans: private socket structure
+ *
+ */
+static void p9_fd_close(struct p9_transport *trans)
+{
+ struct p9_trans_fd *ts;
+
+ if (!trans)
+ return;
+
+ ts = xchg(&trans->priv, NULL);
+
+ if (!ts)
+ return;
+
+ trans->status = Disconnected;
+ if (ts->rd)
+ fput(ts->rd);
+ if (ts->wr)
+ fput(ts->wr);
+ kfree(ts);
+}
+
diff --git a/net/9p/util.c b/net/9p/util.c
new file mode 100644
index 0000000..22077b7
--- /dev/null
+++ b/net/9p/util.c
@@ -0,0 +1,125 @@
+/*
+ * net/9p/util.c
+ *
+ * This file contains some helper functions
+ *
+ * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
+ * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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; if not, write to:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/parser.h>
+#include <linux/idr.h>
+#include <net/9p/9p.h>
+
+struct p9_idpool {
+ struct semaphore lock;
+ struct idr pool;
+};
+
+struct p9_idpool *p9_idpool_create(void)
+{
+ struct p9_idpool *p;
+
+ p = kmalloc(sizeof(struct p9_idpool), GFP_KERNEL);
+ if (!p)
+ return ERR_PTR(-ENOMEM);
+
+ init_MUTEX(&p->lock);
+ idr_init(&p->pool);
+
+ return p;
+}
+EXPORT_SYMBOL(p9_idpool_create);
+
+void p9_idpool_destroy(struct p9_idpool *p)
+{
+ idr_destroy(&p->pool);
+ kfree(p);
+}
+EXPORT_SYMBOL(p9_idpool_destroy);
+
+/**
+ * p9_idpool_get - allocate numeric id from pool
+ * @p - pool to allocate from
+ *
+ * XXX - This seems to be an awful generic function, should it be in idr.c with
+ * the lock included in struct idr?
+ */
+
+int p9_idpool_get(struct p9_idpool *p)
+{
+ int i = 0;
+ int error;
+
+retry:
+ if (idr_pre_get(&p->pool, GFP_KERNEL) == 0)
+ return 0;
+
+ if (down_interruptible(&p->lock) == -EINTR) {
+ P9_EPRINTK(KERN_WARNING, "Interrupted while locking\n");
+ return -1;
+ }
+
+ /* no need to store exactly p, we just need something non-null */
+ error = idr_get_new(&p->pool, p, &i);
+ up(&p->lock);
+
+ if (error == -EAGAIN)
+ goto retry;
+ else if (error)
+ return -1;
+
+ return i;
+}
+EXPORT_SYMBOL(p9_idpool_get);
+
+/**
+ * p9_idpool_put - release numeric id from pool
+ * @p - pool to allocate from
+ *
+ * XXX - This seems to be an awful generic function, should it be in idr.c with
+ * the lock included in struct idr?
+ */
+
+void p9_idpool_put(int id, struct p9_idpool *p)
+{
+ if (down_interruptible(&p->lock) == -EINTR) {
+ P9_EPRINTK(KERN_WARNING, "Interrupted while locking\n");
+ return;
+ }
+ idr_remove(&p->pool, id);
+ up(&p->lock);
+}
+EXPORT_SYMBOL(p9_idpool_put);
+
+/**
+ * p9_idpool_check - check if the specified id is available
+ * @id - id to check
+ * @p - pool
+ */
+int p9_idpool_check(int id, struct p9_idpool *p)
+{
+ return idr_find(&p->pool, id) != NULL;
+}
+EXPORT_SYMBOL(p9_idpool_check);
diff --git a/net/Kconfig b/net/Kconfig
index f3de729..cdba08c 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -227,6 +227,7 @@
endmenu
source "net/rfkill/Kconfig"
+source "net/9p/Kconfig"
endif # if NET
endmenu # Networking
diff --git a/net/Makefile b/net/Makefile
index a87a889..bbe7d2a 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -51,6 +51,7 @@
obj-$(CONFIG_NETLABEL) += netlabel/
obj-$(CONFIG_IUCV) += iucv/
obj-$(CONFIG_RFKILL) += rfkill/
+obj-$(CONFIG_NET_9P) += 9p/
ifeq ($(CONFIG_NET),y)
obj-$(CONFIG_SYSCTL) += sysctl_net.o
diff --git a/net/atm/proc.c b/net/atm/proc.c
index 88154da..99fc1fe 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -110,7 +110,7 @@
}
static int __vcc_seq_open(struct inode *inode, struct file *file,
- int family, struct seq_operations *ops)
+ int family, const struct seq_operations *ops)
{
struct vcc_state *state;
struct seq_file *seq;
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index ac9984f..4169a2a 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -1525,14 +1525,14 @@
if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
return ret;
- printk(KERN_NOTICE "Ebtables v2.0 registered\n");
+ printk(KERN_INFO "Ebtables v2.0 registered\n");
return 0;
}
static void __exit ebtables_fini(void)
{
nf_unregister_sockopt(&ebt_sockopts);
- printk(KERN_NOTICE "Ebtables v2.0 unregistered\n");
+ printk(KERN_INFO "Ebtables v2.0 unregistered\n");
}
EXPORT_SYMBOL(ebt_register_table);
diff --git a/net/core/dev.c b/net/core/dev.c
index 9644305..13a0d9f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -98,6 +98,7 @@
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/if_bridge.h>
+#include <linux/if_macvlan.h>
#include <net/dst.h>
#include <net/pkt_sched.h>
#include <net/checksum.h>
@@ -1813,6 +1814,28 @@
#define handle_bridge(skb, pt_prev, ret, orig_dev) (skb)
#endif
+#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE)
+struct sk_buff *(*macvlan_handle_frame_hook)(struct sk_buff *skb) __read_mostly;
+EXPORT_SYMBOL_GPL(macvlan_handle_frame_hook);
+
+static inline struct sk_buff *handle_macvlan(struct sk_buff *skb,
+ struct packet_type **pt_prev,
+ int *ret,
+ struct net_device *orig_dev)
+{
+ if (skb->dev->macvlan_port == NULL)
+ return skb;
+
+ if (*pt_prev) {
+ *ret = deliver_skb(skb, *pt_prev, orig_dev);
+ *pt_prev = NULL;
+ }
+ return macvlan_handle_frame_hook(skb);
+}
+#else
+#define handle_macvlan(skb, pt_prev, ret, orig_dev) (skb)
+#endif
+
#ifdef CONFIG_NET_CLS_ACT
/* TODO: Maybe we should just force sch_ingress to be compiled in
* when CONFIG_NET_CLS_ACT is? otherwise some useless instructions
@@ -1920,6 +1943,9 @@
skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
if (!skb)
goto out;
+ skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
+ if (!skb)
+ goto out;
type = skb->protocol;
list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) {
@@ -2521,6 +2547,8 @@
{
unsigned short old_flags = dev->flags;
+ ASSERT_RTNL();
+
if ((dev->promiscuity += inc) == 0)
dev->flags &= ~IFF_PROMISC;
else
@@ -2535,6 +2563,9 @@
dev->name, (dev->flags & IFF_PROMISC),
(old_flags & IFF_PROMISC),
audit_get_loginuid(current->audit_context));
+
+ if (dev->change_rx_flags)
+ dev->change_rx_flags(dev, IFF_PROMISC);
}
}
@@ -2573,11 +2604,16 @@
{
unsigned short old_flags = dev->flags;
+ ASSERT_RTNL();
+
dev->flags |= IFF_ALLMULTI;
if ((dev->allmulti += inc) == 0)
dev->flags &= ~IFF_ALLMULTI;
- if (dev->flags ^ old_flags)
+ if (dev->flags ^ old_flags) {
+ if (dev->change_rx_flags)
+ dev->change_rx_flags(dev, IFF_ALLMULTI);
dev_set_rx_mode(dev);
+ }
}
/*
@@ -2778,6 +2814,8 @@
int ret, changes;
int old_flags = dev->flags;
+ ASSERT_RTNL();
+
/*
* Set the flags on our device.
*/
@@ -2792,6 +2830,9 @@
* Load in the correct multicast list now the flags have changed.
*/
+ if (dev->change_rx_flags && (dev->flags ^ flags) & IFF_MULTICAST)
+ dev->change_rx_flags(dev, IFF_MULTICAST);
+
dev_set_rx_mode(dev);
/*
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index aa38100..235a2a8 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -102,6 +102,81 @@
return err;
}
+/**
+ * dev_mc_sync - Synchronize device's multicast list to another device
+ * @to: destination device
+ * @from: source device
+ *
+ * Add newly added addresses to the destination device and release
+ * addresses that have no users left. The source device must be
+ * locked by netif_tx_lock_bh.
+ *
+ * This function is intended to be called from the dev->set_multicast_list
+ * function of layered software devices.
+ */
+int dev_mc_sync(struct net_device *to, struct net_device *from)
+{
+ struct dev_addr_list *da;
+ int err = 0;
+
+ netif_tx_lock_bh(to);
+ for (da = from->mc_list; da != NULL; da = da->next) {
+ if (!da->da_synced) {
+ err = __dev_addr_add(&to->mc_list, &to->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ if (err < 0)
+ break;
+ da->da_synced = 1;
+ da->da_users++;
+ } else if (da->da_users == 1) {
+ __dev_addr_delete(&to->mc_list, &to->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ __dev_addr_delete(&from->mc_list, &from->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ }
+ }
+ if (!err)
+ __dev_set_rx_mode(to);
+ netif_tx_unlock_bh(to);
+
+ return err;
+}
+EXPORT_SYMBOL(dev_mc_sync);
+
+
+/**
+ * dev_mc_unsync - Remove synchronized addresses from the destination
+ * device
+ * @to: destination device
+ * @from: source device
+ *
+ * Remove all addresses that were added to the destination device by
+ * dev_mc_sync(). This function is intended to be called from the
+ * dev->stop function of layered software devices.
+ */
+void dev_mc_unsync(struct net_device *to, struct net_device *from)
+{
+ struct dev_addr_list *da;
+
+ netif_tx_lock_bh(from);
+ netif_tx_lock_bh(to);
+
+ for (da = from->mc_list; da != NULL; da = da->next) {
+ if (!da->da_synced)
+ continue;
+ __dev_addr_delete(&to->mc_list, &to->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ da->da_synced = 0;
+ __dev_addr_delete(&from->mc_list, &from->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ }
+ __dev_set_rx_mode(to);
+
+ netif_tx_unlock_bh(to);
+ netif_tx_unlock_bh(from);
+}
+EXPORT_SYMBOL(dev_mc_unsync);
+
/*
* Discard multicast list when a device is downed
*/
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 8d5e5a0..0b531e9 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -52,6 +52,17 @@
return 0;
}
+
+int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data)
+{
+ if (data)
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ else
+ dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+
+ return 0;
+}
+
u32 ethtool_op_get_sg(struct net_device *dev)
{
return (dev->features & NETIF_F_SG) != 0;
@@ -980,5 +991,6 @@
EXPORT_SYMBOL(ethtool_op_set_tso);
EXPORT_SYMBOL(ethtool_op_set_tx_csum);
EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
+EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
EXPORT_SYMBOL(ethtool_op_set_ufo);
EXPORT_SYMBOL(ethtool_op_get_ufo);
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index e00767e..9ab9d53 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -885,7 +885,7 @@
if (n == NULL &&
arp->ar_op == htons(ARPOP_REPLY) &&
inet_addr_type(sip) == RTN_UNICAST)
- n = __neigh_lookup(&arp_tbl, &sip, dev, -1);
+ n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
}
if (n) {
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index a73cf93..2586df0 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -14,7 +14,8 @@
#include <net/ip.h>
/* Must be called with locally disabled BHs. */
-void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_hashinfo *hashinfo)
+static void __inet_twsk_kill(struct inet_timewait_sock *tw,
+ struct inet_hashinfo *hashinfo)
{
struct inet_bind_hashbucket *bhead;
struct inet_bind_bucket *tb;
@@ -47,8 +48,6 @@
inet_twsk_put(tw);
}
-EXPORT_SYMBOL_GPL(__inet_twsk_kill);
-
/*
* Enter the time wait state. This is called with locally disabled BH.
* Essentially we whip up a timewait bucket, copy the relevant info into it
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index e981232..d1149ab 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -1184,7 +1184,7 @@
if (ret < 0)
goto err4;
- printk("arp_tables: (C) 2002 David S. Miller\n");
+ printk(KERN_INFO "arp_tables: (C) 2002 David S. Miller\n");
return 0;
err4:
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 3c56299..64552af 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -78,21 +78,26 @@
return skb;
}
-static int
-ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
- u_int8_t *protonum)
+static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
+ unsigned int *dataoff, u_int8_t *protonum)
{
+ struct iphdr _iph, *iph;
+
+ iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
+ if (iph == NULL)
+ return -NF_DROP;
+
/* Never happen */
- if (ip_hdr(*pskb)->frag_off & htons(IP_OFFSET)) {
+ if (iph->frag_off & htons(IP_OFFSET)) {
if (net_ratelimit()) {
- printk(KERN_ERR "ipv4_prepare: Frag of proto %u (hook=%u)\n",
- ip_hdr(*pskb)->protocol, hooknum);
+ printk(KERN_ERR "ipv4_get_l4proto: Frag of proto %u\n",
+ iph->protocol);
}
return -NF_DROP;
}
- *dataoff = skb_network_offset(*pskb) + ip_hdrlen(*pskb);
- *protonum = ip_hdr(*pskb)->protocol;
+ *dataoff = nhoff + (iph->ihl << 2);
+ *protonum = iph->protocol;
return NF_ACCEPT;
}
@@ -400,14 +405,14 @@
.get = &getorigdst,
};
-struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = {
+struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = {
.l3proto = PF_INET,
.name = "ipv4",
.pkt_to_tuple = ipv4_pkt_to_tuple,
.invert_tuple = ipv4_invert_tuple,
.print_tuple = ipv4_print_tuple,
.print_conntrack = ipv4_print_conntrack,
- .prepare = ipv4_prepare,
+ .get_l4proto = ipv4_get_l4proto,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = ipv4_tuple_to_nfattr,
.nfattr_to_tuple = ipv4_nfattr_to_tuple,
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 0fe8fb0..6593fd2 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -136,40 +136,22 @@
unsigned int hooknum)
{
struct nf_conntrack_tuple innertuple, origtuple;
- struct {
- struct icmphdr icmp;
- struct iphdr ip;
- } _in, *inside;
struct nf_conntrack_l4proto *innerproto;
struct nf_conntrack_tuple_hash *h;
- int dataoff;
NF_CT_ASSERT(skb->nfct == NULL);
- /* Not enough header? */
- inside = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_in), &_in);
- if (inside == NULL)
- return -NF_ACCEPT;
-
- /* Ignore ICMP's containing fragments (shouldn't happen) */
- if (inside->ip.frag_off & htons(IP_OFFSET)) {
- pr_debug("icmp_error_message: fragment of proto %u\n",
- inside->ip.protocol);
+ /* Are they talking about one of our connections? */
+ if (!nf_ct_get_tuplepr(skb,
+ skb_network_offset(skb) + ip_hdrlen(skb)
+ + sizeof(struct icmphdr),
+ PF_INET, &origtuple)) {
+ pr_debug("icmp_error_message: failed to get tuple\n");
return -NF_ACCEPT;
}
/* rcu_read_lock()ed by nf_hook_slow */
- innerproto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
-
- dataoff = ip_hdrlen(skb) + sizeof(inside->icmp);
- /* Are they talking about one of our connections? */
- if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET,
- inside->ip.protocol, &origtuple,
- &nf_conntrack_l3proto_ipv4, innerproto)) {
- pr_debug("icmp_error_message: ! get_tuple p=%u",
- inside->ip.protocol);
- return -NF_ACCEPT;
- }
+ innerproto = __nf_ct_l4proto_find(PF_INET, origtuple.dst.protonum);
/* Ordinarily, we'd expect the inverted tupleproto, but it's
been preserved inside the ICMP. */
@@ -183,25 +165,13 @@
h = nf_conntrack_find_get(&innertuple);
if (!h) {
- /* Locally generated ICMPs will match inverted if they
- haven't been SNAT'ed yet */
- /* FIXME: NAT code has to handle half-done double NAT --RR */
- if (hooknum == NF_IP_LOCAL_OUT)
- h = nf_conntrack_find_get(&origtuple);
-
- if (!h) {
- pr_debug("icmp_error_message: no match\n");
- return -NF_ACCEPT;
- }
-
- /* Reverse direction from that found */
- if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
- *ctinfo += IP_CT_IS_REPLY;
- } else {
- if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
- *ctinfo += IP_CT_IS_REPLY;
+ pr_debug("icmp_error_message: no match\n");
+ return -NF_ACCEPT;
}
+ if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
+ *ctinfo += IP_CT_IS_REPLY;
+
/* Update skb to refer to this connection */
skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general;
skb->nfctinfo = *ctinfo;
@@ -342,7 +312,7 @@
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */
-struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
{
.l3proto = PF_INET,
.l4proto = IPPROTO_ICMP,
@@ -368,4 +338,3 @@
#endif
#endif
};
-EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_icmp);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 69f9f1e..4e5884a 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1398,7 +1398,9 @@
* waiting for the first ACK and did not get it)...
*/
if ((tp->frto_counter == 1) && !(flag&FLAG_DATA_ACKED)) {
- tp->retrans_out += tcp_skb_pcount(skb);
+ /* For some reason this R-bit might get cleared? */
+ if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
+ tp->retrans_out += tcp_skb_pcount(skb);
/* ...enter this if branch just for the first segment */
flag |= FLAG_DATA_ACKED;
} else {
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index 86624fa..f37d592 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -111,6 +111,7 @@
p->snd_una = tp->snd_una;
p->snd_cwnd = tp->snd_cwnd;
p->snd_wnd = tp->snd_wnd;
+ p->ssthresh = tcp_current_ssthresh(sk);
p->srtt = tp->srtt >> 3;
tcp_probe.head = (tcp_probe.head + 1) % bufsize;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 24424c3..0601292 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2475,6 +2475,7 @@
write_unlock_bh(&idev->lock);
__ipv6_ifa_notify(RTM_DELADDR, ifa);
+ atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
in6_ifa_put(ifa);
write_lock_bh(&idev->lock);
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 4765a29..6a6714d 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -604,7 +604,7 @@
read_lock(&raw_v6_lock);
if ((sk = sk_head(&raw_v6_htable[hash])) != NULL) {
- while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr,
+ while ((sk = __raw_v6_lookup(sk, nexthdr, saddr, daddr,
IP6CB(skb)->iif))) {
rawv6_err(sk, skb, NULL, type, code, inner_offset, info);
sk = sk_next(sk);
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 254c769..aeda617 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1497,7 +1497,7 @@
if (ret < 0)
goto err5;
- printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
+ printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
return 0;
err5:
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 89e20ab..36df221 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -86,7 +86,7 @@
* - Note also special handling of AUTH header. Thanks to IPsec wizards.
*/
-int nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp,
+int nf_ct_ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
int len)
{
u8 nexthdr = *nexthdrp;
@@ -117,22 +117,25 @@
return start;
}
-static int
-ipv6_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
- u_int8_t *protonum)
+static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
+ unsigned int *dataoff, u_int8_t *protonum)
{
- unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data;
- unsigned char pnum = ipv6_hdr(*pskb)->nexthdr;
- int protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
- (*pskb)->len - extoff);
+ unsigned int extoff = nhoff + sizeof(struct ipv6hdr);
+ unsigned char pnum;
+ int protoff;
+
+ if (skb_copy_bits(skb, nhoff + offsetof(struct ipv6hdr, nexthdr),
+ &pnum, sizeof(pnum)) != 0) {
+ pr_debug("ip6_conntrack_core: can't get nexthdr\n");
+ return -NF_ACCEPT;
+ }
+ protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum, skb->len - extoff);
/*
- * (protoff == (*pskb)->len) mean that the packet doesn't have no data
+ * (protoff == skb->len) mean that the packet doesn't have no data
* except of IPv6 & ext headers. but it's tracked anyway. - YK
*/
- if ((protoff < 0) || (protoff > (*pskb)->len)) {
+ if ((protoff < 0) || (protoff > skb->len)) {
pr_debug("ip6_conntrack_core: can't find proto in pkt\n");
- NF_CT_STAT_INC_ATOMIC(error);
- NF_CT_STAT_INC_ATOMIC(invalid);
return -NF_ACCEPT;
}
@@ -370,14 +373,14 @@
}
#endif
-struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = {
+struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = {
.l3proto = PF_INET6,
.name = "ipv6",
.pkt_to_tuple = ipv6_pkt_to_tuple,
.invert_tuple = ipv6_invert_tuple,
.print_tuple = ipv6_print_tuple,
.print_conntrack = ipv6_print_conntrack,
- .prepare = ipv6_prepare,
+ .get_l4proto = ipv6_get_l4proto,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = ipv6_tuple_to_nfattr,
.nfattr_to_tuple = ipv6_nfattr_to_tuple,
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 9defc7e..ab154fb 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -136,48 +136,22 @@
{
struct nf_conntrack_tuple intuple, origtuple;
struct nf_conntrack_tuple_hash *h;
- struct icmp6hdr _hdr, *hp;
- unsigned int inip6off;
struct nf_conntrack_l4proto *inproto;
- u_int8_t inprotonum;
- unsigned int inprotoff;
NF_CT_ASSERT(skb->nfct == NULL);
- hp = skb_header_pointer(skb, icmp6off, sizeof(_hdr), &_hdr);
- if (hp == NULL) {
- pr_debug("icmpv6_error: Can't get ICMPv6 hdr.\n");
- return -NF_ACCEPT;
- }
-
- inip6off = icmp6off + sizeof(_hdr);
- if (skb_copy_bits(skb, inip6off+offsetof(struct ipv6hdr, nexthdr),
- &inprotonum, sizeof(inprotonum)) != 0) {
- pr_debug("icmpv6_error: Can't get nexthdr in inner IPv6 "
- "header.\n");
- return -NF_ACCEPT;
- }
- inprotoff = nf_ct_ipv6_skip_exthdr(skb,
- inip6off + sizeof(struct ipv6hdr),
- &inprotonum,
- skb->len - inip6off
- - sizeof(struct ipv6hdr));
-
- if ((inprotoff > skb->len) || (inprotonum == NEXTHDR_FRAGMENT)) {
- pr_debug("icmpv6_error: Can't get protocol header in ICMPv6 "
- "payload.\n");
+ /* Are they talking about one of our connections? */
+ if (!nf_ct_get_tuplepr(skb,
+ skb_network_offset(skb)
+ + sizeof(struct ipv6hdr)
+ + sizeof(struct icmp6hdr),
+ PF_INET6, &origtuple)) {
+ pr_debug("icmpv6_error: Can't get tuple\n");
return -NF_ACCEPT;
}
/* rcu_read_lock()ed by nf_hook_slow */
- inproto = __nf_ct_l4proto_find(PF_INET6, inprotonum);
-
- /* Are they talking about one of our connections? */
- if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum,
- &origtuple, &nf_conntrack_l3proto_ipv6, inproto)) {
- pr_debug("icmpv6_error: Can't get tuple\n");
- return -NF_ACCEPT;
- }
+ inproto = __nf_ct_l4proto_find(PF_INET6, origtuple.dst.protonum);
/* Ordinarily, we'd expect the inverted tupleproto, but it's
been preserved inside the ICMP. */
@@ -302,7 +276,7 @@
};
#endif /* CONFIG_SYSCTL */
-struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
{
.l3proto = PF_INET6,
.l4proto = IPPROTO_ICMPV6,
@@ -323,5 +297,3 @@
.ctl_table = icmpv6_sysctl_table,
#endif
};
-
-EXPORT_SYMBOL(nf_conntrack_l4proto_icmpv6);
diff --git a/net/iucv/Kconfig b/net/iucv/Kconfig
index f8fcc3d..16ce9cd 100644
--- a/net/iucv/Kconfig
+++ b/net/iucv/Kconfig
@@ -1,13 +1,13 @@
config IUCV
- tristate "IUCV support (VM only)"
+ tristate "IUCV support (S390 - z/VM only)"
depends on S390
help
- Select this option if you want to use inter-user communication under
- VM or VIF sockets. If you run on z/VM, say "Y" to enable a fast
+ Select this option if you want to use inter-user communication
+ under VM or VIF. If you run on z/VM, say "Y" to enable a fast
communication link between VM guests.
config AFIUCV
- tristate "AF_IUCV support (VM only)"
+ tristate "AF_IUCV support (S390 - z/VM only)"
depends on IUCV
help
Select this option if you want to use inter-user communication under
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index d9e9ddb..53ae14c 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -219,6 +219,7 @@
sock_init_data(sock, sk);
INIT_LIST_HEAD(&iucv_sk(sk)->accept_q);
+ spin_lock_init(&iucv_sk(sk)->accept_q_lock);
skb_queue_head_init(&iucv_sk(sk)->send_skb_q);
skb_queue_head_init(&iucv_sk(sk)->backlog_skb_q);
iucv_sk(sk)->send_tag = 0;
@@ -274,15 +275,25 @@
void iucv_accept_enqueue(struct sock *parent, struct sock *sk)
{
+ unsigned long flags;
+ struct iucv_sock *par = iucv_sk(parent);
+
sock_hold(sk);
- list_add_tail(&iucv_sk(sk)->accept_q, &iucv_sk(parent)->accept_q);
+ spin_lock_irqsave(&par->accept_q_lock, flags);
+ list_add_tail(&iucv_sk(sk)->accept_q, &par->accept_q);
+ spin_unlock_irqrestore(&par->accept_q_lock, flags);
iucv_sk(sk)->parent = parent;
parent->sk_ack_backlog++;
}
void iucv_accept_unlink(struct sock *sk)
{
+ unsigned long flags;
+ struct iucv_sock *par = iucv_sk(iucv_sk(sk)->parent);
+
+ spin_lock_irqsave(&par->accept_q_lock, flags);
list_del_init(&iucv_sk(sk)->accept_q);
+ spin_unlock_irqrestore(&par->accept_q_lock, flags);
iucv_sk(sk)->parent->sk_ack_backlog--;
iucv_sk(sk)->parent = NULL;
sock_put(sk);
@@ -298,8 +309,8 @@
lock_sock(sk);
if (sk->sk_state == IUCV_CLOSED) {
- release_sock(sk);
iucv_accept_unlink(sk);
+ release_sock(sk);
continue;
}
@@ -879,6 +890,7 @@
/* Find out if this path belongs to af_iucv. */
read_lock(&iucv_sk_list.lock);
iucv = NULL;
+ sk = NULL;
sk_for_each(sk, node, &iucv_sk_list.head)
if (sk->sk_state == IUCV_LISTEN &&
!memcmp(&iucv_sk(sk)->src_name, src_name, 8)) {
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index b733306..ad5150b 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -1494,7 +1494,10 @@
struct iucv_irq_list *p, *n;
/* Serialize tasklet, iucv_path_sever and iucv_path_connect. */
- spin_lock(&iucv_table_lock);
+ if (!spin_trylock(&iucv_table_lock)) {
+ tasklet_schedule(&iucv_tasklet);
+ return;
+ }
iucv_active_cpu = smp_processor_id();
spin_lock_irq(&iucv_queue_lock);
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 9e39646..a3e01d7 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -118,7 +118,7 @@
sdata->u.sta.authenticated ? "AUTH\n" : "",
sdata->u.sta.associated ? "ASSOC\n" : "",
sdata->u.sta.probereq_poll ? "PROBEREQ POLL\n" : "",
- sdata->u.sta.use_protection ? "CTS prot\n" : "");
+ sdata->use_protection ? "CTS prot\n" : "");
}
__IEEE80211_IF_FILE(flags);
diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h
index 34fa128..52da513 100644
--- a/net/mac80211/hostapd_ioctl.h
+++ b/net/mac80211/hostapd_ioctl.h
@@ -26,24 +26,16 @@
* mess shall be deleted completely. */
enum {
PRISM2_PARAM_IEEE_802_1X = 23,
- PRISM2_PARAM_ANTSEL_TX = 24,
- PRISM2_PARAM_ANTSEL_RX = 25,
/* Instant802 additions */
PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001,
- PRISM2_PARAM_DROP_UNENCRYPTED = 1002,
PRISM2_PARAM_PREAMBLE = 1003,
PRISM2_PARAM_SHORT_SLOT_TIME = 1006,
PRISM2_PARAM_NEXT_MODE = 1008,
- PRISM2_PARAM_CLEAR_KEYS = 1009,
PRISM2_PARAM_RADIO_ENABLED = 1010,
PRISM2_PARAM_ANTENNA_MODE = 1013,
PRISM2_PARAM_STAT_TIME = 1016,
PRISM2_PARAM_STA_ANTENNA_SEL = 1017,
- PRISM2_PARAM_FORCE_UNICAST_RATE = 1018,
- PRISM2_PARAM_RATE_CTRL_NUM_UP = 1019,
- PRISM2_PARAM_RATE_CTRL_NUM_DOWN = 1020,
- PRISM2_PARAM_MAX_RATECTRL_RATE = 1021,
PRISM2_PARAM_TX_POWER_REDUCTION = 1022,
PRISM2_PARAM_KEY_TX_RX_THRESHOLD = 1024,
PRISM2_PARAM_DEFAULT_WEP_ONLY = 1026,
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 4e84f24..2ddf4ef 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -24,6 +24,7 @@
#include <linux/compiler.h>
#include <linux/bitmap.h>
#include <net/cfg80211.h>
+#include <asm/unaligned.h>
#include "ieee80211_common.h"
#include "ieee80211_i.h"
@@ -56,6 +57,17 @@
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
+/*
+ * For seeing transmitted packets on monitor interfaces
+ * we have a radiotap header too.
+ */
+struct ieee80211_tx_status_rtap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ __le16 tx_flags;
+ u8 data_retries;
+} __attribute__ ((packed));
+
+
static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr)
{
@@ -430,7 +442,7 @@
if (!tx->u.tx.rate)
return TXRX_DROP;
if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
- tx->local->cts_protect_erp_frames && tx->fragmented &&
+ tx->sdata->use_protection && tx->fragmented &&
extra.nonerp) {
tx->u.tx.last_frag_rate = tx->u.tx.rate;
tx->u.tx.probe_last_frag = extra.probe ? 1 : 0;
@@ -528,7 +540,7 @@
/* reserve enough extra head and tail room for possible
* encryption */
frag = frags[i] =
- dev_alloc_skb(tx->local->hw.extra_tx_headroom +
+ dev_alloc_skb(tx->local->tx_headroom +
frag_threshold +
IEEE80211_ENCRYPT_HEADROOM +
IEEE80211_ENCRYPT_TAILROOM);
@@ -537,8 +549,8 @@
/* Make sure that all fragments use the same priority so
* that they end up using the same TX queue */
frag->priority = first->priority;
- skb_reserve(frag, tx->local->hw.extra_tx_headroom +
- IEEE80211_ENCRYPT_HEADROOM);
+ skb_reserve(frag, tx->local->tx_headroom +
+ IEEE80211_ENCRYPT_HEADROOM);
fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
memcpy(fhdr, first->data, hdrlen);
if (i == num_fragm - 2)
@@ -856,8 +868,7 @@
* for the frame. */
if (mode->mode == MODE_IEEE80211G &&
(tx->u.tx.rate->flags & IEEE80211_RATE_ERP) &&
- tx->u.tx.unicast &&
- tx->local->cts_protect_erp_frames &&
+ tx->u.tx.unicast && tx->sdata->use_protection &&
!(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
@@ -1118,7 +1129,138 @@
}
-static void inline
+/*
+ * deal with packet injection down monitor interface
+ * with Radiotap Header -- only called for monitor mode interface
+ */
+
+static ieee80211_txrx_result
+__ieee80211_parse_tx_radiotap(
+ struct ieee80211_txrx_data *tx,
+ struct sk_buff *skb, struct ieee80211_tx_control *control)
+{
+ /*
+ * this is the moment to interpret and discard the radiotap header that
+ * must be at the start of the packet injected in Monitor mode
+ *
+ * Need to take some care with endian-ness since radiotap
+ * args are little-endian
+ */
+
+ struct ieee80211_radiotap_iterator iterator;
+ struct ieee80211_radiotap_header *rthdr =
+ (struct ieee80211_radiotap_header *) skb->data;
+ struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode;
+ int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
+
+ /*
+ * default control situation for all injected packets
+ * FIXME: this does not suit all usage cases, expand to allow control
+ */
+
+ control->retry_limit = 1; /* no retry */
+ control->key_idx = -1; /* no encryption key */
+ control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
+ IEEE80211_TXCTL_USE_CTS_PROTECT);
+ control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT |
+ IEEE80211_TXCTL_NO_ACK;
+ control->antenna_sel_tx = 0; /* default to default antenna */
+
+ /*
+ * for every radiotap entry that is present
+ * (ieee80211_radiotap_iterator_next returns -ENOENT when no more
+ * entries present, or -EINVAL on error)
+ */
+
+ while (!ret) {
+ int i, target_rate;
+
+ ret = ieee80211_radiotap_iterator_next(&iterator);
+
+ if (ret)
+ continue;
+
+ /* see if this argument is something we can use */
+ switch (iterator.this_arg_index) {
+ /*
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+ case IEEE80211_RADIOTAP_RATE:
+ /*
+ * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps
+ * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps
+ */
+ target_rate = (*iterator.this_arg) * 5;
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *r = &mode->rates[i];
+
+ if (r->rate > target_rate)
+ continue;
+
+ control->rate = r;
+
+ if (r->flags & IEEE80211_RATE_PREAMBLE2)
+ control->tx_rate = r->val2;
+ else
+ control->tx_rate = r->val;
+
+ /* end on exact match */
+ if (r->rate == target_rate)
+ i = mode->num_rates;
+ }
+ break;
+
+ case IEEE80211_RADIOTAP_ANTENNA:
+ /*
+ * radiotap uses 0 for 1st ant, mac80211 is 1 for
+ * 1st ant
+ */
+ control->antenna_sel_tx = (*iterator.this_arg) + 1;
+ break;
+
+ case IEEE80211_RADIOTAP_DBM_TX_POWER:
+ control->power_level = *iterator.this_arg;
+ break;
+
+ case IEEE80211_RADIOTAP_FLAGS:
+ if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
+ /*
+ * this indicates that the skb we have been
+ * handed has the 32-bit FCS CRC at the end...
+ * we should react to that by snipping it off
+ * because it will be recomputed and added
+ * on transmission
+ */
+ if (skb->len < (iterator.max_length + FCS_LEN))
+ return TXRX_DROP;
+
+ skb_trim(skb, skb->len - FCS_LEN);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
+ return TXRX_DROP;
+
+ /*
+ * remove the radiotap header
+ * iterator->max_length was sanity-checked against
+ * skb->len by iterator init
+ */
+ skb_pull(skb, iterator.max_length);
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result inline
__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
struct sk_buff *skb,
struct net_device *dev,
@@ -1126,6 +1268,9 @@
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_sub_if_data *sdata;
+ ieee80211_txrx_result res = TXRX_CONTINUE;
+
int hdrlen;
memset(tx, 0, sizeof(*tx));
@@ -1135,7 +1280,32 @@
tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
tx->sta = sta_info_get(local, hdr->addr1);
tx->fc = le16_to_cpu(hdr->frame_control);
+
+ /*
+ * set defaults for things that can be set by
+ * injected radiotap headers
+ */
control->power_level = local->hw.conf.power_level;
+ control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+ if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta)
+ control->antenna_sel_tx = tx->sta->antenna_sel_tx;
+
+ /* process and remove the injection radiotap header */
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) {
+ if (__ieee80211_parse_tx_radiotap(tx, skb, control) ==
+ TXRX_DROP) {
+ return TXRX_DROP;
+ }
+ /*
+ * we removed the radiotap header after this point,
+ * we filled control with what we could use
+ * set to the actual ieee header now
+ */
+ hdr = (struct ieee80211_hdr *) skb->data;
+ res = TXRX_QUEUED; /* indication it was monitor packet */
+ }
+
tx->u.tx.control = control;
tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1);
if (is_multicast_ether_addr(hdr->addr1))
@@ -1152,9 +1322,6 @@
control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
tx->sta->clear_dst_mask = 0;
}
- control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta)
- control->antenna_sel_tx = tx->sta->antenna_sel_tx;
hdrlen = ieee80211_get_hdrlen(tx->fc);
if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
@@ -1162,6 +1329,7 @@
}
control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
+ return res;
}
static int inline is_ieee80211_device(struct net_device *dev,
@@ -1274,7 +1442,7 @@
struct sta_info *sta;
ieee80211_tx_handler *handler;
struct ieee80211_txrx_data tx;
- ieee80211_txrx_result res = TXRX_DROP;
+ ieee80211_txrx_result res = TXRX_DROP, res_prepare;
int ret, i;
WARN_ON(__ieee80211_queue_pending(local, control->queue));
@@ -1284,15 +1452,26 @@
return 0;
}
- __ieee80211_tx_prepare(&tx, skb, dev, control);
+ res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control);
+
+ if (res_prepare == TXRX_DROP) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
sta = tx.sta;
tx.u.tx.mgmt_interface = mgmt;
tx.u.tx.mode = local->hw.conf.mode;
- for (handler = local->tx_handlers; *handler != NULL; handler++) {
- res = (*handler)(&tx);
- if (res != TXRX_CONTINUE)
- break;
+ if (res_prepare == TXRX_QUEUED) { /* if it was an injected packet */
+ res = TXRX_CONTINUE;
+ } else {
+ for (handler = local->tx_handlers; *handler != NULL;
+ handler++) {
+ res = (*handler)(&tx);
+ if (res != TXRX_CONTINUE)
+ break;
+ }
}
skb = tx.skb; /* handlers are allowed to change skb */
@@ -1467,8 +1646,7 @@
}
osdata = IEEE80211_DEV_TO_SUB_IF(odev);
- headroom = osdata->local->hw.extra_tx_headroom +
- IEEE80211_ENCRYPT_HEADROOM;
+ headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM;
if (skb_headroom(skb) < headroom) {
if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
dev_kfree_skb(skb);
@@ -1494,6 +1672,56 @@
}
+int ieee80211_monitor_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_radiotap_header *prthdr =
+ (struct ieee80211_radiotap_header *)skb->data;
+ u16 len;
+
+ /*
+ * there must be a radiotap header at the
+ * start in this case
+ */
+ if (unlikely(prthdr->it_version)) {
+ /* only version 0 is supported */
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ skb->dev = local->mdev;
+
+ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+ memset(pkt_data, 0, sizeof(*pkt_data));
+ pkt_data->ifindex = dev->ifindex;
+ pkt_data->mgmt_iface = 0;
+ pkt_data->do_not_encrypt = 1;
+
+ /* above needed because we set skb device to master */
+
+ /*
+ * fix up the pointers accounting for the radiotap
+ * header still being in there. We are being given
+ * a precooked IEEE80211 header so no need for
+ * normal processing
+ */
+ len = le16_to_cpu(get_unaligned(&prthdr->it_len));
+ skb_set_mac_header(skb, len);
+ skb_set_network_header(skb, len + sizeof(struct ieee80211_hdr));
+ skb_set_transport_header(skb, len + sizeof(struct ieee80211_hdr));
+
+ /*
+ * pass the radiotap header up to
+ * the next stage intact
+ */
+ dev_queue_xmit(skb);
+
+ return NETDEV_TX_OK;
+}
+
+
/**
* ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type
* subinterfaces (wlan#, WDS, and VLAN interfaces)
@@ -1509,8 +1737,8 @@
* encapsulated packet will then be passed to master interface, wlan#.11, for
* transmission (through low-level driver).
*/
-static int ieee80211_subif_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
+int ieee80211_subif_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_tx_packet_data *pkt_data;
@@ -1619,7 +1847,7 @@
* build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
* alloc_skb() (net/core/skbuff.c)
*/
- head_need = hdrlen + encaps_len + local->hw.extra_tx_headroom;
+ head_need = hdrlen + encaps_len + local->tx_headroom;
head_need -= skb_headroom(skb);
/* We are going to modify skb data, so make a copy of it if happens to
@@ -1658,7 +1886,7 @@
pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- pkt_data->ifindex = sdata->dev->ifindex;
+ pkt_data->ifindex = dev->ifindex;
pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
pkt_data->do_not_encrypt = no_encrypt;
@@ -1706,9 +1934,9 @@
return 0;
}
- if (skb_headroom(skb) < sdata->local->hw.extra_tx_headroom) {
- if (pskb_expand_head(skb,
- sdata->local->hw.extra_tx_headroom, 0, GFP_ATOMIC)) {
+ if (skb_headroom(skb) < sdata->local->tx_headroom) {
+ if (pskb_expand_head(skb, sdata->local->tx_headroom,
+ 0, GFP_ATOMIC)) {
dev_kfree_skb(skb);
return 0;
}
@@ -1847,12 +2075,12 @@
bh_len = ap->beacon_head_len;
bt_len = ap->beacon_tail_len;
- skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+ skb = dev_alloc_skb(local->tx_headroom +
bh_len + bt_len + 256 /* maximum TIM len */);
if (!skb)
return NULL;
- skb_reserve(skb, local->hw.extra_tx_headroom);
+ skb_reserve(skb, local->tx_headroom);
memcpy(skb_put(skb, bh_len), b_head, bh_len);
ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
@@ -2376,8 +2604,7 @@
struct ieee80211_if_init_conf conf;
if (local->open_count && local->open_count == local->monitors &&
- !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
- local->ops->add_interface) {
+ !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
conf.if_id = -1;
conf.type = IEEE80211_IF_TYPE_MNTR;
conf.mac_addr = NULL;
@@ -2420,21 +2647,14 @@
}
ieee80211_start_soft_monitor(local);
- if (local->ops->add_interface) {
- conf.if_id = dev->ifindex;
- conf.type = sdata->type;
- conf.mac_addr = dev->dev_addr;
- res = local->ops->add_interface(local_to_hw(local), &conf);
- if (res) {
- if (sdata->type == IEEE80211_IF_TYPE_MNTR)
- ieee80211_start_hard_monitor(local);
- return res;
- }
- } else {
- if (sdata->type != IEEE80211_IF_TYPE_STA)
- return -EOPNOTSUPP;
- if (local->open_count > 0)
- return -ENOBUFS;
+ conf.if_id = dev->ifindex;
+ conf.type = sdata->type;
+ conf.mac_addr = dev->dev_addr;
+ res = local->ops->add_interface(local_to_hw(local), &conf);
+ if (res) {
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+ ieee80211_start_hard_monitor(local);
+ return res;
}
if (local->open_count == 0) {
@@ -2941,34 +3161,6 @@
}
EXPORT_SYMBOL(ieee80211_radar_status);
-int ieee80211_set_aid_for_sta(struct ieee80211_hw *hw, u8 *peer_address,
- u16 aid)
-{
- struct sk_buff *skb;
- struct ieee80211_msg_set_aid_for_sta *msg;
- struct ieee80211_local *local = hw_to_local(hw);
-
- /* unlikely because if this event only happens for APs,
- * which require an open ap device. */
- if (unlikely(!local->apdev))
- return 0;
-
- skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
- sizeof(struct ieee80211_msg_set_aid_for_sta));
-
- if (!skb)
- return -ENOMEM;
- skb_reserve(skb, sizeof(struct ieee80211_frame_info));
-
- msg = (struct ieee80211_msg_set_aid_for_sta *)
- skb_put(skb, sizeof(struct ieee80211_msg_set_aid_for_sta));
- memcpy(msg->sta_address, peer_address, ETH_ALEN);
- msg->aid = aid;
-
- ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_set_aid_for_sta);
- return 0;
-}
-EXPORT_SYMBOL(ieee80211_set_aid_for_sta);
static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
{
@@ -4284,6 +4476,9 @@
struct ieee80211_local *local = hw_to_local(hw);
u16 frag, type;
u32 msg_type;
+ struct ieee80211_tx_status_rtap_hdr *rthdr;
+ struct ieee80211_sub_if_data *sdata;
+ int monitors;
if (!status) {
printk(KERN_ERR
@@ -4395,27 +4590,100 @@
local->dot11FailedCount++;
}
- if (!(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS)
- || unlikely(!local->apdev)) {
- dev_kfree_skb(skb);
- return;
- }
-
msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ?
ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail;
- /* skb was the original skb used for TX. Clone it and give the clone
- * to netif_rx(). Free original skb. */
- skb2 = skb_copy(skb, GFP_ATOMIC);
- if (!skb2) {
+ /* this was a transmitted frame, but now we want to reuse it */
+ skb_orphan(skb);
+
+ if ((status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) &&
+ local->apdev) {
+ if (local->monitors) {
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ } else {
+ skb2 = skb;
+ skb = NULL;
+ }
+
+ if (skb2)
+ /* Send frame to hostapd */
+ ieee80211_rx_mgmt(local, skb2, NULL, msg_type);
+
+ if (!skb)
+ return;
+ }
+
+ if (!local->monitors) {
dev_kfree_skb(skb);
return;
}
- dev_kfree_skb(skb);
- skb = skb2;
- /* Send frame to hostapd */
- ieee80211_rx_mgmt(local, skb, NULL, msg_type);
+ /* send frame to monitor interfaces now */
+
+ if (skb_headroom(skb) < sizeof(*rthdr)) {
+ printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ rthdr = (struct ieee80211_tx_status_rtap_hdr*)
+ skb_push(skb, sizeof(*rthdr));
+
+ memset(rthdr, 0, sizeof(*rthdr));
+ rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+ rthdr->hdr.it_present =
+ cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
+
+ if (!(status->flags & IEEE80211_TX_STATUS_ACK) &&
+ !is_multicast_ether_addr(hdr->addr1))
+ rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
+
+ if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
+ (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT))
+ rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
+ else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
+
+ rthdr->data_retries = status->retry_count;
+
+ read_lock(&local->sub_if_lock);
+ monitors = local->monitors;
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ /*
+ * Using the monitors counter is possibly racy, but
+ * if the value is wrong we simply either clone the skb
+ * once too much or forget sending it to one monitor iface
+ * The latter case isn't nice but fixing the race is much
+ * more complicated.
+ */
+ if (!monitors || !skb)
+ goto out;
+
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+ if (!netif_running(sdata->dev))
+ continue;
+ monitors--;
+ if (monitors)
+ skb2 = skb_clone(skb, GFP_KERNEL);
+ else
+ skb2 = NULL;
+ skb->dev = sdata->dev;
+ /* XXX: is this sufficient for BPF? */
+ skb_set_mac_header(skb, 0);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+ skb = skb2;
+ break;
+ }
+ }
+ out:
+ read_unlock(&local->sub_if_lock);
+ if (skb)
+ dev_kfree_skb(skb);
}
EXPORT_SYMBOL(ieee80211_tx_status);
@@ -4619,6 +4887,9 @@
((sizeof(struct ieee80211_local) +
NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
+ BUG_ON(!ops->tx);
+ BUG_ON(!ops->config);
+ BUG_ON(!ops->add_interface);
local->ops = ops;
/* for now, mdev needs sub_if_data :/ */
@@ -4647,8 +4918,6 @@
local->short_retry_limit = 7;
local->long_retry_limit = 4;
local->hw.conf.radio_enabled = 1;
- local->rate_ctrl_num_up = RATE_CONTROL_NUM_UP;
- local->rate_ctrl_num_down = RATE_CONTROL_NUM_DOWN;
local->enabled_modes = (unsigned int) -1;
@@ -4712,6 +4981,14 @@
goto fail_workqueue;
}
+ /*
+ * The hardware needs headroom for sending the frame,
+ * and we need some headroom for passing the frame to monitor
+ * interfaces, but never both at the same time.
+ */
+ local->tx_headroom = max(local->hw.extra_tx_headroom,
+ sizeof(struct ieee80211_tx_status_rtap_hdr));
+
debugfs_hw_add(local);
local->hw.conf.beacon_int = 1000;
diff --git a/net/mac80211/ieee80211_common.h b/net/mac80211/ieee80211_common.h
index b9a73e7..77c6afb 100644
--- a/net/mac80211/ieee80211_common.h
+++ b/net/mac80211/ieee80211_common.h
@@ -47,21 +47,16 @@
ieee80211_msg_normal = 0,
ieee80211_msg_tx_callback_ack = 1,
ieee80211_msg_tx_callback_fail = 2,
- ieee80211_msg_passive_scan = 3,
+ /* hole at 3, was ieee80211_msg_passive_scan but unused */
ieee80211_msg_wep_frame_unknown_key = 4,
ieee80211_msg_michael_mic_failure = 5,
/* hole at 6, was monitor but never sent to userspace */
ieee80211_msg_sta_not_assoc = 7,
- ieee80211_msg_set_aid_for_sta = 8 /* used by Intersil MVC driver */,
+ /* 8 was ieee80211_msg_set_aid_for_sta */
ieee80211_msg_key_threshold_notification = 9,
ieee80211_msg_radar = 11,
};
-struct ieee80211_msg_set_aid_for_sta {
- char sta_address[ETH_ALEN];
- u16 aid;
-};
-
struct ieee80211_msg_key_notification {
int tx_rx_count;
char ifname[IFNAMSIZ];
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index af4d14d..055a2a9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -99,6 +99,12 @@
int probe_resp;
unsigned long last_update;
+ /* during assocation, we save an ERP value from a probe response so
+ * that we can feed ERP info to the driver when handling the
+ * association completes. these fields probably won't be up-to-date
+ * otherwise, you probably don't want to use them. */
+ int has_erp_value;
+ u8 erp_value;
};
@@ -235,7 +241,6 @@
unsigned int authenticated:1;
unsigned int associated:1;
unsigned int probereq_poll:1;
- unsigned int use_protection:1;
unsigned int create_ibss:1;
unsigned int mixed_cell:1;
unsigned int wmm_enabled:1;
@@ -278,6 +283,7 @@
int mc_count;
unsigned int allmulti:1;
unsigned int promisc:1;
+ unsigned int use_protection:1; /* CTS protect ERP frames */
struct net_device_stats stats;
int drop_unencrypted;
@@ -392,6 +398,7 @@
int monitors;
struct iw_statistics wstats;
u8 wstats_flags;
+ int tx_headroom; /* required headroom for hardware/radiotap */
enum {
IEEE80211_DEV_UNINITIALIZED = 0,
@@ -437,7 +444,6 @@
int *basic_rates[NUM_IEEE80211_MODES];
int rts_threshold;
- int cts_protect_erp_frames;
int fragmentation_threshold;
int short_retry_limit; /* dot11ShortRetryLimit */
int long_retry_limit; /* dot11LongRetryLimit */
@@ -513,8 +519,6 @@
STA_ANTENNA_SEL_SW_CTRL_DEBUG = 2
} sta_antenna_sel;
- int rate_ctrl_num_up, rate_ctrl_num_down;
-
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
/* TX/RX handler statistics */
unsigned int tx_handlers_drop;
@@ -719,6 +723,8 @@
struct ieee80211_hw_mode *mode);
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
+int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
+int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
void ieee80211_if_setup(struct net_device *dev);
void ieee80211_if_mgmt_setup(struct net_device *dev);
int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
index cf0f32e..8532a5c 100644
--- a/net/mac80211/ieee80211_iface.c
+++ b/net/mac80211/ieee80211_iface.c
@@ -157,6 +157,8 @@
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
int oldtype = sdata->type;
+ dev->hard_start_xmit = ieee80211_subif_start_xmit;
+
sdata->type = type;
switch (type) {
case IEEE80211_IF_TYPE_WDS:
@@ -196,6 +198,7 @@
}
case IEEE80211_IF_TYPE_MNTR:
dev->type = ARPHRD_IEEE80211_RADIOTAP;
+ dev->hard_start_xmit = ieee80211_monitor_start_xmit;
break;
default:
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index 66e8a97..5918dd0 100644
--- a/net/mac80211/ieee80211_ioctl.c
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -345,6 +345,8 @@
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct iw_range *range = (struct iw_range *) extra;
+ struct ieee80211_hw_mode *mode = NULL;
+ int c = 0;
data->length = sizeof(struct iw_range);
memset(range, 0, sizeof(struct iw_range));
@@ -378,6 +380,29 @@
range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+ list_for_each_entry(mode, &local->modes_list, list) {
+ int i = 0;
+
+ if (!(local->enabled_modes & (1 << mode->mode)) ||
+ (local->hw_modes & local->enabled_modes &
+ (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+ continue;
+
+ while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) {
+ struct ieee80211_channel *chan = &mode->channels[i];
+
+ if (chan->flag & IEEE80211_CHAN_W_SCAN) {
+ range->freq[c].i = chan->chan;
+ range->freq[c].m = chan->freq * 100000;
+ range->freq[c].e = 1;
+ c++;
+ }
+ i++;
+ }
+ }
+ range->num_channels = c;
+ range->num_frequency = c;
+
IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
@@ -838,6 +863,44 @@
}
+static int ieee80211_ioctl_siwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rate, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
+ int i;
+ u32 target_rate = rate->value / 100000;
+ struct ieee80211_sub_if_data *sdata;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (!sdata->bss)
+ return -ENODEV;
+ mode = local->oper_hw_mode;
+ /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
+ * target_rate = X, rate->fixed = 1 means only rate X
+ * target_rate = X, rate->fixed = 0 means all rates <= X */
+ sdata->bss->max_ratectrl_rateidx = -1;
+ sdata->bss->force_unicast_rateidx = -1;
+ if (rate->value < 0)
+ return 0;
+ for (i=0; i< mode->num_rates; i++) {
+ struct ieee80211_rate *rates = &mode->rates[i];
+ int this_rate = rates->rate;
+
+ if (mode->mode == MODE_ATHEROS_TURBO ||
+ mode->mode == MODE_ATHEROS_TURBOG)
+ this_rate *= 2;
+ if (target_rate == this_rate) {
+ sdata->bss->max_ratectrl_rateidx = i;
+ if (rate->fixed)
+ sdata->bss->force_unicast_rateidx = i;
+ break;
+ }
+ }
+ return 0;
+}
+
static int ieee80211_ioctl_giwrate(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rate, char *extra)
@@ -993,118 +1056,6 @@
return 0;
}
-static int ieee80211_ioctl_clear_keys(struct net_device *dev)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_key_conf key;
- int i;
- u8 addr[ETH_ALEN];
- struct ieee80211_key_conf *keyconf;
- struct ieee80211_sub_if_data *sdata;
- struct sta_info *sta;
-
- memset(addr, 0xff, ETH_ALEN);
- read_lock(&local->sub_if_lock);
- list_for_each_entry(sdata, &local->sub_if_list, list) {
- for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
- keyconf = NULL;
- if (sdata->keys[i] &&
- !sdata->keys[i]->force_sw_encrypt &&
- local->ops->set_key &&
- (keyconf = ieee80211_key_data2conf(local,
- sdata->keys[i])))
- local->ops->set_key(local_to_hw(local),
- DISABLE_KEY, addr,
- keyconf, 0);
- kfree(keyconf);
- ieee80211_key_free(sdata->keys[i]);
- sdata->keys[i] = NULL;
- }
- sdata->default_key = NULL;
- }
- read_unlock(&local->sub_if_lock);
-
- spin_lock_bh(&local->sta_lock);
- list_for_each_entry(sta, &local->sta_list, list) {
- keyconf = NULL;
- if (sta->key && !sta->key->force_sw_encrypt &&
- local->ops->set_key &&
- (keyconf = ieee80211_key_data2conf(local, sta->key)))
- local->ops->set_key(local_to_hw(local), DISABLE_KEY,
- sta->addr, keyconf, sta->aid);
- kfree(keyconf);
- ieee80211_key_free(sta->key);
- sta->key = NULL;
- }
- spin_unlock_bh(&local->sta_lock);
-
- memset(&key, 0, sizeof(key));
- if (local->ops->set_key &&
- local->ops->set_key(local_to_hw(local), REMOVE_ALL_KEYS,
- NULL, &key, 0))
- printk(KERN_DEBUG "%s: failed to remove hwaccel keys\n",
- dev->name);
-
- return 0;
-}
-
-
-static int
-ieee80211_ioctl_force_unicast_rate(struct net_device *dev,
- struct ieee80211_sub_if_data *sdata,
- int rate)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_hw_mode *mode;
- int i;
-
- if (sdata->type != IEEE80211_IF_TYPE_AP)
- return -ENOENT;
-
- if (rate == 0) {
- sdata->u.ap.force_unicast_rateidx = -1;
- return 0;
- }
-
- mode = local->oper_hw_mode;
- for (i = 0; i < mode->num_rates; i++) {
- if (mode->rates[i].rate == rate) {
- sdata->u.ap.force_unicast_rateidx = i;
- return 0;
- }
- }
- return -EINVAL;
-}
-
-
-static int
-ieee80211_ioctl_max_ratectrl_rate(struct net_device *dev,
- struct ieee80211_sub_if_data *sdata,
- int rate)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_hw_mode *mode;
- int i;
-
- if (sdata->type != IEEE80211_IF_TYPE_AP)
- return -ENOENT;
-
- if (rate == 0) {
- sdata->u.ap.max_ratectrl_rateidx = -1;
- return 0;
- }
-
- mode = local->oper_hw_mode;
- for (i = 0; i < mode->num_rates; i++) {
- if (mode->rates[i].rate == rate) {
- sdata->u.ap.max_ratectrl_rateidx = i;
- return 0;
- }
- }
- return -EINVAL;
-}
-
-
static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local,
struct ieee80211_key *key)
{
@@ -1228,24 +1179,11 @@
sdata->ieee802_1x = value;
break;
- case PRISM2_PARAM_ANTSEL_TX:
- local->hw.conf.antenna_sel_tx = value;
- if (ieee80211_hw_config(local))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_ANTSEL_RX:
- local->hw.conf.antenna_sel_rx = value;
- if (ieee80211_hw_config(local))
- ret = -EINVAL;
- break;
-
case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
- local->cts_protect_erp_frames = value;
- break;
-
- case PRISM2_PARAM_DROP_UNENCRYPTED:
- sdata->drop_unencrypted = value;
+ if (sdata->type != IEEE80211_IF_TYPE_AP)
+ ret = -ENOENT;
+ else
+ sdata->use_protection = value;
break;
case PRISM2_PARAM_PREAMBLE:
@@ -1274,10 +1212,6 @@
local->next_mode = value;
break;
- case PRISM2_PARAM_CLEAR_KEYS:
- ret = ieee80211_ioctl_clear_keys(dev);
- break;
-
case PRISM2_PARAM_RADIO_ENABLED:
ret = ieee80211_ioctl_set_radio_enabled(dev, value);
break;
@@ -1292,22 +1226,6 @@
local->sta_antenna_sel = value;
break;
- case PRISM2_PARAM_FORCE_UNICAST_RATE:
- ret = ieee80211_ioctl_force_unicast_rate(dev, sdata, value);
- break;
-
- case PRISM2_PARAM_MAX_RATECTRL_RATE:
- ret = ieee80211_ioctl_max_ratectrl_rate(dev, sdata, value);
- break;
-
- case PRISM2_PARAM_RATE_CTRL_NUM_UP:
- local->rate_ctrl_num_up = value;
- break;
-
- case PRISM2_PARAM_RATE_CTRL_NUM_DOWN:
- local->rate_ctrl_num_down = value;
- break;
-
case PRISM2_PARAM_TX_POWER_REDUCTION:
if (value < 0)
ret = -EINVAL;
@@ -1387,20 +1305,8 @@
*param = sdata->ieee802_1x;
break;
- case PRISM2_PARAM_ANTSEL_TX:
- *param = local->hw.conf.antenna_sel_tx;
- break;
-
- case PRISM2_PARAM_ANTSEL_RX:
- *param = local->hw.conf.antenna_sel_rx;
- break;
-
case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
- *param = local->cts_protect_erp_frames;
- break;
-
- case PRISM2_PARAM_DROP_UNENCRYPTED:
- *param = sdata->drop_unencrypted;
+ *param = sdata->use_protection;
break;
case PRISM2_PARAM_PREAMBLE:
@@ -1426,14 +1332,6 @@
*param = local->sta_antenna_sel;
break;
- case PRISM2_PARAM_RATE_CTRL_NUM_UP:
- *param = local->rate_ctrl_num_up;
- break;
-
- case PRISM2_PARAM_RATE_CTRL_NUM_DOWN:
- *param = local->rate_ctrl_num_down;
- break;
-
case PRISM2_PARAM_TX_POWER_REDUCTION:
*param = local->hw.conf.tx_power_reduction;
break;
@@ -1801,7 +1699,7 @@
(iw_handler) NULL, /* SIOCGIWNICKN */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCSIWRATE */
+ (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */
(iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */
(iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */
(iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 91b545c..ba2bf8f 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -76,33 +76,36 @@
/* Parsed Information Elements */
struct ieee802_11_elems {
+ /* pointers to IEs */
u8 *ssid;
- u8 ssid_len;
u8 *supp_rates;
- u8 supp_rates_len;
u8 *fh_params;
- u8 fh_params_len;
u8 *ds_params;
- u8 ds_params_len;
u8 *cf_params;
- u8 cf_params_len;
u8 *tim;
- u8 tim_len;
u8 *ibss_params;
- u8 ibss_params_len;
u8 *challenge;
- u8 challenge_len;
u8 *wpa;
- u8 wpa_len;
u8 *rsn;
- u8 rsn_len;
u8 *erp_info;
- u8 erp_info_len;
u8 *ext_supp_rates;
- u8 ext_supp_rates_len;
u8 *wmm_info;
- u8 wmm_info_len;
u8 *wmm_param;
+
+ /* length of them, respectively */
+ u8 ssid_len;
+ u8 supp_rates_len;
+ u8 fh_params_len;
+ u8 ds_params_len;
+ u8 cf_params_len;
+ u8 tim_len;
+ u8 ibss_params_len;
+ u8 challenge_len;
+ u8 wpa_len;
+ u8 rsn_len;
+ u8 erp_info_len;
+ u8 ext_supp_rates_len;
+ u8 wmm_info_len;
u8 wmm_param_len;
};
@@ -311,6 +314,25 @@
}
+static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+
+ if (use_protection != sdata->use_protection) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
+ MAC_FMT ")\n",
+ dev->name,
+ use_protection ? "enabled" : "disabled",
+ MAC_ARG(ifsta->bssid));
+ }
+ sdata->use_protection = use_protection;
+ }
+}
+
+
static void ieee80211_sta_send_associnfo(struct net_device *dev,
struct ieee80211_if_sta *ifsta)
{
@@ -366,6 +388,7 @@
struct ieee80211_if_sta *ifsta, int assoc)
{
union iwreq_data wrqu;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (ifsta->associated == assoc)
return;
@@ -374,9 +397,18 @@
if (assoc) {
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sta_bss *bss;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type != IEEE80211_IF_TYPE_STA)
return;
+
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ if (bss) {
+ if (bss->has_erp_value)
+ ieee80211_handle_erp_ie(dev, bss->erp_value);
+ ieee80211_rx_bss_put(dev, bss);
+ }
+
netif_carrier_on(dev);
ifsta->prev_bssid_set = 1;
memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
@@ -384,6 +416,7 @@
ieee80211_sta_send_associnfo(dev, ifsta);
} else {
netif_carrier_off(dev);
+ sdata->use_protection = 0;
memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
}
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -1174,6 +1207,18 @@
return;
}
+ /* it probably doesn't, but if the frame includes an ERP value then
+ * update our stored copy */
+ if (elems.erp_info && elems.erp_info_len >= 1) {
+ struct ieee80211_sta_bss *bss
+ = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ if (bss) {
+ bss->erp_value = elems.erp_info[0];
+ bss->has_erp_value = 1;
+ ieee80211_rx_bss_put(dev, bss);
+ }
+ }
+
printk(KERN_DEBUG "%s: associated\n", dev->name);
ifsta->aid = aid;
ifsta->ap_capab = capab_info;
@@ -1496,6 +1541,12 @@
return;
}
+ /* save the ERP value so that it is available at association time */
+ if (elems.erp_info && elems.erp_info_len >= 1) {
+ bss->erp_value = elems.erp_info[0];
+ bss->has_erp_value = 1;
+ }
+
bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) {
@@ -1611,10 +1662,8 @@
size_t len,
struct ieee80211_rx_status *rx_status)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_sta *ifsta;
- int use_protection;
size_t baselen;
struct ieee802_11_elems elems;
@@ -1638,23 +1687,8 @@
&elems) == ParseFailed)
return;
- use_protection = 0;
- if (elems.erp_info && elems.erp_info_len >= 1) {
- use_protection =
- (elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0;
- }
-
- if (use_protection != !!ifsta->use_protection) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
- MAC_FMT ")\n",
- dev->name,
- use_protection ? "enabled" : "disabled",
- MAC_ARG(ifsta->bssid));
- }
- ifsta->use_protection = use_protection ? 1 : 0;
- local->cts_protect_erp_frames = use_protection;
- }
+ if (elems.erp_info && elems.erp_info_len >= 1)
+ ieee80211_handle_erp_ie(dev, elems.erp_info[0]);
if (elems.wmm_param && ifsta->wmm_enabled) {
ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c
index 5ae7fc4..f6780d6 100644
--- a/net/mac80211/rc80211_simple.c
+++ b/net/mac80211/rc80211_simple.c
@@ -187,9 +187,13 @@
}
#endif
- if (per_failed > local->rate_ctrl_num_down) {
+ /*
+ * XXX: Make these configurable once we have an
+ * interface to the rate control algorithms
+ */
+ if (per_failed > RATE_CONTROL_NUM_DOWN) {
rate_control_rate_dec(local, sta);
- } else if (per_failed < local->rate_ctrl_num_up) {
+ } else if (per_failed < RATE_CONTROL_NUM_UP) {
rate_control_rate_inc(local, sta);
}
srctrl->tx_avg_rate_sum += status->control.rate->rate;
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index df5e8da..3ac39f1 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -102,6 +102,16 @@
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+config NF_CT_PROTO_UDPLITE
+ tristate 'UDP-Lite protocol connection tracking support (EXPERIMENTAL)'
+ depends on EXPERIMENTAL && NF_CONNTRACK
+ help
+ With this option enabled, the layer 3 independent connection
+ tracking code will be able to do state tracking on UDP-Lite
+ connections.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NF_CONNTRACK_AMANDA
tristate "Amanda backup protocol support"
depends on NF_CONNTRACK
@@ -423,6 +433,13 @@
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+config NETFILTER_XT_MATCH_CONNLIMIT
+ tristate '"connlimit" match support"'
+ depends on NETFILTER_XTABLES
+ ---help---
+ This match allows you to match against the number of parallel
+ connections to a server per client IP address (or address block).
+
config NETFILTER_XT_MATCH_CONNMARK
tristate '"connmark" connection mark match support'
depends on NETFILTER_XTABLES
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 58b4245..0c054bf 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -16,6 +16,7 @@
# SCTP protocol connection tracking
obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o
+obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o
# netlink interface for nf_conntrack
obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
@@ -52,6 +53,7 @@
# matches
obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 3d14110..8cce814 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -113,6 +113,36 @@
}
EXPORT_SYMBOL_GPL(nf_ct_get_tuple);
+int nf_ct_get_tuplepr(const struct sk_buff *skb,
+ unsigned int nhoff,
+ u_int16_t l3num,
+ struct nf_conntrack_tuple *tuple)
+{
+ struct nf_conntrack_l3proto *l3proto;
+ struct nf_conntrack_l4proto *l4proto;
+ unsigned int protoff;
+ u_int8_t protonum;
+ int ret;
+
+ rcu_read_lock();
+
+ l3proto = __nf_ct_l3proto_find(l3num);
+ ret = l3proto->get_l4proto(skb, nhoff, &protoff, &protonum);
+ if (ret != NF_ACCEPT) {
+ rcu_read_unlock();
+ return 0;
+ }
+
+ l4proto = __nf_ct_l4proto_find(l3num, protonum);
+
+ ret = nf_ct_get_tuple(skb, nhoff, protoff, l3num, protonum, tuple,
+ l3proto, l4proto);
+
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(nf_ct_get_tuplepr);
+
int
nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
const struct nf_conntrack_tuple *orig,
@@ -622,9 +652,12 @@
/* rcu_read_lock()ed by nf_hook_slow */
l3proto = __nf_ct_l3proto_find((u_int16_t)pf);
-
- if ((ret = l3proto->prepare(pskb, hooknum, &dataoff, &protonum)) <= 0) {
+ ret = l3proto->get_l4proto(*pskb, skb_network_offset(*pskb),
+ &dataoff, &protonum);
+ if (ret <= 0) {
pr_debug("not prepared to track yet or error occured\n");
+ NF_CT_STAT_INC_ATOMIC(error);
+ NF_CT_STAT_INC_ATOMIC(invalid);
return -ret;
}
diff --git a/net/netfilter/nf_conntrack_l3proto_generic.c b/net/netfilter/nf_conntrack_l3proto_generic.c
index b1bfa20..991c52c 100644
--- a/net/netfilter/nf_conntrack_l3proto_generic.c
+++ b/net/netfilter/nf_conntrack_l3proto_generic.c
@@ -61,22 +61,21 @@
return 0;
}
-static int
-generic_prepare(struct sk_buff **pskb, unsigned int hooknum,
- unsigned int *dataoff, u_int8_t *protonum)
+static int generic_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
+ unsigned int *dataoff, u_int8_t *protonum)
{
/* Never track !!! */
return -NF_ACCEPT;
}
-struct nf_conntrack_l3proto nf_conntrack_l3proto_generic = {
+struct nf_conntrack_l3proto nf_conntrack_l3proto_generic __read_mostly = {
.l3proto = PF_UNSPEC,
.name = "unknown",
.pkt_to_tuple = generic_pkt_to_tuple,
.invert_tuple = generic_invert_tuple,
.print_tuple = generic_print_tuple,
.print_conntrack = generic_print_conntrack,
- .prepare = generic_prepare,
+ .get_l4proto = generic_get_l4proto,
};
EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_generic);
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index 6faf1be..d8b5018 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -98,7 +98,7 @@
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */
-struct nf_conntrack_l4proto nf_conntrack_l4proto_generic =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
{
.l3proto = PF_UNSPEC,
.l4proto = 0,
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index 771c4c2..bdbead8 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -261,7 +261,7 @@
}
/* protocol helper struct */
-static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 = {
+static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
.l3proto = AF_INET,
.l4proto = IPPROTO_GRE,
.name = "gre",
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index debfe61..04192ac 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -601,7 +601,7 @@
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif
-struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 = {
+static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
.l3proto = PF_INET,
.l4proto = IPPROTO_SCTP,
.name = "sctp",
@@ -622,7 +622,7 @@
#endif
};
-struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 = {
+static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
.l3proto = PF_INET6,
.l4proto = IPPROTO_SCTP,
.name = "sctp",
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 1c8206e..87ad3cc 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -1372,7 +1372,7 @@
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */
-struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
{
.l3proto = PF_INET,
.l4proto = IPPROTO_TCP,
@@ -1401,7 +1401,7 @@
};
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4);
-struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
{
.l3proto = PF_INET6,
.l4proto = IPPROTO_TCP,
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 3620ecc..13d94a0 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -191,7 +191,7 @@
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */
-struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
{
.l3proto = PF_INET,
.l4proto = IPPROTO_UDP,
@@ -218,7 +218,7 @@
};
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4);
-struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
{
.l3proto = PF_INET6,
.l4proto = IPPROTO_UDP,
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c
new file mode 100644
index 0000000..93e747b
--- /dev/null
+++ b/net/netfilter/nf_conntrack_proto_udplite.c
@@ -0,0 +1,266 @@
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2007 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/udp.h>
+#include <linux/seq_file.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <net/netfilter/nf_conntrack_l4proto.h>
+#include <net/netfilter/nf_conntrack_ecache.h>
+
+static unsigned int nf_ct_udplite_timeout __read_mostly = 30*HZ;
+static unsigned int nf_ct_udplite_timeout_stream __read_mostly = 180*HZ;
+
+static int udplite_pkt_to_tuple(const struct sk_buff *skb,
+ unsigned int dataoff,
+ struct nf_conntrack_tuple *tuple)
+{
+ struct udphdr _hdr, *hp;
+
+ hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+ if (hp == NULL)
+ return 0;
+
+ tuple->src.u.udp.port = hp->source;
+ tuple->dst.u.udp.port = hp->dest;
+ return 1;
+}
+
+static int udplite_invert_tuple(struct nf_conntrack_tuple *tuple,
+ const struct nf_conntrack_tuple *orig)
+{
+ tuple->src.u.udp.port = orig->dst.u.udp.port;
+ tuple->dst.u.udp.port = orig->src.u.udp.port;
+ return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static int udplite_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
+{
+ return seq_printf(s, "sport=%hu dport=%hu ",
+ ntohs(tuple->src.u.udp.port),
+ ntohs(tuple->dst.u.udp.port));
+}
+
+/* Print out the private part of the conntrack. */
+static int udplite_print_conntrack(struct seq_file *s,
+ const struct nf_conn *conntrack)
+{
+ return 0;
+}
+
+/* Returns verdict for packet, and may modify conntracktype */
+static int udplite_packet(struct nf_conn *conntrack,
+ const struct sk_buff *skb,
+ unsigned int dataoff,
+ enum ip_conntrack_info ctinfo,
+ int pf,
+ unsigned int hooknum)
+{
+ /* If we've seen traffic both ways, this is some kind of UDP
+ stream. Extend timeout. */
+ if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
+ nf_ct_refresh_acct(conntrack, ctinfo, skb,
+ nf_ct_udplite_timeout_stream);
+ /* Also, more likely to be important, and not a probe */
+ if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status))
+ nf_conntrack_event_cache(IPCT_STATUS, skb);
+ } else
+ nf_ct_refresh_acct(conntrack, ctinfo, skb,
+ nf_ct_udplite_timeout);
+
+ return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int udplite_new(struct nf_conn *conntrack, const struct sk_buff *skb,
+ unsigned int dataoff)
+{
+ return 1;
+}
+
+static int udplite_error(struct sk_buff *skb, unsigned int dataoff,
+ enum ip_conntrack_info *ctinfo,
+ int pf,
+ unsigned int hooknum)
+{
+ unsigned int udplen = skb->len - dataoff;
+ struct udphdr _hdr, *hdr;
+ unsigned int cscov;
+
+ /* Header is too small? */
+ hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+ if (hdr == NULL) {
+ if (LOG_INVALID(IPPROTO_UDPLITE))
+ nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ "nf_ct_udplite: short packet ");
+ return -NF_ACCEPT;
+ }
+
+ cscov = ntohs(hdr->len);
+ if (cscov == 0)
+ cscov = udplen;
+ else if (cscov < sizeof(*hdr) || cscov > udplen) {
+ if (LOG_INVALID(IPPROTO_UDPLITE))
+ nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ "nf_ct_udplite: invalid checksum coverage ");
+ return -NF_ACCEPT;
+ }
+
+ /* UDPLITE mandates checksums */
+ if (!hdr->check) {
+ if (LOG_INVALID(IPPROTO_UDPLITE))
+ nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ "nf_ct_udplite: checksum missing ");
+ return -NF_ACCEPT;
+ }
+
+ /* Checksum invalid? Ignore. */
+ if (nf_conntrack_checksum && !skb_csum_unnecessary(skb) &&
+ ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
+ (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING))) {
+ if (pf == PF_INET) {
+ struct iphdr *iph = ip_hdr(skb);
+
+ skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
+ udplen, IPPROTO_UDPLITE, 0);
+ } else {
+ struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+ __wsum hsum = skb_checksum(skb, 0, dataoff, 0);
+
+ skb->csum = ~csum_unfold(
+ csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
+ udplen, IPPROTO_UDPLITE,
+ csum_sub(0, hsum)));
+ }
+
+ skb->ip_summed = CHECKSUM_NONE;
+ if (__skb_checksum_complete_head(skb, dataoff + cscov)) {
+ if (LOG_INVALID(IPPROTO_UDPLITE))
+ nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ "nf_ct_udplite: bad UDPLite "
+ "checksum ");
+ return -NF_ACCEPT;
+ }
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+
+ return NF_ACCEPT;
+}
+
+#ifdef CONFIG_SYSCTL
+static unsigned int udplite_sysctl_table_users;
+static struct ctl_table_header *udplite_sysctl_header;
+static struct ctl_table udplite_sysctl_table[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "nf_conntrack_udplite_timeout",
+ .data = &nf_ct_udplite_timeout,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "nf_conntrack_udplite_timeout_stream",
+ .data = &nf_ct_udplite_timeout_stream,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ },
+ {
+ .ctl_name = 0
+ }
+};
+#endif /* CONFIG_SYSCTL */
+
+static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
+{
+ .l3proto = PF_INET,
+ .l4proto = IPPROTO_UDPLITE,
+ .name = "udplite",
+ .pkt_to_tuple = udplite_pkt_to_tuple,
+ .invert_tuple = udplite_invert_tuple,
+ .print_tuple = udplite_print_tuple,
+ .print_conntrack = udplite_print_conntrack,
+ .packet = udplite_packet,
+ .new = udplite_new,
+ .error = udplite_error,
+#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+ .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
+ .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
+#endif
+#ifdef CONFIG_SYSCTL
+ .ctl_table_users = &udplite_sysctl_table_users,
+ .ctl_table_header = &udplite_sysctl_header,
+ .ctl_table = udplite_sysctl_table,
+#endif
+};
+
+static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
+{
+ .l3proto = PF_INET6,
+ .l4proto = IPPROTO_UDPLITE,
+ .name = "udplite",
+ .pkt_to_tuple = udplite_pkt_to_tuple,
+ .invert_tuple = udplite_invert_tuple,
+ .print_tuple = udplite_print_tuple,
+ .print_conntrack = udplite_print_conntrack,
+ .packet = udplite_packet,
+ .new = udplite_new,
+ .error = udplite_error,
+#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+ .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
+ .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
+#endif
+#ifdef CONFIG_SYSCTL
+ .ctl_table_users = &udplite_sysctl_table_users,
+ .ctl_table_header = &udplite_sysctl_header,
+ .ctl_table = udplite_sysctl_table,
+#endif
+};
+
+static int __init nf_conntrack_proto_udplite_init(void)
+{
+ int err;
+
+ err = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udplite4);
+ if (err < 0)
+ goto err1;
+ err = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udplite6);
+ if (err < 0)
+ goto err2;
+ return 0;
+err2:
+ nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
+err1:
+ return err;
+}
+
+static void __exit nf_conntrack_proto_udplite_exit(void)
+{
+ nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite6);
+ nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
+}
+
+module_init(nf_conntrack_proto_udplite_init);
+module_exit(nf_conntrack_proto_udplite_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c
new file mode 100644
index 0000000..3335dd5
--- /dev/null
+++ b/net/netfilter/xt_connlimit.c
@@ -0,0 +1,313 @@
+/*
+ * netfilter module to limit the number of parallel tcp
+ * connections per IP address.
+ * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
+ * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
+ * only ignore TIME_WAIT or gone connections
+ * Copyright © Jan Engelhardt <jengelh@gmx.de>, 2007
+ *
+ * based on ...
+ *
+ * Kernel module to match connection tracking information.
+ * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
+ */
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/jhash.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/netfilter/nf_conntrack_tcp.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_connlimit.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_tuple.h>
+
+/* we will save the tuples of all connections we care about */
+struct xt_connlimit_conn {
+ struct list_head list;
+ struct nf_conntrack_tuple tuple;
+};
+
+struct xt_connlimit_data {
+ struct list_head iphash[256];
+ spinlock_t lock;
+};
+
+static u_int32_t connlimit_rnd;
+static bool connlimit_rnd_inited;
+
+static inline unsigned int connlimit_iphash(u_int32_t addr)
+{
+ if (unlikely(!connlimit_rnd_inited)) {
+ get_random_bytes(&connlimit_rnd, sizeof(connlimit_rnd));
+ connlimit_rnd_inited = true;
+ }
+ return jhash_1word(addr, connlimit_rnd) & 0xFF;
+}
+
+static inline unsigned int
+connlimit_iphash6(const union nf_conntrack_address *addr,
+ const union nf_conntrack_address *mask)
+{
+ union nf_conntrack_address res;
+ unsigned int i;
+
+ if (unlikely(!connlimit_rnd_inited)) {
+ get_random_bytes(&connlimit_rnd, sizeof(connlimit_rnd));
+ connlimit_rnd_inited = true;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(addr->ip6); ++i)
+ res.ip6[i] = addr->ip6[i] & mask->ip6[i];
+
+ return jhash2(res.ip6, ARRAY_SIZE(res.ip6), connlimit_rnd) & 0xFF;
+}
+
+static inline bool already_closed(const struct nf_conn *conn)
+{
+ u_int16_t proto = conn->tuplehash[0].tuple.dst.protonum;
+
+ if (proto == IPPROTO_TCP)
+ return conn->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT;
+ else
+ return 0;
+}
+
+static inline unsigned int
+same_source_net(const union nf_conntrack_address *addr,
+ const union nf_conntrack_address *mask,
+ const union nf_conntrack_address *u3, unsigned int family)
+{
+ if (family == AF_INET) {
+ return (addr->ip & mask->ip) == (u3->ip & mask->ip);
+ } else {
+ union nf_conntrack_address lh, rh;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(addr->ip6); ++i) {
+ lh.ip6[i] = addr->ip6[i] & mask->ip6[i];
+ rh.ip6[i] = u3->ip6[i] & mask->ip6[i];
+ }
+
+ return memcmp(&lh.ip6, &rh.ip6, sizeof(lh.ip6)) == 0;
+ }
+}
+
+static int count_them(struct xt_connlimit_data *data,
+ const struct nf_conntrack_tuple *tuple,
+ const union nf_conntrack_address *addr,
+ const union nf_conntrack_address *mask,
+ const struct xt_match *match)
+{
+ struct nf_conntrack_tuple_hash *found;
+ struct xt_connlimit_conn *conn;
+ struct xt_connlimit_conn *tmp;
+ struct nf_conn *found_ct;
+ struct list_head *hash;
+ bool addit = true;
+ int matches = 0;
+
+
+ if (match->family == AF_INET6)
+ hash = &data->iphash[connlimit_iphash6(addr, mask)];
+ else
+ hash = &data->iphash[connlimit_iphash(addr->ip & mask->ip)];
+
+ read_lock_bh(&nf_conntrack_lock);
+
+ /* check the saved connections */
+ list_for_each_entry_safe(conn, tmp, hash, list) {
+ found = __nf_conntrack_find(&conn->tuple, NULL);
+ found_ct = NULL;
+
+ if (found != NULL)
+ found_ct = nf_ct_tuplehash_to_ctrack(found);
+
+ if (found_ct != NULL &&
+ nf_ct_tuple_equal(&conn->tuple, tuple) &&
+ !already_closed(found_ct))
+ /*
+ * Just to be sure we have it only once in the list.
+ * We should not see tuples twice unless someone hooks
+ * this into a table without "-p tcp --syn".
+ */
+ addit = false;
+
+ if (found == NULL) {
+ /* this one is gone */
+ list_del(&conn->list);
+ kfree(conn);
+ continue;
+ }
+
+ if (already_closed(found_ct)) {
+ /*
+ * we do not care about connections which are
+ * closed already -> ditch it
+ */
+ list_del(&conn->list);
+ kfree(conn);
+ continue;
+ }
+
+ if (same_source_net(addr, mask, &conn->tuple.src.u3,
+ match->family))
+ /* same source network -> be counted! */
+ ++matches;
+ }
+
+ read_unlock_bh(&nf_conntrack_lock);
+
+ if (addit) {
+ /* save the new connection in our list */
+ conn = kzalloc(sizeof(*conn), GFP_ATOMIC);
+ if (conn == NULL)
+ return -ENOMEM;
+ conn->tuple = *tuple;
+ list_add(&conn->list, hash);
+ ++matches;
+ }
+
+ return matches;
+}
+
+static bool connlimit_match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo, int offset,
+ unsigned int protoff, bool *hotdrop)
+{
+ const struct xt_connlimit_info *info = matchinfo;
+ union nf_conntrack_address addr, mask;
+ struct nf_conntrack_tuple tuple;
+ const struct nf_conntrack_tuple *tuple_ptr = &tuple;
+ enum ip_conntrack_info ctinfo;
+ const struct nf_conn *ct;
+ int connections;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ if (ct != NULL)
+ tuple_ptr = &ct->tuplehash[0].tuple;
+ else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb),
+ match->family, &tuple))
+ goto hotdrop;
+
+ if (match->family == AF_INET6) {
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
+ memcpy(&addr.ip6, &iph->saddr, sizeof(iph->saddr));
+ memcpy(&mask.ip6, info->v6_mask, sizeof(info->v6_mask));
+ } else {
+ const struct iphdr *iph = ip_hdr(skb);
+ addr.ip = iph->saddr;
+ mask.ip = info->v4_mask;
+ }
+
+ spin_lock_bh(&info->data->lock);
+ connections = count_them(info->data, tuple_ptr, &addr, &mask, match);
+ spin_unlock_bh(&info->data->lock);
+
+ if (connections < 0) {
+ /* kmalloc failed, drop it entirely */
+ *hotdrop = true;
+ return false;
+ }
+
+ return (connections > info->limit) ^ info->inverse;
+
+ hotdrop:
+ *hotdrop = true;
+ return false;
+}
+
+static bool connlimit_check(const char *tablename, const void *ip,
+ const struct xt_match *match, void *matchinfo,
+ unsigned int hook_mask)
+{
+ struct xt_connlimit_info *info = matchinfo;
+ unsigned int i;
+
+ if (nf_ct_l3proto_try_module_get(match->family) < 0) {
+ printk(KERN_WARNING "cannot load conntrack support for "
+ "address family %u\n", match->family);
+ return false;
+ }
+
+ /* init private data */
+ info->data = kmalloc(sizeof(struct xt_connlimit_data), GFP_KERNEL);
+ if (info->data == NULL) {
+ nf_ct_l3proto_module_put(match->family);
+ return false;
+ }
+
+ spin_lock_init(&info->data->lock);
+ for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i)
+ INIT_LIST_HEAD(&info->data->iphash[i]);
+
+ return true;
+}
+
+static void connlimit_destroy(const struct xt_match *match, void *matchinfo)
+{
+ struct xt_connlimit_info *info = matchinfo;
+ struct xt_connlimit_conn *conn;
+ struct xt_connlimit_conn *tmp;
+ struct list_head *hash = info->data->iphash;
+ unsigned int i;
+
+ nf_ct_l3proto_module_put(match->family);
+
+ for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i) {
+ list_for_each_entry_safe(conn, tmp, &hash[i], list) {
+ list_del(&conn->list);
+ kfree(conn);
+ }
+ }
+
+ kfree(info->data);
+}
+
+static struct xt_match connlimit_reg[] __read_mostly = {
+ {
+ .name = "connlimit",
+ .family = AF_INET,
+ .checkentry = connlimit_check,
+ .match = connlimit_match,
+ .matchsize = sizeof(struct xt_connlimit_info),
+ .destroy = connlimit_destroy,
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "connlimit",
+ .family = AF_INET6,
+ .checkentry = connlimit_check,
+ .match = connlimit_match,
+ .matchsize = sizeof(struct xt_connlimit_info),
+ .destroy = connlimit_destroy,
+ .me = THIS_MODULE,
+ },
+};
+
+static int __init xt_connlimit_init(void)
+{
+ return xt_register_matches(connlimit_reg, ARRAY_SIZE(connlimit_reg));
+}
+
+static void __exit xt_connlimit_exit(void)
+{
+ xt_unregister_matches(connlimit_reg, ARRAY_SIZE(connlimit_reg));
+}
+
+module_init(xt_connlimit_init);
+module_exit(xt_connlimit_exit);
+MODULE_AUTHOR("Jan Engelhardt <jengelh@gmx.de>");
+MODULE_DESCRIPTION("netfilter xt_connlimit match module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_connlimit");
+MODULE_ALIAS("ip6t_connlimit");
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index e5c840c..230e35c 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -55,7 +55,7 @@
static void rfkill_schedule_toggle(struct rfkill_task *task)
{
- unsigned int flags;
+ unsigned long flags;
spin_lock_irqsave(&task->lock, flags);
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index b466288..d3f7c3f 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -472,12 +472,12 @@
config NET_CLS_POLICE
bool "Traffic Policing (obsolete)"
- depends on NET_CLS_ACT!=y
+ select NET_CLS_ACT
+ select NET_ACT_POLICE
---help---
Say Y here if you want to do traffic policing, i.e. strict
- bandwidth limiting. This option is obsoleted by the traffic
- policer implemented as action, it stays here for compatibility
- reasons.
+ bandwidth limiting. This option is obsolete and just selects
+ the option replacing it. It will be removed in the future.
config NET_CLS_IND
bool "Incoming device classification"
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 020767a..b67c36f 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -8,7 +8,6 @@
obj-$(CONFIG_NET_CLS) += cls_api.o
obj-$(CONFIG_NET_CLS_ACT) += act_api.o
obj-$(CONFIG_NET_ACT_POLICE) += act_police.o
-obj-$(CONFIG_NET_CLS_POLICE) += act_police.o
obj-$(CONFIG_NET_ACT_GACT) += act_gact.o
obj-$(CONFIG_NET_ACT_MIRRED) += act_mirred.o
obj-$(CONFIG_NET_ACT_IPT) += act_ipt.o
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index d204038..bf90e60f 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -50,7 +50,6 @@
/* Each policer is serialized by its individual spinlock */
-#ifdef CONFIG_NET_CLS_ACT
static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb,
int type, struct tc_action *a)
{
@@ -96,9 +95,8 @@
nlmsg_trim(skb, r);
goto done;
}
-#endif
-void tcf_police_destroy(struct tcf_police *p)
+static void tcf_police_destroy(struct tcf_police *p)
{
unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK);
struct tcf_common **p1p;
@@ -121,7 +119,6 @@
BUG_TRAP(0);
}
-#ifdef CONFIG_NET_CLS_ACT
static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,
struct tc_action *a, int ovr, int bind)
{
@@ -247,10 +244,19 @@
static int tcf_act_police_cleanup(struct tc_action *a, int bind)
{
struct tcf_police *p = a->priv;
+ int ret = 0;
- if (p != NULL)
- return tcf_police_release(p, bind);
- return 0;
+ if (p != NULL) {
+ if (bind)
+ p->tcf_bindcnt--;
+
+ p->tcf_refcnt--;
+ if (p->tcf_refcnt <= 0 && !p->tcf_bindcnt) {
+ tcf_police_destroy(p);
+ ret = 1;
+ }
+ }
+ return ret;
}
static int tcf_act_police(struct sk_buff *skb, struct tc_action *a,
@@ -372,229 +378,3 @@
module_init(police_init_module);
module_exit(police_cleanup_module);
-
-#else /* CONFIG_NET_CLS_ACT */
-
-static struct tcf_common *tcf_police_lookup(u32 index)
-{
- struct tcf_hashinfo *hinfo = &police_hash_info;
- struct tcf_common *p;
-
- read_lock(hinfo->lock);
- for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p;
- p = p->tcfc_next) {
- if (p->tcfc_index == index)
- break;
- }
- read_unlock(hinfo->lock);
-
- return p;
-}
-
-static u32 tcf_police_new_index(void)
-{
- u32 *idx_gen = &police_idx_gen;
- u32 val = *idx_gen;
-
- do {
- if (++val == 0)
- val = 1;
- } while (tcf_police_lookup(val));
-
- return (*idx_gen = val);
-}
-
-struct tcf_police *tcf_police_locate(struct rtattr *rta, struct rtattr *est)
-{
- unsigned int h;
- struct tcf_police *police;
- struct rtattr *tb[TCA_POLICE_MAX];
- struct tc_police *parm;
- int size;
-
- if (rtattr_parse_nested(tb, TCA_POLICE_MAX, rta) < 0)
- return NULL;
-
- if (tb[TCA_POLICE_TBF-1] == NULL)
- return NULL;
- size = RTA_PAYLOAD(tb[TCA_POLICE_TBF-1]);
- if (size != sizeof(*parm) && size != sizeof(struct tc_police_compat))
- return NULL;
-
- parm = RTA_DATA(tb[TCA_POLICE_TBF-1]);
-
- if (parm->index) {
- struct tcf_common *pc;
-
- pc = tcf_police_lookup(parm->index);
- if (pc) {
- police = to_police(pc);
- police->tcf_refcnt++;
- return police;
- }
- }
- police = kzalloc(sizeof(*police), GFP_KERNEL);
- if (unlikely(!police))
- return NULL;
-
- police->tcf_refcnt = 1;
- spin_lock_init(&police->tcf_lock);
- if (parm->rate.rate) {
- police->tcfp_R_tab =
- qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]);
- if (police->tcfp_R_tab == NULL)
- goto failure;
- if (parm->peakrate.rate) {
- police->tcfp_P_tab =
- qdisc_get_rtab(&parm->peakrate,
- tb[TCA_POLICE_PEAKRATE-1]);
- if (police->tcfp_P_tab == NULL)
- goto failure;
- }
- }
- if (tb[TCA_POLICE_RESULT-1]) {
- if (RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
- goto failure;
- police->tcfp_result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]);
- }
- if (tb[TCA_POLICE_AVRATE-1]) {
- if (RTA_PAYLOAD(tb[TCA_POLICE_AVRATE-1]) != sizeof(u32))
- goto failure;
- police->tcfp_ewma_rate =
- *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
- }
- police->tcfp_toks = police->tcfp_burst = parm->burst;
- police->tcfp_mtu = parm->mtu;
- if (police->tcfp_mtu == 0) {
- police->tcfp_mtu = ~0;
- if (police->tcfp_R_tab)
- police->tcfp_mtu = 255<<police->tcfp_R_tab->rate.cell_log;
- }
- if (police->tcfp_P_tab)
- police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu);
- police->tcfp_t_c = psched_get_time();
- police->tcf_index = parm->index ? parm->index :
- tcf_police_new_index();
- police->tcf_action = parm->action;
- if (est)
- gen_new_estimator(&police->tcf_bstats, &police->tcf_rate_est,
- &police->tcf_lock, est);
- h = tcf_hash(police->tcf_index, POL_TAB_MASK);
- write_lock_bh(&police_lock);
- police->tcf_next = tcf_police_ht[h];
- tcf_police_ht[h] = &police->common;
- write_unlock_bh(&police_lock);
- return police;
-
-failure:
- if (police->tcfp_R_tab)
- qdisc_put_rtab(police->tcfp_R_tab);
- kfree(police);
- return NULL;
-}
-
-int tcf_police(struct sk_buff *skb, struct tcf_police *police)
-{
- psched_time_t now;
- long toks;
- long ptoks = 0;
-
- spin_lock(&police->tcf_lock);
-
- police->tcf_bstats.bytes += skb->len;
- police->tcf_bstats.packets++;
-
- if (police->tcfp_ewma_rate &&
- police->tcf_rate_est.bps >= police->tcfp_ewma_rate) {
- police->tcf_qstats.overlimits++;
- spin_unlock(&police->tcf_lock);
- return police->tcf_action;
- }
- if (skb->len <= police->tcfp_mtu) {
- if (police->tcfp_R_tab == NULL) {
- spin_unlock(&police->tcf_lock);
- return police->tcfp_result;
- }
-
- now = psched_get_time();
- toks = psched_tdiff_bounded(now, police->tcfp_t_c,
- police->tcfp_burst);
- if (police->tcfp_P_tab) {
- ptoks = toks + police->tcfp_ptoks;
- if (ptoks > (long)L2T_P(police, police->tcfp_mtu))
- ptoks = (long)L2T_P(police, police->tcfp_mtu);
- ptoks -= L2T_P(police, skb->len);
- }
- toks += police->tcfp_toks;
- if (toks > (long)police->tcfp_burst)
- toks = police->tcfp_burst;
- toks -= L2T(police, skb->len);
- if ((toks|ptoks) >= 0) {
- police->tcfp_t_c = now;
- police->tcfp_toks = toks;
- police->tcfp_ptoks = ptoks;
- spin_unlock(&police->tcf_lock);
- return police->tcfp_result;
- }
- }
-
- police->tcf_qstats.overlimits++;
- spin_unlock(&police->tcf_lock);
- return police->tcf_action;
-}
-EXPORT_SYMBOL(tcf_police);
-
-int tcf_police_dump(struct sk_buff *skb, struct tcf_police *police)
-{
- unsigned char *b = skb_tail_pointer(skb);
- struct tc_police opt;
-
- opt.index = police->tcf_index;
- opt.action = police->tcf_action;
- opt.mtu = police->tcfp_mtu;
- opt.burst = police->tcfp_burst;
- if (police->tcfp_R_tab)
- opt.rate = police->tcfp_R_tab->rate;
- else
- memset(&opt.rate, 0, sizeof(opt.rate));
- if (police->tcfp_P_tab)
- opt.peakrate = police->tcfp_P_tab->rate;
- else
- memset(&opt.peakrate, 0, sizeof(opt.peakrate));
- RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt);
- if (police->tcfp_result)
- RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int),
- &police->tcfp_result);
- if (police->tcfp_ewma_rate)
- RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &police->tcfp_ewma_rate);
- return skb->len;
-
-rtattr_failure:
- nlmsg_trim(skb, b);
- return -1;
-}
-
-int tcf_police_dump_stats(struct sk_buff *skb, struct tcf_police *police)
-{
- struct gnet_dump d;
-
- if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
- TCA_XSTATS, &police->tcf_lock,
- &d) < 0)
- goto errout;
-
- if (gnet_stats_copy_basic(&d, &police->tcf_bstats) < 0 ||
- gnet_stats_copy_rate_est(&d, &police->tcf_rate_est) < 0 ||
- gnet_stats_copy_queue(&d, &police->tcf_qstats) < 0)
- goto errout;
-
- if (gnet_stats_finish_copy(&d) < 0)
- goto errout;
-
- return 0;
-
-errout:
- return -1;
-}
-
-#endif /* CONFIG_NET_CLS_ACT */
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 36b72aa..5f0fbca 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -458,11 +458,6 @@
tcf_action_destroy(exts->action, TCA_ACT_UNBIND);
exts->action = NULL;
}
-#elif defined CONFIG_NET_CLS_POLICE
- if (exts->police) {
- tcf_police_release(exts->police, TCA_ACT_UNBIND);
- exts->police = NULL;
- }
#endif
}
@@ -496,17 +491,6 @@
exts->action = act;
}
}
-#elif defined CONFIG_NET_CLS_POLICE
- if (map->police && tb[map->police-1]) {
- struct tcf_police *p;
-
- p = tcf_police_locate(tb[map->police-1], rate_tlv);
- if (p == NULL)
- return -EINVAL;
-
- exts->police = p;
- } else if (map->action && tb[map->action-1])
- return -EOPNOTSUPP;
#else
if ((map->action && tb[map->action-1]) ||
(map->police && tb[map->police-1]))
@@ -529,15 +513,6 @@
if (act)
tcf_action_destroy(act, TCA_ACT_UNBIND);
}
-#elif defined CONFIG_NET_CLS_POLICE
- if (src->police) {
- struct tcf_police *p;
- tcf_tree_lock(tp);
- p = xchg(&dst->police, src->police);
- tcf_tree_unlock(tp);
- if (p)
- tcf_police_release(p, TCA_ACT_UNBIND);
- }
#endif
}
@@ -566,17 +541,6 @@
p_rta->rta_len = skb_tail_pointer(skb) - (u8 *)p_rta;
}
}
-#elif defined CONFIG_NET_CLS_POLICE
- if (map->police && exts->police) {
- struct rtattr *p_rta = (struct rtattr *)skb_tail_pointer(skb);
-
- RTA_PUT(skb, map->police, 0, NULL);
-
- if (tcf_police_dump(skb, exts->police) < 0)
- goto rtattr_failure;
-
- p_rta->rta_len = skb_tail_pointer(skb) - (u8 *)p_rta;
- }
#endif
return 0;
rtattr_failure: __attribute__ ((unused))
@@ -591,10 +555,6 @@
if (exts->action)
if (tcf_action_copy_stats(skb, exts->action, 1) < 0)
goto rtattr_failure;
-#elif defined CONFIG_NET_CLS_POLICE
- if (exts->police)
- if (tcf_police_dump_stats(skb, exts->police) < 0)
- goto rtattr_failure;
#endif
return 0;
rtattr_failure: __attribute__ ((unused))
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 77961e2..8dbe369 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -782,9 +782,6 @@
#ifdef CONFIG_CLS_U32_PERF
printk(" Performance counters on\n");
#endif
-#ifdef CONFIG_NET_CLS_POLICE
- printk(" OLD policer on \n");
-#endif
#ifdef CONFIG_NET_CLS_IND
printk(" input device check on \n");
#endif
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index d92ea26..13c09bc 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -278,11 +278,7 @@
wd->qdisc->flags &= ~TCQ_F_THROTTLED;
smp_wmb();
- if (spin_trylock(&dev->queue_lock)) {
- qdisc_run(dev);
- spin_unlock(&dev->queue_lock);
- } else
- netif_schedule(dev);
+ netif_schedule(dev);
return HRTIMER_NORESTART;
}
@@ -1149,47 +1145,57 @@
to this qdisc, (optionally) tests for protocol and asks
specific classifiers.
*/
+int tc_classify_compat(struct sk_buff *skb, struct tcf_proto *tp,
+ struct tcf_result *res)
+{
+ __be16 protocol = skb->protocol;
+ int err = 0;
+
+ for (; tp; tp = tp->next) {
+ if ((tp->protocol == protocol ||
+ tp->protocol == htons(ETH_P_ALL)) &&
+ (err = tp->classify(skb, tp, res)) >= 0) {
+#ifdef CONFIG_NET_CLS_ACT
+ if (err != TC_ACT_RECLASSIFY && skb->tc_verd)
+ skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0);
+#endif
+ return err;
+ }
+ }
+ return -1;
+}
+EXPORT_SYMBOL(tc_classify_compat);
+
int tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
- struct tcf_result *res)
+ struct tcf_result *res)
{
int err = 0;
- __be16 protocol = skb->protocol;
+ __be16 protocol;
#ifdef CONFIG_NET_CLS_ACT
struct tcf_proto *otp = tp;
reclassify:
#endif
protocol = skb->protocol;
- for ( ; tp; tp = tp->next) {
- if ((tp->protocol == protocol ||
- tp->protocol == htons(ETH_P_ALL)) &&
- (err = tp->classify(skb, tp, res)) >= 0) {
+ err = tc_classify_compat(skb, tp, res);
#ifdef CONFIG_NET_CLS_ACT
- if ( TC_ACT_RECLASSIFY == err) {
- __u32 verd = (__u32) G_TC_VERD(skb->tc_verd);
- tp = otp;
+ if (err == TC_ACT_RECLASSIFY) {
+ u32 verd = G_TC_VERD(skb->tc_verd);
+ tp = otp;
- if (MAX_REC_LOOP < verd++) {
- printk("rule prio %d protocol %02x reclassify is buggy packet dropped\n",
- tp->prio&0xffff, ntohs(tp->protocol));
- return TC_ACT_SHOT;
- }
- skb->tc_verd = SET_TC_VERD(skb->tc_verd,verd);
- goto reclassify;
- } else {
- if (skb->tc_verd)
- skb->tc_verd = SET_TC_VERD(skb->tc_verd,0);
- return err;
- }
-#else
-
- return err;
-#endif
+ if (verd++ >= MAX_REC_LOOP) {
+ printk("rule prio %u protocol %02x reclassify loop, "
+ "packet dropped\n",
+ tp->prio&0xffff, ntohs(tp->protocol));
+ return TC_ACT_SHOT;
}
-
+ skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd);
+ goto reclassify;
}
- return -1;
+#endif
+ return err;
}
+EXPORT_SYMBOL(tc_classify);
void tcf_destroy(struct tcf_proto *tp)
{
@@ -1256,4 +1262,3 @@
EXPORT_SYMBOL(qdisc_put_rtab);
EXPORT_SYMBOL(register_qdisc);
EXPORT_SYMBOL(unregister_qdisc);
-EXPORT_SYMBOL(tc_classify);
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 54b92d2..417ec8f 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -2,7 +2,6 @@
/* Written 1998-2000 by Werner Almesberger, EPFL ICA */
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
@@ -11,12 +10,11 @@
#include <linux/atmdev.h>
#include <linux/atmclip.h>
#include <linux/rtnetlink.h>
-#include <linux/file.h> /* for fput */
+#include <linux/file.h> /* for fput */
#include <net/netlink.h>
#include <net/pkt_sched.h>
-
-extern struct socket *sockfd_lookup(int fd, int *err); /* @@@ fix this */
+extern struct socket *sockfd_lookup(int fd, int *err); /* @@@ fix this */
#if 0 /* control */
#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
@@ -30,7 +28,6 @@
#define D2PRINTK(format,args...)
#endif
-
/*
* The ATM queuing discipline provides a framework for invoking classifiers
* (aka "filters"), which in turn select classes of this queuing discipline.
@@ -52,16 +49,15 @@
* - should lock the flow while there is data in the queue (?)
*/
-
#define PRIV(sch) qdisc_priv(sch)
#define VCC2FLOW(vcc) ((struct atm_flow_data *) ((vcc)->user_back))
-
struct atm_flow_data {
- struct Qdisc *q; /* FIFO, TBF, etc. */
+ struct Qdisc *q; /* FIFO, TBF, etc. */
struct tcf_proto *filter_list;
- struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */
- void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* chaining */
+ struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */
+ void (*old_pop)(struct atm_vcc *vcc,
+ struct sk_buff * skb); /* chaining */
struct atm_qdisc_data *parent; /* parent qdisc */
struct socket *sock; /* for closing */
u32 classid; /* x:y type ID */
@@ -82,76 +78,74 @@
struct tasklet_struct task; /* requeue tasklet */
};
-
/* ------------------------- Class/flow operations ------------------------- */
-
-static int find_flow(struct atm_qdisc_data *qdisc,struct atm_flow_data *flow)
+static int find_flow(struct atm_qdisc_data *qdisc, struct atm_flow_data *flow)
{
struct atm_flow_data *walk;
- DPRINTK("find_flow(qdisc %p,flow %p)\n",qdisc,flow);
+ DPRINTK("find_flow(qdisc %p,flow %p)\n", qdisc, flow);
for (walk = qdisc->flows; walk; walk = walk->next)
- if (walk == flow) return 1;
+ if (walk == flow)
+ return 1;
DPRINTK("find_flow: not found\n");
return 0;
}
-
-static __inline__ struct atm_flow_data *lookup_flow(struct Qdisc *sch,
- u32 classid)
+static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid)
{
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
for (flow = p->flows; flow; flow = flow->next)
- if (flow->classid == classid) break;
+ if (flow->classid == classid)
+ break;
return flow;
}
-
-static int atm_tc_graft(struct Qdisc *sch,unsigned long arg,
- struct Qdisc *new,struct Qdisc **old)
+static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
+ struct Qdisc *new, struct Qdisc **old)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = (struct atm_flow_data *) arg;
+ struct atm_flow_data *flow = (struct atm_flow_data *)arg;
- DPRINTK("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",sch,
- p,flow,new,old);
- if (!find_flow(p,flow)) return -EINVAL;
- if (!new) new = &noop_qdisc;
- *old = xchg(&flow->q,new);
- if (*old) qdisc_reset(*old);
+ DPRINTK("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",
+ sch, p, flow, new, old);
+ if (!find_flow(p, flow))
+ return -EINVAL;
+ if (!new)
+ new = &noop_qdisc;
+ *old = xchg(&flow->q, new);
+ if (*old)
+ qdisc_reset(*old);
return 0;
}
-
-static struct Qdisc *atm_tc_leaf(struct Qdisc *sch,unsigned long cl)
+static struct Qdisc *atm_tc_leaf(struct Qdisc *sch, unsigned long cl)
{
- struct atm_flow_data *flow = (struct atm_flow_data *) cl;
+ struct atm_flow_data *flow = (struct atm_flow_data *)cl;
- DPRINTK("atm_tc_leaf(sch %p,flow %p)\n",sch,flow);
+ DPRINTK("atm_tc_leaf(sch %p,flow %p)\n", sch, flow);
return flow ? flow->q : NULL;
}
-
-static unsigned long atm_tc_get(struct Qdisc *sch,u32 classid)
+static unsigned long atm_tc_get(struct Qdisc *sch, u32 classid)
{
- struct atm_qdisc_data *p __attribute__((unused)) = PRIV(sch);
+ struct atm_qdisc_data *p __maybe_unused = PRIV(sch);
struct atm_flow_data *flow;
- DPRINTK("atm_tc_get(sch %p,[qdisc %p],classid %x)\n",sch,p,classid);
- flow = lookup_flow(sch,classid);
- if (flow) flow->ref++;
- DPRINTK("atm_tc_get: flow %p\n",flow);
- return (unsigned long) flow;
+ DPRINTK("atm_tc_get(sch %p,[qdisc %p],classid %x)\n", sch, p, classid);
+ flow = lookup_flow(sch, classid);
+ if (flow)
+ flow->ref++;
+ DPRINTK("atm_tc_get: flow %p\n", flow);
+ return (unsigned long)flow;
}
-
static unsigned long atm_tc_bind_filter(struct Qdisc *sch,
- unsigned long parent, u32 classid)
+ unsigned long parent, u32 classid)
{
- return atm_tc_get(sch,classid);
+ return atm_tc_get(sch, classid);
}
/*
@@ -159,72 +153,75 @@
* requested (atm_tc_destroy, etc.). The assumption here is that we never drop
* anything that still seems to be in use.
*/
-
static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = (struct atm_flow_data *) cl;
+ struct atm_flow_data *flow = (struct atm_flow_data *)cl;
struct atm_flow_data **prev;
- DPRINTK("atm_tc_put(sch %p,[qdisc %p],flow %p)\n",sch,p,flow);
- if (--flow->ref) return;
+ DPRINTK("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
+ if (--flow->ref)
+ return;
DPRINTK("atm_tc_put: destroying\n");
for (prev = &p->flows; *prev; prev = &(*prev)->next)
- if (*prev == flow) break;
+ if (*prev == flow)
+ break;
if (!*prev) {
- printk(KERN_CRIT "atm_tc_put: class %p not found\n",flow);
+ printk(KERN_CRIT "atm_tc_put: class %p not found\n", flow);
return;
}
*prev = flow->next;
- DPRINTK("atm_tc_put: qdisc %p\n",flow->q);
+ DPRINTK("atm_tc_put: qdisc %p\n", flow->q);
qdisc_destroy(flow->q);
tcf_destroy_chain(flow->filter_list);
if (flow->sock) {
DPRINTK("atm_tc_put: f_count %d\n",
- file_count(flow->sock->file));
+ file_count(flow->sock->file));
flow->vcc->pop = flow->old_pop;
sockfd_put(flow->sock);
}
- if (flow->excess) atm_tc_put(sch,(unsigned long) flow->excess);
- if (flow != &p->link) kfree(flow);
+ if (flow->excess)
+ atm_tc_put(sch, (unsigned long)flow->excess);
+ if (flow != &p->link)
+ kfree(flow);
/*
* If flow == &p->link, the qdisc no longer works at this point and
* needs to be removed. (By the caller of atm_tc_put.)
*/
}
-
-static void sch_atm_pop(struct atm_vcc *vcc,struct sk_buff *skb)
+static void sch_atm_pop(struct atm_vcc *vcc, struct sk_buff *skb)
{
struct atm_qdisc_data *p = VCC2FLOW(vcc)->parent;
- D2PRINTK("sch_atm_pop(vcc %p,skb %p,[qdisc %p])\n",vcc,skb,p);
- VCC2FLOW(vcc)->old_pop(vcc,skb);
+ D2PRINTK("sch_atm_pop(vcc %p,skb %p,[qdisc %p])\n", vcc, skb, p);
+ VCC2FLOW(vcc)->old_pop(vcc, skb);
tasklet_schedule(&p->task);
}
static const u8 llc_oui_ip[] = {
- 0xaa, /* DSAP: non-ISO */
- 0xaa, /* SSAP: non-ISO */
- 0x03, /* Ctrl: Unnumbered Information Command PDU */
- 0x00, /* OUI: EtherType */
+ 0xaa, /* DSAP: non-ISO */
+ 0xaa, /* SSAP: non-ISO */
+ 0x03, /* Ctrl: Unnumbered Information Command PDU */
+ 0x00, /* OUI: EtherType */
0x00, 0x00,
- 0x08, 0x00 }; /* Ethertype IP (0800) */
+ 0x08, 0x00
+}; /* Ethertype IP (0800) */
static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
- struct rtattr **tca, unsigned long *arg)
+ struct rtattr **tca, unsigned long *arg)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = (struct atm_flow_data *) *arg;
+ struct atm_flow_data *flow = (struct atm_flow_data *)*arg;
struct atm_flow_data *excess = NULL;
- struct rtattr *opt = tca[TCA_OPTIONS-1];
+ struct rtattr *opt = tca[TCA_OPTIONS - 1];
struct rtattr *tb[TCA_ATM_MAX];
struct socket *sock;
- int fd,error,hdr_len;
+ int fd, error, hdr_len;
void *hdr;
DPRINTK("atm_tc_change(sch %p,[qdisc %p],classid %x,parent %x,"
- "flow %p,opt %p)\n",sch,p,classid,parent,flow,opt);
+ "flow %p,opt %p)\n", sch, p, classid, parent, flow, opt);
/*
* The concept of parents doesn't apply for this qdisc.
*/
@@ -237,33 +234,36 @@
* class needs to be removed and a new one added. (This may be changed
* later.)
*/
- if (flow) return -EBUSY;
+ if (flow)
+ return -EBUSY;
if (opt == NULL || rtattr_parse_nested(tb, TCA_ATM_MAX, opt))
return -EINVAL;
- if (!tb[TCA_ATM_FD-1] || RTA_PAYLOAD(tb[TCA_ATM_FD-1]) < sizeof(fd))
+ if (!tb[TCA_ATM_FD - 1] || RTA_PAYLOAD(tb[TCA_ATM_FD - 1]) < sizeof(fd))
return -EINVAL;
- fd = *(int *) RTA_DATA(tb[TCA_ATM_FD-1]);
- DPRINTK("atm_tc_change: fd %d\n",fd);
- if (tb[TCA_ATM_HDR-1]) {
- hdr_len = RTA_PAYLOAD(tb[TCA_ATM_HDR-1]);
- hdr = RTA_DATA(tb[TCA_ATM_HDR-1]);
- }
- else {
+ fd = *(int *)RTA_DATA(tb[TCA_ATM_FD - 1]);
+ DPRINTK("atm_tc_change: fd %d\n", fd);
+ if (tb[TCA_ATM_HDR - 1]) {
+ hdr_len = RTA_PAYLOAD(tb[TCA_ATM_HDR - 1]);
+ hdr = RTA_DATA(tb[TCA_ATM_HDR - 1]);
+ } else {
hdr_len = RFC1483LLC_LEN;
- hdr = NULL; /* default LLC/SNAP for IP */
+ hdr = NULL; /* default LLC/SNAP for IP */
}
- if (!tb[TCA_ATM_EXCESS-1]) excess = NULL;
+ if (!tb[TCA_ATM_EXCESS - 1])
+ excess = NULL;
else {
- if (RTA_PAYLOAD(tb[TCA_ATM_EXCESS-1]) != sizeof(u32))
+ if (RTA_PAYLOAD(tb[TCA_ATM_EXCESS - 1]) != sizeof(u32))
return -EINVAL;
- excess = (struct atm_flow_data *) atm_tc_get(sch,
- *(u32 *) RTA_DATA(tb[TCA_ATM_EXCESS-1]));
- if (!excess) return -ENOENT;
+ excess = (struct atm_flow_data *)
+ atm_tc_get(sch, *(u32 *)RTA_DATA(tb[TCA_ATM_EXCESS - 1]));
+ if (!excess)
+ return -ENOENT;
}
DPRINTK("atm_tc_change: type %d, payload %d, hdr_len %d\n",
- opt->rta_type,RTA_PAYLOAD(opt),hdr_len);
- if (!(sock = sockfd_lookup(fd,&error))) return error; /* f_count++ */
- DPRINTK("atm_tc_change: f_count %d\n",file_count(sock->file));
+ opt->rta_type, RTA_PAYLOAD(opt), hdr_len);
+ if (!(sock = sockfd_lookup(fd, &error)))
+ return error; /* f_count++ */
+ DPRINTK("atm_tc_change: f_count %d\n", file_count(sock->file));
if (sock->ops->family != PF_ATMSVC && sock->ops->family != PF_ATMPVC) {
error = -EPROTOTYPE;
goto err_out;
@@ -276,37 +276,37 @@
error = -EINVAL;
goto err_out;
}
- if (find_flow(p,flow)) {
+ if (find_flow(p, flow)) {
error = -EEXIST;
goto err_out;
}
- }
- else {
+ } else {
int i;
unsigned long cl;
for (i = 1; i < 0x8000; i++) {
- classid = TC_H_MAKE(sch->handle,0x8000 | i);
- if (!(cl = atm_tc_get(sch,classid))) break;
- atm_tc_put(sch,cl);
+ classid = TC_H_MAKE(sch->handle, 0x8000 | i);
+ if (!(cl = atm_tc_get(sch, classid)))
+ break;
+ atm_tc_put(sch, cl);
}
}
- DPRINTK("atm_tc_change: new id %x\n",classid);
- flow = kmalloc(sizeof(struct atm_flow_data)+hdr_len,GFP_KERNEL);
- DPRINTK("atm_tc_change: flow %p\n",flow);
+ DPRINTK("atm_tc_change: new id %x\n", classid);
+ flow = kmalloc(sizeof(struct atm_flow_data) + hdr_len, GFP_KERNEL);
+ DPRINTK("atm_tc_change: flow %p\n", flow);
if (!flow) {
error = -ENOBUFS;
goto err_out;
}
- memset(flow,0,sizeof(*flow));
+ memset(flow, 0, sizeof(*flow));
flow->filter_list = NULL;
- if (!(flow->q = qdisc_create_dflt(sch->dev,&pfifo_qdisc_ops,classid)))
+ if (!(flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid)))
flow->q = &noop_qdisc;
- DPRINTK("atm_tc_change: qdisc %p\n",flow->q);
+ DPRINTK("atm_tc_change: qdisc %p\n", flow->q);
flow->sock = sock;
- flow->vcc = ATM_SD(sock); /* speedup */
+ flow->vcc = ATM_SD(sock); /* speedup */
flow->vcc->user_back = flow;
- DPRINTK("atm_tc_change: vcc %p\n",flow->vcc);
+ DPRINTK("atm_tc_change: vcc %p\n", flow->vcc);
flow->old_pop = flow->vcc->pop;
flow->parent = p;
flow->vcc->pop = sch_atm_pop;
@@ -317,50 +317,53 @@
p->link.next = flow;
flow->hdr_len = hdr_len;
if (hdr)
- memcpy(flow->hdr,hdr,hdr_len);
+ memcpy(flow->hdr, hdr, hdr_len);
else
- memcpy(flow->hdr,llc_oui_ip,sizeof(llc_oui_ip));
- *arg = (unsigned long) flow;
+ memcpy(flow->hdr, llc_oui_ip, sizeof(llc_oui_ip));
+ *arg = (unsigned long)flow;
return 0;
err_out:
- if (excess) atm_tc_put(sch,(unsigned long) excess);
+ if (excess)
+ atm_tc_put(sch, (unsigned long)excess);
sockfd_put(sock);
return error;
}
-
-static int atm_tc_delete(struct Qdisc *sch,unsigned long arg)
+static int atm_tc_delete(struct Qdisc *sch, unsigned long arg)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = (struct atm_flow_data *) arg;
+ struct atm_flow_data *flow = (struct atm_flow_data *)arg;
- DPRINTK("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n",sch,p,flow);
- if (!find_flow(PRIV(sch),flow)) return -EINVAL;
- if (flow->filter_list || flow == &p->link) return -EBUSY;
+ DPRINTK("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
+ if (!find_flow(PRIV(sch), flow))
+ return -EINVAL;
+ if (flow->filter_list || flow == &p->link)
+ return -EBUSY;
/*
* Reference count must be 2: one for "keepalive" (set at class
* creation), and one for the reference held when calling delete.
*/
if (flow->ref < 2) {
- printk(KERN_ERR "atm_tc_delete: flow->ref == %d\n",flow->ref);
+ printk(KERN_ERR "atm_tc_delete: flow->ref == %d\n", flow->ref);
return -EINVAL;
}
- if (flow->ref > 2) return -EBUSY; /* catch references via excess, etc.*/
- atm_tc_put(sch,arg);
+ if (flow->ref > 2)
+ return -EBUSY; /* catch references via excess, etc. */
+ atm_tc_put(sch, arg);
return 0;
}
-
-static void atm_tc_walk(struct Qdisc *sch,struct qdisc_walker *walker)
+static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker)
{
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
- DPRINTK("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n",sch,p,walker);
- if (walker->stop) return;
+ DPRINTK("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
+ if (walker->stop)
+ return;
for (flow = p->flows; flow; flow = flow->next) {
if (walker->count >= walker->skip)
- if (walker->fn(sch,(unsigned long) flow,walker) < 0) {
+ if (walker->fn(sch, (unsigned long)flow, walker) < 0) {
walker->stop = 1;
break;
}
@@ -368,73 +371,71 @@
}
}
-
-static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch,unsigned long cl)
+static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch, unsigned long cl)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = (struct atm_flow_data *) cl;
+ struct atm_flow_data *flow = (struct atm_flow_data *)cl;
- DPRINTK("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n",sch,p,flow);
+ DPRINTK("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
return flow ? &flow->filter_list : &p->link.filter_list;
}
-
/* --------------------------- Qdisc operations ---------------------------- */
-
-static int atm_tc_enqueue(struct sk_buff *skb,struct Qdisc *sch)
+static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = NULL ; /* @@@ */
+ struct atm_flow_data *flow = NULL; /* @@@ */
struct tcf_result res;
int result;
int ret = NET_XMIT_POLICED;
- D2PRINTK("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p);
- result = TC_POLICE_OK; /* be nice to gcc */
+ D2PRINTK("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
+ result = TC_POLICE_OK; /* be nice to gcc */
if (TC_H_MAJ(skb->priority) != sch->handle ||
- !(flow = (struct atm_flow_data *) atm_tc_get(sch,skb->priority)))
+ !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority)))
for (flow = p->flows; flow; flow = flow->next)
if (flow->filter_list) {
- result = tc_classify(skb,flow->filter_list,
- &res);
- if (result < 0) continue;
- flow = (struct atm_flow_data *) res.class;
- if (!flow) flow = lookup_flow(sch,res.classid);
+ result = tc_classify_compat(skb,
+ flow->filter_list,
+ &res);
+ if (result < 0)
+ continue;
+ flow = (struct atm_flow_data *)res.class;
+ if (!flow)
+ flow = lookup_flow(sch, res.classid);
break;
}
- if (!flow) flow = &p->link;
+ if (!flow)
+ flow = &p->link;
else {
if (flow->vcc)
ATM_SKB(skb)->atm_options = flow->vcc->atm_options;
- /*@@@ looks good ... but it's not supposed to work :-)*/
-#ifdef CONFIG_NET_CLS_POLICE
+ /*@@@ looks good ... but it's not supposed to work :-) */
+#ifdef CONFIG_NET_CLS_ACT
switch (result) {
- case TC_POLICE_SHOT:
- kfree_skb(skb);
- break;
- case TC_POLICE_RECLASSIFY:
- if (flow->excess) flow = flow->excess;
- else {
- ATM_SKB(skb)->atm_options |=
- ATM_ATMOPT_CLP;
- break;
- }
- /* fall through */
- case TC_POLICE_OK:
- /* fall through */
- default:
- break;
+ case TC_ACT_QUEUED:
+ case TC_ACT_STOLEN:
+ kfree_skb(skb);
+ return NET_XMIT_SUCCESS;
+ case TC_ACT_SHOT:
+ kfree_skb(skb);
+ goto drop;
+ case TC_POLICE_RECLASSIFY:
+ if (flow->excess)
+ flow = flow->excess;
+ else
+ ATM_SKB(skb)->atm_options |= ATM_ATMOPT_CLP;
+ break;
}
#endif
}
- if (
-#ifdef CONFIG_NET_CLS_POLICE
- result == TC_POLICE_SHOT ||
-#endif
- (ret = flow->q->enqueue(skb,flow->q)) != 0) {
+
+ if ((ret = flow->q->enqueue(skb, flow->q)) != 0) {
+drop: __maybe_unused
sch->qstats.drops++;
- if (flow) flow->qstats.drops++;
+ if (flow)
+ flow->qstats.drops++;
return ret;
}
sch->bstats.bytes += skb->len;
@@ -458,7 +459,6 @@
return NET_XMIT_BYPASS;
}
-
/*
* Dequeue packets and send them over ATM. Note that we quite deliberately
* avoid checking net_device's flow control here, simply because sch_atm
@@ -466,167 +466,163 @@
* non-ATM interfaces.
*/
-
static void sch_atm_dequeue(unsigned long data)
{
- struct Qdisc *sch = (struct Qdisc *) data;
+ struct Qdisc *sch = (struct Qdisc *)data;
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
struct sk_buff *skb;
- D2PRINTK("sch_atm_dequeue(sch %p,[qdisc %p])\n",sch,p);
+ D2PRINTK("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p);
for (flow = p->link.next; flow; flow = flow->next)
/*
* If traffic is properly shaped, this won't generate nasty
* little bursts. Otherwise, it may ... (but that's okay)
*/
while ((skb = flow->q->dequeue(flow->q))) {
- if (!atm_may_send(flow->vcc,skb->truesize)) {
- (void) flow->q->ops->requeue(skb,flow->q);
+ if (!atm_may_send(flow->vcc, skb->truesize)) {
+ (void)flow->q->ops->requeue(skb, flow->q);
break;
}
- D2PRINTK("atm_tc_dequeue: sending on class %p\n",flow);
+ D2PRINTK("atm_tc_dequeue: sending on class %p\n", flow);
/* remove any LL header somebody else has attached */
skb_pull(skb, skb_network_offset(skb));
if (skb_headroom(skb) < flow->hdr_len) {
struct sk_buff *new;
- new = skb_realloc_headroom(skb,flow->hdr_len);
+ new = skb_realloc_headroom(skb, flow->hdr_len);
dev_kfree_skb(skb);
- if (!new) continue;
+ if (!new)
+ continue;
skb = new;
}
D2PRINTK("sch_atm_dequeue: ip %p, data %p\n",
skb_network_header(skb), skb->data);
ATM_SKB(skb)->vcc = flow->vcc;
- memcpy(skb_push(skb,flow->hdr_len),flow->hdr,
- flow->hdr_len);
+ memcpy(skb_push(skb, flow->hdr_len), flow->hdr,
+ flow->hdr_len);
atomic_add(skb->truesize,
&sk_atm(flow->vcc)->sk_wmem_alloc);
/* atm.atm_options are already set by atm_tc_enqueue */
- (void) flow->vcc->send(flow->vcc,skb);
+ flow->vcc->send(flow->vcc, skb);
}
}
-
static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
{
struct atm_qdisc_data *p = PRIV(sch);
struct sk_buff *skb;
- D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n",sch,p);
+ D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n", sch, p);
tasklet_schedule(&p->task);
skb = p->link.q->dequeue(p->link.q);
- if (skb) sch->q.qlen--;
+ if (skb)
+ sch->q.qlen--;
return skb;
}
-
-static int atm_tc_requeue(struct sk_buff *skb,struct Qdisc *sch)
+static int atm_tc_requeue(struct sk_buff *skb, struct Qdisc *sch)
{
struct atm_qdisc_data *p = PRIV(sch);
int ret;
- D2PRINTK("atm_tc_requeue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p);
- ret = p->link.q->ops->requeue(skb,p->link.q);
+ D2PRINTK("atm_tc_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
+ ret = p->link.q->ops->requeue(skb, p->link.q);
if (!ret) {
- sch->q.qlen++;
- sch->qstats.requeues++;
- } else {
+ sch->q.qlen++;
+ sch->qstats.requeues++;
+ } else {
sch->qstats.drops++;
p->link.qstats.drops++;
}
return ret;
}
-
static unsigned int atm_tc_drop(struct Qdisc *sch)
{
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
unsigned int len;
- DPRINTK("atm_tc_drop(sch %p,[qdisc %p])\n",sch,p);
+ DPRINTK("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p);
for (flow = p->flows; flow; flow = flow->next)
if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q)))
return len;
return 0;
}
-
-static int atm_tc_init(struct Qdisc *sch,struct rtattr *opt)
+static int atm_tc_init(struct Qdisc *sch, struct rtattr *opt)
{
struct atm_qdisc_data *p = PRIV(sch);
- DPRINTK("atm_tc_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt);
+ DPRINTK("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
p->flows = &p->link;
- if(!(p->link.q = qdisc_create_dflt(sch->dev,&pfifo_qdisc_ops,
- sch->handle)))
+ if (!(p->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+ sch->handle)))
p->link.q = &noop_qdisc;
- DPRINTK("atm_tc_init: link (%p) qdisc %p\n",&p->link,p->link.q);
+ DPRINTK("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
p->link.filter_list = NULL;
p->link.vcc = NULL;
p->link.sock = NULL;
p->link.classid = sch->handle;
p->link.ref = 1;
p->link.next = NULL;
- tasklet_init(&p->task,sch_atm_dequeue,(unsigned long) sch);
+ tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch);
return 0;
}
-
static void atm_tc_reset(struct Qdisc *sch)
{
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
- DPRINTK("atm_tc_reset(sch %p,[qdisc %p])\n",sch,p);
- for (flow = p->flows; flow; flow = flow->next) qdisc_reset(flow->q);
+ DPRINTK("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p);
+ for (flow = p->flows; flow; flow = flow->next)
+ qdisc_reset(flow->q);
sch->q.qlen = 0;
}
-
static void atm_tc_destroy(struct Qdisc *sch)
{
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
- DPRINTK("atm_tc_destroy(sch %p,[qdisc %p])\n",sch,p);
+ DPRINTK("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
/* races ? */
while ((flow = p->flows)) {
tcf_destroy_chain(flow->filter_list);
flow->filter_list = NULL;
if (flow->ref > 1)
- printk(KERN_ERR "atm_destroy: %p->ref = %d\n",flow,
- flow->ref);
- atm_tc_put(sch,(unsigned long) flow);
+ printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow,
+ flow->ref);
+ atm_tc_put(sch, (unsigned long)flow);
if (p->flows == flow) {
printk(KERN_ERR "atm_destroy: putting flow %p didn't "
- "kill it\n",flow);
- p->flows = flow->next; /* brute force */
+ "kill it\n", flow);
+ p->flows = flow->next; /* brute force */
break;
}
}
tasklet_kill(&p->task);
}
-
static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
- struct sk_buff *skb, struct tcmsg *tcm)
+ struct sk_buff *skb, struct tcmsg *tcm)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = (struct atm_flow_data *) cl;
+ struct atm_flow_data *flow = (struct atm_flow_data *)cl;
unsigned char *b = skb_tail_pointer(skb);
struct rtattr *rta;
DPRINTK("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n",
- sch,p,flow,skb,tcm);
- if (!find_flow(p,flow)) return -EINVAL;
+ sch, p, flow, skb, tcm);
+ if (!find_flow(p, flow))
+ return -EINVAL;
tcm->tcm_handle = flow->classid;
tcm->tcm_info = flow->q->handle;
- rta = (struct rtattr *) b;
- RTA_PUT(skb,TCA_OPTIONS,0,NULL);
- RTA_PUT(skb,TCA_ATM_HDR,flow->hdr_len,flow->hdr);
+ rta = (struct rtattr *)b;
+ RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
+ RTA_PUT(skb, TCA_ATM_HDR, flow->hdr_len, flow->hdr);
if (flow->vcc) {
struct sockaddr_atmpvc pvc;
int state;
@@ -635,16 +631,16 @@
pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1;
pvc.sap_addr.vpi = flow->vcc->vpi;
pvc.sap_addr.vci = flow->vcc->vci;
- RTA_PUT(skb,TCA_ATM_ADDR,sizeof(pvc),&pvc);
+ RTA_PUT(skb, TCA_ATM_ADDR, sizeof(pvc), &pvc);
state = ATM_VF2VS(flow->vcc->flags);
- RTA_PUT(skb,TCA_ATM_STATE,sizeof(state),&state);
+ RTA_PUT(skb, TCA_ATM_STATE, sizeof(state), &state);
}
if (flow->excess)
- RTA_PUT(skb,TCA_ATM_EXCESS,sizeof(u32),&flow->classid);
+ RTA_PUT(skb, TCA_ATM_EXCESS, sizeof(u32), &flow->classid);
else {
static u32 zero;
- RTA_PUT(skb,TCA_ATM_EXCESS,sizeof(zero),&zero);
+ RTA_PUT(skb, TCA_ATM_EXCESS, sizeof(zero), &zero);
}
rta->rta_len = skb_tail_pointer(skb) - b;
return skb->len;
@@ -655,9 +651,9 @@
}
static int
atm_tc_dump_class_stats(struct Qdisc *sch, unsigned long arg,
- struct gnet_dump *d)
+ struct gnet_dump *d)
{
- struct atm_flow_data *flow = (struct atm_flow_data *) arg;
+ struct atm_flow_data *flow = (struct atm_flow_data *)arg;
flow->qstats.qlen = flow->q->q.qlen;
@@ -674,38 +670,35 @@
}
static struct Qdisc_class_ops atm_class_ops = {
- .graft = atm_tc_graft,
- .leaf = atm_tc_leaf,
- .get = atm_tc_get,
- .put = atm_tc_put,
- .change = atm_tc_change,
- .delete = atm_tc_delete,
- .walk = atm_tc_walk,
- .tcf_chain = atm_tc_find_tcf,
- .bind_tcf = atm_tc_bind_filter,
- .unbind_tcf = atm_tc_put,
- .dump = atm_tc_dump_class,
- .dump_stats = atm_tc_dump_class_stats,
+ .graft = atm_tc_graft,
+ .leaf = atm_tc_leaf,
+ .get = atm_tc_get,
+ .put = atm_tc_put,
+ .change = atm_tc_change,
+ .delete = atm_tc_delete,
+ .walk = atm_tc_walk,
+ .tcf_chain = atm_tc_find_tcf,
+ .bind_tcf = atm_tc_bind_filter,
+ .unbind_tcf = atm_tc_put,
+ .dump = atm_tc_dump_class,
+ .dump_stats = atm_tc_dump_class_stats,
};
static struct Qdisc_ops atm_qdisc_ops = {
- .next = NULL,
- .cl_ops = &atm_class_ops,
- .id = "atm",
- .priv_size = sizeof(struct atm_qdisc_data),
- .enqueue = atm_tc_enqueue,
- .dequeue = atm_tc_dequeue,
- .requeue = atm_tc_requeue,
- .drop = atm_tc_drop,
- .init = atm_tc_init,
- .reset = atm_tc_reset,
- .destroy = atm_tc_destroy,
- .change = NULL,
- .dump = atm_tc_dump,
- .owner = THIS_MODULE,
+ .cl_ops = &atm_class_ops,
+ .id = "atm",
+ .priv_size = sizeof(struct atm_qdisc_data),
+ .enqueue = atm_tc_enqueue,
+ .dequeue = atm_tc_dequeue,
+ .requeue = atm_tc_requeue,
+ .drop = atm_tc_drop,
+ .init = atm_tc_init,
+ .reset = atm_tc_reset,
+ .destroy = atm_tc_destroy,
+ .dump = atm_tc_dump,
+ .owner = THIS_MODULE,
};
-
static int __init atm_init(void)
{
return register_qdisc(&atm_qdisc_ops);
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index b184c35..e38c283 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -82,7 +82,7 @@
unsigned char priority2; /* priority to be used after overlimit */
unsigned char ewma_log; /* time constant for idle time calculation */
unsigned char ovl_strategy;
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
unsigned char police;
#endif
@@ -154,7 +154,7 @@
struct cbq_class *active[TC_CBQ_MAXPRIO+1]; /* List of all classes
with backlog */
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
struct cbq_class *rx_class;
#endif
struct cbq_class *tx_class;
@@ -196,7 +196,7 @@
return NULL;
}
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
static struct cbq_class *
cbq_reclassify(struct sk_buff *skb, struct cbq_class *this)
@@ -247,7 +247,8 @@
/*
* Step 2+n. Apply classifier.
*/
- if (!head->filter_list || (result = tc_classify(skb, head->filter_list, &res)) < 0)
+ if (!head->filter_list ||
+ (result = tc_classify_compat(skb, head->filter_list, &res)) < 0)
goto fallback;
if ((cl = (void*)res.class) == NULL) {
@@ -267,15 +268,8 @@
*qerr = NET_XMIT_SUCCESS;
case TC_ACT_SHOT:
return NULL;
- }
-#elif defined(CONFIG_NET_CLS_POLICE)
- switch (result) {
- case TC_POLICE_RECLASSIFY:
+ case TC_ACT_RECLASSIFY:
return cbq_reclassify(skb, cl);
- case TC_POLICE_SHOT:
- return NULL;
- default:
- break;
}
#endif
if (cl->level == 0)
@@ -389,7 +383,7 @@
int ret;
struct cbq_class *cl = cbq_classify(skb, sch, &ret);
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
q->rx_class = cl;
#endif
if (cl == NULL) {
@@ -399,7 +393,7 @@
return ret;
}
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
cl->q->__parent = sch;
#endif
if ((ret = cl->q->enqueue(skb, cl->q)) == NET_XMIT_SUCCESS) {
@@ -434,7 +428,7 @@
cbq_mark_toplevel(q, cl);
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
q->rx_class = cl;
cl->q->__parent = sch;
#endif
@@ -669,9 +663,7 @@
return HRTIMER_NORESTART;
}
-
-#ifdef CONFIG_NET_CLS_POLICE
-
+#ifdef CONFIG_NET_CLS_ACT
static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child)
{
int len = skb->len;
@@ -1364,7 +1356,7 @@
return 0;
}
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
static int cbq_set_police(struct cbq_class *cl, struct tc_cbq_police *p)
{
cl->police = p->police;
@@ -1532,7 +1524,7 @@
return -1;
}
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
static __inline__ int cbq_dump_police(struct sk_buff *skb, struct cbq_class *cl)
{
unsigned char *b = skb_tail_pointer(skb);
@@ -1558,7 +1550,7 @@
cbq_dump_rate(skb, cl) < 0 ||
cbq_dump_wrr(skb, cl) < 0 ||
cbq_dump_ovl(skb, cl) < 0 ||
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
cbq_dump_police(skb, cl) < 0 ||
#endif
cbq_dump_fopt(skb, cl) < 0)
@@ -1653,7 +1645,7 @@
cl->classid)) == NULL)
return -ENOBUFS;
} else {
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (cl->police == TC_POLICE_RECLASSIFY)
new->reshape_fail = cbq_reshape_fail;
#endif
@@ -1718,7 +1710,7 @@
struct cbq_class *cl;
unsigned h;
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
q->rx_class = NULL;
#endif
/*
@@ -1747,7 +1739,7 @@
struct cbq_class *cl = (struct cbq_class*)arg;
if (--cl->refcnt == 0) {
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
struct cbq_sched_data *q = qdisc_priv(sch);
spin_lock_bh(&sch->dev->queue_lock);
@@ -1795,7 +1787,7 @@
RTA_PAYLOAD(tb[TCA_CBQ_WRROPT-1]) < sizeof(struct tc_cbq_wrropt))
return -EINVAL;
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (tb[TCA_CBQ_POLICE-1] &&
RTA_PAYLOAD(tb[TCA_CBQ_POLICE-1]) < sizeof(struct tc_cbq_police))
return -EINVAL;
@@ -1838,7 +1830,7 @@
if (tb[TCA_CBQ_OVL_STRATEGY-1])
cbq_set_overlimit(cl, RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY-1]));
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (tb[TCA_CBQ_POLICE-1])
cbq_set_police(cl, RTA_DATA(tb[TCA_CBQ_POLICE-1]));
#endif
@@ -1931,7 +1923,7 @@
cl->overlimit = cbq_ovl_classic;
if (tb[TCA_CBQ_OVL_STRATEGY-1])
cbq_set_overlimit(cl, RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY-1]));
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (tb[TCA_CBQ_POLICE-1])
cbq_set_police(cl, RTA_DATA(tb[TCA_CBQ_POLICE-1]));
#endif
@@ -1975,7 +1967,7 @@
q->tx_class = NULL;
q->tx_borrowed = NULL;
}
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (q->rx_class == cl)
q->rx_class = NULL;
#endif
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 4d2c233..60f8919 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -237,25 +237,23 @@
D2PRINTK("result %d class 0x%04x\n", result, res.classid);
switch (result) {
-#ifdef CONFIG_NET_CLS_POLICE
- case TC_POLICE_SHOT:
- kfree_skb(skb);
- sch->qstats.drops++;
- return NET_XMIT_POLICED;
-#if 0
- case TC_POLICE_RECLASSIFY:
- /* FIXME: what to do here ??? */
+#ifdef CONFIG_NET_CLS_ACT
+ case TC_ACT_QUEUED:
+ case TC_ACT_STOLEN:
+ kfree_skb(skb);
+ return NET_XMIT_SUCCESS;
+ case TC_ACT_SHOT:
+ kfree_skb(skb);
+ sch->qstats.drops++;
+ return NET_XMIT_BYPASS;
#endif
-#endif
- case TC_POLICE_OK:
- skb->tc_index = TC_H_MIN(res.classid);
- break;
- case TC_POLICE_UNSPEC:
- /* fall through */
- default:
- if (p->default_index != NO_DEFAULT_INDEX)
- skb->tc_index = p->default_index;
- break;
+ case TC_ACT_OK:
+ skb->tc_index = TC_H_MIN(res.classid);
+ break;
+ default:
+ if (p->default_index != NO_DEFAULT_INDEX)
+ skb->tc_index = p->default_index;
+ break;
}
}
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 874452c..55e7e45 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1174,9 +1174,6 @@
case TC_ACT_SHOT:
return NULL;
}
-#elif defined(CONFIG_NET_CLS_POLICE)
- if (result == TC_POLICE_SHOT)
- return NULL;
#endif
if ((cl = (struct hfsc_class *)res.class) == NULL) {
if ((cl = hfsc_find_class(res.classid, sch)) == NULL)
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index b417a95..246a2f9 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -249,9 +249,6 @@
case TC_ACT_SHOT:
return NULL;
}
-#elif defined(CONFIG_NET_CLS_POLICE)
- if (result == TC_POLICE_SHOT)
- return HTB_DIRECT;
#endif
if ((cl = (void *)res.class) == NULL) {
if (res.classid == sch->handle)
diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
index cd0aab6..51f16b0 100644
--- a/net/sched/sch_ingress.c
+++ b/net/sched/sch_ingress.c
@@ -164,31 +164,12 @@
result = TC_ACT_OK;
break;
}
-/* backward compat */
-#else
-#ifdef CONFIG_NET_CLS_POLICE
- switch (result) {
- case TC_POLICE_SHOT:
- result = NF_DROP;
- sch->qstats.drops++;
- break;
- case TC_POLICE_RECLASSIFY: /* DSCP remarking here ? */
- case TC_POLICE_OK:
- case TC_POLICE_UNSPEC:
- default:
- sch->bstats.packets++;
- sch->bstats.bytes += skb->len;
- result = NF_ACCEPT;
- break;
- }
-
#else
D2PRINTK("Overriding result to ACCEPT\n");
result = NF_ACCEPT;
sch->bstats.packets++;
sch->bstats.bytes += skb->len;
#endif
-#endif
return result;
}
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 22e431d..8c2639a 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -125,7 +125,7 @@
if (skb->len > q->max_size) {
sch->qstats.drops++;
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (sch->reshape_fail == NULL || sch->reshape_fail(skb, sch))
#endif
kfree_skb(skb);
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 3a96ae6..092116e 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -1,4 +1,4 @@
obj-$(CONFIG_WIRELESS_EXT) += wext.o
obj-$(CONFIG_CFG80211) += cfg80211.o
-cfg80211-y += core.o sysfs.o
+cfg80211-y += core.o sysfs.o radiotap.o
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c
new file mode 100644
index 0000000..68c11d0
--- /dev/null
+++ b/net/wireless/radiotap.c
@@ -0,0 +1,257 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007 Andy Green <andy@warmcat.com>
+ */
+
+#include <net/cfg80211.h>
+#include <net/ieee80211_radiotap.h>
+#include <asm/unaligned.h>
+
+/* function prototypes and related defs are in include/net/cfg80211.h */
+
+/**
+ * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
+ * @iterator: radiotap_iterator to initialize
+ * @radiotap_header: radiotap header to parse
+ * @max_length: total length we can parse into (eg, whole packet length)
+ *
+ * Returns: 0 or a negative error code if there is a problem.
+ *
+ * This function initializes an opaque iterator struct which can then
+ * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
+ * argument which is present in the header. It knows about extended
+ * present headers and handles them.
+ *
+ * How to use:
+ * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
+ * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
+ * checking for a good 0 return code. Then loop calling
+ * __ieee80211_radiotap_iterator_next()... it returns either 0,
+ * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
+ * The iterator's @this_arg member points to the start of the argument
+ * associated with the current argument index that is present, which can be
+ * found in the iterator's @this_arg_index member. This arg index corresponds
+ * to the IEEE80211_RADIOTAP_... defines.
+ *
+ * Radiotap header length:
+ * You can find the CPU-endian total radiotap header length in
+ * iterator->max_length after executing ieee80211_radiotap_iterator_init()
+ * successfully.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ *
+ * Example code:
+ * See Documentation/networking/radiotap-headers.txt
+ */
+
+int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length)
+{
+ /* Linux only supports version 0 radiotap format */
+ if (radiotap_header->it_version)
+ return -EINVAL;
+
+ /* sanity check for allowed length and radiotap length field */
+ if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+ return -EINVAL;
+
+ iterator->rtheader = radiotap_header;
+ iterator->max_length = le16_to_cpu(get_unaligned(
+ &radiotap_header->it_len));
+ iterator->arg_index = 0;
+ iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
+ &radiotap_header->it_present));
+ iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
+ iterator->this_arg = NULL;
+
+ /* find payload start allowing for extended bitmap(s) */
+
+ if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
+ while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
+ (1<<IEEE80211_RADIOTAP_EXT)) {
+ iterator->arg += sizeof(u32);
+
+ /*
+ * check for insanity where the present bitmaps
+ * keep claiming to extend up to or even beyond the
+ * stated radiotap header length
+ */
+
+ if (((ulong)iterator->arg -
+ (ulong)iterator->rtheader) > iterator->max_length)
+ return -EINVAL;
+ }
+
+ iterator->arg += sizeof(u32);
+
+ /*
+ * no need to check again for blowing past stated radiotap
+ * header length, because ieee80211_radiotap_iterator_next
+ * checks it before it is dereferenced
+ */
+ }
+
+ /* we are all initialized happily */
+
+ return 0;
+}
+EXPORT_SYMBOL(ieee80211_radiotap_iterator_init);
+
+
+/**
+ * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
+ * @iterator: radiotap_iterator to move to next arg (if any)
+ *
+ * Returns: 0 if there is an argument to handle,
+ * -ENOENT if there are no more args or -EINVAL
+ * if there is something else wrong.
+ *
+ * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
+ * in @this_arg_index and sets @this_arg to point to the
+ * payload for the field. It takes care of alignment handling and extended
+ * present fields. @this_arg can be changed by the caller (eg,
+ * incremented to move inside a compound argument like
+ * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
+ * little-endian format whatever the endianess of your CPU.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+
+int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator)
+{
+
+ /*
+ * small length lookup table for all radiotap types we heard of
+ * starting from b0 in the bitmap, so we can walk the payload
+ * area of the radiotap header
+ *
+ * There is a requirement to pad args, so that args
+ * of a given length must begin at a boundary of that length
+ * -- but note that compound args are allowed (eg, 2 x u16
+ * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
+ * a reliable indicator of alignment requirement.
+ *
+ * upper nybble: content alignment for arg
+ * lower nybble: content length for arg
+ */
+
+ static const u8 rt_sizes[] = {
+ [IEEE80211_RADIOTAP_TSFT] = 0x88,
+ [IEEE80211_RADIOTAP_FLAGS] = 0x11,
+ [IEEE80211_RADIOTAP_RATE] = 0x11,
+ [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
+ [IEEE80211_RADIOTAP_FHSS] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
+ [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
+ [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11
+ /*
+ * add more here as they are defined in
+ * include/net/ieee80211_radiotap.h
+ */
+ };
+
+ /*
+ * for every radiotap entry we can at
+ * least skip (by knowing the length)...
+ */
+
+ while (iterator->arg_index < sizeof(rt_sizes)) {
+ int hit = 0;
+ int pad;
+
+ if (!(iterator->bitmap_shifter & 1))
+ goto next_entry; /* arg not present */
+
+ /*
+ * arg is present, account for alignment padding
+ * 8-bit args can be at any alignment
+ * 16-bit args must start on 16-bit boundary
+ * 32-bit args must start on 32-bit boundary
+ * 64-bit args must start on 64-bit boundary
+ *
+ * note that total arg size can differ from alignment of
+ * elements inside arg, so we use upper nybble of length
+ * table to base alignment on
+ *
+ * also note: these alignments are ** relative to the
+ * start of the radiotap header **. There is no guarantee
+ * that the radiotap header itself is aligned on any
+ * kind of boundary.
+ *
+ * the above is why get_unaligned() is used to dereference
+ * multibyte elements from the radiotap area
+ */
+
+ pad = (((ulong)iterator->arg) -
+ ((ulong)iterator->rtheader)) &
+ ((rt_sizes[iterator->arg_index] >> 4) - 1);
+
+ if (pad)
+ iterator->arg +=
+ (rt_sizes[iterator->arg_index] >> 4) - pad;
+
+ /*
+ * this is what we will return to user, but we need to
+ * move on first so next call has something fresh to test
+ */
+ iterator->this_arg_index = iterator->arg_index;
+ iterator->this_arg = iterator->arg;
+ hit = 1;
+
+ /* internally move on the size of this arg */
+ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
+
+ /*
+ * check for insanity where we are given a bitmap that
+ * claims to have more arg content than the length of the
+ * radiotap section. We will normally end up equalling this
+ * max_length on the last arg, never exceeding it.
+ */
+
+ if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
+ iterator->max_length)
+ return -EINVAL;
+
+ next_entry:
+ iterator->arg_index++;
+ if (unlikely((iterator->arg_index & 31) == 0)) {
+ /* completed current u32 bitmap */
+ if (iterator->bitmap_shifter & 1) {
+ /* b31 was set, there is more */
+ /* move to next u32 bitmap */
+ iterator->bitmap_shifter = le32_to_cpu(
+ get_unaligned(iterator->next_bitmap));
+ iterator->next_bitmap++;
+ } else
+ /* no more bitmaps: end */
+ iterator->arg_index = sizeof(rt_sizes);
+ } else /* just try the next bit */
+ iterator->bitmap_shifter >>= 1;
+
+ /* if we found a valid arg earlier, return it now */
+ if (hit)
+ return 0;
+ }
+
+ /* we don't know how to handle any more args, we're done */
+ return -ENOENT;
+}
+EXPORT_SYMBOL(ieee80211_radiotap_iterator_next);