From a53eb5e060c0ec7245c8f93b9dcd94afa6041e06 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 27 Apr 2007 12:41:09 -0400 Subject: [SCSI] FC Transport support for vports based on NPIV This patch provides support for FC virtual ports based on NPIV. For information on the interfaces and design, please read the Documentation/scsi/scsi_fc_transport.txt file enclosed within the patch. The RFC was originally posted here: http://marc.info/?l=linux-scsi&m=117226959918393&w=2 Changes from the initial RFC: - Bug fix: needed a transport_class_unregister() for the vport class - Create a symlink to the vport in the shost device if it is not the parent of the vport. - Made symbolic name writable so it can be set after creation - Made the temporary fc_vport_identifiers struct private to the transport. - Deleted the vport_id field from the vport. I couldn't find any good use for it (and symname is a good replacement). - Made the vport_state and vport_last_state "private" attributes. Added the fc_vport_set_state() helper function to manage state transitions - Updated vport_create() to allow a vport to be created in a disabled state. - Added INITIALIZING and FAILED vport states - Added VPCERR_xxx defines for errors to be returned from vport_create() - Created a Documentation/scsi/scsi_fc_transport.txt file that describes the interfaces and expected LLDD behaviors. Signed-off-by: James Smart Signed-off-by: James Bottomley --- include/scsi/scsi_transport_fc.h | 173 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 166 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 1e797308640a..81ea7b4bf81e 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -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 @@ enum fc_port_type { 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,6 +85,25 @@ enum fc_port_state { }; +/* + * 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 @@ -124,17 +145,114 @@ enum fc_tgtid_binding_type { }; /* - * 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; +} __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 * to uniquely identify a remote FC port. The driver uses this data @@ -149,6 +267,7 @@ struct fc_rport_identifiers { 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 = \ @@ -343,6 +462,7 @@ struct fc_host_attrs { 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 +481,11 @@ struct fc_host_attrs { /* 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 +511,8 @@ struct fc_host_attrs { (((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 +537,16 @@ struct fc_host_attrs { (((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,8 +583,14 @@ struct fc_function_template { 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 @@ -512,7 +649,7 @@ fc_remote_port_chkready(struct fc_rport *rport) 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 +686,27 @@ static inline void u64_to_wwn(u64 inm, u8 *wwn) 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 +725,6 @@ void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number, * 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 */ -- cgit v1.2.3 From 1dfcda06a67d6ad6f890dbd1bab84be5f17ef46d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 21 Mar 2007 16:05:16 +0900 Subject: [SCSI] kill scsi host template suspend/resume With libata converted to use sdev->manage_start_stop for suspend and resume, sht->suspend/resume() has no user left and low level suspend/ressume should be taken care of by low level driver's suspend/resume callbacks (e.g. PCI or PCMCIA driver callbacks). This patch removes sht->suspend/resume() callbacks. This change is suggested by Christoph Hellwig. Signed-off-by: Tejun Heo Cc: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/scsi_sysfs.c | 25 +++---------------------- include/scsi/scsi_host.h | 6 ------ 2 files changed, 3 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 67a38a1409ba..ed720863ab97 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -293,30 +293,18 @@ static int scsi_bus_suspend(struct device * dev, pm_message_t state) { 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 @@ static int scsi_bus_resume(struct device * dev) { 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; - - /* call host resume first */ - if (sht->resume) - err = sht->resume(sdev); + int err = 0; - /* 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/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 68f461b7a835..4a2e490abfed 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -338,12 +338,6 @@ struct scsi_host_template { */ 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 */ -- cgit v1.2.3 From 9ef3e4a4527e1f65b8776287c6d4fd1fca5ba98f Mon Sep 17 00:00:00 2001 From: James Smart Date: Thu, 24 May 2007 19:04:44 -0400 Subject: [SCSI] fc_transport: fix sysfs deadlock on vport delete When the vport attribute "delete" is used to delete the vport, sysfs deadlocks waiting for the write to complete, which is waiting for the sysfs teardown to complete. Moved this effort to a work_q element. Took the opportunity to make some other cosmetic changes: - removed tabs in Doc file - replaced with expanded spaces - minor copyright text and author text updates - removed a bunch of trailing whitespace Signed-off-by: James Smart Signed-off-by: James Bottomley --- Documentation/scsi/scsi_fc_transport.txt | 126 +++++++++++++++---------------- drivers/scsi/scsi_transport_fc.c | 59 +++++++++------ include/scsi/scsi_transport_fc.h | 13 ++-- 3 files changed, 105 insertions(+), 93 deletions(-) (limited to 'include') diff --git a/Documentation/scsi/scsi_fc_transport.txt b/Documentation/scsi/scsi_fc_transport.txt index ab057afc757f..d403e46d8463 100644 --- a/Documentation/scsi/scsi_fc_transport.txt +++ b/Documentation/scsi/scsi_fc_transport.txt @@ -119,67 +119,67 @@ Vport Attributes: The new fc_vport class object has the following attributes - node_name: Read_Only + node_name: Read_Only The WWNN of the vport - port_name: Read_Only + port_name: Read_Only The WWPN of the vport - roles: Read_Only + roles: Read_Only Indicates the FC4 roles enabled on the vport. - symbolic_name: Read_Write + 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 + vport_delete: Write_Only When written with a "1", will tear down the vport. - vport_disable: Write_Only + 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 + vport_last_state: Read_Only Indicates the previous state of the vport. See the section below on "Vport States". - vport_state: Read_Only + vport_state: Read_Only Indicates the state of the vport. See the section below on "Vport States". - vport_type: Read_Only + 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 + 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 + npiv_vports_inuse: Read_Only Indicates how many NPIV-based vports have been instantiated on the fc_host. - vport_create: Write_Only + vport_create: Write_Only A "simple" create interface to instantiate a vport on an fc_host. A ":" 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 + vport_delete: Write_Only A "simple" delete interface to teardown a vport. A ":" - 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). + 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: @@ -198,23 +198,23 @@ Vport States: 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 + 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 + FC_VPORT_ACTIVE - Active The vport has been successfully been created on the FC link. It is fully functional. - FC_VPORT_DISABLED - Disabled + 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 + FC_VPORT_LINKDOWN - Linkdown The vport is not operational as the physical link is not operational. - FC_VPORT_INITIALIZING - Initializing + 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 @@ -222,65 +222,65 @@ Vport States: (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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + Disable request Disable + Link goes down Linkdown Transport <-> LLDD Interfaces : @@ -303,9 +303,9 @@ Vport Creation: 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. + 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 @@ -342,7 +342,7 @@ Vport Creation: - 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. + 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 @@ -351,9 +351,9 @@ Vport Creation: 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. + - 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). @@ -376,9 +376,9 @@ Vport Disable/Enable: 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. + 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. @@ -404,7 +404,7 @@ Vport Deletion: int vport_delete(struct fc_vport *vport) where: - vport: Is vport to delete + 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 diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 217651468115..4953f0dca029 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. @@ -22,6 +22,7 @@ * 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 @@ -37,6 +38,7 @@ #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 @@ -377,7 +379,7 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, 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. @@ -1198,12 +1200,9 @@ store_fc_vport_delete(struct class_device *cdev, const char *buf, size_t count) { struct fc_vport *vport = transport_class_to_vport(cdev); - int stat; - - stat = fc_vport_terminate(vport); - if (stat) - return stat; + 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, @@ -1996,7 +1995,7 @@ fc_attach_transport(struct fc_function_template *ft) i->t.eh_timed_out = fc_timed_out; i->t.user_scan = fc_user_scan; - + /* * Setup SCSI Target Attributes. */ @@ -2215,23 +2214,12 @@ fc_remove_host(struct Scsi_Host *shost) struct workqueue_struct *work_q; struct fc_host_attrs *fc_host = shost_to_fc_host(shost); unsigned long flags; - int stat; spin_lock_irqsave(shost->host_lock, flags); /* Remove any vports */ - list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers) { - spin_unlock_irqrestore(shost->host_lock, flags); - /* this must be called synchronously */ - stat = fc_vport_terminate(vport); - spin_lock_irqsave(shost->host_lock, flags); - if (stat) - dev_printk(KERN_ERR, vport->dev.parent, - "%s: %s could not be deleted created via " - "shost%d channel %d\n", __FUNCTION__, - vport->dev.bus_id, vport->shost->host_no, - vport->channel); - } + 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, @@ -2308,7 +2296,7 @@ fc_rport_final_delete(struct work_struct *work) 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) @@ -2858,7 +2846,7 @@ EXPORT_SYMBOL(fc_remote_port_rolechg); * 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 @@ -3061,6 +3049,7 @@ fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev, 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); @@ -3207,8 +3196,30 @@ fc_vport_terminate(struct fc_vport *vport) } 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); +} + -MODULE_AUTHOR("Martin Hicks"); +/* Original Author: Martin Hicks */ +MODULE_AUTHOR("James Smart"); MODULE_DESCRIPTION("FC Transport Attributes"); MODULE_LICENSE("GPL"); diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 81ea7b4bf81e..a0d80bcaa93d 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. @@ -104,7 +104,7 @@ enum fc_vport_state { -/* +/* * 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, @@ -117,7 +117,7 @@ enum fc_vport_state { #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, @@ -223,6 +223,7 @@ struct fc_vport { 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: */ @@ -397,7 +398,7 @@ struct fc_host_statistics { 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; @@ -592,11 +593,11 @@ struct fc_function_template { 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 */ -- cgit v1.2.3 From 824d7b570b4dec49e868c251d670941b02a1e489 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sat, 26 May 2007 14:04:03 +0900 Subject: [SCSI] scsi_lib: add scatter/gather data buffer accessors This adds a set of accessors for the scsi data buffer. This is in preparation for chaining sg lists and bidirectional requests (and possibly, the mid-layer dma mapping). Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 38 ++++++++++++++++++++++++++++++++++++++ include/scsi/scsi_cmnd.h | 20 ++++++++++++++++++++ 2 files changed, 58 insertions(+) (limited to 'include') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 1f5a07bf2a75..70454b4e8485 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2290,3 +2290,41 @@ void scsi_kunmap_atomic_sg(void *virt) kunmap_atomic(virt, KM_BIO_SRC_IRQ); } EXPORT_SYMBOL(scsi_kunmap_atomic_sg); + +/** + * 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/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index a2e0c1032491..53e170586c26 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -135,4 +135,24 @@ extern void scsi_kunmap_atomic_sg(void *virt); 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 */ -- cgit v1.2.3 From bcd92c9fbcc679ee95003083056f0441a1f474fa Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 31 May 2007 20:12:26 +0200 Subject: [SCSI] introduce shost_priv helper Currently accessing the scsi host private data is rather messy because it comes as an unsigned long that always needs a cast first. This patch introduces a helper that does the cast called shost_priv. It's similar in spirit to netdev_priv for network drivers. This is the first patch introducing the macro, and the second patch in the series will convert esp and it's subdrivers as an example. Further conversion will wait until the helper is in the tree to make patch juggling easier. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- include/scsi/scsi_host.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 4a2e490abfed..ba07cf7c04ba 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -671,6 +671,10 @@ struct Scsi_Host { #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 *); -- cgit v1.2.3 From 1819dc8143eff2a5850af274bcf8bcbc3e73ec76 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:08 -0500 Subject: [SCSI] iscsi_transport: export hw address Add hw address sysfs file. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_iscsi.c | 35 +++++++++++++++++++++++++++++++++-- include/scsi/iscsi_if.h | 8 ++++++++ include/scsi/scsi_transport_iscsi.h | 5 ++++- 3 files changed, 45 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 4fbd8e1a0695..1ba98d255fac 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -32,7 +32,7 @@ #define ISCSI_SESSION_ATTRS 11 #define ISCSI_CONN_ATTRS 11 -#define ISCSI_HOST_ATTRS 0 +#define ISCSI_HOST_ATTRS 1 #define ISCSI_TRANSPORT_VERSION "2.0-724" struct iscsi_internal { @@ -1197,6 +1197,25 @@ static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \ 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(hwaddress, ISCSI_HOST_PARAM_HWADDRESS); + #define SETUP_PRIV_SESSION_RD_ATTR(field) \ do { \ priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \ @@ -1220,6 +1239,14 @@ do { \ } \ } 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) { @@ -1321,9 +1348,13 @@ iscsi_register_transport(struct iscsi_transport *tt) 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(hwaddress, ISCSI_HOST_HWADDRESS); + 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; diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 55ebf035e620..fba211743729 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -250,6 +250,14 @@ enum iscsi_param { #define ISCSI_CONN_PORT (1 << ISCSI_PARAM_CONN_PORT) #define ISCSI_CONN_ADDRESS (1 << ISCSI_PARAM_CONN_ADDRESS) +/* iSCSI HBA params */ +enum iscsi_host_param { + ISCSI_HOST_PARAM_HWADDRESS, + ISCSI_HOST_PARAM_MAX, +}; + +#define ISCSI_HOST_HWADDRESS (1 << ISCSI_HOST_PARAM_HWADDRESS) + #define iscsi_ptr(_handle) ((void*)(unsigned long)_handle) #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr) #define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata)) diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index d5c218ddc527..e962c5357eef 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -79,7 +79,8 @@ struct iscsi_transport { 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; @@ -105,6 +106,8 @@ struct iscsi_transport { 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 (*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, -- cgit v1.2.3 From 2174a04ee7d8304a270de183fbc58b36dd05b395 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:10 -0500 Subject: [SCSI] iscsi_transport, qla4xxx: have class lookup host for drivers We are going to be adding more host level sysfs attrs and set_params, so this patch has them take a scsi_host instead of either a scsi_host or host no. Signed-off-by: Mike Christie Cc: David C Somayajulu Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 19 ++++++------------- drivers/scsi/scsi_transport_iscsi.c | 17 ++++++++++++++--- include/scsi/scsi_transport_iscsi.h | 2 +- 3 files changed, 21 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 01308e7ef2ae..29cd4b90ebed 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -54,8 +54,9 @@ static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); /* * 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, @@ -243,21 +244,15 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, 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) { @@ -281,8 +276,6 @@ static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no, default: ret = -ENOSYS; } - - scsi_host_put(shost); return ret; } diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 1ba98d255fac..59287601bd41 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -945,15 +945,26 @@ static int 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 diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index e962c5357eef..902e69f0272c 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -127,7 +127,7 @@ struct iscsi_transport { 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); }; -- cgit v1.2.3 From 1d9bf13a9cf91f8faf221e98a64dd1157bcf5fa9 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:11 -0500 Subject: [SCSI] iscsi class: add iscsi host set param event The iscsi class uses the set_param event to set session and connection params. This patch adds a set_host_param so we can set host level values. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_iscsi.c | 29 ++++++++++++++++++++++++++++- include/scsi/iscsi_if.h | 6 ++++++ include/scsi/scsi_transport_iscsi.h | 3 +++ 3 files changed, 37 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 59287601bd41..3fd2da451fe1 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -967,6 +967,30 @@ iscsi_tgt_dscvr(struct iscsi_transport *transport, 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 iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { @@ -1058,8 +1082,11 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 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; } diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index fba211743729..3d0372e30ca1 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -48,6 +48,7 @@ enum iscsi_uevent_e { 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, @@ -136,6 +137,11 @@ struct iscsi_uevent { */ 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 */ diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 902e69f0272c..1ac450b06909 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -108,6 +108,9 @@ struct iscsi_transport { 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, -- cgit v1.2.3 From 0801c242a33426fddc005c2f559a3d2fa6fca7eb Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:12 -0500 Subject: [SCSI] libiscsi, iscsi_tcp, ib_iser : add sw iscsi host get/set params helpers iscsid and udev need to key off the hw address being used so add some helpers for iser and iscsi tcp. Also convert them Signed-off-by: Mike Christie Cc: Roland Dreier Signed-off-by: James Bottomley --- drivers/infiniband/ulp/iser/iscsi_iser.c | 4 ++++ drivers/scsi/iscsi_tcp.c | 4 ++++ drivers/scsi/libiscsi.c | 40 ++++++++++++++++++++++++++++++++ include/scsi/libiscsi.h | 13 ++++++++++- 4 files changed, 60 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index dd221eda3ea6..2a99b7b6c906 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -576,6 +576,7 @@ static struct iscsi_transport iscsi_iser_transport = { ISCSI_PERSISTENT_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT, + .host_param_mask = ISCSI_HOST_HWADDRESS, .host_template = &iscsi_iser_sht, .conndata_size = sizeof(struct iscsi_conn), .max_lun = ISCSI_ISER_MAX_LUN, @@ -592,6 +593,9 @@ static struct iscsi_transport iscsi_iser_transport = { .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/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index c9a3abf9e7b6..9a42fc074b76 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2181,6 +2181,7 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_PERSISTENT_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT, + .host_param_mask = ISCSI_HOST_HWADDRESS, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, @@ -2197,6 +2198,9 @@ static struct iscsi_transport iscsi_tcp_transport = { .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_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/libiscsi.c b/drivers/scsi/libiscsi.c index 3f5b9b445b29..d430e227e9b7 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1462,6 +1462,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) iscsi_pool_free(&session->cmdpool, (void**)session->cmds); kfree(session->targetname); + kfree(session->hwaddress); iscsi_destroy_session(cls_session); scsi_host_put(shost); @@ -1990,6 +1991,45 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, } 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_HWADDRESS: + if (!session->hwaddress) + len = sprintf(buf, "%s\n", "default"); + else + len = sprintf(buf, "%s\n", session->hwaddress); + 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_HWADDRESS: + if (!session->hwaddress) + session->hwaddress = 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/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index ea0816d4904d..e202cc00c8e7 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -224,7 +224,8 @@ struct iscsi_session { int erl; int tpgt; char *targetname; - + /* hw address being used for iscsi connection */ + char *hwaddress; /* control data */ struct iscsi_transport *tt; struct Scsi_Host *host; @@ -255,6 +256,16 @@ extern int iscsi_eh_host_reset(struct scsi_cmnd *sc); 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 */ -- cgit v1.2.3 From 8ad5781ae9702a8f95cfdf30967752e4297613ee Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:13 -0500 Subject: [SCSI] iscsi class, qla4xxx, iscsi_tcp, ib_iser: export/set initiator name For iscsi root boot, software iscsi needs to know what the BIOS/OF initiator used for the initiator name so this puts it in sysfs for userspace to be able to pick up. For hw iscsi, it is nice to see what the card is using. This patch adds the new param, and hooks in qla4xxx, iscsi_tcp, and ib_iser. Signed-off-by: Mike Christie Cc: Roland Dreier Cc: David C Somayajulu Signed-off-by: James Bottomley --- drivers/infiniband/ulp/iser/iscsi_iser.c | 3 ++- drivers/scsi/iscsi_tcp.c | 3 ++- drivers/scsi/libiscsi.c | 12 ++++++++++++ drivers/scsi/qla4xxx/ql4_os.c | 6 +++++- drivers/scsi/scsi_transport_iscsi.c | 4 +++- include/scsi/iscsi_if.h | 2 ++ include/scsi/libiscsi.h | 1 + 7 files changed, 27 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 2a99b7b6c906..e39d9a07bc5d 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -576,7 +576,8 @@ static struct iscsi_transport iscsi_iser_transport = { ISCSI_PERSISTENT_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT, - .host_param_mask = ISCSI_HOST_HWADDRESS, + .host_param_mask = ISCSI_HOST_HWADDRESS | + ISCSI_HOST_INITIATOR_NAME, .host_template = &iscsi_iser_sht, .conndata_size = sizeof(struct iscsi_conn), .max_lun = ISCSI_ISER_MAX_LUN, diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 9a42fc074b76..8201e6c4d8a9 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2181,7 +2181,8 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_PERSISTENT_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT, - .host_param_mask = ISCSI_HOST_HWADDRESS, + .host_param_mask = ISCSI_HOST_HWADDRESS | + ISCSI_HOST_INITIATOR_NAME, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index d430e227e9b7..5e6a42429c39 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1463,6 +1463,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) kfree(session->targetname); kfree(session->hwaddress); + kfree(session->initiatorname); iscsi_destroy_session(cls_session); scsi_host_put(shost); @@ -2004,6 +2005,13 @@ int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, 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; } @@ -2022,6 +2030,10 @@ int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param, 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; } diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 29cd4b90ebed..7502bb4808d6 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -104,7 +104,8 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { .name = DRIVER_NAME, .param_mask = ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT, - .host_param_mask = ISCSI_HOST_HWADDRESS, + .host_param_mask = ISCSI_HOST_HWADDRESS | + ISCSI_HOST_INITIATOR_NAME, .sessiondata_size = sizeof(struct ddb_entry), .host_template = &qla4xxx_driver_template, @@ -190,6 +191,9 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost, case ISCSI_HOST_PARAM_HWADDRESS: len = format_addr(buf, ha->my_mac, MAC_ADDR_LEN); break; + case ISCSI_HOST_PARAM_INITIATOR_NAME: + len = sprintf(buf, ha->name_string); + break; default: return -ENOSYS; } diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 3fd2da451fe1..5ec2fbea8937 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -32,7 +32,7 @@ #define ISCSI_SESSION_ATTRS 11 #define ISCSI_CONN_ATTRS 11 -#define ISCSI_HOST_ATTRS 1 +#define ISCSI_HOST_ATTRS 2 #define ISCSI_TRANSPORT_VERSION "2.0-724" struct iscsi_internal { @@ -1253,6 +1253,7 @@ static ISCSI_CLASS_ATTR(host, field, S_IRUGO, show_host_param_##param, \ NULL); iscsi_host_attr(hwaddress, ISCSI_HOST_PARAM_HWADDRESS); +iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME); #define SETUP_PRIV_SESSION_RD_ATTR(field) \ do { \ @@ -1389,6 +1390,7 @@ iscsi_register_transport(struct iscsi_transport *tt) transport_container_register(&priv->t.host_attrs); 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; diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 3d0372e30ca1..e057c5d3703d 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -259,10 +259,12 @@ enum iscsi_param { /* iSCSI HBA params */ enum iscsi_host_param { ISCSI_HOST_PARAM_HWADDRESS, + ISCSI_HOST_PARAM_INITIATOR_NAME, 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_ptr(_handle) ((void*)(unsigned long)_handle) #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr) diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index e202cc00c8e7..deae90a56a0d 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -224,6 +224,7 @@ struct iscsi_session { int erl; int tpgt; char *targetname; + char *initiatorname; /* hw address being used for iscsi connection */ char *hwaddress; /* control data */ -- cgit v1.2.3 From d473cc7f15f64ab8a90c3d7288ef30f46785d8d5 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:14 -0500 Subject: [SCSI] iscsi: Some fixes in preparation for bidirectional support - exp_datasn This patch fixes handling of expected datasn/r2tsn as received from target. It is done according to: T10 rfc3720 section 3.2.2.3. Data Sequencing. . unify expected datasn/r2tsn into one counter . calculate than check expected datasn/r2tsn. On error print a message and fail the request. (TODO use iscsi retransmits) . remove the FIXME ;) . avoid zero length memset Signed-off-by: Boaz Harrosh Signed-off-by: Benny Halevy Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 18 +++++++++++------- drivers/scsi/iscsi_tcp.h | 2 +- drivers/scsi/libiscsi.c | 5 +++-- include/scsi/libiscsi.h | 1 - 4 files changed, 15 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 8201e6c4d8a9..17fc79c408a2 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -229,10 +229,13 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) 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) @@ -365,15 +368,16 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) 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); if (!ctask->sc || ctask->mtask || @@ -414,7 +418,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) 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; list_move_tail(&ctask->running, &conn->xmitqueue); @@ -1284,10 +1288,10 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) tcp_ctask->sent = 0; tcp_ctask->sg_count = 0; + tcp_ctask->exp_datasn = 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) { diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index 32736831790e..f909edbf61ee 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -152,7 +152,7 @@ struct iscsi_tcp_cmd_task { 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/libiscsi.c b/drivers/scsi/libiscsi.c index 5e6a42429c39..eb5113607958 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -120,7 +120,9 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) 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; if (sc->sc_data_direction == DMA_TO_DEVICE) { @@ -165,7 +167,6 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) /* 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); diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index deae90a56a0d..61e069206ac5 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -99,7 +99,6 @@ struct iscsi_cmd_task { */ struct iscsi_cmd *hdr; int itt; /* this ITT */ - int datasn; /* DataSN */ uint32_t unsol_datasn; int imm_count; /* imm-data (bytes) */ -- cgit v1.2.3 From 857ae0bdb72999936a28ce621e38e2e288c485da Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:15 -0500 Subject: [SCSI] iscsi: Some fixes in preparation for bidirectional support - total_length - Remove shadow of request length from struct iscsi_cmd_task. - change all users to use scsi_cmnd->request_bufflen directly (With bidi we will use scsi-ml API to retrieve in/out length) Signed-off-by: Boaz Harrosh Signed-off-by: Benny Halevy Signed-off-by: Mike Christie Cc: Roland Dreier Signed-off-by: James Bottomley --- drivers/infiniband/ulp/iser/iscsi_iser.c | 4 ++-- drivers/scsi/iscsi_tcp.c | 21 ++++++++++++--------- drivers/scsi/libiscsi.c | 9 ++++----- include/scsi/libiscsi.h | 21 ++++++++++----------- 4 files changed, 28 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index e39d9a07bc5d..568f88bf7c91 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -140,10 +140,10 @@ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask) iser_ctask->iser_conn = iser_conn; if (sc->sc_data_direction == DMA_TO_DEVICE) { - BUG_ON(ctask->total_length == 0); + BUG_ON(sc->request_bufflen == 0); debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n", - ctask->itt, ctask->total_length, ctask->imm_count, + ctask->itt, sc->request_bufflen, ctask->imm_count, ctask->unsol_count); } diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 17fc79c408a2..b2827d112cb0 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -216,6 +216,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) 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); @@ -238,12 +239,14 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) 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 > sc->request_bufflen) { + debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n", + __FUNCTION__, tcp_ctask->data_offset, + tcp_conn->in.datalen, sc->request_bufflen); 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); @@ -405,11 +408,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) 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 > ctask->sc->request_bufflen) { 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, ctask->sc->request_bufflen); return ISCSI_ERR_DATALEN; } @@ -604,7 +607,7 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask, { 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); @@ -613,7 +616,7 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask, 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 > ctask->sc->request_bufflen); rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset, (char*)buf + (offset + tcp_conn->data_copied), size); @@ -1292,7 +1295,7 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) if (sc->sc_data_direction == DMA_TO_DEVICE) { tcp_ctask->xmstate = XMSTATE_W_HDR; - BUG_ON(ctask->total_length == 0); + BUG_ON(sc->request_bufflen == 0); if (sc->use_sg) { struct scatterlist *sg = sc->request_buffer; @@ -1309,7 +1312,7 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) } 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->itt, sc->request_bufflen, ctask->imm_count, ctask->unsol_count, ctask->unsol_offset); } else tcp_ctask->xmstate = XMSTATE_R_HDR; diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index eb5113607958..0a9c64e9ce8b 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -147,19 +147,19 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) ctask->unsol_datasn = 0; if (session->imm_data_en) { - if (ctask->total_length >= session->first_burst) + if (sc->request_bufflen >= 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(sc->request_bufflen, 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), + (sc->request_bufflen)) - ctask->imm_count; ctask->unsol_offset = ctask->imm_count; } @@ -815,7 +815,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) 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); diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 61e069206ac5..348265d4a27e 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -80,7 +80,7 @@ struct iscsi_mgmt_task { */ 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; @@ -101,13 +101,12 @@ struct iscsi_cmd_task { int itt; /* this ITT */ 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 */ @@ -173,8 +172,8 @@ struct iscsi_conn { 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; @@ -212,10 +211,10 @@ struct iscsi_session { /* 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; -- cgit v1.2.3 From b2c6416736b847b91950bd43cc5153e11a1f83ee Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:16 -0500 Subject: [SCSI] iscsi class, iscsi_tcp, ib_iser: add sysfs chap file The attached patches add sysfs files for the chap settings to the iscsi transport class, iscsi_tcp and ib_iser. This is needed for software iscsi because there are times when iscsid can die and it will need to reread the values it was using. And it is needed by qla4xxx for basic management opertaions. This patch does not hook in qla4xxx yet, because I am not sure the mbx command to use. Signed-off-by: Mike Christie Cc: Roland Dreier Signed-off-by: James Bottomley --- drivers/infiniband/ulp/iser/iscsi_iser.c | 5 ++-- drivers/scsi/iscsi_tcp.c | 5 ++-- drivers/scsi/libiscsi.c | 40 ++++++++++++++++++++++++++++++++ drivers/scsi/scsi_transport_iscsi.c | 39 ++++++++++++++++++++----------- include/scsi/iscsi_if.h | 9 +++++++ include/scsi/libiscsi.h | 4 ++++ 6 files changed, 84 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 568f88bf7c91..6c8cd09c58f0 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -574,8 +574,9 @@ static struct iscsi_transport iscsi_iser_transport = { 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_INITIATOR_NAME, .host_template = &iscsi_iser_sht, diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index b2827d112cb0..1e722f5aabd4 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2186,8 +2186,9 @@ static struct iscsi_transport iscsi_tcp_transport = { 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_INITIATOR_NAME, .host_template = &iscsi_sht, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 0a9c64e9ce8b..63981edf9ab9 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1461,6 +1461,10 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) 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->hwaddress); kfree(session->initiatorname); @@ -1869,6 +1873,30 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, 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) @@ -1942,6 +1970,18 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, 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; } diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 5ec2fbea8937..341d4fb5c6f8 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -30,7 +30,7 @@ #include #include -#define ISCSI_SESSION_ATTRS 11 +#define ISCSI_SESSION_ATTRS 15 #define ISCSI_CONN_ATTRS 11 #define ISCSI_HOST_ATTRS 2 #define ISCSI_TRANSPORT_VERSION "2.0-724" @@ -1196,30 +1196,37 @@ iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS); /* * 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 \ @@ -1433,6 +1440,10 @@ iscsi_register_transport(struct iscsi_transport *tt) 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/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index e057c5d3703d..1a18196d77f6 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -229,6 +229,11 @@ enum iscsi_param { 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, }; @@ -255,6 +260,10 @@ enum iscsi_param { #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 { diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 348265d4a27e..61bc8f75b267 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -221,6 +221,10 @@ struct iscsi_session { int dataseq_inorder_en; int erl; int tpgt; + char *username; + char *username_in; + char *password; + char *password_in; char *targetname; char *initiatorname; /* hw address being used for iscsi connection */ -- cgit v1.2.3 From 77a23c21aaa723f6b0ffc4a701be8c8e5a32346d Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:18 -0500 Subject: [SCSI] libiscsi: fix iscsi cmdsn allocation The cmdsn allocation and pdu transmit code can race, and we can end up sending a pdu with cmdsn 10 before a pdu with 5. The target will then fail the connection/session. This patch fixes the problem by delaying the cmdsn allocation until we are about to send the pdu. This also removes the xmitmutex. We were using the connection xmitmutex during error handling to handle races with mtask and ctask cleanup and completion. For ctasks we now have nice refcounting and for the mtask, if we hit the case where the mtask timesout and it is floating around somewhere in the driver, we end up dropping the session. And to handle session level cleanup, we use the xmit suspend bit along with scsi_flush_queue and the session lock to make sure that the xmit thread is not possibly transmitting a task while we are trying to kill it. Signed-off-by: Mike Christie Cc: Roland Dreier Signed-off-by: James Bottomley --- drivers/infiniband/ulp/iser/iscsi_iser.c | 18 +- drivers/scsi/iscsi_tcp.c | 33 +-- drivers/scsi/libiscsi.c | 491 +++++++++++++++---------------- include/scsi/libiscsi.h | 11 +- include/scsi/scsi_transport_iscsi.h | 3 +- 5 files changed, 250 insertions(+), 306 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 6c8cd09c58f0..9782190a9ee5 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -134,19 +134,9 @@ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask) { 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(sc->request_bufflen == 0); - - debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n", - ctask->itt, sc->request_bufflen, ctask->imm_count, - ctask->unsol_count); - } - iser_ctask_rdma_init(iser_ctask); } @@ -219,6 +209,14 @@ iscsi_iser_ctask_xmit(struct iscsi_conn *conn, struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; int error = 0; + if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) { + BUG_ON(ctask->sc->request_bufflen == 0); + + debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n", + ctask->itt, ctask->sc->request_bufflen, + ctask->imm_count, ctask->unsol_count); + } + debug_scsi("ctask deq [cid %d itt 0x%x]\n", conn->id, ctask->itt); diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 0afdca2224c2..8edcfddc0baf 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -211,7 +210,6 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) 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; @@ -219,9 +217,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) 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..) */ @@ -377,12 +373,10 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) return ISCSI_ERR_R2TSN; } - rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); - if (rc) - return rc; - /* 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 " @@ -1762,12 +1756,6 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) 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) - return rc; - rc = iscsi_send_cmd_hdr(conn, ctask); if (rc) return rc; @@ -1949,8 +1937,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, /* 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; tcp_mtask->xmstate = XMSTATE_IMM_HDR_INIT; @@ -2073,22 +2060,15 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, switch(param) { case ISCSI_PARAM_CONN_PORT: - mutex_lock(&conn->xmitmutex); - if (!tcp_conn->sock) { - mutex_unlock(&conn->xmitmutex); + if (!tcp_conn->sock) return -EINVAL; - } inet = inet_sk(tcp_conn->sock->sk); len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport)); - mutex_unlock(&conn->xmitmutex); break; case ISCSI_PARAM_CONN_ADDRESS: - mutex_lock(&conn->xmitmutex); - if (!tcp_conn->sock) { - mutex_unlock(&conn->xmitmutex); + if (!tcp_conn->sock) return -EINVAL; - } sk = tcp_conn->sock->sk; if (sk->sk_family == PF_INET) { @@ -2099,7 +2079,6 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, np = inet6_sk(sk); len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr)); } - mutex_unlock(&conn->xmitmutex); break; default: return iscsi_conn_get_param(cls_conn, param, buf); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 63f0a15d9887..938f527cd81a 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 -#include #include #include #include @@ -46,27 +45,53 @@ class_to_transport_session(struct iscsi_cls_session *cls_session) } 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) @@ -175,8 +200,13 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) } 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, sc->request_bufflen, + 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 @@ -205,26 +235,12 @@ static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask) 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 @@ -236,21 +252,15 @@ static void iscsi_put_ctask(struct iscsi_cmd_task *ctask) * 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; @@ -302,7 +312,6 @@ out: conn->scsirsp_pdus_cnt++; __iscsi_put_ctask(ctask); - return rc; } static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) @@ -382,8 +391,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 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); @@ -406,11 +415,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 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) { @@ -459,10 +464,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 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: @@ -492,7 +494,6 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } else rc = ISCSI_ERR_BAD_ITT; -done: return rc; } EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); @@ -579,17 +580,47 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) } 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; @@ -603,6 +634,45 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn) 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 @@ -614,106 +684,79 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn) **/ 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; } @@ -725,11 +768,9 @@ static void iscsi_xmitworker(struct work_struct *work) /* * 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 { @@ -787,20 +828,23 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) 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; @@ -815,17 +859,8 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) ctask->conn = conn; ctask->sc = sc; INIT_LIST_HEAD(&ctask->running); - 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); @@ -856,19 +891,16 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) } 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 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 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 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 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; - - mutex_lock(&conn->xmitmutex); - rc = iscsi_conn_send_generic(conn, hdr, data, data_size); - mutex_unlock(&conn->xmitmutex); + struct iscsi_session *session = conn->session; + int err = 0; - 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 @@ static void iscsi_tmabort_timedout(unsigned long data) 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 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, 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 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, 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 @@ static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) 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 @@ static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) } /* - * 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 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, 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; + if (conn->ctask == ctask) + conn->ctask = NULL; /* release ref from queuecommand */ __iscsi_put_ctask(ctask); } @@ -1179,7 +1175,6 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) 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 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) /* 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 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) 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 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) 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; } @@ -1505,11 +1496,6 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) 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)) @@ -1533,7 +1519,6 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) conn->login_mtask->data = conn->data = data; init_timer(&conn->tmabort_timer); - mutex_init(&conn->xmitmutex); init_waitqueue_head(&conn->ehwait); return cls_conn; @@ -1544,8 +1529,6 @@ login_mtask_data_alloc_fail: 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; } @@ -1564,10 +1547,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) 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) { /* @@ -1578,8 +1559,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) } spin_unlock_bh(&session->lock); - mutex_unlock(&conn->xmitmutex); - /* * Block until all in-progress commands for this connection * time out or fail. @@ -1616,7 +1595,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) } spin_unlock_bh(&session->lock); - kfifo_free(conn->immqueue); kfifo_free(conn->mgmtqueue); iscsi_destroy_conn(cls_conn); @@ -1677,8 +1655,7 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) 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); @@ -1748,12 +1725,12 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, 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 @@ -1777,8 +1754,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, 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) diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 61bc8f75b267..8d48cf8f2e3f 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -90,6 +90,7 @@ enum { ISCSI_TASK_COMPLETED, ISCSI_TASK_PENDING, ISCSI_TASK_RUNNING, + ISCSI_TASK_ABORTING, }; struct iscsi_cmd_task { @@ -150,18 +151,11 @@ struct iscsi_conn { 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 */ @@ -303,8 +297,7 @@ extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, /* * 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_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 1ac450b06909..abc4068621d8 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -117,8 +117,7 @@ struct iscsi_transport { 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, -- cgit v1.2.3 From 1548271ece9e9312fd5feb41fd58773b56a71d39 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:19 -0500 Subject: [SCSI] libiscsi: make can_queue configurable This patch allows us to set can_queue and cmds_per_lun from userspace when we create the session/host. From there we can set it on a per target basis. The patch fully converts iscsi_tcp, but only hooks up ib_iser for cmd_per_lun since it currently has a lots of preallocations based on can_queue. Signed-off-by: Mike Christie Cc: Roland Dreier Signed-off-by: James Bottomley --- drivers/infiniband/ulp/iser/iscsi_iser.c | 11 +++++++++-- drivers/infiniband/ulp/iser/iscsi_iser.h | 4 ++-- drivers/infiniband/ulp/iser/iser_verbs.c | 4 ++-- drivers/scsi/iscsi_tcp.c | 5 +++-- drivers/scsi/libiscsi.c | 28 +++++++++++++++++++++++++++- drivers/scsi/scsi_transport_iscsi.c | 2 ++ include/scsi/iscsi_if.h | 2 ++ include/scsi/libiscsi.h | 7 +++---- include/scsi/scsi_transport_iscsi.h | 3 ++- 9 files changed, 52 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 9782190a9ee5..bed583c426e6 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -373,7 +373,8 @@ static struct iscsi_transport iscsi_iser_transport; 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; @@ -384,7 +385,13 @@ iscsi_iser_session_create(struct iscsi_transport *iscsit, 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); @@ -543,7 +550,7 @@ iscsi_iser_ep_disconnect(__u64 ep_handle) 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, diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 8960196ffb0f..e2353701e8bb 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_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 3702e2375553..2044de1164ac 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -155,8 +155,8 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn) 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/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 8edcfddc0baf..eca4d611dd49 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2114,6 +2114,7 @@ iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) 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; @@ -2121,7 +2122,7 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit, 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); @@ -2164,7 +2165,7 @@ 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, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 938f527cd81a..1632866f52cc 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1330,6 +1330,10 @@ EXPORT_SYMBOL_GPL(iscsi_pool_free); * 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 * @@ -1339,6 +1343,7 @@ EXPORT_SYMBOL_GPL(iscsi_pool_free); 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) { @@ -1347,11 +1352,32 @@ iscsi_session_setup(struct iscsi_transport *iscsit, 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; @@ -1365,7 +1391,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, 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; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 341d4fb5c6f8..859bd2100856 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -814,6 +814,8 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) 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) diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 1a18196d77f6..a046a329189c 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -72,6 +72,8 @@ struct iscsi_uevent { /* 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; diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 8d48cf8f2e3f..2f303a3b270e 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -48,9 +48,8 @@ struct iscsi_nopin; #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 @@ -268,7 +267,7 @@ extern int iscsi_host_get_param(struct Scsi_Host *shost, */ 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 *); diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index abc4068621d8..706c0cd36c14 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -90,7 +90,8 @@ struct iscsi_transport { 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); -- cgit v1.2.3 From 0ab823db869f1c9454c5b031a9b8f8812ccd0aa7 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:22 -0500 Subject: [SCSI] qla4xxx: add iscsi_transport capps for fw capacilities Userspace will want to know what the driver/FW/HW capabilites when it comes to some operations like if the hardware can do discovery or if it can store iscsi info like what target was used for boot. This patch adds some new caps so userspace can tell if the driver supports hardware/fw based sendtargets discovery and if the hardware has some flash which may be holding or can contain some iscsi target info . Signed-off-by: Mike Christie Cc: David C Somayajulu Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 1 + include/scsi/iscsi_if.h | 2 ++ 2 files changed, 3 insertions(+) (limited to 'include') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 7502bb4808d6..315ab691056f 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -102,6 +102,7 @@ static struct scsi_host_template qla4xxx_driver_template = { static struct iscsi_transport qla4xxx_iscsi_transport = { .owner = THIS_MODULE, .name = DRIVER_NAME, + .caps = CAP_FW_DB | CAP_SENDTARGETS_OFFLOAD, .param_mask = ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT, .host_param_mask = ISCSI_HOST_HWADDRESS | diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index a046a329189c..81a542506dfe 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -299,6 +299,8 @@ enum iscsi_host_param { #define CAP_MULTI_CONN 0x40 #define CAP_TEXT_NEGO 0x80 #define CAP_MARKERS 0x100 +#define CAP_FW_DB 0x200 +#define CAP_SENDTARGETS_OFFLOAD 0x400 /* * These flags describes reason of stop_conn() call -- cgit v1.2.3 From 2223696192c687f2853e42b7c1e0d3ef002081fd Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:24 -0500 Subject: [SCSI] iscsi class, qla4xxx, iscsi_tcp: export local address This patch exports the local address for the session. For qla4xxx this is the ip of the hba's port. For software this is the src addr of the socket. Signed-off-by: Mike Christie Cc: David C Somayajulu Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 127 ++++++++++++++++++++++++++++-------- drivers/scsi/qla4xxx/ql4_os.c | 8 ++- drivers/scsi/scsi_transport_iscsi.c | 4 +- include/scsi/iscsi_if.h | 2 + include/scsi/libiscsi.h | 8 +++ 5 files changed, 118 insertions(+), 31 deletions(-) (limited to 'include') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 7ce177e30a53..da66fb524b5b 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1870,18 +1870,22 @@ tcp_conn_alloc_fail: 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); - sockfd_put(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 @@ -1912,6 +1916,46 @@ iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) 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, @@ -1929,10 +1973,24 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, 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; @@ -1956,8 +2014,11 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, * 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 */ @@ -2077,33 +2138,18 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, 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: - if (!tcp_conn->sock) - return -EINVAL; - - inet = inet_sk(tcp_conn->sock->sk); - len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport)); + 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: - if (!tcp_conn->sock) - 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)); - } + 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); @@ -2112,6 +2158,29 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, 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) { @@ -2233,7 +2302,7 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_TARGET_NAME | ISCSI_TPGT | ISCSI_USERNAME | ISCSI_PASSWORD | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN, - .host_param_mask = ISCSI_HOST_HWADDRESS | + .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | ISCSI_HOST_INITIATOR_NAME, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), @@ -2252,7 +2321,7 @@ static struct iscsi_transport iscsi_tcp_transport = { .start_conn = iscsi_conn_start, .stop_conn = iscsi_tcp_conn_stop, /* iscsi host params */ - .get_host_param = iscsi_host_get_param, + .get_host_param = iscsi_tcp_host_get_param, .set_host_param = iscsi_host_set_param, /* IO */ .send_pdu = iscsi_conn_send_pdu, diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 315ab691056f..b87b460832ea 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -106,6 +106,7 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { .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, @@ -192,8 +193,13 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost, 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, ha->name_string); + len = sprintf(buf, "%s\n", ha->name_string); break; default: return -ENOSYS; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 859bd2100856..9b54eea20560 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -32,7 +32,7 @@ #define ISCSI_SESSION_ATTRS 15 #define ISCSI_CONN_ATTRS 11 -#define ISCSI_HOST_ATTRS 2 +#define ISCSI_HOST_ATTRS 3 #define ISCSI_TRANSPORT_VERSION "2.0-724" struct iscsi_internal { @@ -1261,6 +1261,7 @@ show_host_param_##param(struct class_device *cdev, char *buf) \ static ISCSI_CLASS_ATTR(host, field, S_IRUGO, show_host_param_##param, \ NULL); +iscsi_host_attr(ipaddress, ISCSI_HOST_PARAM_IPADDRESS); iscsi_host_attr(hwaddress, ISCSI_HOST_PARAM_HWADDRESS); iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME); @@ -1398,6 +1399,7 @@ iscsi_register_transport(struct iscsi_transport *tt) priv->t.host_size = sizeof(struct iscsi_host); transport_container_register(&priv->t.host_attrs); + 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); diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 81a542506dfe..642998069e00 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -271,11 +271,13 @@ enum iscsi_param { enum iscsi_host_param { ISCSI_HOST_PARAM_HWADDRESS, ISCSI_HOST_PARAM_INITIATOR_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_IPADDRESS (1 << ISCSI_HOST_PARAM_IPADDRESS) #define iscsi_ptr(_handle) ((void*)(unsigned long)_handle) #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr) diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 2f303a3b270e..eea33f7b1544 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -72,6 +72,8 @@ struct iscsi_nopin; #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 @@ -174,6 +176,12 @@ struct iscsi_conn { /* 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; -- cgit v1.2.3 From d8196ed2181b4595eaf464a5bcbddb6c28649a39 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:25 -0500 Subject: [SCSI] iscsi class, iscsi_tcp, iser, qla4xxx: add netdevname sysfs attr iSCSI must support software iscsi (iscsi_tcp, iser), hardware iscsi (qla4xxx), and partial offload (broadcom). To be able to allow each stack or driver or port (virtual or physical) to be able to log into the same target portal we use the initiator tuple [[HWADDRESS | NETDEVNAME], INITIATOR_NAME] and the target tuple [TARGETNAME, CONN_ADDRESS, CONN_PORT] to id a session. This patch adds the netdev name, which is used by software iscsi when it binds a session to a netdevice using the SO_BINDTODEVICE sock opt. It cannot use HWADDRESS because if someone did vlans then the same netdevice will have the same mac and the initiator,target id will not be unique. Signed-off-by: Mike Christie Cc: Roland Dreier Cc: David C Somayajulu Signed-off-by: James Bottomley --- drivers/infiniband/ulp/iser/iscsi_iser.c | 1 + drivers/scsi/iscsi_tcp.c | 3 ++- drivers/scsi/libiscsi.c | 11 +++++++++++ drivers/scsi/qla4xxx/ql4_os.c | 3 ++- drivers/scsi/scsi_transport_iscsi.c | 6 ++++-- include/scsi/iscsi_if.h | 3 +++ include/scsi/libiscsi.h | 3 ++- 7 files changed, 25 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index bed583c426e6..1bf173decade 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -583,6 +583,7 @@ static struct iscsi_transport iscsi_iser_transport = { 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), diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index da66fb524b5b..d5a6527b3b3d 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2303,7 +2303,8 @@ static struct iscsi_transport iscsi_tcp_transport = { 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_INITIATOR_NAME | + ISCSI_HOST_NETDEV_NAME, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 1632866f52cc..865dd5739f0e 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1483,6 +1483,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) kfree(session->username); kfree(session->username_in); kfree(session->targetname); + kfree(session->netdev); kfree(session->hwaddress); kfree(session->initiatorname); @@ -2040,6 +2041,12 @@ int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, 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"); @@ -2067,6 +2074,10 @@ int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param, 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); diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index b87b460832ea..e69160a7bc60 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -102,7 +102,8 @@ static struct scsi_host_template qla4xxx_driver_template = { static struct iscsi_transport qla4xxx_iscsi_transport = { .owner = THIS_MODULE, .name = DRIVER_NAME, - .caps = CAP_FW_DB | CAP_SENDTARGETS_OFFLOAD, + .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 | diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 9b54eea20560..34c1860a259d 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -32,7 +32,7 @@ #define ISCSI_SESSION_ATTRS 15 #define ISCSI_CONN_ATTRS 11 -#define ISCSI_HOST_ATTRS 3 +#define ISCSI_HOST_ATTRS 4 #define ISCSI_TRANSPORT_VERSION "2.0-724" struct iscsi_internal { @@ -1261,8 +1261,9 @@ show_host_param_##param(struct class_device *cdev, char *buf) \ static ISCSI_CLASS_ATTR(host, field, S_IRUGO, show_host_param_##param, \ NULL); -iscsi_host_attr(ipaddress, ISCSI_HOST_PARAM_IPADDRESS); +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) \ @@ -1399,6 +1400,7 @@ iscsi_register_transport(struct iscsi_transport *tt) priv->t.host_size = sizeof(struct iscsi_host); 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); diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 642998069e00..50e907f42048 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -271,12 +271,14 @@ enum iscsi_param { 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) @@ -303,6 +305,7 @@ enum iscsi_host_param { #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 eea33f7b1544..3f631b08a1ab 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -228,8 +228,9 @@ struct iscsi_session { char *password_in; char *targetname; char *initiatorname; - /* hw address being used for iscsi connection */ + /* hw address or netdev iscsi connection is bound to */ char *hwaddress; + char *netdev; /* control data */ struct iscsi_transport *tt; struct Scsi_Host *host; -- cgit v1.2.3 From 462b7859a07c9c2b060fa2b5b1d49f8b33706d4e Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 19 Jun 2007 10:25:30 +0200 Subject: [SCSI] zfcp: Report FCP LUN to SCSI midlayer When reporting SCSI devices to the SCSI midlayer, use the FCP LUN as LUN reported to the SCSI layer. With this approach, zfcp does not have to create unique LUNS, and this code can be removed. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 20 +++----------------- drivers/scsi/scsi_scan.c | 3 ++- include/scsi/scsi_device.h | 1 + 3 files changed, 6 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 821cde65e369..a1db95925138 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -815,9 +815,7 @@ zfcp_get_adapter_by_busid(char *bus_id) 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_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) } 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/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index a67f315244d7..5df28e2fd3bb 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1204,7 +1204,7 @@ static void scsi_sequential_lun_scan(struct scsi_target *starget, * 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; @@ -1215,6 +1215,7 @@ static int scsilun_to_int(struct scsi_lun *scsilun) 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/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 2f3c5b8b1d6a..6fe1cf672d77 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -287,6 +287,7 @@ extern void scsi_target_block(struct device *); 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 *); -- cgit v1.2.3 From d0f656cad313bb04a151273bb57e108b2cc9876f Mon Sep 17 00:00:00 2001 From: Priyanka Gupta Date: Tue, 19 Jun 2007 14:02:10 -0700 Subject: [SCSI] Remove unused method scsi_device_cancel Removes an obsolete method scsi_device_cancel which isn't being used anywhere in the kernel. Signed-off-by: Priyanka Gupta Acked-by: Grant Grundler Signed-off-by: James Bottomley --- drivers/scsi/scsi.c | 46 ---------------------------------------------- include/scsi/scsi_device.h | 1 - 2 files changed, 47 deletions(-) (limited to 'include') diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 4c1e31334765..64c8595ee712 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1016,52 +1016,6 @@ struct scsi_device *scsi_device_lookup(struct Scsi_Host *shost, } 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/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 6fe1cf672d77..d5057bc338ff 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -209,7 +209,6 @@ extern struct scsi_device *__scsi_add_device(struct Scsi_Host *, 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 *); -- cgit v1.2.3