be2iscsi: Enabling MSIX and mcc_rings V2
Subsystems (2)
PATCH 1/1 be2iscsi: Enabling MSIX and mcc_rings V2
This patch
1) Turns on msix
2) Adds mcc_ring support for sending FW commands
3) Adds Support for Ring Mode of WRB Posting
4) Adds sysfs for FW commands
--- drivers/scsi/be2iscsi/be.h | 24 +- drivers/scsi/be2iscsi/be_cmds.c | 254 +++++++++-- drivers/scsi/be2iscsi/be_cmds.h | 35 ++- drivers/scsi/be2iscsi/be_iscsi.c | 16 +- drivers/scsi/be2iscsi/be_main.c | 1027 ++++++++++++++++++++++++++++++-------- drivers/scsi/be2iscsi/be_main.h | 48 +- drivers/scsi/be2iscsi/be_mgmt.c | 114 ++++- drivers/scsi/be2iscsi/be_mgmt.h | 8 +- 8 files changed, 1213 insertions(+), 313 deletions(-)
drivers/scsi/be2iscsi/be.h +9 -15
@@ -20,8 +20,10 @@#include <linux/pci.h> #include <linux/if_vlan.h> - -#define FW_VER_LEN 32 +#include <linux/blk-iopoll.h> +#define FW_VER_LEN 32 +#define MCC_Q_LEN 128 +#define MCC_CQ_LEN 256struct be_dma_mem {void *va;
@@ -74,18 +76,14 @@ static inline void queue_tail_inc(struct be_queue_info *q)struct be_eq_obj {struct be_queue_info q; -char desc[32 ]; - -/* Adaptive interrupt coalescing (AIC) info */ -bool enable_aic; -u16 min_eqd;/* in usecs */ -u16 max_eqd;/* in usecs */ -u16 cur_eqd;/* in usecs */ +struct beiscsi_hba *phba; +struct be_queue_info *cq; +struct blk_iopoll iopoll; };struct be_mcc_obj { -struct be_queue_info *q; -struct be_queue_info *cq; +struct be_queue_info q; +struct be_queue_info cq; };struct be_ctrl_info {
@@ -176,8 +174,4 @@ static inline void swap_dws(void *wrb, int len) } while (len);#endif /* __BIG_ENDIAN */ } - -extern void beiscsi_cq_notify (struct be_ctrl_info *ctrl,u16 qid,bool arm, -u16 num_popped); -#endif /* BEISCSI_H */
drivers/scsi/be2iscsi/be_cmds.c +225 -29
350 lines not on this page · raw message
drivers/scsi/be2iscsi/be_cmds.h +30 -5
@@ -47,6 +47,8 @@ struct be_mcc_wrb {#define CQE_FLAGS_VALID_MASK (1 << 31)#define CQE_FLAGS_ASYNC_MASK (1 << 30) +#define CQE_FLAGS_COMPLETED_MASK (1 << 28) +#define CQE_FLAGS_CONSUMED_MASK (1 << 27)/* Completion Status */ #define MCC_STATUS_SUCCESS 0x0
@@ -382,7 +384,6 @@ struct be_cmd_req_modify_eq_delay {#define ETH_ALEN 6 -struct be_cmd_req_get_mac_addr {struct be_cmd_req_hdr hdr;u32 nic_port_count;
@@ -417,14 +418,21 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,int beiscsi_cmd_q_destroy (struct be_ctrl_info *ctrl,struct be_queue_info *q,int type); +int be_cmd_mccq_create (struct beiscsi_hba *phba, +struct be_queue_info *mccq, +struct be_queue_info *cq); +int be_poll_mcc (struct be_ctrl_info *ctrl); -unsigned char mgmt_check_supported_fw (struct be_ctrl_info *ctrl); -int be_cmd_get_mac_addr (struct be_ctrl_info *ctrl,u8 *mac_addr); +unsigned char mgmt_check_supported_fw (struct be_ctrl_info *ctrl, +struct beiscsi_hba *phba); +int be_cmd_get_mac_addr (struct beiscsi_hba *phba,u8 *mac_addr);/*ISCSI Functuions */ int be_cmd_fw_initialize (struct be_ctrl_info *ctrl);struct be_mcc_wrb *wrb_from_mbox (struct be_dma_mem *mbox_mem); +struct be_mcc_wrb *wrb_from_mccq (struct beiscsi_hba *phba); +int be_mcc_notify_wait (struct beiscsi_hba *phba);int be_mbox_notify (struct be_ctrl_info *ctrl);
@@ -531,6 +539,23 @@ struct amap_sol_cqe {u8 valid;/* dword 3 */ } __packed; +#define SOL_ICD_INDEX_MASK 0x0003FFC0 +struct amap_sol_cqe_ring { +u8 hw_sts[8 ];/* dword 0 */ +u8 i_sts[8 ];/* dword 0 */ +u8 i_resp[8 ];/* dword 0 */ +u8 i_flags[7 ];/* dword 0 */ +u8 s;/* dword 0 */ +u8 i_exp_cmd_sn[32 ];/* dword 1 */ +u8 code[6 ];/* dword 2 */ +u8 icd_index[12 ];/* dword 2 */ +u8 rsvd[6 ];/* dword 2 */ +u8 i_cmd_wnd[8 ];/* dword 2 */ +u8 i_res_cnt[31 ];/* dword 3 */ +u8 valid;/* dword 3 */ +} __packed; + +/** * Post WRB Queue Doorbell Register used by the host Storage
@@ -664,8 +689,8 @@ struct be_fw_cfg {#define OPCODE_COMMON_TCP_UPLOAD 56#define OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS 1/* --- CMD_ISCSI_INVALIDATE_CONNECTION_TYPE --- */ -#define CMD_ISCSI_CONNECTION_INVALIDATE 1 -#define CMD_ISCSI_CONNECTION_ISSUE_TCP_RST 2 +#define CMD_ISCSI_CONNECTION_INVALIDATE 0x8001 +#define CMD_ISCSI_CONNECTION_ISSUE_TCP_RST 0x8002#define OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION 42#define INI_WR_CMD 1/* Initiator write command */
drivers/scsi/be2iscsi/be_iscsi.c +6 -10
@@ -67,11 +67,11 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, cmds_max = beiscsi_ep->phba->params.wrbs_per_cxn; } - cls_session =iscsi_session_setup (&beiscsi_iscsi_transport, - shost, cmds_max, -sizeof (*beiscsi_sess), -sizeof (*io_task), - initial_cmdsn,ISCSI_MAX_TARGET ); + cls_session =iscsi_session_setup (&beiscsi_iscsi_transport, + shost, cmds_max, +sizeof (*beiscsi_sess), +sizeof (*io_task), + initial_cmdsn,ISCSI_MAX_TARGET );if (!cls_session)return NULL ; sess = cls_session->dd_data;
@@ -297,7 +297,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,switch (param) {case ISCSI_HOST_PARAM_HWADDRESS : -be_cmd_get_mac_addr (&phba->ctrl, phba->mac_address); +be_cmd_get_mac_addr (phba, phba->mac_address); len =sysfs_format_mac (buf, phba->mac_address,ETH_ALEN );break ;default :
@@ -377,16 +377,12 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)struct beiscsi_conn *beiscsi_conn = conn->dd_data;struct beiscsi_endpoint *beiscsi_ep;struct beiscsi_offload_params params; -struct iscsi_session *session = conn->session; -struct Scsi_Host *shost =iscsi_session_to_shost (session->cls_session); -struct beiscsi_hba *phba =iscsi_host_priv (shost);memset (¶ms,0 ,sizeof (struct beiscsi_offload_params )); beiscsi_ep = beiscsi_conn->ep;if (!beiscsi_ep)SE_DEBUG (DBG_LVL_1 ,"In beiscsi_conn_start , no beiscsi_ep\n" ); -free_mgmt_sgl_handle (phba, beiscsi_conn->plogin_sgl_handle); beiscsi_conn->login_in_progress =0 ;beiscsi_set_params_for_offld (beiscsi_conn, ¶ms);beiscsi_offload_connection (beiscsi_conn, ¶ms);
drivers/scsi/be2iscsi/be_main.c +811 -216
1,705 lines not on this page · raw message
drivers/scsi/be2iscsi/be_main.h +27 -21
151 lines not on this page · raw message
drivers/scsi/be2iscsi/be_mgmt.c +98 -16
226 lines not on this page · raw message
drivers/scsi/be2iscsi/be_mgmt.h +7 -1
@@ -175,7 +175,9 @@ struct mgmt_hba_attributes {u8 phy_port;u32 firmware_post_status;u32 hba_mtu[8 ]; -u32 future_u32[4 ]; +u8 iscsi_features; +u8 future_u8[3 ]; +u32 future_u32[3 ]; } __packed;struct mgmt_controller_attributes {
@@ -246,4 +248,8 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,unsigned short cid, unsigned short issue_reset, unsigned short savecfg_flag); + +unsigned char mgmt_fw_cmd (struct be_ctrl_info *ctrl, +struct beiscsi_hba *phba, +char *buf,unsigned int len);#endif
Signature · 1 line
1.6.4
A few code review comments:
drivers/scsi/be2iscsi/be_main.c static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = { · line 132
Quoted 11 lines · Jayamohan Kallickal
drivers/scsi/be2iscsi/be_main.c +11
-0+static struct bin_attribute sysfs_drvr_fw_prgrm_attr = { + .attr = { + .name ="be2iscsi_fw_prgrm" , + .mode =S_IRUSR |S_IWUSR , + .owner =THIS_MODULE , + }, + .size =0 , + .read = beiscsi_sysfs_fw_rd, + .write = beiscsi_sysfs_fw_wr, +}; +
Use the DEVICE_ATTR macro...
Quoted 9 lines
drivers/scsi/be2iscsi/be_main.c +4
-1@@ -355,13 +526,32 @@ static irqreturn_t be_isr(int irq, void *dev_id)static int beiscsi_init_irqs (struct beiscsi_hba *phba) {struct pci_dev *pcidev = phba->pcidev; -int ret; +struct hwi_controller *phwi_ctrlr; +struct hwi_context_memory *phwi_context; +int ret, msix_vec, i =0 ; +char desc[32 ];
drivers/scsi/be2iscsi/be_main.c static irqreturn_t be_isr(int irq, void *dev_id) · line 537
Quoted 10 lines
drivers/scsi/be2iscsi/be_main.c +4
-5- ret =request_irq (pcidev->irq, be_isr,IRQF_SHARED ,"beiscsi" , phba); -if (ret) { -shost_printk (KERN_ERR , phba->shost,"beiscsi_init_irqs-" -"Failed to register irq\\n" ); -return ret; + phwi_ctrlr = phba->phwi_ctrlr; + phwi_context = phwi_ctrlr->phwi_ctxt; + +if (enable_msix) {
This should be checking phba->msix_enabled instead. This code is checking the module-global variable for whether to attempt MSIX mode. The phba-specific value must be checked to see if pci_enable_msix was successful on this adapter.
There are lots of other occurrences of the same issue in the cq/eq create routines and handlers, as well as error paths, etc.
Quoted 33 lines
drivers/scsi/be2iscsi/be_main.c +7
-19-static int beiscsi_create_eq (struct beiscsi_hba *phba, +static int beiscsi_create_eqs (struct beiscsi_hba *phba,struct hwi_context_memory *phwi_context) { -unsigned int idx; -int ret; +unsigned int i, num_eq_pages; +int ret, eq_for_mcc;struct be_queue_info *eq;struct be_dma_mem *mem; -struct be_mem_descriptor *mem_descr;void *eq_vaddress; +dma_addr_t paddr; - idx =0 ; - eq = &phwi_context->be_eq.q; - mem = &eq->dma_mem; - mem_descr = phba->init_mem; - mem_descr +=HWI_MEM_EQ ; - eq_vaddress = mem_descr->mem_array[idx].virtual_address; - - ret =be_fill_queue (eq, phba->params.num_eq_entries, -sizeof (struct be_eq_entry ), eq_vaddress); -if (ret) { -shost_printk (KERN_ERR , phba->shost, -"be_fill_queue Failed for EQ \n" ); -return ret; - } + num_eq_pages =PAGES_REQUIRED (phba->params.num_eq_entries * \ +sizeof (struct be_eq_entry )); - mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address; +if (enable_msix)
drivers/scsi/be2iscsi/be_main.c static int be_fill_queue(struct be_queue_info *q, · line 2358
Quoted 10 lines
drivers/scsi/be2iscsi/be_main.c +10
-0+ eq_for_mcc =1 ; + else + eq_for_mcc =0 ; +for (i =0 ; i < (phba->num_cpus + eq_for_mcc); i++) { + eq = &phwi_context->be_eq[i].q; + mem = &eq->dma_mem; + phwi_context->be_eq[i].phba = phba; + eq_vaddress =pci_alloc_consistent (phba->pcidev, + num_eq_pages *PAGE_SIZE , + &paddr);
Missing check for NULL return from pci_alloc_consistent(). There are several other occurrences of the same issue in the patch.
I see you are no longer applying the "round down" logic for the eq's/cq's.
Quoted 8 lines
drivers/scsi/be2iscsi/be_main.c +8
-0+static int +beiscsi_alloc_sysfs_attr (struct Scsi_Host *shost) +{ +int ret; + + ret =sysfs_create_bin_file (&shost->shost_dev.kobj, + &sysfs_drvr_fw_prgrm_attr); +if (ret)
drivers/scsi/be2iscsi/be_main.c static int beiscsi_task_xmit(struct iscsi_task *task) · line 3687
Quoted 10 lines
drivers/scsi/be2iscsi/be_main.c +10
-0+shost_printk (KERN_WARNING , shost, +"Failed in be2iscsi_alloc_sysfs_attr\n" ); +return ret; +} + +static void beiscsi_free_sysfs_attr (struct Scsi_Host *shost) +{ +sysfs_remove_bin_file (&shost->shost_dev.kobj, + &sysfs_drvr_fw_prgrm_attr); +}
This style of creating sysfs attributes is odd for SCSI hosts. Attributes usually use the DEVICE_ATTR macro, with an attribute array that is set in the scsi_host_template via the .shost_attrs field.
Quoted 5 lines
drivers/scsi/be2iscsi/be_main.c +5
-0+static void beiscsi_msix_enable (struct beiscsi_hba *phba) +{ +int i, status; + +for (i =0 ; i <= phba->num_cpus; i++)
drivers/scsi/be2iscsi/be_main.c static void beiscsi_remove(struct pci_dev *pcidev) · line 3751
Quoted 10 lines
drivers/scsi/be2iscsi/be_main.c +10
-0+ phba->msix_entries[i].entry = i; + + status =pci_enable_msix (phba->pcidev, phba->msix_entries, + (phba->num_cpus +1 )); +if (!status) + phba->msix_enabled = true; + +return ; +} +
Here's where you set the per-phba setting for msix enabled or not....
drivers/scsi/be2iscsi/be_main.c static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, · line 3844
Quoted 2 lines
drivers/scsi/be2iscsi/be_main.c +2
-0+if (beiscsi_alloc_sysfs_attr (phba->shost)) + goto free_attr_mem;
See comment above on sysfs attributes on scsi hosts....
-- james s
Quoted 6 lines · Jayamohan Kallickal
This patch
1) Turns on msix
2) Addsmcc_ringsupport for sending FW commands
3) Adds Support for Ring Mode of WRB Posting
4) Adds sysfs for FW commands
I think msix should be a separate patch from the fw command one, and the ring mode changes could probably be in a separate patch too.
drivers/scsi/be2iscsi/be_cmds.c static int be_mcc_compl_process(struct be_ctrl_info *ctrl, · line 94
Quoted 9 lines
drivers/scsi/be2iscsi/be_cmds.c +9
-0+ +static void beiscsi_async_link_state_process (struct beiscsi_hba *phba, +struct be_async_event_link_state *evt) +{ +switch (evt->port_link_status) { +case ASYNC_EVENT_LINK_DOWN : +SE_DEBUG (DBG_LVL_1 ,"Link Down on Physical Port %d \n" , + evt->physical_port); +break ;
When you get a link down, does it cause the fw do start iscsi recovery or does it send the driver a notification that a command is failed due to the link down. For example if we were doing erl0, and the link is gone, would the fw return some error for each command?
For link down maybe you want to fire a iscsi conn error for each session/connection on the port, so that way the iscsi layer can block the sessions and start recovery.
_____
From: Mike Christie [mailto:[email protected]]
To: Jayamohan Kalickal [mailto:[email protected]]
Cc: [email protected]
Sent: Wed, 21 Oct 2009 10:19:06 -0700
Subject: Re: [PATCH 1/1] be2iscsi: Enabling MSIX and mcc_rings V2
Quoted 6 lines · Jayamohan Kallickal
This patch
1) Turns on msix
2) Addsmcc_ringsupport for sending FW commands
3) Adds Support for Ring Mode of WRB Posting
4) Adds sysfs for FW commands
I think msix should be a separate patch from the fw command one, and the ring mode changes could probably be in a separate patch too.
Will Do that
drivers/scsi/be2iscsi/be_cmds.c static int be_mcc_compl_process(struct be_ctrl_info *ctrl, · line 94
Quoted 9 lines
drivers/scsi/be2iscsi/be_cmds.c +9
-0+ +static void beiscsi_async_link_state_process (struct beiscsi_hba *phba, +struct be_async_event_link_state *evt) +{ +switch (evt->port_link_status) { +case ASYNC_EVENT_LINK_DOWN : +SE_DEBUG (DBG_LVL_1 ,"Link Down on Physical Port %d \n" , + evt->physical_port); +break ;
When you get a link down, does it cause the fw do start iscsi recovery or does it send the driver a notification that a command is failed due to the link down. For example if we were doing erl0, and the link is gone, would the fw return some error for each command?
For link down maybe you want to fire a iscsi conn error for each session/connection on the port, so that way the iscsi layer can block the sessions and start recovery.
The FW will report LINKDOWN event almost immediately when the event is noticed.
Some thoughts on the implementation
1) Rather than immediately shutting down all the sessions , wait for a predetermined
time ,say, 10 Secs(if the user has pulled the cable and is connecting it back ,for eg, to
connect to a different port on the switch etc). Since IO's will not exceed the Queue Depth, this should be fine. However, for MPIO, we may need to load with a parameter (or something better) so that we will fail immediately and IO's can be switched over to other port faster.
2) Since this function to shutdown sessions will be used by many drivers , shall we make this part of libiscsi. Can do this.
2) Since this is
2)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
___________________________________________________________________________________
This message, together with any attachment(s), contains confidential and proprietary information of ServerEngines Corporation and is intended only for the designated recipient(s) named above. Any unauthorized review, printing, retention, copying, disclosure or distribution is strictly prohibited. If you are not the intended recipient of this message, please immediately advise the sender by reply email message and delete all copies of this message and any attachment(s). Thank you.
Quoted 35 lines · Jayamohan Kalickal
_____ From: Mike Christie [mailto:[email protected]]
To: Jayamohan Kalickal [mailto:[email protected]]
Cc: [email protected]
Sent: Wed, 21 Oct 2009 10:19:06 -0700
Subject: Re: [PATCH 1/1] be2iscsi: Enabling MSIX andmcc_ringsV2Quoted 6 lines · Jayamohan Kallickal
This patch
1) Turns on msix
2) Addsmcc_ringsupport for sending FW commands
3) Adds Support for Ring Mode of WRB Posting
4) Adds sysfs for FW commandsI think msix should be a separate patch from the fw command one, and the ring mode changes could probably be in a separate patch too.
Will Do that
drivers/scsi/be2iscsi/be_cmds.c static int be_mcc_compl_process(struct be_ctrl_info *ctrl, · line 94
Quoted 9 lines
drivers/scsi/be2iscsi/be_cmds.c +9
-0+ +static void beiscsi_async_link_state_process (struct beiscsi_hba *phba, +struct be_async_event_link_state *evt) +{ +switch (evt->port_link_status) { +case ASYNC_EVENT_LINK_DOWN : +SE_DEBUG (DBG_LVL_1 ,"Link Down on Physical Port %d \n" , + evt->physical_port); +break ;When you get a link down, does it cause the fw do start iscsi recovery or does it send the driver a notification that a command is failed due to the link down. For example if we were doing erl0, and the link is gone, would the fw return some error for each command?
For link down maybe you want to fire a iscsi conn error for each session/connection on the port, so that way the iscsi layer can block the sessions and start recovery.
Quoted 8 lines
The FW will report LINKDOWN event almost immediately when the event is noticed.
Some thoughts on the implementation
1) Rather than immediately shutting down all the sessions , wait for a predetermined
time ,say, 10 Secs(if the user has pulled the cable and is connecting it back ,for eg, to
connect to a different port on the switch etc). Since IO's will not exceed the Queue Depth, this should be fine. However, for MPIO, we may need to load with a parameter (or something better) so that we will fail immediately and IO's can be switched over to other port faster.
We have a timer it is called the replacement_timeout/recovery_timeout. This will determine how fast we fail cmds upwards when handling these type of errors. When you call iscsi_session_failure or iscsi_conn_faulure it will start the timer. Today, users will set this very short for MPIO setups and very high for something else like root on iscsi.
Quoted 3 lines
2) Since this function to shutdown sessions will be used by many drivers , shall we make this part of libiscsi. Can do this.
Yes, libiscsi is best. See bnx2i's iscsi_host_for_each_session+iscsi_session_failure use.
Quoted 21 lines
2) Since this is
2)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html___________________________________________________________________________________
This message, together with any attachment(s), contains confidential and proprietary information of ServerEngines Corporation and is intended only for the designated recipient(s) named above. Any unauthorized review, printing, retention, copying, disclosure or distribution is strictly prohibited. If you are not the intended recipient of this message, please immediately advise the sender by reply email message and delete all copies of this message and any attachment(s). Thank you.--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Adding Qlogic guys on this one, because I think they want something similar.
Quoted 2 lines · Jayamohan Kallickal
4) Adds sysfs for FW commands
Jay, what operations are you wanting to do with the binary sysfs file? Are there any operations that should be common with Qlogic?
Also if you guys both need binary operations for card specific operations then binary sysfs is fine. However, James S had suggested using bsg for this too. Since that is upstream now, and you could just copy the FC implementation that might be a easier route (I think qlogic might have mentioned sysfs was a pain sometimes, and it is something you both could work on and help each other out on).
Comment on the implementation.
drivers/scsi/be2iscsi/be_main.c static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = { · line 102
Quoted 12 lines
MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);drivers/scsi/be2iscsi/be_main.c +10
-0+static ssize_t +beiscsi_sysfs_fw_wr (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { + +unsigned int ret_len =0 ; +struct Scsi_Host *shost =class_to_shost (container_of (kobj, + struct device, kobj)); +struct beiscsi_hba *phba =iscsi_host_priv (shost); + + ret_len =mgmt_fw_cmd (&phba->ctrl, phba, buf, count);
For normal sysfs files I think we normally want it to do only one thing. This one seems to be a cmd to exec and the data buffer. I am not sure if that is right. Maybe you just want one file per operation. Or maybe you want another file for the length of the opertaion so you do not have to waste mem on that phba buffer.
Or JamesS's comment offlist about using the bsg pass through stuff is also ok. Adding the infrastucture is a little more work, but it is probably easier in the long run for the reasons he explained.
Quoted 30 lines
drivers/scsi/be2iscsi/be_main.c +30
-0+if (!ret_len) { +memcpy (buf, phba->attr_mem, count); +return count; + }else +return ret_len; +} + +static ssize_t +beiscsi_sysfs_fw_rd (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { + +struct Scsi_Host *shost =class_to_shost (container_of (kobj, + struct device, kobj)); +struct beiscsi_hba *phba =iscsi_host_priv (shost); + +memcpy (buf, phba->attr_mem, count); +return count; +} + +static struct bin_attribute sysfs_drvr_fw_prgrm_attr = { + .attr = { + .name ="be2iscsi_fw_prgrm" , + .mode =S_IRUSR |S_IWUSR , + .owner =THIS_MODULE , + }, + .size =0 , + .read = beiscsi_sysfs_fw_rd, + .write = beiscsi_sysfs_fw_wr, +}; +