From f3506b755f730f199aea3289712f9604ae562319 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 22 Jul 2010 20:40:10 +0900 Subject: [SCSI] 53c700: remove dma_is_consistent usage This driver is the only user of dma_is_consistent(). We plan to remove this API. The driver uses the API in the following way: BUG_ON(!dma_is_consistent(hostdata->dev, pScript) && L1_CACHE_BYTES < dma_get_cache_alignment()); The above code tries to see if L1_CACHE_BYTES is greater than dma_get_cache_alignment() on sysmtes that can not allocate coherent memory (some old systems can't). James Bottomley exmplained that this is necesary because the driver packs the set of mailboxes into a single coherent area and separates the different usages by a L1 cache stride. So it's fatal if the dma coherence stride is greater than the L1 cache size. He also pointed out that we can kill this checking because we don't hit this BUG_ON on all architectures that actually use the driver. Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- drivers/scsi/53c700.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 80dc3ac12cde..89fc1c8af86b 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -309,9 +309,6 @@ NCR_700_detect(struct scsi_host_template *tpnt, hostdata->msgin = memory + MSGIN_OFFSET; hostdata->msgout = memory + MSGOUT_OFFSET; hostdata->status = memory + STATUS_OFFSET; - /* all of these offsets are L1_CACHE_BYTES separated. It is fatal - * if this isn't sufficient separation to avoid dma flushing issues */ - BUG_ON(!dma_is_consistent(hostdata->dev, pScript) && L1_CACHE_BYTES < dma_get_cache_alignment()); hostdata->slots = (struct NCR_700_command_slot *)(memory + SLOTS_OFFSET); hostdata->dev = dev; -- cgit From c7acc5b8f9a0e6cb17d313ebfbc5d392aa837ac7 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:29:18 +0530 Subject: [SCSI] be2iscsi: Add support for iscsi boot This patch contains changes for adding support for iscsi_boot. Have modified to make read of mac address from chip as a function. The mac_address is being cached after teh first call as it is not expected to change Signed-off-by: Mike Christie Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_cmds.h | 147 +++++++++++++++--- drivers/scsi/be2iscsi/be_iscsi.c | 76 ++++++---- drivers/scsi/be2iscsi/be_iscsi.h | 2 + drivers/scsi/be2iscsi/be_main.c | 311 +++++++++++++++++++++++++++++++++++++++ drivers/scsi/be2iscsi/be_main.h | 3 + drivers/scsi/be2iscsi/be_mgmt.c | 71 +++++++++ 6 files changed, 564 insertions(+), 46 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 40641d0845f4..5218de4ab35a 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -162,6 +162,13 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_ISCSI_CFG_POST_SGL_PAGES 2 #define OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES 3 #define OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG 7 +#define OPCODE_COMMON_ISCSI_NTWK_SET_VLAN 14 +#define OPCODE_COMMON_ISCSI_NTWK_CONFIGURE_STATELESS_IP_ADDR 17 +#define OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR 21 +#define OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY 22 +#define OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY 23 +#define OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID 24 +#define OPCODE_COMMON_ISCSI_NTWK_GET_IF_INFO 25 #define OPCODE_COMMON_ISCSI_SET_FRAGNUM_BITS_FOR_SGL_CRA 61 #define OPCODE_COMMON_ISCSI_DEFQ_CREATE 64 #define OPCODE_COMMON_ISCSI_DEFQ_DESTROY 65 @@ -237,11 +244,109 @@ struct be_cmd_resp_eq_create { u16 rsvd0; /* sword */ } __packed; +struct mgmt_chap_format { + u32 flags; + u8 intr_chap_name[256]; + u8 intr_secret[16]; + u8 target_chap_name[256]; + u8 target_secret[16]; + u16 intr_chap_name_length; + u16 intr_secret_length; + u16 target_chap_name_length; + u16 target_secret_length; +} __packed; + +struct mgmt_auth_method_format { + u8 auth_method_type; + u8 padding[3]; + struct mgmt_chap_format chap; +} __packed; + +struct mgmt_conn_login_options { + u8 flags; + u8 header_digest; + u8 data_digest; + u8 rsvd0; + u32 max_recv_datasegment_len_ini; + u32 max_recv_datasegment_len_tgt; + u32 tcp_mss; + u32 tcp_window_size; + struct mgmt_auth_method_format auth_data; +} __packed; + +struct ip_address_format { + u16 size_of_structure; + u8 reserved; + u8 ip_type; + u8 ip_address[16]; + u32 rsvd0; +} __packed; + +struct mgmt_conn_info { + u32 connection_handle; + u32 connection_status; + u16 src_port; + u16 dest_port; + u16 dest_port_redirected; + u16 cid; + u32 estimated_throughput; + struct ip_address_format src_ipaddr; + struct ip_address_format dest_ipaddr; + struct ip_address_format dest_ipaddr_redirected; + struct mgmt_conn_login_options negotiated_login_options; +} __packed; + +struct mgmt_session_login_options { + u8 flags; + u8 error_recovery_level; + u16 rsvd0; + u32 first_burst_length; + u32 max_burst_length; + u16 max_connections; + u16 max_outstanding_r2t; + u16 default_time2wait; + u16 default_time2retain; +} __packed; + +struct mgmt_session_info { + u32 session_handle; + u32 status; + u8 isid[6]; + u16 tsih; + u32 session_flags; + u16 conn_count; + u16 pad; + u8 target_name[224]; + u8 initiator_iscsiname[224]; + struct mgmt_session_login_options negotiated_login_options; + struct mgmt_conn_info conn_list[1]; +} __packed; + +struct be_cmd_req_get_session { + struct be_cmd_req_hdr hdr; + u32 session_handle; +} __packed; + +struct be_cmd_resp_get_session { + struct be_cmd_resp_hdr hdr; + struct mgmt_session_info session_info; +} __packed; + struct mac_addr { u16 size_of_struct; u8 addr[ETH_ALEN]; } __packed; +struct be_cmd_req_get_boot_target { + struct be_cmd_req_hdr hdr; +} __packed; + +struct be_cmd_resp_get_boot_target { + struct be_cmd_resp_hdr hdr; + u32 boot_session_count; + int boot_session_handle; +}; + struct be_cmd_req_mac_query { struct be_cmd_req_hdr hdr; u8 type; @@ -426,6 +531,11 @@ int be_poll_mcc(struct be_ctrl_info *ctrl); int mgmt_check_supported_fw(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba); unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba); +unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba); +unsigned int beiscsi_get_session_info(struct beiscsi_hba *phba, + u32 boot_session_handle, + struct be_dma_mem *nonemb_cmd); + void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag); /*ISCSI Functuions */ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl); @@ -601,14 +711,6 @@ struct be_eq_delay_params_in { struct eq_delay delay[8]; } __packed; -struct ip_address_format { - u16 size_of_structure; - u8 reserved; - u8 ip_type; - u8 ip_address[16]; - u32 rsvd0; -} __packed; - struct tcp_connect_and_offload_in { struct be_cmd_req_hdr hdr; struct ip_address_format ip_address; @@ -688,18 +790,29 @@ struct be_fw_cfg { u32 function_caps; } __packed; -#define CMD_ISCSI_COMMAND_INVALIDATE 1 -#define ISCSI_OPCODE_SCSI_DATA_OUT 5 +struct be_all_if_id { + struct be_cmd_req_hdr hdr; + u32 if_count; + u32 if_hndl_list[1]; +} __packed; + +#define ISCSI_OPCODE_SCSI_DATA_OUT 5 +#define OPCODE_COMMON_MODIFY_EQ_DELAY 41 +#define OPCODE_COMMON_ISCSI_CLEANUP 59 +#define OPCODE_COMMON_TCP_UPLOAD 56 #define OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD 70 -#define OPCODE_ISCSI_INI_DRIVER_OFFLOAD_SESSION 41 -#define OPCODE_COMMON_MODIFY_EQ_DELAY 41 -#define OPCODE_COMMON_ISCSI_CLEANUP 59 -#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 0x8001 -#define CMD_ISCSI_CONNECTION_ISSUE_TCP_RST 0x8002 +#define OPCODE_ISCSI_INI_CFG_GET_HBA_NAME 6 +#define OPCODE_ISCSI_INI_CFG_SET_HBA_NAME 7 +#define OPCODE_ISCSI_INI_SESSION_GET_A_SESSION 14 +#define OPCODE_ISCSI_INI_DRIVER_OFFLOAD_SESSION 41 #define OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION 42 +#define OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET 52 + +/* --- CMD_ISCSI_INVALIDATE_CONNECTION_TYPE --- */ +#define CMD_ISCSI_COMMAND_INVALIDATE 1 +#define CMD_ISCSI_CONNECTION_INVALIDATE 0x8001 +#define CMD_ISCSI_CONNECTION_ISSUE_TCP_RST 0x8002 #define INI_WR_CMD 1 /* Initiator write command */ #define INI_TMF_CMD 2 /* Initiator TMF command */ diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 6d63e7b312cf..7d4d2275573c 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -300,40 +300,16 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf) { struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost); - struct be_cmd_resp_get_mac_addr *resp; - struct be_mcc_wrb *wrb; - unsigned int tag, wrb_num; int len = 0; - unsigned short status, extd_status; - struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + int status; SE_DEBUG(DBG_LVL_8, "In beiscsi_get_host_param, param= %d\n", param); switch (param) { case ISCSI_HOST_PARAM_HWADDRESS: - tag = be_cmd_get_mac_addr(phba); - if (!tag) { - SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n"); - return -EAGAIN; - } else - wait_event_interruptible(phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_numtag[tag]); - - wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; - extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; - status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; - if (status || extd_status) { - SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed" - " status = %d extd_status = %d\n", - status, extd_status); - free_mcc_tag(&phba->ctrl, tag); - return -EAGAIN; - } else { - wrb = queue_get_wrb(mccq, wrb_num); - free_mcc_tag(&phba->ctrl, tag); - resp = embedded_payload(wrb); - memcpy(phba->mac_address, resp->mac_address, ETH_ALEN); - len = sysfs_format_mac(buf, phba->mac_address, - ETH_ALEN); + status = beiscsi_get_macaddr(buf, phba); + if (status < 0) { + SE_DEBUG(DBG_LVL_1, "beiscsi_get_macaddr Failed\n"); + return status; } break; default: @@ -342,6 +318,48 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, return len; } +int beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba) +{ + struct be_cmd_resp_get_mac_addr *resp; + struct be_mcc_wrb *wrb; + unsigned int tag, wrb_num; + unsigned short status, extd_status; + struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + int rc; + + if (phba->read_mac_address) + return sysfs_format_mac(buf, phba->mac_address, + ETH_ALEN); + + tag = be_cmd_get_mac_addr(phba); + if (!tag) { + SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n"); + return -EBUSY; + } else + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + + wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; + extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; + status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; + if (status || extd_status) { + SE_DEBUG(DBG_LVL_1, "Failed to get be_cmd_get_mac_addr" + " status = %d extd_status = %d\n", + status, extd_status); + free_mcc_tag(&phba->ctrl, tag); + return -EAGAIN; + } + wrb = queue_get_wrb(mccq, wrb_num); + free_mcc_tag(&phba->ctrl, tag); + resp = embedded_payload(wrb); + memcpy(phba->mac_address, resp->mac_address, ETH_ALEN); + rc = sysfs_format_mac(buf, phba->mac_address, + ETH_ALEN); + phba->read_mac_address = 1; + return rc; +} + + /** * beiscsi_conn_get_stats - get the iscsi stats * @cls_conn: pointer to iscsi cls conn diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h index 870cdb2a73e4..8950a702b9f4 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.h +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -54,6 +54,8 @@ int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, int beiscsi_get_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf); +int beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba); + int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, char *buf, int buflen); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 7436c5ad5697..8220bde6c04c 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -211,6 +212,218 @@ unlock: return rc; } +static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) +{ + struct beiscsi_hba *phba = data; + char *str = buf; + int rc; + + switch (type) { + case ISCSI_BOOT_TGT_NAME: + rc = sprintf(buf, "%.*s\n", + (int)strlen(phba->boot_sess.target_name), + (char *)&phba->boot_sess.target_name); + break; + case ISCSI_BOOT_TGT_IP_ADDR: + if (phba->boot_sess.conn_list[0].dest_ipaddr.ip_type == 0x1) + rc = sprintf(buf, "%pI4\n", + (char *)&phba->boot_sess.conn_list[0]. + dest_ipaddr.ip_address); + else + rc = sprintf(str, "%pI6\n", + (char *)&phba->boot_sess.conn_list[0]. + dest_ipaddr.ip_address); + break; + case ISCSI_BOOT_TGT_PORT: + rc = sprintf(str, "%d\n", phba->boot_sess.conn_list[0]. + dest_port); + break; + + case ISCSI_BOOT_TGT_CHAP_NAME: + rc = sprintf(str, "%.*s\n", + phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + target_chap_name_length, + (char *)&phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + target_chap_name); + break; + case ISCSI_BOOT_TGT_CHAP_SECRET: + rc = sprintf(str, "%.*s\n", + phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + target_secret_length, + (char *)&phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + target_secret); + + break; + case ISCSI_BOOT_TGT_REV_CHAP_NAME: + rc = sprintf(str, "%.*s\n", + phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + intr_chap_name_length, + (char *)&phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + intr_chap_name); + + break; + case ISCSI_BOOT_TGT_REV_CHAP_SECRET: + rc = sprintf(str, "%.*s\n", + phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + intr_secret_length, + (char *)&phba->boot_sess.conn_list[0]. + negotiated_login_options.auth_data.chap. + intr_secret); + break; + case ISCSI_BOOT_TGT_FLAGS: + rc = sprintf(str, "2\n"); + break; + case ISCSI_BOOT_TGT_NIC_ASSOC: + rc = sprintf(str, "0\n"); + break; + default: + rc = -ENOSYS; + break; + } + return rc; +} + +static ssize_t beiscsi_show_boot_ini_info(void *data, int type, char *buf) +{ + struct beiscsi_hba *phba = data; + char *str = buf; + int rc; + + switch (type) { + case ISCSI_BOOT_INI_INITIATOR_NAME: + rc = sprintf(str, "%s\n", phba->boot_sess.initiator_iscsiname); + break; + default: + rc = -ENOSYS; + break; + } + return rc; +} + +static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) +{ + struct beiscsi_hba *phba = data; + char *str = buf; + int rc; + + switch (type) { + case ISCSI_BOOT_ETH_FLAGS: + rc = sprintf(str, "2\n"); + break; + case ISCSI_BOOT_ETH_INDEX: + rc = sprintf(str, "0\n"); + break; + case ISCSI_BOOT_ETH_MAC: + rc = beiscsi_get_macaddr(buf, phba); + if (rc < 0) { + SE_DEBUG(DBG_LVL_1, "beiscsi_get_macaddr Failed\n"); + return rc; + } + break; + default: + rc = -ENOSYS; + break; + } + return rc; +} + + +static mode_t beiscsi_tgt_get_attr_visibility(void *data, int type) +{ + int rc; + + switch (type) { + case ISCSI_BOOT_TGT_NAME: + case ISCSI_BOOT_TGT_IP_ADDR: + case ISCSI_BOOT_TGT_PORT: + case ISCSI_BOOT_TGT_CHAP_NAME: + case ISCSI_BOOT_TGT_CHAP_SECRET: + case ISCSI_BOOT_TGT_REV_CHAP_NAME: + case ISCSI_BOOT_TGT_REV_CHAP_SECRET: + case ISCSI_BOOT_TGT_NIC_ASSOC: + case ISCSI_BOOT_TGT_FLAGS: + rc = S_IRUGO; + break; + default: + rc = 0; + break; + } + return rc; +} + +static mode_t beiscsi_ini_get_attr_visibility(void *data, int type) +{ + int rc; + + switch (type) { + case ISCSI_BOOT_INI_INITIATOR_NAME: + rc = S_IRUGO; + break; + default: + rc = 0; + break; + } + return rc; +} + + +static mode_t beiscsi_eth_get_attr_visibility(void *data, int type) +{ + int rc; + + switch (type) { + case ISCSI_BOOT_ETH_FLAGS: + case ISCSI_BOOT_ETH_MAC: + case ISCSI_BOOT_ETH_INDEX: + rc = S_IRUGO; + break; + default: + rc = 0; + break; + } + return rc; +} + +static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) +{ + struct iscsi_boot_kobj *boot_kobj; + + phba->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); + if (!phba->boot_kset) + return -ENOMEM; + + /* get boot info using mgmt cmd */ + boot_kobj = iscsi_boot_create_target(phba->boot_kset, 0, phba, + beiscsi_show_boot_tgt_info, + beiscsi_tgt_get_attr_visibility); + if (!boot_kobj) + goto free_kset; + + boot_kobj = iscsi_boot_create_initiator(phba->boot_kset, 0, phba, + beiscsi_show_boot_ini_info, + beiscsi_ini_get_attr_visibility); + if (!boot_kobj) + goto free_kset; + + boot_kobj = iscsi_boot_create_ethernet(phba->boot_kset, 0, phba, + beiscsi_show_boot_eth_info, + beiscsi_eth_get_attr_visibility); + if (!boot_kobj) + goto free_kset; + return 0; + +free_kset: + iscsi_boot_destroy_kset(phba->boot_kset); + return -ENOMEM; +} + /*------------------- PCI Driver operations and data ----------------- */ static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = { { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, @@ -268,6 +481,15 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) if (iscsi_host_add(shost, &phba->pcidev->dev)) goto free_devices; + + if (beiscsi_setup_boot_info(phba)) + /* + * log error but continue, because we may not be using + * iscsi boot. + */ + shost_printk(KERN_ERR, phba->shost, "Could not set up " + "iSCSI boot info."); + return phba; free_devices: @@ -3279,6 +3501,89 @@ static void hwi_disable_intr(struct beiscsi_hba *phba) "In hwi_disable_intr, Already Disabled\n"); } +static int beiscsi_get_boot_info(struct beiscsi_hba *phba) +{ + struct be_cmd_resp_get_boot_target *boot_resp; + struct be_cmd_resp_get_session *session_resp; + struct be_mcc_wrb *wrb; + struct be_dma_mem nonemb_cmd; + unsigned int tag, wrb_num; + unsigned short status, extd_status; + struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + + tag = beiscsi_get_boot_target(phba); + if (!tag) { + SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n"); + return -EAGAIN; + } else + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + + wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; + extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; + status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; + if (status || extd_status) { + SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed" + " status = %d extd_status = %d\n", + status, extd_status); + free_mcc_tag(&phba->ctrl, tag); + return -EBUSY; + } + wrb = queue_get_wrb(mccq, wrb_num); + free_mcc_tag(&phba->ctrl, tag); + boot_resp = embedded_payload(wrb); + + if (boot_resp->boot_session_handle < 0) { + printk(KERN_ERR "No Boot Session for this pci_func," + "session Hndl = %d\n", boot_resp->boot_session_handle); + return -ENXIO; + } + + nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, + sizeof(*session_resp), + &nonemb_cmd.dma); + if (nonemb_cmd.va == NULL) { + SE_DEBUG(DBG_LVL_1, + "Failed to allocate memory for" + "beiscsi_get_session_info\n"); + return -ENOMEM; + } + + memset(nonemb_cmd.va, 0, sizeof(*session_resp)); + tag = beiscsi_get_session_info(phba, + boot_resp->boot_session_handle, &nonemb_cmd); + if (!tag) { + SE_DEBUG(DBG_LVL_1, "beiscsi_get_session_info" + " Failed\n"); + goto boot_freemem; + } else + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + + wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; + extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; + status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; + if (status || extd_status) { + SE_DEBUG(DBG_LVL_1, "beiscsi_get_session_info Failed" + " status = %d extd_status = %d\n", + status, extd_status); + free_mcc_tag(&phba->ctrl, tag); + goto boot_freemem; + } + wrb = queue_get_wrb(mccq, wrb_num); + free_mcc_tag(&phba->ctrl, tag); + session_resp = nonemb_cmd.va ; + memcpy(&phba->boot_sess, &session_resp->session_info, + sizeof(struct mgmt_session_info)); + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + return 0; +boot_freemem: + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + return -ENOMEM; +} + static int beiscsi_init_port(struct beiscsi_hba *phba) { int ret; @@ -3841,6 +4146,7 @@ static void beiscsi_remove(struct pci_dev *pcidev) iscsi_host_remove(phba->shost); pci_dev_put(phba->pcidev); iscsi_host_free(phba->shost); + iscsi_boot_destroy_kset(phba->boot_kset); } static void beiscsi_msix_enable(struct beiscsi_hba *phba) @@ -3996,6 +4302,11 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, goto free_blkenbld; } hwi_enable_intr(phba); + ret = beiscsi_get_boot_info(phba); + if (ret < 0) { + shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" + "No Boot Devices !!!!!\n"); + } SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n"); return 0; diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index c643bb3736fc..48b7d4d28d9d 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -312,6 +312,7 @@ struct beiscsi_hba { struct list_head hba_queue; unsigned short *cid_array; struct iscsi_endpoint **ep_array; + struct iscsi_boot_kset *boot_kset; struct Scsi_Host *shost; struct { /** @@ -342,6 +343,8 @@ struct beiscsi_hba { struct work_struct work_cqs; /* The work being queued */ struct be_ctrl_info ctrl; unsigned int generation; + unsigned int read_mac_address; + struct mgmt_session_info boot_sess; struct invalidate_command_table inv_tbl[128]; }; diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 3f3fab91a7d1..26350e470bcc 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -20,6 +20,77 @@ #include "be_mgmt.h" #include "be_iscsi.h" +#include + +unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_mac_addr *req; + unsigned int tag = 0; + + SE_DEBUG(DBG_LVL_8, "In bescsi_get_boot_target\n"); + spin_lock(&ctrl->mbox_lock); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + + wrb = wrb_from_mccq(phba); + req = embedded_payload(wrb); + wrb->tag0 |= tag; + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET, + sizeof(*req)); + + be_mcc_notify(phba); + spin_unlock(&ctrl->mbox_lock); + return tag; +} + +unsigned int beiscsi_get_session_info(struct beiscsi_hba *phba, + u32 boot_session_handle, + struct be_dma_mem *nonemb_cmd) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb; + unsigned int tag = 0; + struct be_cmd_req_get_session *req; + struct be_cmd_resp_get_session *resp; + struct be_sge *sge; + + SE_DEBUG(DBG_LVL_8, "In beiscsi_get_session_info\n"); + spin_lock(&ctrl->mbox_lock); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + + nonemb_cmd->size = sizeof(*resp); + req = nonemb_cmd->va; + memset(req, 0, sizeof(*req)); + wrb = wrb_from_mccq(phba); + sge = nonembedded_sgl(wrb); + wrb->tag0 |= tag; + + + wrb->tag0 |= tag; + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_SESSION_GET_A_SESSION, + sizeof(*resp)); + req->session_handle = boot_session_handle; + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); + + be_mcc_notify(phba); + spin_unlock(&ctrl->mbox_lock); + return tag; +} int mgmt_get_fw_config(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba) -- cgit From e919dee8a398fea1db184ce1418e70170a01c8fa Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:30:32 +0530 Subject: [SCSI] be2iscsi: Increase max sector This patch increases the max_sectors to 2048 Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 48b7d4d28d9d..6cfa55d019da 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -63,7 +63,7 @@ #define BEISCSI_SGLIST_ELEMENTS 30 #define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */ -#define BEISCSI_MAX_SECTORS 256 /* scsi_host->max_sectors */ +#define BEISCSI_MAX_SECTORS 2048 /* scsi_host->max_sectors */ #define BEISCSI_MAX_CMD_LEN 16 /* scsi_host->max_cmd_len */ #define BEISCSI_NUM_MAX_LUN 256 /* scsi_host->max_lun */ -- cgit From dd81beaee9a8bf000f7fbfe609b5a0fc9607e233 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:31:07 +0530 Subject: [SCSI] be2iscsi: Driver Version change to 2.0.549.0 Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 6cfa55d019da..90eb74f6bcab 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -35,7 +35,7 @@ #include "be.h" #define DRV_NAME "be2iscsi" -#define BUILD_STR "2.0.527.0" +#define BUILD_STR "2.0.549.0" #define BE_NAME "ServerEngines BladeEngine2" \ "Linux iSCSI Driver version" BUILD_STR #define DRV_DESC BE_NAME " " "Driver" -- cgit From 787f0bd3376aedb3f9ba9bbf862d85e4b176f9b0 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 29 Jul 2010 10:16:09 -0700 Subject: [SCSI] be2iscsi: select ISCSI_BOOT_SYSFS be2iscsi uses iscsi_boot_*() interfaces, so it should ensure that ISCSI_BOOT_SYSFS is enabled. ERROR: "iscsi_boot_create_target" [drivers/scsi/be2iscsi/be2iscsi.ko] undefined! ERROR: "iscsi_boot_create_ethernet" [drivers/scsi/be2iscsi/be2iscsi.ko] undefined! ERROR: "iscsi_boot_create_host_kset" [drivers/scsi/be2iscsi/be2iscsi.ko] undefined! ERROR: "iscsi_boot_create_initiator" [drivers/scsi/be2iscsi/be2iscsi.ko] undefined! ERROR: "iscsi_boot_destroy_kset" [drivers/scsi/be2iscsi/be2iscsi.ko] undefined! Signed-off-by: Randy Dunlap Acked-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig index 84c275fb9f6b..ceaca32e788d 100644 --- a/drivers/scsi/be2iscsi/Kconfig +++ b/drivers/scsi/be2iscsi/Kconfig @@ -2,6 +2,7 @@ config BE2ISCSI tristate "ServerEngines' 10Gbps iSCSI - BladeEngine 2" depends on PCI && SCSI && NET select SCSI_ISCSI_ATTRS + select ISCSI_BOOT_SYSFS help This driver implements the iSCSI functionality for ServerEngines' -- cgit From 2dc11581376829303b98eadb2de253bee065a56a Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 6 Aug 2010 09:25:50 -0600 Subject: of/device: Replace struct of_device with struct platform_device of_device is just an alias for platform_device, so remove it entirely. Also replace to_of_device() with to_platform_device() and update comment blocks. This patch was initially generated from the following semantic patch, and then edited by hand to pick up the bits that coccinelle didn't catch. @@ @@ -struct of_device +struct platform_device Signed-off-by: Grant Likely Reviewed-by: David S. Miller --- drivers/scsi/qlogicpti.c | 14 +++++++------- drivers/scsi/qlogicpti.h | 2 +- drivers/scsi/sun_esp.c | 44 ++++++++++++++++++++++---------------------- 3 files changed, 30 insertions(+), 30 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 53d7ed0dc169..f8c561cf751e 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -704,7 +704,7 @@ static void __devexit qpti_chain_del(struct qlogicpti *qpti) static int __devinit qpti_map_regs(struct qlogicpti *qpti) { - struct of_device *op = qpti->op; + struct platform_device *op = qpti->op; qpti->qregs = of_ioremap(&op->resource[0], 0, resource_size(&op->resource[0]), @@ -727,7 +727,7 @@ static int __devinit qpti_map_regs(struct qlogicpti *qpti) static int __devinit qpti_register_irq(struct qlogicpti *qpti) { - struct of_device *op = qpti->op; + struct platform_device *op = qpti->op; qpti->qhost->irq = qpti->irq = op->archdata.irqs[0]; @@ -752,7 +752,7 @@ fail: static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti) { - struct of_device *op = qpti->op; + struct platform_device *op = qpti->op; struct device_node *dp; dp = op->dev.of_node; @@ -773,7 +773,7 @@ static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti) static void qpti_get_bursts(struct qlogicpti *qpti) { - struct of_device *op = qpti->op; + struct platform_device *op = qpti->op; u8 bursts, bmask; bursts = of_getintprop_default(op->dev.of_node, "burst-sizes", 0xff); @@ -806,7 +806,7 @@ static void qpti_get_clock(struct qlogicpti *qpti) */ static int __devinit qpti_map_queues(struct qlogicpti *qpti) { - struct of_device *op = qpti->op; + struct platform_device *op = qpti->op; #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) qpti->res_cpu = dma_alloc_coherent(&op->dev, @@ -1290,7 +1290,7 @@ static struct scsi_host_template qpti_template = { .use_clustering = ENABLE_CLUSTERING, }; -static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit qpti_sbus_probe(struct platform_device *op, const struct of_device_id *match) { struct scsi_host_template *tpnt = match->data; struct device_node *dp = op->dev.of_node; @@ -1401,7 +1401,7 @@ fail_unlink: return -ENODEV; } -static int __devexit qpti_sbus_remove(struct of_device *op) +static int __devexit qpti_sbus_remove(struct platform_device *op) { struct qlogicpti *qpti = dev_get_drvdata(&op->dev); diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h index e3c74d1ee2db..4377e87ee79c 100644 --- a/drivers/scsi/qlogicpti.h +++ b/drivers/scsi/qlogicpti.h @@ -342,7 +342,7 @@ struct qlogicpti { u_int req_in_ptr; /* index of next request slot */ u_int res_out_ptr; /* index of next result slot */ long send_marker; /* must we send a marker? */ - struct of_device *op; + struct platform_device *op; unsigned long __pad; int cmd_count[MAX_TARGETS]; diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index 89ba6fe02f80..193b37ba1834 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -44,7 +44,7 @@ enum dvma_rev { }; static int __devinit esp_sbus_setup_dma(struct esp *esp, - struct of_device *dma_of) + struct platform_device *dma_of) { esp->dma = dma_of; @@ -81,7 +81,7 @@ static int __devinit esp_sbus_setup_dma(struct esp *esp, static int __devinit esp_sbus_map_regs(struct esp *esp, int hme) { - struct of_device *op = esp->dev; + struct platform_device *op = esp->dev; struct resource *res; /* On HME, two reg sets exist, first is DVMA, @@ -101,7 +101,7 @@ static int __devinit esp_sbus_map_regs(struct esp *esp, int hme) static int __devinit esp_sbus_map_command_block(struct esp *esp) { - struct of_device *op = esp->dev; + struct platform_device *op = esp->dev; esp->command_block = dma_alloc_coherent(&op->dev, 16, &esp->command_block_dma, @@ -114,15 +114,15 @@ static int __devinit esp_sbus_map_command_block(struct esp *esp) static int __devinit esp_sbus_register_irq(struct esp *esp) { struct Scsi_Host *host = esp->host; - struct of_device *op = esp->dev; + struct platform_device *op = esp->dev; host->irq = op->archdata.irqs[0]; return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); } -static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma) +static void __devinit esp_get_scsi_id(struct esp *esp, struct platform_device *espdma) { - struct of_device *op = esp->dev; + struct platform_device *op = esp->dev; struct device_node *dp; dp = op->dev.of_node; @@ -144,7 +144,7 @@ done: static void __devinit esp_get_differential(struct esp *esp) { - struct of_device *op = esp->dev; + struct platform_device *op = esp->dev; struct device_node *dp; dp = op->dev.of_node; @@ -156,7 +156,7 @@ static void __devinit esp_get_differential(struct esp *esp) static void __devinit esp_get_clock_params(struct esp *esp) { - struct of_device *op = esp->dev; + struct platform_device *op = esp->dev; struct device_node *bus_dp, *dp; int fmhz; @@ -170,10 +170,10 @@ static void __devinit esp_get_clock_params(struct esp *esp) esp->cfreq = fmhz; } -static void __devinit esp_get_bursts(struct esp *esp, struct of_device *dma_of) +static void __devinit esp_get_bursts(struct esp *esp, struct platform_device *dma_of) { struct device_node *dma_dp = dma_of->dev.of_node; - struct of_device *op = esp->dev; + struct platform_device *op = esp->dev; struct device_node *dp; u8 bursts, val; @@ -195,7 +195,7 @@ static void __devinit esp_get_bursts(struct esp *esp, struct of_device *dma_of) esp->bursts = bursts; } -static void __devinit esp_sbus_get_props(struct esp *esp, struct of_device *espdma) +static void __devinit esp_sbus_get_props(struct esp *esp, struct platform_device *espdma) { esp_get_scsi_id(esp, espdma); esp_get_differential(esp); @@ -216,7 +216,7 @@ static u8 sbus_esp_read8(struct esp *esp, unsigned long reg) static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf, size_t sz, int dir) { - struct of_device *op = esp->dev; + struct platform_device *op = esp->dev; return dma_map_single(&op->dev, buf, sz, dir); } @@ -224,7 +224,7 @@ static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf, static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg, int num_sg, int dir) { - struct of_device *op = esp->dev; + struct platform_device *op = esp->dev; return dma_map_sg(&op->dev, sg, num_sg, dir); } @@ -232,7 +232,7 @@ static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg, static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr, size_t sz, int dir) { - struct of_device *op = esp->dev; + struct platform_device *op = esp->dev; dma_unmap_single(&op->dev, addr, sz, dir); } @@ -240,7 +240,7 @@ static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr, static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, int num_sg, int dir) { - struct of_device *op = esp->dev; + struct platform_device *op = esp->dev; dma_unmap_sg(&op->dev, sg, num_sg, dir); } @@ -256,7 +256,7 @@ static void sbus_esp_reset_dma(struct esp *esp) { int can_do_burst16, can_do_burst32, can_do_burst64; int can_do_sbus64, lim; - struct of_device *op; + struct platform_device *op; u32 val; can_do_burst16 = (esp->bursts & DMA_BURST16) != 0; @@ -487,8 +487,8 @@ static const struct esp_driver_ops sbus_esp_ops = { .dma_error = sbus_esp_dma_error, }; -static int __devinit esp_sbus_probe_one(struct of_device *op, - struct of_device *espdma, +static int __devinit esp_sbus_probe_one(struct platform_device *op, + struct platform_device *espdma, int hme) { struct scsi_host_template *tpnt = &scsi_esp_template; @@ -562,11 +562,11 @@ fail: return err; } -static int __devinit esp_sbus_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit esp_sbus_probe(struct platform_device *op, const struct of_device_id *match) { struct device_node *dma_node = NULL; struct device_node *dp = op->dev.of_node; - struct of_device *dma_of = NULL; + struct platform_device *dma_of = NULL; int hme = 0; if (dp->parent && @@ -585,10 +585,10 @@ static int __devinit esp_sbus_probe(struct of_device *op, const struct of_device return esp_sbus_probe_one(op, dma_of, hme); } -static int __devexit esp_sbus_remove(struct of_device *op) +static int __devexit esp_sbus_remove(struct platform_device *op) { struct esp *esp = dev_get_drvdata(&op->dev); - struct of_device *dma_of = esp->dma; + struct platform_device *dma_of = esp->dma; unsigned int irq = esp->host->irq; bool is_hme; u32 val; -- cgit From aab7a8fd19d0c2f7fcac4d07616899655e326dfe Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 2 Aug 2010 12:46:12 -0500 Subject: [SCSI] iscsi boot: mv iscsi_boot_sysfs to drivers/scsi iscsi_boot_sysfs does not depend on firmware. Any iscsi driver can use it. This patch moves iscsi_boot_sysfs to the scsi dir, so that it can be used on any arch with any driver. Signed-off-by: Mike Christie Acked-by: Konrad Rzeszutek Wilk Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 8 + drivers/scsi/Makefile | 1 + drivers/scsi/iscsi_boot_sysfs.c | 481 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 490 insertions(+) create mode 100644 drivers/scsi/iscsi_boot_sysfs.c (limited to 'drivers/scsi') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 158284f05732..a479b3b7ea90 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -370,6 +370,14 @@ config ISCSI_TCP http://open-iscsi.org +config ISCSI_BOOT_SYSFS + tristate "iSCSI Boot Sysfs Interface" + default n + help + This option enables support for exposing iSCSI boot information + via sysfs to userspace. If you wish to export this information, + say Y. Otherwise, say N. + source "drivers/scsi/cxgb3i/Kconfig" source "drivers/scsi/bnx2i/Kconfig" source "drivers/scsi/be2iscsi/Kconfig" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 2a3fca2eca6a..2703c6ec5e36 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_FCOE) += fcoe/ obj-$(CONFIG_FCOE_FNIC) += fnic/ obj-$(CONFIG_ISCSI_TCP) += libiscsi.o libiscsi_tcp.o iscsi_tcp.o obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o +obj-$(CONFIG_ISCSI_BOOT_SYSFS) += iscsi_boot_sysfs.o obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o obj-$(CONFIG_SCSI_ZORRO7XX) += 53c700.o zorro7xx.o obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c new file mode 100644 index 000000000000..df6bff7366cf --- /dev/null +++ b/drivers/scsi/iscsi_boot_sysfs.c @@ -0,0 +1,481 @@ +/* + * Export the iSCSI boot info to userland via sysfs. + * + * Copyright (C) 2010 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010 Mike Christie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2.0 as published by + * the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + + +MODULE_AUTHOR("Mike Christie "); +MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI boot information"); +MODULE_LICENSE("GPL"); +/* + * The kobject and attribute structures. + */ +struct iscsi_boot_attr { + struct attribute attr; + int type; + ssize_t (*show) (void *data, int type, char *buf); +}; + +/* + * The routine called for all sysfs attributes. + */ +static ssize_t iscsi_boot_show_attribute(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct iscsi_boot_kobj *boot_kobj = + container_of(kobj, struct iscsi_boot_kobj, kobj); + struct iscsi_boot_attr *boot_attr = + container_of(attr, struct iscsi_boot_attr, attr); + ssize_t ret = -EIO; + char *str = buf; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (boot_kobj->show) + ret = boot_kobj->show(boot_kobj->data, boot_attr->type, str); + return ret; +} + +static const struct sysfs_ops iscsi_boot_attr_ops = { + .show = iscsi_boot_show_attribute, +}; + +static void iscsi_boot_kobj_release(struct kobject *kobj) +{ + struct iscsi_boot_kobj *boot_kobj = + container_of(kobj, struct iscsi_boot_kobj, kobj); + + kfree(boot_kobj->data); + kfree(boot_kobj); +} + +static struct kobj_type iscsi_boot_ktype = { + .release = iscsi_boot_kobj_release, + .sysfs_ops = &iscsi_boot_attr_ops, +}; + +#define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type) \ +static struct iscsi_boot_attr iscsi_boot_attr_##fnname = { \ + .attr = { .name = __stringify(sysfs_name), .mode = 0444 }, \ + .type = attr_type, \ +} + +/* Target attrs */ +iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX); +iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS); +iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR); +iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT); +iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN); +iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE); +iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC); +iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME); +iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME); +iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET); +iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name, + ISCSI_BOOT_TGT_REV_CHAP_NAME); +iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret, + ISCSI_BOOT_TGT_REV_CHAP_SECRET); + +static struct attribute *target_attrs[] = { + &iscsi_boot_attr_tgt_index.attr, + &iscsi_boot_attr_tgt_flags.attr, + &iscsi_boot_attr_tgt_ip.attr, + &iscsi_boot_attr_tgt_port.attr, + &iscsi_boot_attr_tgt_lun.attr, + &iscsi_boot_attr_tgt_chap.attr, + &iscsi_boot_attr_tgt_nic.attr, + &iscsi_boot_attr_tgt_name.attr, + &iscsi_boot_attr_tgt_chap_name.attr, + &iscsi_boot_attr_tgt_chap_secret.attr, + &iscsi_boot_attr_tgt_chap_rev_name.attr, + &iscsi_boot_attr_tgt_chap_rev_secret.attr, + NULL +}; + +static mode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct iscsi_boot_kobj *boot_kobj = + container_of(kobj, struct iscsi_boot_kobj, kobj); + + if (attr == &iscsi_boot_attr_tgt_index.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_INDEX); + else if (attr == &iscsi_boot_attr_tgt_flags.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_FLAGS); + else if (attr == &iscsi_boot_attr_tgt_ip.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_IP_ADDR); + else if (attr == &iscsi_boot_attr_tgt_port.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_PORT); + else if (attr == &iscsi_boot_attr_tgt_lun.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_LUN); + else if (attr == &iscsi_boot_attr_tgt_chap.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_CHAP_TYPE); + else if (attr == &iscsi_boot_attr_tgt_nic.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_NIC_ASSOC); + else if (attr == &iscsi_boot_attr_tgt_name.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_NAME); + else if (attr == &iscsi_boot_attr_tgt_chap_name.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_CHAP_NAME); + else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_CHAP_SECRET); + else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_REV_CHAP_NAME); + else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_TGT_REV_CHAP_SECRET); + return 0; +} + +static struct attribute_group iscsi_boot_target_attr_group = { + .attrs = target_attrs, + .is_visible = iscsi_boot_tgt_attr_is_visible, +}; + +/* Ethernet attrs */ +iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX); +iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS); +iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR); +iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK); +iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN); +iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY); +iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS); +iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns, + ISCSI_BOOT_ETH_SECONDARY_DNS); +iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP); +iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN); +iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC); +iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME); + +static struct attribute *ethernet_attrs[] = { + &iscsi_boot_attr_eth_index.attr, + &iscsi_boot_attr_eth_flags.attr, + &iscsi_boot_attr_eth_ip.attr, + &iscsi_boot_attr_eth_subnet.attr, + &iscsi_boot_attr_eth_origin.attr, + &iscsi_boot_attr_eth_gateway.attr, + &iscsi_boot_attr_eth_primary_dns.attr, + &iscsi_boot_attr_eth_secondary_dns.attr, + &iscsi_boot_attr_eth_dhcp.attr, + &iscsi_boot_attr_eth_vlan.attr, + &iscsi_boot_attr_eth_mac.attr, + &iscsi_boot_attr_eth_hostname.attr, + NULL +}; + +static mode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct iscsi_boot_kobj *boot_kobj = + container_of(kobj, struct iscsi_boot_kobj, kobj); + + if (attr == &iscsi_boot_attr_eth_index.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_INDEX); + else if (attr == &iscsi_boot_attr_eth_flags.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_FLAGS); + else if (attr == &iscsi_boot_attr_eth_ip.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_IP_ADDR); + else if (attr == &iscsi_boot_attr_eth_subnet.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_SUBNET_MASK); + else if (attr == &iscsi_boot_attr_eth_origin.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_ORIGIN); + else if (attr == &iscsi_boot_attr_eth_gateway.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_GATEWAY); + else if (attr == &iscsi_boot_attr_eth_primary_dns.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_PRIMARY_DNS); + else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_SECONDARY_DNS); + else if (attr == &iscsi_boot_attr_eth_dhcp.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_DHCP); + else if (attr == &iscsi_boot_attr_eth_vlan.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_VLAN); + else if (attr == &iscsi_boot_attr_eth_mac.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_MAC); + else if (attr == &iscsi_boot_attr_eth_hostname.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_ETH_HOSTNAME); + return 0; +} + +static struct attribute_group iscsi_boot_ethernet_attr_group = { + .attrs = ethernet_attrs, + .is_visible = iscsi_boot_eth_attr_is_visible, +}; + +/* Initiator attrs */ +iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX); +iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS); +iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER); +iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER); +iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server, + ISCSI_BOOT_INI_PRI_RADIUS_SERVER); +iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server, + ISCSI_BOOT_INI_SEC_RADIUS_SERVER); +iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME); + +static struct attribute *initiator_attrs[] = { + &iscsi_boot_attr_ini_index.attr, + &iscsi_boot_attr_ini_flags.attr, + &iscsi_boot_attr_ini_isns.attr, + &iscsi_boot_attr_ini_slp.attr, + &iscsi_boot_attr_ini_primary_radius.attr, + &iscsi_boot_attr_ini_secondary_radius.attr, + &iscsi_boot_attr_ini_name.attr, + NULL +}; + +static mode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct iscsi_boot_kobj *boot_kobj = + container_of(kobj, struct iscsi_boot_kobj, kobj); + + if (attr == &iscsi_boot_attr_ini_index.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_INDEX); + if (attr == &iscsi_boot_attr_ini_flags.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_FLAGS); + if (attr == &iscsi_boot_attr_ini_isns.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_ISNS_SERVER); + if (attr == &iscsi_boot_attr_ini_slp.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_SLP_SERVER); + if (attr == &iscsi_boot_attr_ini_primary_radius.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_PRI_RADIUS_SERVER); + if (attr == &iscsi_boot_attr_ini_secondary_radius.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_SEC_RADIUS_SERVER); + if (attr == &iscsi_boot_attr_ini_name.attr) + return boot_kobj->is_visible(boot_kobj->data, + ISCSI_BOOT_INI_INITIATOR_NAME); + + return 0; +} + +static struct attribute_group iscsi_boot_initiator_attr_group = { + .attrs = initiator_attrs, + .is_visible = iscsi_boot_ini_attr_is_visible, +}; + +static struct iscsi_boot_kobj * +iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, + struct attribute_group *attr_group, + const char *name, int index, void *data, + ssize_t (*show) (void *data, int type, char *buf), + mode_t (*is_visible) (void *data, int type)) +{ + struct iscsi_boot_kobj *boot_kobj; + + boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL); + if (!boot_kobj) + return NULL; + INIT_LIST_HEAD(&boot_kobj->list); + + boot_kobj->kobj.kset = boot_kset->kset; + if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype, + NULL, name, index)) { + kfree(boot_kobj); + return NULL; + } + boot_kobj->data = data; + boot_kobj->show = show; + boot_kobj->is_visible = is_visible; + + if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { + /* + * We do not want to free this because the caller + * will assume that since the creation call failed + * the boot kobj was not setup and the normal release + * path is not being run. + */ + boot_kobj->data = NULL; + kobject_put(&boot_kobj->kobj); + return NULL; + } + boot_kobj->attr_group = attr_group; + + kobject_uevent(&boot_kobj->kobj, KOBJ_ADD); + /* Nothing broke so lets add it to the list. */ + list_add_tail(&boot_kobj->list, &boot_kset->kobj_list); + return boot_kobj; +} + +static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj) +{ + list_del(&boot_kobj->list); + sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group); + kobject_put(&boot_kobj->kobj); +} + +/** + * iscsi_boot_create_target() - create boot target sysfs dir + * @boot_kset: boot kset + * @index: the target id + * @data: driver specific data for target + * @show: attr show function + * @is_visible: attr visibility function + * + * Note: The boot sysfs lib will free the data passed in for the caller + * when all refs to the target kobject have been released. + */ +struct iscsi_boot_kobj * +iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, + void *data, + ssize_t (*show) (void *data, int type, char *buf), + mode_t (*is_visible) (void *data, int type)) +{ + return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, + "target%d", index, data, show, is_visible); +} +EXPORT_SYMBOL_GPL(iscsi_boot_create_target); + +/** + * iscsi_boot_create_initiator() - create boot initiator sysfs dir + * @boot_kset: boot kset + * @index: the initiator id + * @data: driver specific data + * @show: attr show function + * @is_visible: attr visibility function + * + * Note: The boot sysfs lib will free the data passed in for the caller + * when all refs to the initiator kobject have been released. + */ +struct iscsi_boot_kobj * +iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, + void *data, + ssize_t (*show) (void *data, int type, char *buf), + mode_t (*is_visible) (void *data, int type)) +{ + return iscsi_boot_create_kobj(boot_kset, + &iscsi_boot_initiator_attr_group, + "initiator", index, data, show, + is_visible); +} +EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); + +/** + * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir + * @boot_kset: boot kset + * @index: the ethernet device id + * @data: driver specific data + * @show: attr show function + * @is_visible: attr visibility function + * + * Note: The boot sysfs lib will free the data passed in for the caller + * when all refs to the ethernet kobject have been released. + */ +struct iscsi_boot_kobj * +iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, + void *data, + ssize_t (*show) (void *data, int type, char *buf), + mode_t (*is_visible) (void *data, int type)) +{ + return iscsi_boot_create_kobj(boot_kset, + &iscsi_boot_ethernet_attr_group, + "ethernet%d", index, data, show, + is_visible); +} +EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); + +/** + * iscsi_boot_create_kset() - creates root sysfs tree + * @set_name: name of root dir + */ +struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name) +{ + struct iscsi_boot_kset *boot_kset; + + boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL); + if (!boot_kset) + return NULL; + + boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj); + if (!boot_kset->kset) { + kfree(boot_kset); + return NULL; + } + + INIT_LIST_HEAD(&boot_kset->kobj_list); + return boot_kset; +} +EXPORT_SYMBOL_GPL(iscsi_boot_create_kset); + +/** + * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host + * @hostno: host number of scsi host + */ +struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno) +{ + struct iscsi_boot_kset *boot_kset; + char *set_name; + + set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno); + if (!set_name) + return NULL; + + boot_kset = iscsi_boot_create_kset(set_name); + kfree(set_name); + return boot_kset; +} +EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset); + +/** + * iscsi_boot_destroy_kset() - destroy kset and kobjects under it + * @boot_kset: boot kset + * + * This will remove the kset and kobjects and attrs under it. + */ +void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) +{ + struct iscsi_boot_kobj *boot_kobj, *tmp_kobj; + + list_for_each_entry_safe(boot_kobj, tmp_kobj, + &boot_kset->kobj_list, list) + iscsi_boot_remove_kobj(boot_kobj); + + kset_unregister(boot_kset->kset); +} +EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset); -- cgit From 26845f585fad66dc23d87dad89d403cd64b48780 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 5 Aug 2010 13:17:10 -0400 Subject: [SCSI] remove fake "address-of" expression Fake "address-of" expressions that evaluate to NULL generally confuse readers and can provoke compiler warnings. This patch (as1411) removes one such fake expression introduced by: commit db5bd1e0b505c54ff492172ce4abc245cf6cd639 Author: Alan Stern Date: Thu Jun 17 10:36:49 2010 -0400 [SCSI] convert to the new PM framework using an "#ifdef" in its place. Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/scsi_priv.h | 2 -- drivers/scsi/scsi_sysfs.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 026295e2c539..b4056d14f812 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -148,8 +148,6 @@ static inline void scsi_netlink_exit(void) {} /* scsi_pm.c */ #ifdef CONFIG_PM_OPS extern const struct dev_pm_ops scsi_bus_pm_ops; -#else /* CONFIG_PM_OPS */ -#define scsi_bus_pm_ops (*NULL) #endif #ifdef CONFIG_PM_RUNTIME extern void scsi_autopm_get_target(struct scsi_target *); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 562fb3bce261..c3f67373a4f8 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -381,7 +381,9 @@ struct bus_type scsi_bus_type = { .name = "scsi", .match = scsi_bus_match, .uevent = scsi_bus_uevent, +#ifdef CONFIG_PM_OPS .pm = &scsi_bus_pm_ops, +#endif }; EXPORT_SYMBOL_GPL(scsi_bus_type); -- cgit From be948fc30dabc347e4fba4daf4da9fd83d2abf49 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 2 Aug 2010 16:02:24 -0500 Subject: [SCSI] libfc: call fc_remote_port_chkready under the host lock. The rport port state and flags are set under the host lock, so this patch calls fc_remote_port_chkready with the host lock held like is also done in the other fc drivers. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_fcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index eac4d09314eb..c797f6b48f05 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1765,14 +1765,14 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *)) struct fcoe_dev_stats *stats; lport = shost_priv(sc_cmd->device->host); - spin_unlock_irq(lport->host->host_lock); rval = fc_remote_port_chkready(rport); if (rval) { sc_cmd->result = rval; done(sc_cmd); - goto out; + return 0; } + spin_unlock_irq(lport->host->host_lock); if (!*(struct fc_remote_port **)rport->dd_data) { /* -- cgit From 3013cea83ef3532e49b973a0bc9b3562f56871c6 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Fri, 30 Jul 2010 14:25:46 +0530 Subject: [SCSI] qla4xxx: set correct value in sess->recovery_tmo Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_def.h | 5 +++-- drivers/scsi/qla4xxx/ql4_init.c | 3 --- drivers/scsi/qla4xxx/ql4_mbx.c | 1 - drivers/scsi/qla4xxx/ql4_os.c | 7 ++++--- 4 files changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index a79da8dd2064..6af5d04c5290 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -137,6 +137,9 @@ #define ISCSI_ALIAS_SIZE 32 /* ISCSI Alias name size */ #define ISCSI_NAME_SIZE 0xE0 /* ISCSI Name size */ +#define QL4_SESS_RECOVERY_TMO 30 /* iSCSI session */ + /* recovery timeout */ + #define LSDW(x) ((u32)((u64)(x))) #define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16)) @@ -249,7 +252,6 @@ struct ddb_entry { uint32_t default_time2wait; /* Default Min time between * relogins (+aens) */ - atomic_t port_down_timer; /* Device connection timer */ atomic_t retry_relogin_timer; /* Min Time between relogins * (4000 only) */ atomic_t relogin_timer; /* Max Time to wait for relogin to complete */ @@ -474,7 +476,6 @@ struct scsi_qla_host { uint32_t timer_active; /* Recovery Timers */ - uint32_t port_down_retry_count; uint32_t discovery_wait; atomic_t check_relogin_timeouts; uint32_t retry_reset_ha_cnt; diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 30073577c3a4..b69c5736cb43 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -669,7 +669,6 @@ static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, } ddb_entry->fw_ddb_index = fw_ddb_index; - atomic_set(&ddb_entry->port_down_timer, ha->port_down_retry_count); atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); atomic_set(&ddb_entry->relogin_timer, 0); atomic_set(&ddb_entry->relogin_retry_count, 0); @@ -1556,8 +1555,6 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, /* Device is back online. */ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); - atomic_set(&ddb_entry->port_down_timer, - ha->port_down_retry_count); atomic_set(&ddb_entry->relogin_retry_count, 0); atomic_set(&ddb_entry->relogin_timer, 0); clear_bit(DF_RELOGIN, &ddb_entry->flags); diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 940ee561ee0a..c4e036b449c2 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -361,7 +361,6 @@ qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ /* Save Command Line Paramater info */ - ha->port_down_retry_count = le16_to_cpu(init_fw_cb->conn_ka_timeout); ha->discovery_wait = ql4xdiscoverywait; if (ha->acb_version == ACB_SUPPORTED) { diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 5529b2a39741..fd1af23e6801 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -163,10 +163,10 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { atomic_set(&ddb_entry->state, DDB_STATE_DEAD); - DEBUG2(printk("scsi%ld: %s: ddb [%d] port down retry count " + DEBUG2(printk("scsi%ld: %s: ddb [%d] session recovery timeout " "of (%d) secs exhausted, marking device DEAD.\n", ha->host_no, __func__, ddb_entry->fw_ddb_index, - ha->port_down_retry_count)); + QL4_SESS_RECOVERY_TMO)); qla4xxx_wake_dpc(ha); } @@ -298,7 +298,8 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) { int err; - ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count; + ddb_entry->sess->recovery_tmo = QL4_SESS_RECOVERY_TMO; + err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); if (err) { DEBUG2(printk(KERN_ERR "Could not add session.\n")); -- cgit From b173a132cbf0a4a48b2f341716e20a6d8b24957e Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Fri, 30 Jul 2010 14:26:08 +0530 Subject: [SCSI] qla4xxx: Use the correct request queue. Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_iocb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c index f89973deac5b..4ef9ba112ee8 100644 --- a/drivers/scsi/qla4xxx/ql4_iocb.c +++ b/drivers/scsi/qla4xxx/ql4_iocb.c @@ -19,7 +19,7 @@ qla4xxx_space_in_req_ring(struct scsi_qla_host *ha, uint16_t req_cnt) /* Calculate number of free request entries. */ if ((req_cnt + 2) >= ha->req_q_count) { - cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out); + cnt = (uint16_t) ha->isp_ops->rd_shdw_req_q_out(ha); if (ha->request_in < cnt) ha->req_q_count = cnt - ha->request_in; else -- cgit From 9d4946f89fc050cadf66d08c47379ab62848a5b7 Mon Sep 17 00:00:00 2001 From: Lalit Chandivade Date: Fri, 30 Jul 2010 14:26:31 +0530 Subject: [SCSI] qla4xxx: Stop firmware before doing init firmware. If BIOS is enabled then drivers init firmware fails since BIOS has done the init once. Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_init.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index b69c5736cb43..39048d9339ac 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -445,6 +445,12 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha) { int status = QLA_ERROR; + /* For 82xx, stop firmware before initializing because if BIOS + * has previously initialized firmware, then driver's initialize + * firmware will fail. */ + if (is_qla8022(ha)) + qla4_8xxx_stop_firmware(ha); + ql4_printk(KERN_INFO, ha, "Initializing firmware..\n"); if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) { DEBUG2(printk("scsi%ld: %s: Failed to initialize firmware " -- cgit From 0753b4871d5b09687cee652b380a6ca15aee330e Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Fri, 30 Jul 2010 14:27:19 +0530 Subject: [SCSI] qla4xxx: clear AF_DPC_SCHEDULED flage when exit from do_dpc Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index fd1af23e6801..e575d765ba26 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -1208,7 +1208,7 @@ static void qla4xxx_do_dpc(struct work_struct *work) /* Initialization not yet finished. Don't do anything yet. */ if (!test_bit(AF_INIT_DONE, &ha->flags)) - return; + goto do_dpc_exit; /* HBA is in the process of being permanently disabled. * Don't process anything */ @@ -1347,6 +1347,8 @@ dpc_post_reset_ha: } } } + +do_dpc_exit: clear_bit(AF_DPC_SCHEDULED, &ha->flags); } -- cgit From 2ccdf0dce41a39db3721fe801dac5c5effa8e4be Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Fri, 30 Jul 2010 14:27:45 +0530 Subject: [SCSI] qla4xxx: updated mbx_sys_info struct to sync with FW 4.6.x Also, changed boundary checking from size of total structure to verification that we received the amount of data needed to cache inernally. This change will provide compatibility with mbx_sys_info structure sizes in both older and newer firmware versions. Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_fw.h | 20 ++++++++++---------- drivers/scsi/qla4xxx/ql4_nx.c | 3 ++- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index c94c9ddfb3a6..0336c6db8cb3 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -673,17 +673,17 @@ struct flash_sys_info { }; /* 200 */ struct mbx_sys_info { - uint8_t board_id_str[16]; /* Keep board ID string first */ - /* in this structure for GUI. */ - uint16_t board_id; /* board ID code */ - uint16_t phys_port_cnt; /* number of physical network ports */ - uint16_t port_num; /* network port for this PCI function */ + uint8_t board_id_str[16]; /* 0-f Keep board ID string first */ + /* in this structure for GUI. */ + uint16_t board_id; /* 10-11 board ID code */ + uint16_t phys_port_cnt; /* 12-13 number of physical network ports */ + uint16_t port_num; /* 14-15 network port for this PCI function */ /* (port 0 is first port) */ - uint8_t mac_addr[6]; /* MAC address for this PCI function */ - uint32_t iscsi_pci_func_cnt; /* number of iSCSI PCI functions */ - uint32_t pci_func; /* this PCI function */ - unsigned char serial_number[16]; /* serial number string */ - uint8_t reserved[16]; + uint8_t mac_addr[6]; /* 16-1b MAC address for this PCI function */ + uint32_t iscsi_pci_func_cnt; /* 1c-1f number of iSCSI PCI functions */ + uint32_t pci_func; /* 20-23 this PCI function */ + unsigned char serial_number[16]; /* 24-33 serial number string */ + uint8_t reserved[12]; /* 34-3f */ }; struct crash_record { diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 3e119ae78397..ec46651100cb 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -2145,7 +2145,8 @@ int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha) goto exit_validate_mac82; } - if (mbox_sts[4] < sizeof(*sys_info)) { + /* Make sure we receive the minimum required data to cache internally */ + if (mbox_sts[4] < offsetof(struct mbx_sys_info, reserved)) { DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO data receive" " error (%x)\n", ha->host_no, __func__, mbox_sts[4])); goto exit_validate_mac82; -- cgit From 21033639699d883668f6937b03e7b710771ad37e Mon Sep 17 00:00:00 2001 From: Nilesh Javali Date: Fri, 30 Jul 2010 14:28:07 +0530 Subject: [SCSI] qla4xxx: Handle outstanding mbx cmds on hung f/w scenarios Outstanding mailbox commands, have no way to recover on f/w hung, and we timeout on waiting for mbx response. This in turn affects the recovery process as follows: - We might already be in dpc while waiting for mbx to complete, so recovery for that pci function will never get invoked. Reset Timeout (10 sec) is far less than mbx timeout (30 sec). - Other mbx cmds will get stuck due to serial mbx access. Solution is to identify fw-hung scenario and handle outstanding mbx commands to have an early-exit instead of waiting for response. Other mbx commands waiting for access will also do an early-exit if fw-hung is still applicable. Signed-off-by: Nilesh Javali Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_def.h | 1 + drivers/scsi/qla4xxx/ql4_glbl.h | 1 + drivers/scsi/qla4xxx/ql4_mbx.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/scsi/qla4xxx/ql4_nx.c | 3 +++ drivers/scsi/qla4xxx/ql4_os.c | 3 +++ 5 files changed, 47 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 6af5d04c5290..6c9262753243 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -380,6 +380,7 @@ struct scsi_qla_host { #define AF_MSI_ENABLED 16 /* 0x00010000 */ #define AF_MSIX_ENABLED 17 /* 0x00020000 */ #define AF_MBOX_COMMAND_NOPOLL 18 /* 0x00040000 */ +#define AF_FW_RECOVERY 19 /* 0x00080000 */ unsigned long dpc_flags; diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index c9cd5d6db982..ea3db23602e6 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -93,6 +93,7 @@ void qla4xxx_free_irqs(struct scsi_qla_host *ha); void qla4xxx_process_response_queue(struct scsi_qla_host *ha); void qla4xxx_wake_dpc(struct scsi_qla_host *ha); void qla4xxx_get_conn_event_log(struct scsi_qla_host *ha); +void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha); void qla4_8xxx_pci_config(struct scsi_qla_host *); int qla4_8xxx_iospace_config(struct scsi_qla_host *ha); diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index c4e036b449c2..1003e48d2200 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -39,6 +39,15 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, "pointer\n", ha->host_no, __func__)); return status; } + + if (is_qla8022(ha) && + test_bit(AF_FW_RECOVERY, &ha->flags)) { + DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: prematurely " + "completing mbx cmd as firmware recovery detected\n", + ha->host_no, __func__)); + return status; + } + /* Mailbox code active */ wait_count = MBOX_TOV * 100; @@ -196,6 +205,14 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, /* Check for mailbox timeout. */ if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) { + if (is_qla8022(ha) && + test_bit(AF_FW_RECOVERY, &ha->flags)) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld: %s: prematurely completing mbx cmd as " + "firmware recovery detected\n", + ha->host_no, __func__)); + goto mbox_exit; + } DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...," " Scheduling Adapter Reset\n", ha->host_no, mbx_cmd[0])); @@ -246,6 +263,28 @@ mbox_exit: return status; } +void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha) +{ + set_bit(AF_FW_RECOVERY, &ha->flags); + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: set FW RECOVERY!\n", + ha->host_no, __func__); + + if (test_bit(AF_MBOX_COMMAND, &ha->flags)) { + if (test_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags)) { + complete(&ha->mbx_intr_comp); + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Due to fw " + "recovery, doing premature completion of " + "mbx cmd\n", ha->host_no, __func__); + + } else { + set_bit(AF_MBOX_COMMAND_DONE, &ha->flags); + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Due to fw " + "recovery, doing premature completion of " + "polling mbx cmd\n", ha->host_no, __func__); + } + } +} + static uint8_t qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index ec46651100cb..0830ea9d708c 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -2105,6 +2105,9 @@ qla4_8xxx_isp_reset(struct scsi_qla_host *ha) qla4_8xxx_clear_rst_ready(ha); qla4_8xxx_idc_unlock(ha); + if (rval == QLA_SUCCESS) + clear_bit(AF_FW_RECOVERY, &ha->flags); + return rval; } diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index e575d765ba26..2bb362c6e634 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -663,6 +663,7 @@ static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) ha->seconds_since_last_heartbeat = 0; halt_status = qla4_8xxx_rd_32(ha, QLA82XX_PEG_HALT_STATUS1); + /* Since we cannot change dev_state in interrupt * context, set appropriate DPC flag then wakeup * DPC */ @@ -674,6 +675,7 @@ static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) set_bit(DPC_RESET_HA, &ha->dpc_flags); } qla4xxx_wake_dpc(ha); + qla4xxx_mailbox_premature_completion(ha); } } ha->fw_heartbeat_counter = fw_heartbeat_counter; @@ -699,6 +701,7 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) ha->host_no, __func__); set_bit(DPC_RESET_HA, &ha->dpc_flags); qla4xxx_wake_dpc(ha); + qla4xxx_mailbox_premature_completion(ha); } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { printk("scsi%ld: %s: HW State: NEED QUIES!\n", -- cgit From 2232be0d5707cd331b92027c0fd7ea5e843c2121 Mon Sep 17 00:00:00 2001 From: Lalit Chandivade Date: Fri, 30 Jul 2010 14:38:47 +0530 Subject: [SCSI] qla4xxx: Added AER support for ISP82xx Added support for PCI error handling Signed-off-by: Lalit Chandivade Signed-off-by: Vikas Chaudhary Signed-off-by: Poornima Vonti Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_def.h | 30 +++- drivers/scsi/qla4xxx/ql4_glbl.h | 1 + drivers/scsi/qla4xxx/ql4_init.c | 5 +- drivers/scsi/qla4xxx/ql4_isr.c | 3 + drivers/scsi/qla4xxx/ql4_mbx.c | 8 ++ drivers/scsi/qla4xxx/ql4_nx.c | 8 +- drivers/scsi/qla4xxx/ql4_os.c | 301 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 352 insertions(+), 4 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 6c9262753243..9dc0a6616edd 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -36,6 +36,24 @@ #include "ql4_dbg.h" #include "ql4_nx.h" +#if defined(CONFIG_PCIEAER) +#include +#else +/* AER releated */ +static inline int pci_enable_pcie_error_reporting(struct pci_dev *dev) +{ + return -EINVAL; +} +static inline int pci_disable_pcie_error_reporting(struct pci_dev *dev) +{ + return -EINVAL; +} +static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) +{ + return -EINVAL; +} +#endif + #ifndef PCI_DEVICE_ID_QLOGIC_ISP4010 #define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010 #endif @@ -381,7 +399,8 @@ struct scsi_qla_host { #define AF_MSIX_ENABLED 17 /* 0x00020000 */ #define AF_MBOX_COMMAND_NOPOLL 18 /* 0x00040000 */ #define AF_FW_RECOVERY 19 /* 0x00080000 */ - +#define AF_EEH_BUSY 20 /* 0x00100000 */ +#define AF_PCI_CHANNEL_IO_PERM_FAILURE 21 /* 0x00200000 */ unsigned long dpc_flags; @@ -617,6 +636,15 @@ static inline int is_qla8022(struct scsi_qla_host *ha) return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022; } +/* Note: Currently AER/EEH is now supported only for 8022 cards + * This function needs to be updated when AER/EEH is enabled + * for other cards. + */ +static inline int is_aer_supported(struct scsi_qla_host *ha) +{ + return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022; +} + static inline int adapter_up(struct scsi_qla_host *ha) { return (test_bit(AF_ONLINE, &ha->flags) != 0) && diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index ea3db23602e6..f065204e401b 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -132,6 +132,7 @@ void qla4_8xxx_idc_unlock(struct scsi_qla_host *ha); int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha); void qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha); void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha); +inline void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha); extern int ql4xextended_error_logging; extern int ql4xdiscoverywait; diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 39048d9339ac..4c9be77ee70b 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -308,7 +308,6 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) DEBUG2(printk("scsi%ld: %s: unable to get firmware " "state\n", ha->host_no, __func__)); break; - } if (ha->firmware_state & FW_STATE_ERROR) { @@ -445,6 +444,10 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha) { int status = QLA_ERROR; + if (is_aer_supported(ha) && + test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags)) + return status; + /* For 82xx, stop firmware before initializing because if BIOS * has previously initialized firmware, then driver's initialize * firmware will fail. */ diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index aa65697a86b4..2a1ab63f3eb0 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -816,6 +816,9 @@ irqreturn_t qla4_8xxx_intr_handler(int irq, void *dev_id) unsigned long flags = 0; uint8_t reqs_count = 0; + if (unlikely(pci_channel_offline(ha->pdev))) + return IRQ_HANDLED; + ha->isr_count++; status = qla4_8xxx_rd_32(ha, ISR_INT_VECTOR); if (!(status & ha->nx_legacy_intr.int_vec_bit)) diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 1003e48d2200..90021704d8ca 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -48,6 +48,13 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, return status; } + if ((is_aer_supported(ha)) && + (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))) { + DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Perm failure on EEH, " + "timeout MBX Exiting.\n", ha->host_no, __func__)); + return status; + } + /* Mailbox code active */ wait_count = MBOX_TOV * 100; @@ -159,6 +166,7 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) { if (time_after_eq(jiffies, wait_count)) break; + /* * Service the interrupt. * The ISR will save the mailbox status registers diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 0830ea9d708c..1b85235efd8c 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -1418,7 +1418,7 @@ static int qla4_8xxx_rcvpeg_ready(struct scsi_qla_host *ha) return QLA_SUCCESS; } -static inline void +inline void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha) { uint32_t drv_active; @@ -1441,11 +1441,15 @@ qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha) static inline int qla4_8xxx_need_reset(struct scsi_qla_host *ha) { - uint32_t drv_state; + uint32_t drv_state, drv_active; int rval; + drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); rval = drv_state & (1 << (ha->func_num * 4)); + if ((test_bit(AF_EEH_BUSY, &ha->flags)) && drv_active) + rval = 1; + return rval; } diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 2bb362c6e634..370d40ff1529 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -475,6 +475,14 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, struct srb *srb; int rval; + if (test_bit(AF_EEH_BUSY, &ha->flags)) { + if (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags)) + cmd->result = DID_NO_CONNECT << 16; + else + cmd->result = DID_REQUEUE << 16; + goto qc_fail_command; + } + if (!sess) { cmd->result = DID_IMM_RETRY << 16; goto qc_fail_command; @@ -655,6 +663,13 @@ static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) uint32_t fw_heartbeat_counter, halt_status; fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); + /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */ + if (fw_heartbeat_counter == 0xffffffff) { + DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen " + "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n", + ha->host_no, __func__)); + return; + } if (ha->fw_heartbeat_counter == fw_heartbeat_counter) { ha->seconds_since_last_heartbeat++; @@ -723,6 +738,19 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) { struct ddb_entry *ddb_entry, *dtemp; int start_dpc = 0; + uint16_t w; + + /* If we are in the middle of AER/EEH processing + * skip any processing and reschedule the timer + */ + if (test_bit(AF_EEH_BUSY, &ha->flags)) { + mod_timer(&ha->timer, jiffies + HZ); + return; + } + + /* Hardware read to trigger an EEH error during mailbox waits. */ + if (!pci_channel_offline(ha->pdev)) + pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); if (test_bit(AF_HBA_GOING_AWAY, &ha->flags)) { DEBUG2(ql4_printk(KERN_INFO, ha, "%s exited. HBA GOING AWAY\n", @@ -1213,6 +1241,12 @@ static void qla4xxx_do_dpc(struct work_struct *work) if (!test_bit(AF_INIT_DONE, &ha->flags)) goto do_dpc_exit; + if (test_bit(AF_EEH_BUSY, &ha->flags)) { + DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n", + ha->host_no, __func__, ha->flags)); + goto do_dpc_exit; + } + /* HBA is in the process of being permanently disabled. * Don't process anything */ if (test_bit(AF_HBA_GOING_AWAY, &ha->flags)) @@ -1618,6 +1652,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ha->host = host; ha->host_no = host->host_no; + pci_enable_pcie_error_reporting(pdev); + /* Setup Runtime configurable options */ if (is_qla8022(ha)) { ha->isp_ops = &qla4_8xxx_isp_ops; @@ -1636,6 +1672,10 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ha->isp_ops = &qla4xxx_isp_ops; } + /* Set EEH reset type to fundamental if required by hba */ + if (is_qla8022(ha)) + pdev->needs_freset = 1; + /* Configure PCI I/O space. */ ret = ha->isp_ops->iospace_config(ha); if (ret) @@ -1732,6 +1772,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, } } + pci_save_state(ha->pdev); ha->isp_ops->enable_intrs(ha); /* Start timer thread. */ @@ -1758,6 +1799,7 @@ probe_failed: qla4xxx_free_adapter(ha); probe_failed_ioconfig: + pci_disable_pcie_error_reporting(pdev); scsi_host_put(ha->host); probe_disable_device: @@ -1787,6 +1829,7 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) scsi_host_put(ha->host); + pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } @@ -1883,6 +1926,17 @@ static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, int done = 0; struct srb *rp; uint32_t max_wait_time = EH_WAIT_CMD_TOV; + int ret = SUCCESS; + + /* Dont wait on command if PCI error is being handled + * by PCI AER driver + */ + if (unlikely(pci_channel_offline(ha->pdev)) || + (test_bit(AF_EEH_BUSY, &ha->flags))) { + ql4_printk(KERN_WARNING, ha, "scsi%ld: Return from %s\n", + ha->host_no, __func__); + return ret; + } do { /* Checking to see if its returned to OS */ @@ -2178,6 +2232,252 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) return return_status; } +/* PCI AER driver recovers from all correctable errors w/o + * driver intervention. For uncorrectable errors PCI AER + * driver calls the following device driver's callbacks + * + * - Fatal Errors - link_reset + * - Non-Fatal Errors - driver's pci_error_detected() which + * returns CAN_RECOVER, NEED_RESET or DISCONNECT. + * + * PCI AER driver calls + * CAN_RECOVER - driver's pci_mmio_enabled(), mmio_enabled + * returns RECOVERED or NEED_RESET if fw_hung + * NEED_RESET - driver's slot_reset() + * DISCONNECT - device is dead & cannot recover + * RECOVERED - driver's pci_resume() + */ +static pci_ers_result_t +qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) +{ + struct scsi_qla_host *ha = pci_get_drvdata(pdev); + + ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: error detected:state %x\n", + ha->host_no, __func__, state); + + if (!is_aer_supported(ha)) + return PCI_ERS_RESULT_NONE; + + switch (state) { + case pci_channel_io_normal: + clear_bit(AF_EEH_BUSY, &ha->flags); + return PCI_ERS_RESULT_CAN_RECOVER; + case pci_channel_io_frozen: + set_bit(AF_EEH_BUSY, &ha->flags); + qla4xxx_mailbox_premature_completion(ha); + qla4xxx_free_irqs(ha); + pci_disable_device(pdev); + return PCI_ERS_RESULT_NEED_RESET; + case pci_channel_io_perm_failure: + set_bit(AF_EEH_BUSY, &ha->flags); + set_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags); + qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); + return PCI_ERS_RESULT_DISCONNECT; + } + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * qla4xxx_pci_mmio_enabled() gets called if + * qla4xxx_pci_error_detected() returns PCI_ERS_RESULT_CAN_RECOVER + * and read/write to the device still works. + **/ +static pci_ers_result_t +qla4xxx_pci_mmio_enabled(struct pci_dev *pdev) +{ + struct scsi_qla_host *ha = pci_get_drvdata(pdev); + + if (!is_aer_supported(ha)) + return PCI_ERS_RESULT_NONE; + + if (test_bit(AF_FW_RECOVERY, &ha->flags)) { + ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: firmware hang -- " + "mmio_enabled\n", ha->host_no, __func__); + return PCI_ERS_RESULT_NEED_RESET; + } else + return PCI_ERS_RESULT_RECOVERED; +} + +uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) +{ + uint32_t rval = QLA_ERROR; + int fn; + struct pci_dev *other_pdev = NULL; + + ql4_printk(KERN_WARNING, ha, "scsi%ld: In %s\n", ha->host_no, __func__); + + set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); + + if (test_bit(AF_ONLINE, &ha->flags)) { + clear_bit(AF_ONLINE, &ha->flags); + qla4xxx_mark_all_devices_missing(ha); + qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); + qla4xxx_abort_active_cmds(ha, DID_RESET << 16); + } + + fn = PCI_FUNC(ha->pdev->devfn); + while (fn > 0) { + fn--; + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at " + "func %x\n", ha->host_no, __func__, fn); + /* Get the pci device given the domain, bus, + * slot/function number */ + other_pdev = + pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), + ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), + fn)); + + if (!other_pdev) + continue; + + if (atomic_read(&other_pdev->enable_cnt)) { + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI " + "func in enabled state%x\n", ha->host_no, + __func__, fn); + pci_dev_put(other_pdev); + break; + } + pci_dev_put(other_pdev); + } + + /* The first function on the card, the reset owner will + * start & initialize the firmware. The other functions + * on the card will reset the firmware context + */ + if (!fn) { + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn being reset " + "0x%x is the owner\n", ha->host_no, __func__, + ha->pdev->devfn); + + qla4_8xxx_idc_lock(ha); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_COLD); + + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, + QLA82XX_IDC_VERSION); + + qla4_8xxx_idc_unlock(ha); + clear_bit(AF_FW_RECOVERY, &ha->flags); + rval = qla4xxx_initialize_adapter(ha, PRESERVE_DDB_LIST); + qla4_8xxx_idc_lock(ha); + + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " + "FAILED\n", ha->host_no, __func__); + qla4_8xxx_clear_drv_active(ha); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_FAILED); + } else { + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " + "READY\n", ha->host_no, __func__); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_READY); + /* Clear driver state register */ + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); + qla4_8xxx_set_drv_active(ha); + ha->isp_ops->enable_intrs(ha); + } + qla4_8xxx_idc_unlock(ha); + } else { + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not " + "the reset owner\n", ha->host_no, __func__, + ha->pdev->devfn); + if ((qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == + QLA82XX_DEV_READY)) { + clear_bit(AF_FW_RECOVERY, &ha->flags); + rval = qla4xxx_initialize_adapter(ha, + PRESERVE_DDB_LIST); + if (rval == QLA_SUCCESS) + ha->isp_ops->enable_intrs(ha); + qla4_8xxx_idc_lock(ha); + qla4_8xxx_set_drv_active(ha); + qla4_8xxx_idc_unlock(ha); + } + } + clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); + return rval; +} + +static pci_ers_result_t +qla4xxx_pci_slot_reset(struct pci_dev *pdev) +{ + pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; + struct scsi_qla_host *ha = pci_get_drvdata(pdev); + int rc; + + ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: slot_reset\n", + ha->host_no, __func__); + + if (!is_aer_supported(ha)) + return PCI_ERS_RESULT_NONE; + + /* Restore the saved state of PCIe device - + * BAR registers, PCI Config space, PCIX, MSI, + * IOV states + */ + pci_restore_state(pdev); + + /* pci_restore_state() clears the saved_state flag of the device + * save restored state which resets saved_state flag + */ + pci_save_state(pdev); + + /* Initialize device or resume if in suspended state */ + rc = pci_enable_device(pdev); + if (rc) { + ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Cant re-enable " + "device after reset\n", ha->host_no, __func__); + goto exit_slot_reset; + } + + ret = qla4xxx_request_irqs(ha); + if (ret) { + ql4_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d" + " already in use.\n", pdev->irq); + goto exit_slot_reset; + } + + if (is_qla8022(ha)) { + if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) { + ret = PCI_ERS_RESULT_RECOVERED; + goto exit_slot_reset; + } else + goto exit_slot_reset; + } + +exit_slot_reset: + ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Return=%x\n" + "device after reset\n", ha->host_no, __func__, ret); + return ret; +} + +static void +qla4xxx_pci_resume(struct pci_dev *pdev) +{ + struct scsi_qla_host *ha = pci_get_drvdata(pdev); + int ret; + + ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: pci_resume\n", + ha->host_no, __func__); + + ret = qla4xxx_wait_for_hba_online(ha); + if (ret != QLA_SUCCESS) { + ql4_printk(KERN_ERR, ha, "scsi%ld: %s: the device failed to " + "resume I/O from slot/link_reset\n", ha->host_no, + __func__); + } + + pci_cleanup_aer_uncorrect_error_status(pdev); + clear_bit(AF_EEH_BUSY, &ha->flags); +} + +static struct pci_error_handlers qla4xxx_err_handler = { + .error_detected = qla4xxx_pci_error_detected, + .mmio_enabled = qla4xxx_pci_mmio_enabled, + .slot_reset = qla4xxx_pci_slot_reset, + .resume = qla4xxx_pci_resume, +}; + static struct pci_device_id qla4xxx_pci_tbl[] = { { .vendor = PCI_VENDOR_ID_QLOGIC, @@ -2212,6 +2512,7 @@ static struct pci_driver qla4xxx_pci_driver = { .id_table = qla4xxx_pci_tbl, .probe = qla4xxx_probe_adapter, .remove = qla4xxx_remove_adapter, + .err_handler = &qla4xxx_err_handler, }; static int __init qla4xxx_module_init(void) -- cgit From e8ed741fcd521a25f1d983ec81f72ac823d8429a Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Fri, 30 Jul 2010 14:28:52 +0530 Subject: [SCSI] qla4xxx: Update driver version to 5.02.00-k3 Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index c905dbd75331..a77b973f2cbc 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.02.00-k2" +#define QLA4XXX_DRIVER_VERSION "5.02.00-k3" -- cgit From 823d219f23b958292279cfdc8583dc4f1f91c2d5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 1 Aug 2010 19:23:35 +0200 Subject: [SCSI] pm8001: introduce missing kfree Error handling code following a kmalloc should free the allocated data. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; expression E; identifier f,f1; position p1,p2; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); <... when != x when != if (...) { <+...x...+> } when != (x) == NULL when != (x) != NULL when != (x) == 0 when != (x) != 0 ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return <+...x...+>; | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Acked-by: jack wang Signed-off-by: James Bottomley --- drivers/scsi/pm8001/pm8001_hwi.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 58d1134935ef..9793aa6afb10 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -4199,8 +4199,10 @@ static int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, circularQ = &pm8001_ha->inbnd_q_tbl[0]; memset(&nvmd_req, 0, sizeof(nvmd_req)); rc = pm8001_tag_alloc(pm8001_ha, &tag); - if (rc) + if (rc) { + kfree(fw_control_context); return rc; + } ccb = &pm8001_ha->ccb_info[tag]; ccb->ccb_tag = tag; ccb->fw_control_context = fw_control_context; @@ -4276,8 +4278,10 @@ static int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, ioctl_payload->length); memset(&nvmd_req, 0, sizeof(nvmd_req)); rc = pm8001_tag_alloc(pm8001_ha, &tag); - if (rc) + if (rc) { + kfree(fw_control_context); return rc; + } ccb = &pm8001_ha->ccb_info[tag]; ccb->fw_control_context = fw_control_context; ccb->ccb_tag = tag; @@ -4387,6 +4391,7 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha, fw_control->len, 0) != 0) { PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("Mem alloc failure\n")); + kfree(fw_control_context); return -ENOMEM; } } @@ -4401,8 +4406,10 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha, fw_control_context->virtAddr = buffer; fw_control_context->len = fw_control->len; rc = pm8001_tag_alloc(pm8001_ha, &tag); - if (rc) + if (rc) { + kfree(fw_control_context); return rc; + } ccb = &pm8001_ha->ccb_info[tag]; ccb->fw_control_context = fw_control_context; ccb->ccb_tag = tag; -- cgit From bc73905abf7701920fe687564ecd3c6b316b9a2e Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 4 Aug 2010 16:11:18 -0400 Subject: [SCSI] lpfc 8.3.16: SLI Additions, updates, and code cleanup - Remove unneeded Endian swap for Block Guard IOCB response - Add a check for mailbox active before issuing the heartbeat command - Correct heartbeat last_completion updates to avoid unneeded heartbeats - Add Security crypto support to CONFIG_PORT mailbox command - Add fips level and fips spec revision sysfs parameters - Remove duplicate setting of ext_byte_len fields in lpfc_bsg_issue_mbox - Switch call to memcpy_toio to __write32_copy to prevent unaligned 64 bit copy - Change log message 0318 from an error to a warning as it is not an error - Patch an incorrect call to lpfc_drain_txq on SLI-3 functions Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 3 +++ drivers/scsi/lpfc/lpfc_attr.c | 46 +++++++++++++++++++++++++++++++++- drivers/scsi/lpfc/lpfc_bsg.c | 9 ------- drivers/scsi/lpfc/lpfc_compat.h | 3 +-- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 +- drivers/scsi/lpfc/lpfc_hw.h | 26 +++++++++++--------- drivers/scsi/lpfc/lpfc_init.c | 53 +++++++++++++++++++++++++++------------- drivers/scsi/lpfc/lpfc_scsi.c | 8 +++--- drivers/scsi/lpfc/lpfc_sli.c | 29 +++++++++++++++++----- 9 files changed, 128 insertions(+), 51 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 3482d5a5aed2..a50aa03b8ac1 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -775,6 +775,7 @@ struct lpfc_hba { uint8_t temp_sensor_support; /* Fields used for heart beat. */ unsigned long last_completion_time; + unsigned long skipped_hb; struct timer_list hb_tmofunc; uint8_t hb_outstanding; enum hba_temp_state over_temp_state; @@ -817,6 +818,8 @@ struct lpfc_hba { uint32_t iocb_cnt; uint32_t iocb_max; atomic_t sdev_cnt; + uint8_t fips_spec_rev; + uint8_t fips_level; }; static inline struct Scsi_Host * diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 868874c28f99..fac26e4445f9 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1238,6 +1238,44 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr, return strlen(buf); } +/** + * lpfc_fips_level_show - Return the current FIPS level for the HBA + * @dev: class unused variable. + * @attr: device attribute, not used. + * @buf: on return contains the module description text. + * + * Returns: size of formatted string. + **/ +static ssize_t +lpfc_fips_level_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + + return snprintf(buf, PAGE_SIZE, "%d\n", phba->fips_level); +} + +/** + * lpfc_fips_rev_show - Return the FIPS Spec revision for the HBA + * @dev: class unused variable. + * @attr: device attribute, not used. + * @buf: on return contains the module description text. + * + * Returns: size of formatted string. + **/ +static ssize_t +lpfc_fips_rev_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + + return snprintf(buf, PAGE_SIZE, "%d\n", phba->fips_spec_rev); +} + /** * lpfc_param_show - Return a cfg attribute value in decimal * @@ -1676,6 +1714,8 @@ static DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL); static DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL); static DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL); static DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show, NULL); +static DEVICE_ATTR(lpfc_fips_level, S_IRUGO, lpfc_fips_level_show, NULL); +static DEVICE_ATTR(lpfc_fips_rev, S_IRUGO, lpfc_fips_rev_show, NULL); static char *lpfc_soft_wwn_key = "C99G71SL8032A"; @@ -3280,7 +3320,7 @@ LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support"); # - Default will result in registering capabilities for all profiles. # */ -unsigned int lpfc_prot_mask = SHOST_DIX_TYPE0_PROTECTION; +unsigned int lpfc_prot_mask = SHOST_DIF_TYPE1_PROTECTION; module_param(lpfc_prot_mask, uint, 0); MODULE_PARM_DESC(lpfc_prot_mask, "host protection mask"); @@ -3385,6 +3425,8 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_iocb_hw, &dev_attr_txq_hw, &dev_attr_txcmplq_hw, + &dev_attr_lpfc_fips_level, + &dev_attr_lpfc_fips_rev, NULL, }; @@ -3411,6 +3453,8 @@ struct device_attribute *lpfc_vport_attrs[] = { &dev_attr_lpfc_max_scsicmpl_time, &dev_attr_lpfc_stat_data_ctrl, &dev_attr_lpfc_static_vport, + &dev_attr_lpfc_fips_level, + &dev_attr_lpfc_fips_rev, NULL, }; diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index d521569e6620..49d0cf99c24c 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -2722,15 +2722,6 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, mbox_req->inExtWLen * sizeof(uint32_t)); } - pmboxq->context2 = ext; - pmboxq->in_ext_byte_len = - mbox_req->inExtWLen * - sizeof(uint32_t); - pmboxq->out_ext_byte_len = - mbox_req->outExtWLen * - sizeof(uint32_t); - pmboxq->mbox_offset_word = - mbox_req->mbOffset; pmboxq->context2 = ext; pmboxq->in_ext_byte_len = mbox_req->inExtWLen * sizeof(uint32_t); diff --git a/drivers/scsi/lpfc/lpfc_compat.h b/drivers/scsi/lpfc/lpfc_compat.h index a11f1ae7b98e..75e2e569dede 100644 --- a/drivers/scsi/lpfc/lpfc_compat.h +++ b/drivers/scsi/lpfc/lpfc_compat.h @@ -82,8 +82,7 @@ lpfc_memcpy_from_slim( void *dest, void __iomem *src, unsigned int bytes) static inline void lpfc_memcpy_to_slim( void __iomem *dest, void *src, unsigned int bytes) { - /* actually returns 1 byte past dest */ - memcpy_toio( dest, src, bytes); + __iowrite32_copy(dest, src, bytes); } static inline void diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 0639c994349c..efba65b368a8 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -588,7 +588,7 @@ lpfc_work_done(struct lpfc_hba *phba) (status & HA_RXMASK)); } - if (pring->txq_cnt) + if ((phba->sli_rev == LPFC_SLI_REV4) && pring->txq_cnt) lpfc_drain_txq(phba); /* * Turn on Ring interrupts diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index f5dbf2be3eab..897caa05e94d 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -2806,11 +2806,15 @@ typedef struct { uint32_t rsvd6; /* Reserved */ #ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd7 : 16; /* Reserved */ + uint32_t fips_rev : 3; /* FIPS Spec Revision */ + uint32_t fips_level : 4; /* FIPS Level */ + uint32_t sec_err : 9; /* security crypto error */ uint32_t max_vpi : 16; /* Max number of virt N-Ports */ #else /* __LITTLE_ENDIAN */ uint32_t max_vpi : 16; /* Max number of virt N-Ports */ - uint32_t rsvd7 : 16; /* Reserved */ + uint32_t sec_err : 9; /* security crypto error */ + uint32_t fips_level : 4; /* FIPS Level */ + uint32_t fips_rev : 3; /* FIPS Spec Revision */ #endif } CONFIG_PORT_VAR; @@ -3441,63 +3445,63 @@ struct sli3_bg_fields { static inline uint32_t lpfc_bgs_get_bidir_bg_prof(uint32_t bgstat) { - return (le32_to_cpu(bgstat) & BGS_BIDIR_BG_PROF_MASK) >> + return (bgstat & BGS_BIDIR_BG_PROF_MASK) >> BGS_BIDIR_BG_PROF_SHIFT; } static inline uint32_t lpfc_bgs_get_bidir_err_cond(uint32_t bgstat) { - return (le32_to_cpu(bgstat) & BGS_BIDIR_ERR_COND_FLAGS_MASK) >> + return (bgstat & BGS_BIDIR_ERR_COND_FLAGS_MASK) >> BGS_BIDIR_ERR_COND_SHIFT; } static inline uint32_t lpfc_bgs_get_bg_prof(uint32_t bgstat) { - return (le32_to_cpu(bgstat) & BGS_BG_PROFILE_MASK) >> + return (bgstat & BGS_BG_PROFILE_MASK) >> BGS_BG_PROFILE_SHIFT; } static inline uint32_t lpfc_bgs_get_invalid_prof(uint32_t bgstat) { - return (le32_to_cpu(bgstat) & BGS_INVALID_PROF_MASK) >> + return (bgstat & BGS_INVALID_PROF_MASK) >> BGS_INVALID_PROF_SHIFT; } static inline uint32_t lpfc_bgs_get_uninit_dif_block(uint32_t bgstat) { - return (le32_to_cpu(bgstat) & BGS_UNINIT_DIF_BLOCK_MASK) >> + return (bgstat & BGS_UNINIT_DIF_BLOCK_MASK) >> BGS_UNINIT_DIF_BLOCK_SHIFT; } static inline uint32_t lpfc_bgs_get_hi_water_mark_present(uint32_t bgstat) { - return (le32_to_cpu(bgstat) & BGS_HI_WATER_MARK_PRESENT_MASK) >> + return (bgstat & BGS_HI_WATER_MARK_PRESENT_MASK) >> BGS_HI_WATER_MARK_PRESENT_SHIFT; } static inline uint32_t lpfc_bgs_get_reftag_err(uint32_t bgstat) { - return (le32_to_cpu(bgstat) & BGS_REFTAG_ERR_MASK) >> + return (bgstat & BGS_REFTAG_ERR_MASK) >> BGS_REFTAG_ERR_SHIFT; } static inline uint32_t lpfc_bgs_get_apptag_err(uint32_t bgstat) { - return (le32_to_cpu(bgstat) & BGS_APPTAG_ERR_MASK) >> + return (bgstat & BGS_APPTAG_ERR_MASK) >> BGS_APPTAG_ERR_SHIFT; } static inline uint32_t lpfc_bgs_get_guard_err(uint32_t bgstat) { - return (le32_to_cpu(bgstat) & BGS_GUARD_ERR_MASK) >> + return (bgstat & BGS_GUARD_ERR_MASK) >> BGS_GUARD_ERR_SHIFT; } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 2786ee3b605d..9244aa64b3be 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1032,27 +1032,46 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) /* If there is no heart beat outstanding, issue a heartbeat command */ if (phba->cfg_enable_hba_heartbeat) { if (!phba->hb_outstanding) { - pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); - if (!pmboxq) { - mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_INTERVAL); - return; - } + if ((!(psli->sli_flag & LPFC_SLI_MBOX_ACTIVE)) && + (list_empty(&psli->mboxq))) { + pmboxq = mempool_alloc(phba->mbox_mem_pool, + GFP_KERNEL); + if (!pmboxq) { + mod_timer(&phba->hb_tmofunc, + jiffies + + HZ * LPFC_HB_MBOX_INTERVAL); + return; + } - lpfc_heart_beat(phba, pmboxq); - pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl; - pmboxq->vport = phba->pport; - retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); + lpfc_heart_beat(phba, pmboxq); + pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl; + pmboxq->vport = phba->pport; + retval = lpfc_sli_issue_mbox(phba, pmboxq, + MBX_NOWAIT); + + if (retval != MBX_BUSY && + retval != MBX_SUCCESS) { + mempool_free(pmboxq, + phba->mbox_mem_pool); + mod_timer(&phba->hb_tmofunc, + jiffies + + HZ * LPFC_HB_MBOX_INTERVAL); + return; + } + phba->skipped_hb = 0; + phba->hb_outstanding = 1; + } else if (time_before_eq(phba->last_completion_time, + phba->skipped_hb)) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2857 Last completion time not " + " updated in %d ms\n", + jiffies_to_msecs(jiffies + - phba->last_completion_time)); + } else + phba->skipped_hb = jiffies; - if (retval != MBX_BUSY && retval != MBX_SUCCESS) { - mempool_free(pmboxq, phba->mbox_mem_pool); - mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_INTERVAL); - return; - } mod_timer(&phba->hb_tmofunc, jiffies + HZ * LPFC_HB_MBOX_TIMEOUT); - phba->hb_outstanding = 1; return; } else { /* diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index c818a7255962..2e51aa6b45b3 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1325,7 +1325,7 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR); pde5->reftag = reftag; - /* Endian convertion if necessary for PDE5 */ + /* Endianness conversion if necessary for PDE5 */ pde5->word0 = cpu_to_le32(pde5->word0); pde5->reftag = cpu_to_le32(pde5->reftag); @@ -1347,7 +1347,7 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, bf_set(pde6_ai, pde6, 1); bf_set(pde6_apptagval, pde6, apptagval); - /* Endian convertion if necessary for PDE6 */ + /* Endianness conversion if necessary for PDE6 */ pde6->word0 = cpu_to_le32(pde6->word0); pde6->word1 = cpu_to_le32(pde6->word1); pde6->word2 = cpu_to_le32(pde6->word2); @@ -1459,7 +1459,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR); pde5->reftag = reftag; - /* Endian convertion if necessary for PDE5 */ + /* Endianness conversion if necessary for PDE5 */ pde5->word0 = cpu_to_le32(pde5->word0); pde5->reftag = cpu_to_le32(pde5->reftag); @@ -1479,7 +1479,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, bf_set(pde6_ai, pde6, 1); bf_set(pde6_apptagval, pde6, apptagval); - /* Endian convertion if necessary for PDE6 */ + /* Endianness conversion if necessary for PDE6 */ pde6->word0 = cpu_to_le32(pde6->word0); pde6->word1 = cpu_to_le32(pde6->word1); pde6->word2 = cpu_to_le32(pde6->word2); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index e758eae0d0fd..0ce9eb7ca4ee 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1046,7 +1046,7 @@ lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) } else spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR,LOG_SLI, + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0318 Failed to allocate IOTAG.last IOTAG is %d\n", psli->last_iotag); @@ -3914,7 +3914,8 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) phba->sli3_options &= ~(LPFC_SLI3_NPIV_ENABLED | LPFC_SLI3_HBQ_ENABLED | LPFC_SLI3_CRP_ENABLED | - LPFC_SLI3_BG_ENABLED); + LPFC_SLI3_BG_ENABLED | + LPFC_SLI3_DSS_ENABLED); if (rc != MBX_SUCCESS) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0442 Adapter failed to init, mbxCmd x%x " @@ -3949,8 +3950,23 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) } else phba->max_vpi = 0; - if (pmb->u.mb.un.varCfgPort.gdss) + phba->fips_level = 0; + phba->fips_spec_rev = 0; + if (pmb->u.mb.un.varCfgPort.gdss) { phba->sli3_options |= LPFC_SLI3_DSS_ENABLED; + phba->fips_level = pmb->u.mb.un.varCfgPort.fips_level; + phba->fips_spec_rev = pmb->u.mb.un.varCfgPort.fips_rev; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2850 Security Crypto Active. FIPS x%d " + "(Spec Rev: x%d)", + phba->fips_level, phba->fips_spec_rev); + } + if (pmb->u.mb.un.varCfgPort.sec_err) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2856 Config Port Security Crypto " + "Error: x%x ", + pmb->u.mb.un.varCfgPort.sec_err); + } if (pmb->u.mb.un.varCfgPort.gerbm) phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED; if (pmb->u.mb.un.varCfgPort.gcrp) @@ -9040,6 +9056,7 @@ lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, switch (bf_get(lpfc_cqe_code, &cqevt)) { case CQE_CODE_COMPL_WQE: /* Process the WQ/RQ complete event */ + phba->last_completion_time = jiffies; workposted = lpfc_sli4_sp_handle_els_wcqe(phba, (struct lpfc_wcqe_complete *)&cqevt); break; @@ -9050,11 +9067,13 @@ lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, break; case CQE_CODE_XRI_ABORTED: /* Process the WQ XRI abort event */ + phba->last_completion_time = jiffies; workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq, (struct sli4_wcqe_xri_aborted *)&cqevt); break; case CQE_CODE_RECEIVE: /* Process the RQ event */ + phba->last_completion_time = jiffies; workposted = lpfc_sli4_sp_handle_rcqe(phba, (struct lpfc_rcqe *)&cqevt); break; @@ -9276,7 +9295,6 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, { struct lpfc_wcqe_release wcqe; bool workposted = false; - unsigned long iflag; /* Copy the work queue CQE and convert endian order if needed */ lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe)); @@ -9285,9 +9303,7 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, switch (bf_get(lpfc_wcqe_c_code, &wcqe)) { case CQE_CODE_COMPL_WQE: /* Process the WQ complete event */ - spin_lock_irqsave(&phba->hbalock, iflag); phba->last_completion_time = jiffies; - spin_unlock_irqrestore(&phba->hbalock, iflag); lpfc_sli4_fp_handle_fcp_wcqe(phba, (struct lpfc_wcqe_complete *)&wcqe); break; @@ -9298,6 +9314,7 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, break; case CQE_CODE_XRI_ABORTED: /* Process the WQ XRI abort event */ + phba->last_completion_time = jiffies; workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq, (struct sli4_wcqe_xri_aborted *)&wcqe); break; -- cgit From 38b92ef89b0d5a255f2f812c623fcdec4e63a21c Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 4 Aug 2010 16:11:39 -0400 Subject: [SCSI] lpfc 8.3.16: FCoE Discovery and Failover Fixes - Add support for re-reg'ing changed VPI w/o unregister VPI - Copy WWN and state from old nodelist when target DID change. - Clean up old nodelist rport and put the nodelist when target DID change. - Clear the VFI_REGISTERED flag when UNREG_VFI completes. - Made both checks of port_state against LPFC_FLOGI and LPFC_FDISC non-inclusive for ignoring CVL events. - Added logic to stop retrying of the ongoing PLOGI and FDISC if transitioned back to the FCF rediscovery state in reaction to CVL. - Removed the dependency of scanning of all the available FCF table entries for bulding round-robin bitmap. - Use the lpfc_sli4_fcf_rr_read_fcf_rec() in responding to individual New FCF found event. Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 76 +++++++++++++++++++++++++++++++++++--- drivers/scsi/lpfc/lpfc_hbadisc.c | 15 ++++++-- drivers/scsi/lpfc/lpfc_hw.h | 6 ++- drivers/scsi/lpfc/lpfc_init.c | 79 +++++++++++++++++++++++++--------------- drivers/scsi/lpfc/lpfc_mbox.c | 8 +++- drivers/scsi/lpfc/lpfc_sli.c | 7 +--- 6 files changed, 144 insertions(+), 47 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index afbed6bc31f0..8d09191c327e 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -600,6 +600,14 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; spin_unlock_irq(shost->host_lock); } + } else if ((phba->sli_rev == LPFC_SLI_REV4) && + !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { + /* + * Driver needs to re-reg VPI in order for f/w + * to update the MAC address. + */ + lpfc_register_new_vport(phba, vport, ndlp); + return 0; } if (phba->sli_rev < LPFC_SLI_REV4) { @@ -801,9 +809,12 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) { lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS, "2611 FLOGI failed on registered " - "FCF record fcf_index:%d, trying " - "to perform round robin failover\n", - phba->fcf.current_rec.fcf_indx); + "FCF record fcf_index(%d), status: " + "x%x/x%x, tmo:x%x, trying to perform " + "round robin failover\n", + phba->fcf.current_rec.fcf_indx, + irsp->ulpStatus, irsp->un.ulpWord[4], + irsp->ulpTimeout); fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba); if (fcf_index == LPFC_FCOE_FCF_NEXT_NONE) { /* @@ -841,6 +852,12 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } + /* FLOGI failure */ + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "2858 FLOGI failure Status:x%x/x%x TMO:x%x\n", + irsp->ulpStatus, irsp->un.ulpWord[4], + irsp->ulpTimeout); + /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) goto out; @@ -1291,6 +1308,8 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, struct serv_parm *sp; uint8_t name[sizeof(struct lpfc_name)]; uint32_t rc, keepDID = 0; + int put_node; + int put_rport; /* Fabric nodes can have the same WWPN so we don't bother searching * by WWPN. Just return the ndlp that was given to us. @@ -1379,6 +1398,28 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, /* Two ndlps cannot have the same did */ ndlp->nlp_DID = keepDID; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + /* Since we are swapping the ndlp passed in with the new one + * and the did has already been swapped, copy over the + * state and names. + */ + memcpy(&new_ndlp->nlp_portname, &ndlp->nlp_portname, + sizeof(struct lpfc_name)); + memcpy(&new_ndlp->nlp_nodename, &ndlp->nlp_nodename, + sizeof(struct lpfc_name)); + new_ndlp->nlp_state = ndlp->nlp_state; + /* Fix up the rport accordingly */ + rport = ndlp->rport; + if (rport) { + rdata = rport->dd_data; + put_node = rdata->pnode != NULL; + put_rport = ndlp->rport != NULL; + rdata->pnode = NULL; + ndlp->rport = NULL; + if (put_node) + lpfc_nlp_put(ndlp); + if (put_rport) + put_device(&rport->dev); + } } return new_ndlp; } @@ -2880,6 +2921,17 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, retry = 0; if (retry) { + if ((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_FDISC)) { + /* Stop retrying PLOGI and FDISC if in FCF discovery */ + if (phba->fcf.fcf_flag & FCF_DISCOVERY) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "2849 Stop retry ELS command " + "x%x to remote NPORT x%x, " + "Data: x%x x%x\n", cmd, did, + cmdiocb->retry, delay); + return 0; + } + } /* Retry ELS command to remote NPORT */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, @@ -6076,8 +6128,12 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (mb->mbxStatus) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "0915 Register VPI failed: 0x%x\n", - mb->mbxStatus); + "0915 Register VPI failed : Status: x%x" + " upd bit: x%x \n", mb->mbxStatus, + mb->un.varRegVpi.upd); + if (phba->sli_rev == LPFC_SLI_REV4 && + mb->un.varRegVpi.upd) + goto mbox_err_exit ; switch (mb->mbxStatus) { case 0x11: /* unsupported feature */ @@ -6142,7 +6198,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else lpfc_do_scr_ns_plogi(phba, vport); } - +mbox_err_exit: /* Now, we decrement the ndlp reference count held for this * callback function */ @@ -6387,6 +6443,14 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, else vport->fc_flag |= FC_LOGO_RCVD_DID_CHNG; spin_unlock_irq(shost->host_lock); + } else if ((phba->sli_rev == LPFC_SLI_REV4) && + !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { + /* + * Driver needs to re-reg VPI in order for f/w + * to update the MAC address. + */ + lpfc_register_new_vport(phba, vport, ndlp); + return ; } if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index efba65b368a8..1f62ea8c165d 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1852,8 +1852,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) __lpfc_sli4_stop_fcf_redisc_wait_timer(phba); else if (phba->fcf.fcf_flag & FCF_REDISC_FOV) /* If in fast failover, mark it's completed */ - phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | - FCF_DISCOVERY); + phba->fcf.fcf_flag &= ~FCF_REDISC_FOV; spin_unlock_irq(&phba->hbalock); lpfc_printf_log(phba, KERN_INFO, LOG_FIP, "2836 The new FCF record (x%x) " @@ -2651,7 +2650,6 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) spin_unlock_irq(&phba->hbalock); lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, "2778 Start FCF table scan at linkup\n"); - rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); if (rc) { @@ -2660,6 +2658,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) spin_unlock_irq(&phba->hbalock); goto out; } + /* Reset FCF roundrobin bmask for new discovery */ + memset(phba->fcf.fcf_rr_bmask, 0, + sizeof(*phba->fcf.fcf_rr_bmask)); } return; @@ -5097,6 +5098,7 @@ static void lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { struct lpfc_vport *vport = mboxq->vport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); if (mboxq->u.mb.mbxStatus) { lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, @@ -5104,6 +5106,9 @@ lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) "HBA state x%x\n", mboxq->u.mb.mbxStatus, vport->port_state); } + spin_lock_irq(shost->host_lock); + phba->pport->fc_flag &= ~FC_VFI_REGISTERED; + spin_unlock_irq(shost->host_lock); mempool_free(mboxq, phba->mbox_mem_pool); return; } @@ -5285,6 +5290,10 @@ lpfc_unregister_fcf_rescan(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); phba->fcf.fcf_flag |= FCF_INIT_DISC; spin_unlock_irq(&phba->hbalock); + + /* Reset FCF roundrobin bmask for new discovery */ + memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask)); + rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); if (rc) { diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 897caa05e94d..1676f61291e7 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -2291,7 +2291,8 @@ typedef struct { typedef struct { #ifdef __BIG_ENDIAN_BITFIELD uint32_t rsvd1; - uint32_t rsvd2:8; + uint32_t rsvd2:7; + uint32_t upd:1; uint32_t sid:24; uint32_t wwn[2]; uint32_t rsvd5; @@ -2300,7 +2301,8 @@ typedef struct { #else /* __LITTLE_ENDIAN */ uint32_t rsvd1; uint32_t sid:24; - uint32_t rsvd2:8; + uint32_t upd:1; + uint32_t rsvd2:7; uint32_t wwn[2]; uint32_t rsvd5; uint16_t vpi; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 9244aa64b3be..da9ba06ad583 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -3300,10 +3300,10 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport) if (!ndlp) return 0; } - if (phba->pport->port_state <= LPFC_FLOGI) + if (phba->pport->port_state < LPFC_FLOGI) return NULL; /* If virtual link is not yet instantiated ignore CVL */ - if (vport->port_state <= LPFC_FDISC) + if ((vport != phba->pport) && (vport->port_state < LPFC_FDISC)) return NULL; shost = lpfc_shost_from_vport(vport); if (!shost) @@ -3376,21 +3376,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, "evt_tag:x%x, fcf_index:x%x\n", acqe_fcoe->event_tag, acqe_fcoe->index); - /* If the FCF discovery is in progress, do nothing. */ - spin_lock_irq(&phba->hbalock); - if (phba->hba_flag & FCF_DISC_INPROGRESS) { - spin_unlock_irq(&phba->hbalock); - break; - } - /* If fast FCF failover rescan event is pending, do nothing */ - if (phba->fcf.fcf_flag & FCF_REDISC_EVT) { - spin_unlock_irq(&phba->hbalock); - break; - } - spin_unlock_irq(&phba->hbalock); - - if ((phba->fcf.fcf_flag & FCF_DISCOVERY) && - !(phba->fcf.fcf_flag & FCF_REDISC_FOV)) { + if (phba->fcf.fcf_flag & FCF_DISCOVERY) { /* * During period of FCF discovery, read the FCF * table record indexed by the event to update @@ -3404,13 +3390,26 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, acqe_fcoe->index); rc = lpfc_sli4_read_fcf_rec(phba, acqe_fcoe->index); } - /* If the FCF has been in discovered state, do nothing. */ + + /* If the FCF discovery is in progress, do nothing. */ spin_lock_irq(&phba->hbalock); + if (phba->hba_flag & FCF_DISC_INPROGRESS) { + spin_unlock_irq(&phba->hbalock); + break; + } + /* If fast FCF failover rescan event is pending, do nothing */ + if (phba->fcf.fcf_flag & FCF_REDISC_EVT) { + spin_unlock_irq(&phba->hbalock); + break; + } + + /* If the FCF has been in discovered state, do nothing. */ if (phba->fcf.fcf_flag & FCF_SCAN_DONE) { spin_unlock_irq(&phba->hbalock); break; } spin_unlock_irq(&phba->hbalock); + /* Otherwise, scan the entire FCF table and re-discover SAN */ lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, "2770 Start FCF table scan due to new FCF " @@ -3436,13 +3435,9 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, "2549 FCF disconnected from network index 0x%x" " tag 0x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag); - /* If the event is not for currently used fcf do nothing */ - if (phba->fcf.current_rec.fcf_indx != acqe_fcoe->index) - break; - /* We request port to rediscover the entire FCF table for - * a fast recovery from case that the current FCF record - * is no longer valid if we are not in the middle of FCF - * failover process already. + /* + * If we are in the middle of FCF failover process, clear + * the corresponding FCF bit in the roundrobin bitmap. */ spin_lock_irq(&phba->hbalock); if (phba->fcf.fcf_flag & FCF_DISCOVERY) { @@ -3451,9 +3446,23 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, lpfc_sli4_fcf_rr_index_clear(phba, acqe_fcoe->index); break; } + spin_unlock_irq(&phba->hbalock); + + /* If the event is not for currently used fcf do nothing */ + if (phba->fcf.current_rec.fcf_indx != acqe_fcoe->index) + break; + + /* + * Otherwise, request the port to rediscover the entire FCF + * table for a fast recovery from case that the current FCF + * is no longer valid as we are not in the middle of FCF + * failover process already. + */ + spin_lock_irq(&phba->hbalock); /* Mark the fast failover process in progress */ phba->fcf.fcf_flag |= FCF_DEAD_DISC; spin_unlock_irq(&phba->hbalock); + lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, "2771 Start FCF fast failover process due to " "FCF DEAD event: evt_tag:x%x, fcf_index:x%x " @@ -3473,12 +3482,16 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, * as a link down to FCF registration. */ lpfc_sli4_fcf_dead_failthrough(phba); - } else - /* Handling fast FCF failover to a DEAD FCF event - * is considered equalivant to receiving CVL to all - * vports. + } else { + /* Reset FCF roundrobin bmask for new discovery */ + memset(phba->fcf.fcf_rr_bmask, 0, + sizeof(*phba->fcf.fcf_rr_bmask)); + /* + * Handling fast FCF failover to a DEAD FCF event is + * considered equalivant to receiving CVL to all vports. */ lpfc_sli4_perform_all_vport_cvl(phba); + } break; case LPFC_FCOE_EVENT_TYPE_CVL: lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, @@ -3553,7 +3566,13 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, * the current registered FCF entry. */ lpfc_retry_pport_discovery(phba); - } + } else + /* + * Reset FCF roundrobin bmask for new + * discovery. + */ + memset(phba->fcf.fcf_rr_bmask, 0, + sizeof(*phba->fcf.fcf_rr_bmask)); } break; default: diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 9c2c7c7140c7..0dfa310cd609 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -815,9 +815,15 @@ void lpfc_reg_vpi(struct lpfc_vport *vport, LPFC_MBOXQ_t *pmb) { MAILBOX_t *mb = &pmb->u.mb; + struct lpfc_hba *phba = vport->phba; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - + /* + * Set the re-reg VPI bit for f/w to update the MAC address. + */ + if ((phba->sli_rev == LPFC_SLI_REV4) && + !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) + mb->un.varRegVpi.upd = 1; mb->un.varRegVpi.vpi = vport->vpi + vport->phba->vpi_base; mb->un.varRegVpi.sid = vport->fc_myDID; mb->un.varRegVpi.vfi = vport->vfi + vport->phba->vfi_base; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 0ce9eb7ca4ee..fb8905f893f5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -12295,12 +12295,9 @@ lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index) spin_lock_irq(&phba->hbalock); phba->hba_flag |= FCF_DISC_INPROGRESS; spin_unlock_irq(&phba->hbalock); - /* Reset FCF round robin index bmask for new scan */ - if (fcf_index == LPFC_FCOE_FCF_GET_FIRST) { - memset(phba->fcf.fcf_rr_bmask, 0, - sizeof(*phba->fcf.fcf_rr_bmask)); + /* Reset eligible FCF count for new scan */ + if (fcf_index == LPFC_FCOE_FCF_GET_FIRST) phba->fcf.eligible_fcf_cnt = 0; - } error = 0; } fail_fcf_scan: -- cgit From 161155519c27773b8f35ee3d7a1b49acfc9eee73 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 4 Aug 2010 16:12:12 -0400 Subject: [SCSI] lpfc 8.3.16: Change LPFC driver version to 8.3.16 Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index d28830af71d8..61afb3420a96 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.15" +#define LPFC_DRIVER_VERSION "8.3.16" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" -- cgit From d5da3040d798df4bbb62579b97f8b6b83749da22 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 5 Aug 2010 16:38:31 -0500 Subject: [SCSI] ibmvfc: Fix rport add/delete race resulting in oops Commit 43c8da907ccc656935d1085701f4db83385d8a59 introduced a race condition which can occur when adding/deleting rports. There are two possible threads now that can be deleting rports in the ibmvfc driver, which can result in list_del being called twice, resulting in an oops. This patch adds a new state to the ibmvfc_target struct to indicate the target has been removed from the list and is in the process of being deleted. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvfc.c | 8 ++++++++ drivers/scsi/ibmvscsi/ibmvfc.h | 1 + 2 files changed, 9 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index bd96cecaa619..a13db5908426 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -433,6 +433,9 @@ static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt, { switch (tgt->action) { case IBMVFC_TGT_ACTION_DEL_RPORT: + if (action == IBMVFC_TGT_ACTION_DELETED_RPORT) + tgt->action = action; + case IBMVFC_TGT_ACTION_DELETED_RPORT: break; default: if (action == IBMVFC_TGT_ACTION_DEL_RPORT) @@ -4193,11 +4196,15 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { tgt_dbg(tgt, "Deleting rport\n"); list_del(&tgt->queue); + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT); spin_unlock_irqrestore(vhost->host->host_lock, flags); fc_remote_port_delete(rport); del_timer_sync(&tgt->timer); kref_put(&tgt->kref, ibmvfc_release_tgt); return; + } else if (rport && tgt->action == IBMVFC_TGT_ACTION_DELETED_RPORT) { + spin_unlock_irqrestore(vhost->host->host_lock, flags); + return; } if (rport) { @@ -4297,6 +4304,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) rport = tgt->rport; tgt->rport = NULL; list_del(&tgt->queue); + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT); spin_unlock_irqrestore(vhost->host->host_lock, flags); if (rport) fc_remote_port_delete(rport); diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index d7e8dcd90650..af48172112fa 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -597,6 +597,7 @@ enum ibmvfc_target_action { IBMVFC_TGT_ACTION_INIT, IBMVFC_TGT_ACTION_INIT_WAIT, IBMVFC_TGT_ACTION_DEL_RPORT, + IBMVFC_TGT_ACTION_DELETED_RPORT, }; struct ibmvfc_target { -- cgit From d2fab5cf3979c55f802c96616daf96e9e8de1c80 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 5 Aug 2010 16:38:34 -0500 Subject: [SCSI] ibmvfc: Fix terminate_rport_io The ibmvfc driver was incorrectly obtaining a scsi_target pointer from an fc_rport. The way it is coded ensures that ibmvfc's terminate_rport_io handler does absolutely nothing. Fix this up to iterate through affected devices differently, sending cancel and abort task set as appropriate. Without this patch, fast_io_fail_tmo is broken for ibmvfc. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvfc.c | 372 ++++++++++++++++++++++------------------- drivers/scsi/ibmvscsi/ibmvfc.h | 1 + 2 files changed, 204 insertions(+), 169 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index a13db5908426..9f75a6d519a2 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -2039,95 +2039,108 @@ static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc) } /** - * ibmvfc_abort_task_set - Abort outstanding commands to the device - * @sdev: scsi device to abort commands - * - * This sends an Abort Task Set to the VIOS for the specified device. This does - * NOT send any cancel to the VIOS. That must be done separately. + * ibmvfc_match_rport - Match function for specified remote port + * @evt: ibmvfc event struct + * @device: device to match (rport) * * Returns: - * 0 on success / other on failure + * 1 if event matches rport / 0 if event does not match rport **/ -static int ibmvfc_abort_task_set(struct scsi_device *sdev) +static int ibmvfc_match_rport(struct ibmvfc_event *evt, void *rport) { - struct ibmvfc_host *vhost = shost_priv(sdev->host); - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - struct ibmvfc_cmd *tmf; - struct ibmvfc_event *evt, *found_evt; - union ibmvfc_iu rsp_iu; - struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; - int rsp_rc = -EBUSY; - unsigned long flags; - int rsp_code = 0; + struct fc_rport *cmd_rport; - spin_lock_irqsave(vhost->host->host_lock, flags); - found_evt = NULL; - list_for_each_entry(evt, &vhost->sent, queue) { - if (evt->cmnd && evt->cmnd->device == sdev) { - found_evt = evt; - break; - } - } - - if (!found_evt) { - if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) - sdev_printk(KERN_INFO, sdev, "No events found to abort\n"); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return 0; - } - - if (vhost->state == IBMVFC_ACTIVE) { - evt = ibmvfc_get_event(vhost); - ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); - - tmf = &evt->iu.cmd; - memset(tmf, 0, sizeof(*tmf)); - tmf->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); - tmf->resp.len = sizeof(tmf->rsp); - tmf->frame_type = IBMVFC_SCSI_FCP_TYPE; - tmf->payload_len = sizeof(tmf->iu); - tmf->resp_len = sizeof(tmf->rsp); - tmf->cancel_key = (unsigned long)sdev->hostdata; - tmf->tgt_scsi_id = rport->port_id; - int_to_scsilun(sdev->lun, &tmf->iu.lun); - tmf->flags = (IBMVFC_NO_MEM_DESC | IBMVFC_TMF); - tmf->iu.tmf_flags = IBMVFC_ABORT_TASK_SET; - evt->sync_iu = &rsp_iu; - - init_completion(&evt->comp); - rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); + if (evt->cmnd) { + cmd_rport = starget_to_rport(scsi_target(evt->cmnd->device)); + if (cmd_rport == rport) + return 1; } + return 0; +} - spin_unlock_irqrestore(vhost->host->host_lock, flags); +/** + * ibmvfc_match_target - Match function for specified target + * @evt: ibmvfc event struct + * @device: device to match (starget) + * + * Returns: + * 1 if event matches starget / 0 if event does not match starget + **/ +static int ibmvfc_match_target(struct ibmvfc_event *evt, void *device) +{ + if (evt->cmnd && scsi_target(evt->cmnd->device) == device) + return 1; + return 0; +} - if (rsp_rc != 0) { - sdev_printk(KERN_ERR, sdev, "Failed to send abort. rc=%d\n", rsp_rc); - return -EIO; - } +/** + * ibmvfc_match_lun - Match function for specified LUN + * @evt: ibmvfc event struct + * @device: device to match (sdev) + * + * Returns: + * 1 if event matches sdev / 0 if event does not match sdev + **/ +static int ibmvfc_match_lun(struct ibmvfc_event *evt, void *device) +{ + if (evt->cmnd && evt->cmnd->device == device) + return 1; + return 0; +} - sdev_printk(KERN_INFO, sdev, "Aborting outstanding commands\n"); - wait_for_completion(&evt->comp); +/** + * ibmvfc_wait_for_ops - Wait for ops to complete + * @vhost: ibmvfc host struct + * @device: device to match (starget or sdev) + * @match: match function + * + * Returns: + * SUCCESS / FAILED + **/ +static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device, + int (*match) (struct ibmvfc_event *, void *)) +{ + struct ibmvfc_event *evt; + DECLARE_COMPLETION_ONSTACK(comp); + int wait; + unsigned long flags; + signed long timeout = IBMVFC_ABORT_WAIT_TIMEOUT * HZ; - if (rsp_iu.cmd.status) - rsp_code = ibmvfc_get_err_result(&rsp_iu.cmd); + ENTER; + do { + wait = 0; + spin_lock_irqsave(vhost->host->host_lock, flags); + list_for_each_entry(evt, &vhost->sent, queue) { + if (match(evt, device)) { + evt->eh_comp = ∁ + wait++; + } + } + spin_unlock_irqrestore(vhost->host->host_lock, flags); - if (rsp_code) { - if (fc_rsp->flags & FCP_RSP_LEN_VALID) - rsp_code = fc_rsp->data.info.rsp_code; + if (wait) { + timeout = wait_for_completion_timeout(&comp, timeout); - sdev_printk(KERN_ERR, sdev, "Abort failed: %s (%x:%x) " - "flags: %x fcp_rsp: %x, scsi_status: %x\n", - ibmvfc_get_cmd_error(rsp_iu.cmd.status, rsp_iu.cmd.error), - rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code, - fc_rsp->scsi_status); - rsp_rc = -EIO; - } else - sdev_printk(KERN_INFO, sdev, "Abort successful\n"); + if (!timeout) { + wait = 0; + spin_lock_irqsave(vhost->host->host_lock, flags); + list_for_each_entry(evt, &vhost->sent, queue) { + if (match(evt, device)) { + evt->eh_comp = NULL; + wait++; + } + } + spin_unlock_irqrestore(vhost->host->host_lock, flags); + if (wait) + dev_err(vhost->dev, "Timed out waiting for aborted commands\n"); + LEAVE; + return wait ? FAILED : SUCCESS; + } + } + } while (wait); - spin_lock_irqsave(vhost->host->host_lock, flags); - ibmvfc_free_event(evt); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return rsp_rc; + LEAVE; + return SUCCESS; } /** @@ -2215,88 +2228,130 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) } /** - * ibmvfc_match_target - Match function for specified target + * ibmvfc_match_key - Match function for specified cancel key * @evt: ibmvfc event struct - * @device: device to match (starget) + * @key: cancel key to match * * Returns: - * 1 if event matches starget / 0 if event does not match starget + * 1 if event matches key / 0 if event does not match key **/ -static int ibmvfc_match_target(struct ibmvfc_event *evt, void *device) +static int ibmvfc_match_key(struct ibmvfc_event *evt, void *key) { - if (evt->cmnd && scsi_target(evt->cmnd->device) == device) - return 1; - return 0; -} + unsigned long cancel_key = (unsigned long)key; -/** - * ibmvfc_match_lun - Match function for specified LUN - * @evt: ibmvfc event struct - * @device: device to match (sdev) - * - * Returns: - * 1 if event matches sdev / 0 if event does not match sdev - **/ -static int ibmvfc_match_lun(struct ibmvfc_event *evt, void *device) -{ - if (evt->cmnd && evt->cmnd->device == device) + if (evt->crq.format == IBMVFC_CMD_FORMAT && + evt->iu.cmd.cancel_key == cancel_key) return 1; return 0; } /** - * ibmvfc_wait_for_ops - Wait for ops to complete - * @vhost: ibmvfc host struct - * @device: device to match (starget or sdev) - * @match: match function + * ibmvfc_abort_task_set - Abort outstanding commands to the device + * @sdev: scsi device to abort commands + * + * This sends an Abort Task Set to the VIOS for the specified device. This does + * NOT send any cancel to the VIOS. That must be done separately. * * Returns: - * SUCCESS / FAILED + * 0 on success / other on failure **/ -static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device, - int (*match) (struct ibmvfc_event *, void *)) +static int ibmvfc_abort_task_set(struct scsi_device *sdev) { - struct ibmvfc_event *evt; - DECLARE_COMPLETION_ONSTACK(comp); - int wait; - unsigned long flags; - signed long timeout = IBMVFC_ABORT_WAIT_TIMEOUT * HZ; + struct ibmvfc_host *vhost = shost_priv(sdev->host); + struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + struct ibmvfc_cmd *tmf; + struct ibmvfc_event *evt, *found_evt; + union ibmvfc_iu rsp_iu; + struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; + int rc, rsp_rc = -EBUSY; + unsigned long flags, timeout = IBMVFC_ABORT_TIMEOUT; + int rsp_code = 0; - ENTER; - do { - wait = 0; - spin_lock_irqsave(vhost->host->host_lock, flags); - list_for_each_entry(evt, &vhost->sent, queue) { - if (match(evt, device)) { - evt->eh_comp = ∁ - wait++; - } + spin_lock_irqsave(vhost->host->host_lock, flags); + found_evt = NULL; + list_for_each_entry(evt, &vhost->sent, queue) { + if (evt->cmnd && evt->cmnd->device == sdev) { + found_evt = evt; + break; } + } + + if (!found_evt) { + if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) + sdev_printk(KERN_INFO, sdev, "No events found to abort\n"); spin_unlock_irqrestore(vhost->host->host_lock, flags); + return 0; + } - if (wait) { - timeout = wait_for_completion_timeout(&comp, timeout); + if (vhost->state == IBMVFC_ACTIVE) { + evt = ibmvfc_get_event(vhost); + ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); - if (!timeout) { - wait = 0; - spin_lock_irqsave(vhost->host->host_lock, flags); - list_for_each_entry(evt, &vhost->sent, queue) { - if (match(evt, device)) { - evt->eh_comp = NULL; - wait++; - } - } - spin_unlock_irqrestore(vhost->host->host_lock, flags); - if (wait) - dev_err(vhost->dev, "Timed out waiting for aborted commands\n"); - LEAVE; - return wait ? FAILED : SUCCESS; - } + tmf = &evt->iu.cmd; + memset(tmf, 0, sizeof(*tmf)); + tmf->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); + tmf->resp.len = sizeof(tmf->rsp); + tmf->frame_type = IBMVFC_SCSI_FCP_TYPE; + tmf->payload_len = sizeof(tmf->iu); + tmf->resp_len = sizeof(tmf->rsp); + tmf->cancel_key = (unsigned long)sdev->hostdata; + tmf->tgt_scsi_id = rport->port_id; + int_to_scsilun(sdev->lun, &tmf->iu.lun); + tmf->flags = (IBMVFC_NO_MEM_DESC | IBMVFC_TMF); + tmf->iu.tmf_flags = IBMVFC_ABORT_TASK_SET; + evt->sync_iu = &rsp_iu; + + init_completion(&evt->comp); + rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); + } + + spin_unlock_irqrestore(vhost->host->host_lock, flags); + + if (rsp_rc != 0) { + sdev_printk(KERN_ERR, sdev, "Failed to send abort. rc=%d\n", rsp_rc); + return -EIO; + } + + sdev_printk(KERN_INFO, sdev, "Aborting outstanding commands\n"); + timeout = wait_for_completion_timeout(&evt->comp, timeout); + + if (!timeout) { + rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET); + if (!rc) { + rc = ibmvfc_wait_for_ops(vhost, sdev->hostdata, ibmvfc_match_key); + if (rc == SUCCESS) + rc = 0; } - } while (wait); - LEAVE; - return SUCCESS; + if (rc) { + sdev_printk(KERN_INFO, sdev, "Cancel failed, resetting host\n"); + ibmvfc_reset_host(vhost); + rsp_rc = 0; + goto out; + } + } + + if (rsp_iu.cmd.status) + rsp_code = ibmvfc_get_err_result(&rsp_iu.cmd); + + if (rsp_code) { + if (fc_rsp->flags & FCP_RSP_LEN_VALID) + rsp_code = fc_rsp->data.info.rsp_code; + + sdev_printk(KERN_ERR, sdev, "Abort failed: %s (%x:%x) " + "flags: %x fcp_rsp: %x, scsi_status: %x\n", + ibmvfc_get_cmd_error(rsp_iu.cmd.status, rsp_iu.cmd.error), + rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code, + fc_rsp->scsi_status); + rsp_rc = -EIO; + } else + sdev_printk(KERN_INFO, sdev, "Abort successful\n"); + +out: + spin_lock_irqsave(vhost->host->host_lock, flags); + ibmvfc_free_event(evt); + spin_unlock_irqrestore(vhost->host->host_lock, flags); + return rsp_rc; } /** @@ -2353,18 +2408,6 @@ static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd) return rc; } -/** - * ibmvfc_dev_cancel_all_abts - Device iterated cancel all function - * @sdev: scsi device struct - * @data: return code - * - **/ -static void ibmvfc_dev_cancel_all_abts(struct scsi_device *sdev, void *data) -{ - unsigned long *rc = data; - *rc |= ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET); -} - /** * ibmvfc_dev_cancel_all_reset - Device iterated cancel all function * @sdev: scsi device struct @@ -2377,18 +2420,6 @@ static void ibmvfc_dev_cancel_all_reset(struct scsi_device *sdev, void *data) *rc |= ibmvfc_cancel_all(sdev, IBMVFC_TMF_TGT_RESET); } -/** - * ibmvfc_dev_abort_all - Device iterated abort task set function - * @sdev: scsi device struct - * @data: return code - * - **/ -static void ibmvfc_dev_abort_all(struct scsi_device *sdev, void *data) -{ - unsigned long *rc = data; - *rc |= ibmvfc_abort_task_set(sdev); -} - /** * ibmvfc_eh_target_reset_handler - Reset the target * @cmd: scsi command struct @@ -2443,19 +2474,22 @@ static int ibmvfc_eh_host_reset_handler(struct scsi_cmnd *cmd) **/ static void ibmvfc_terminate_rport_io(struct fc_rport *rport) { - struct scsi_target *starget = to_scsi_target(&rport->dev); - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct Scsi_Host *shost = rport_to_shost(rport); struct ibmvfc_host *vhost = shost_priv(shost); - unsigned long cancel_rc = 0; - unsigned long abort_rc = 0; - int rc = FAILED; + struct fc_rport *dev_rport; + struct scsi_device *sdev; + unsigned long rc; ENTER; - starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all_abts); - starget_for_each_device(starget, &abort_rc, ibmvfc_dev_abort_all); + shost_for_each_device(sdev, shost) { + dev_rport = starget_to_rport(scsi_target(sdev)); + if (dev_rport != rport) + continue; + ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET); + ibmvfc_abort_task_set(sdev); + } - if (!cancel_rc && !abort_rc) - rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); + rc = ibmvfc_wait_for_ops(vhost, rport, ibmvfc_match_rport); if (rc == FAILED) ibmvfc_issue_fc_host_lip(shost); diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index af48172112fa..d47cefc22ed3 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -38,6 +38,7 @@ #define IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT \ (IBMVFC_ADISC_TIMEOUT + IBMVFC_ADISC_CANCEL_TIMEOUT) #define IBMVFC_INIT_TIMEOUT 120 +#define IBMVFC_ABORT_TIMEOUT 8 #define IBMVFC_ABORT_WAIT_TIMEOUT 40 #define IBMVFC_MAX_REQUESTS_DEFAULT 100 -- cgit From 7e41dfdaf11a45ab4f4dfc444a7d42bf79dd9356 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 5 Aug 2010 16:38:36 -0500 Subject: [SCSI] ibmvfc: Driver version 1.0.9 Bump driver version. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvfc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index d47cefc22ed3..608af394c8cf 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -29,8 +29,8 @@ #include "viosrp.h" #define IBMVFC_NAME "ibmvfc" -#define IBMVFC_DRIVER_VERSION "1.0.8" -#define IBMVFC_DRIVER_DATE "(June 17, 2010)" +#define IBMVFC_DRIVER_VERSION "1.0.9" +#define IBMVFC_DRIVER_DATE "(August 5, 2010)" #define IBMVFC_DEFAULT_TIMEOUT 60 #define IBMVFC_ADISC_CANCEL_TIMEOUT 45 -- cgit From b375a612ad931264b71cf162d692b4420f2578a9 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 17 Jun 2010 14:58:21 +0200 Subject: aha1532: remove ISA_DMA_THRESHOLD usage We can safely remove ISA_DMA_THRESHOLD usage in aha1542. aha1542 uses ISA_DMA_THRESHOLD to see if: - the buffers in scatter/list are below 16MB. - scsi_host is below 16MB. Both checkings were added in the ancient times but aren't necessary nowadays since we properly bounce the buffers and allocate scsi_host below 16MB with non-zero unchecked_isa_dma. Signed-off-by: FUJITA Tomonori Acked-by: James Bottomley Signed-off-by: Jens Axboe --- drivers/scsi/aha1542.c | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 2a8cf137f609..4f785f254c1f 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -52,22 +52,6 @@ #define SCSI_BUF_PA(address) isa_virt_to_bus(address) #define SCSI_SG_PA(sgent) (isa_page_to_bus(sg_page((sgent))) + (sgent)->offset) -static void BAD_SG_DMA(Scsi_Cmnd * SCpnt, - struct scatterlist *sgp, - int nseg, - int badseg) -{ - printk(KERN_CRIT "sgpnt[%d:%d] page %p/0x%llx length %u\n", - badseg, nseg, sg_virt(sgp), - (unsigned long long)SCSI_SG_PA(sgp), - sgp->length); - - /* - * Not safe to continue. - */ - panic("Buffer at physical address > 16Mb used for aha1542"); -} - #include #ifdef DEBUG @@ -691,8 +675,6 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) } scsi_for_each_sg(SCpnt, sg, sg_count, i) { any2scsi(cptr[i].dataptr, SCSI_SG_PA(sg)); - if (SCSI_SG_PA(sg) + sg->length - 1 > ISA_DMA_THRESHOLD) - BAD_SG_DMA(SCpnt, scsi_sglist(SCpnt), sg_count, i); any2scsi(cptr[i].datalen, sg->length); }; any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain)); @@ -1133,16 +1115,9 @@ static int __init aha1542_detect(struct scsi_host_template * tpnt) release_region(bases[indx], 4); continue; } - /* For now we do this - until kmalloc is more intelligent - we are resigned to stupid hacks like this */ - if (SCSI_BUF_PA(shpnt) >= ISA_DMA_THRESHOLD) { - printk(KERN_ERR "Invalid address for shpnt with 1542.\n"); - goto unregister; - } if (!aha1542_test_port(bases[indx], shpnt)) goto unregister; - base_io = bases[indx]; /* Set the Bus on/off-times as not to ruin floppy performance */ -- cgit From 33659ebbae262228eef4e0fe990f393d1f0ed941 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 7 Aug 2010 18:17:56 +0200 Subject: block: remove wrappers for request type/flags Remove all the trivial wrappers for the cmd_type and cmd_flags fields in struct requests. This allows much easier grepping for different request types instead of unwinding through macros. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/scsi/scsi_error.c | 10 +++++----- drivers/scsi/scsi_lib.c | 5 +++-- drivers/scsi/sd.c | 12 ++++++------ drivers/scsi/sun3_NCR5380.c | 2 +- drivers/scsi/sun3_scsi.c | 2 +- drivers/scsi/sun3_scsi_vme.c | 2 +- 6 files changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index a5d630f5f519..1b88af89d0c7 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -307,7 +307,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) (sshdr.asc == 0x04) && (sshdr.ascq == 0x02)) return FAILED; - if (blk_barrier_rq(scmd->request)) + if (scmd->request->cmd_flags & REQ_HARDBARRIER) /* * barrier requests should always retry on UA * otherwise block will get a spurious error @@ -1318,16 +1318,16 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd) case DID_OK: break; case DID_BUS_BUSY: - return blk_failfast_transport(scmd->request); + return (scmd->request->cmd_flags & REQ_FAILFAST_TRANSPORT); case DID_PARITY: - return blk_failfast_dev(scmd->request); + return (scmd->request->cmd_flags & REQ_FAILFAST_DEV); case DID_ERROR: if (msg_byte(scmd->result) == COMMAND_COMPLETE && status_byte(scmd->result) == RESERVATION_CONFLICT) return 0; /* fall through */ case DID_SOFT_ERROR: - return blk_failfast_driver(scmd->request); + return (scmd->request->cmd_flags & REQ_FAILFAST_DRIVER); } switch (status_byte(scmd->result)) { @@ -1336,7 +1336,7 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd) * assume caller has checked sense and determinted * the check condition was retryable. */ - return blk_failfast_dev(scmd->request); + return (scmd->request->cmd_flags & REQ_FAILFAST_DEV); } return 0; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 1646fe7cbd4b..5f1160841b0e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -722,7 +722,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) sense_deferred = scsi_sense_is_deferred(&sshdr); } - if (blk_pc_request(req)) { /* SG_IO ioctl from block level */ + if (req->cmd_type == REQ_TYPE_BLOCK_PC) { /* SG_IO ioctl from block level */ req->errors = result; if (result) { if (sense_valid && req->sense) { @@ -757,7 +757,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) } } - BUG_ON(blk_bidi_rq(req)); /* bidi not support for !blk_pc_request yet */ + /* no bidi support for !REQ_TYPE_BLOCK_PC yet */ + BUG_ON(blk_bidi_rq(req)); /* * Next deal with any sectors which we were able to correctly diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8802e48bc063..a3fdf4dc59da 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -485,7 +485,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) * Discard request come in as REQ_TYPE_FS but we turn them into * block PC requests to make life easier. */ - if (blk_discard_rq(rq)) + if (rq->cmd_flags & REQ_DISCARD) ret = sd_prepare_discard(rq); if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { @@ -636,7 +636,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) SCpnt->cmnd[0] = VARIABLE_LENGTH_CMD; SCpnt->cmnd[7] = 0x18; SCpnt->cmnd[9] = (rq_data_dir(rq) == READ) ? READ_32 : WRITE_32; - SCpnt->cmnd[10] = protect | (blk_fua_rq(rq) ? 0x8 : 0); + SCpnt->cmnd[10] = protect | ((rq->cmd_flags & REQ_FUA) ? 0x8 : 0); /* LBA */ SCpnt->cmnd[12] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0; @@ -661,7 +661,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) SCpnt->cmnd[31] = (unsigned char) this_count & 0xff; } else if (block > 0xffffffff) { SCpnt->cmnd[0] += READ_16 - READ_6; - SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0); + SCpnt->cmnd[1] = protect | ((rq->cmd_flags & REQ_FUA) ? 0x8 : 0); SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0; SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0; SCpnt->cmnd[4] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0; @@ -682,7 +682,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) this_count = 0xffff; SCpnt->cmnd[0] += READ_10 - READ_6; - SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0); + SCpnt->cmnd[1] = protect | ((rq->cmd_flags & REQ_FUA) ? 0x8 : 0); SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff; SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; @@ -691,7 +691,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff; SCpnt->cmnd[8] = (unsigned char) this_count & 0xff; } else { - if (unlikely(blk_fua_rq(rq))) { + if (unlikely(rq->cmd_flags & REQ_FUA)) { /* * This happens only if this drive failed * 10byte rw command with ILLEGAL_REQUEST @@ -1112,7 +1112,7 @@ static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd) u64 bad_lba; int info_valid; - if (!blk_fs_request(scmd->request)) + if (scmd->request->cmd_type != REQ_TYPE_FS) return 0; info_valid = scsi_get_sense_info_fld(scmd->sense_buffer, diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c index b5838d547c68..713620ed70d9 100644 --- a/drivers/scsi/sun3_NCR5380.c +++ b/drivers/scsi/sun3_NCR5380.c @@ -2022,7 +2022,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done != cmd)) { - if(blk_fs_request(cmd->request)) { + if (cmd->request->cmd_type == REQ_TYPE_FS) { sun3scsi_dma_setup(d, count, rq_data_dir(cmd->request)); sun3_dma_setup_done = cmd; diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index e606cf0a2eb7..613f5880d135 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -524,7 +524,7 @@ static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, struct scsi_cmnd *cmd, int write_flag) { - if(blk_fs_request(cmd->request)) + if (cmd->request->cmd_type == REQ_TYPE_FS) return wanted; else return 0; diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c index aaa4fd0dd1b9..7c526b8e30ac 100644 --- a/drivers/scsi/sun3_scsi_vme.c +++ b/drivers/scsi/sun3_scsi_vme.c @@ -458,7 +458,7 @@ static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, struct scsi_cmnd *cmd, int write_flag) { - if(blk_fs_request(cmd->request)) + if (cmd->request->cmd_type == REQ_TYPE_FS) return wanted; else return 0; -- cgit From 7b6d91daee5cac6402186ff224c3af39d79f4a0e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 7 Aug 2010 18:20:39 +0200 Subject: block: unify flags for struct bio and struct request Remove the current bio flags and reuse the request flags for the bio, too. This allows to more easily trace the type of I/O from the filesystem down to the block driver. There were two flags in the bio that were missing in the requests: BIO_RW_UNPLUG and BIO_RW_AHEAD. Also I've renamed two request flags that had a superflous RW in them. Note that the flags are in bio.h despite having the REQ_ name - as blkdev.h includes bio.h that is the only way to go for now. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/scsi/osd/osd_initiator.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index ee4b6914667f..fda4de3440c4 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -716,7 +716,7 @@ static int _osd_req_list_objects(struct osd_request *or, return PTR_ERR(bio); } - bio->bi_rw &= ~(1 << BIO_RW); + bio->bi_rw &= ~REQ_WRITE; or->in.bio = bio; or->in.total_bytes = bio->bi_size; return 0; @@ -814,7 +814,7 @@ void osd_req_write(struct osd_request *or, { _osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, len); WARN_ON(or->out.bio || or->out.total_bytes); - WARN_ON(0 == bio_rw_flagged(bio, BIO_RW)); + WARN_ON(0 == (bio->bi_rw & REQ_WRITE)); or->out.bio = bio; or->out.total_bytes = len; } @@ -829,7 +829,7 @@ int osd_req_write_kern(struct osd_request *or, if (IS_ERR(bio)) return PTR_ERR(bio); - bio->bi_rw |= (1 << BIO_RW); /* FIXME: bio_set_dir() */ + bio->bi_rw |= REQ_WRITE; /* FIXME: bio_set_dir() */ osd_req_write(or, obj, offset, bio, len); return 0; } @@ -865,7 +865,7 @@ void osd_req_read(struct osd_request *or, { _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, len); WARN_ON(or->in.bio || or->in.total_bytes); - WARN_ON(1 == bio_rw_flagged(bio, BIO_RW)); + WARN_ON(1 == (bio->bi_rw & REQ_WRITE)); or->in.bio = bio; or->in.total_bytes = len; } -- cgit From 66ac0280197981f88774e74b60c8e5f9f07c1dba Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 18 Jun 2010 16:59:42 +0200 Subject: block: don't allocate a payload for discard request Allocating a fixed payload for discard requests always was a horrible hack, and it's not coming to byte us when adding support for discard in DM/MD. So change the code to leave the allocation of a payload to the lowlevel driver. Unfortunately that means we'll need another hack, which allows us to update the various block layer length fields indicating that we have a payload. Instead of hiding this in sd.c, which we already partially do for UNMAP support add a documented helper in the core block layer for it. Signed-off-by: Christoph Hellwig Acked-by: Mike Snitzer Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 52 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 18 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index a3fdf4dc59da..86da819c70eb 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -411,22 +411,25 @@ static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif) } /** - * sd_prepare_discard - unmap blocks on thinly provisioned device + * scsi_setup_discard_cmnd - unmap blocks on thinly provisioned device + * @sdp: scsi device to operate one * @rq: Request to prepare * * Will issue either UNMAP or WRITE SAME(16) depending on preference * indicated by target device. **/ -static int sd_prepare_discard(struct request *rq) +static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) { struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); struct bio *bio = rq->bio; sector_t sector = bio->bi_sector; - unsigned int num = bio_sectors(bio); + unsigned int nr_sectors = bio_sectors(bio); + unsigned int len; + struct page *page; if (sdkp->device->sector_size == 4096) { sector >>= 3; - num >>= 3; + nr_sectors >>= 3; } rq->cmd_type = REQ_TYPE_BLOCK_PC; @@ -434,31 +437,35 @@ static int sd_prepare_discard(struct request *rq) memset(rq->cmd, 0, rq->cmd_len); + page = alloc_page(GFP_ATOMIC | __GFP_ZERO); + if (!page) + return BLKPREP_DEFER; + if (sdkp->unmap) { - char *buf = kmap_atomic(bio_page(bio), KM_USER0); + char *buf = page_address(page); + rq->cmd_len = 10; rq->cmd[0] = UNMAP; rq->cmd[8] = 24; - rq->cmd_len = 10; - - /* Ensure that data length matches payload */ - rq->__data_len = bio->bi_size = bio->bi_io_vec->bv_len = 24; put_unaligned_be16(6 + 16, &buf[0]); put_unaligned_be16(16, &buf[2]); put_unaligned_be64(sector, &buf[8]); - put_unaligned_be32(num, &buf[16]); + put_unaligned_be32(nr_sectors, &buf[16]); - kunmap_atomic(buf, KM_USER0); + len = 24; } else { + rq->cmd_len = 16; rq->cmd[0] = WRITE_SAME_16; rq->cmd[1] = 0x8; /* UNMAP */ put_unaligned_be64(sector, &rq->cmd[2]); - put_unaligned_be32(num, &rq->cmd[10]); - rq->cmd_len = 16; + put_unaligned_be32(nr_sectors, &rq->cmd[10]); + + len = sdkp->device->sector_size; } - return BLKPREP_OK; + blk_add_request_payload(rq, page, len); + return scsi_setup_blk_pc_cmnd(sdp, rq); } /** @@ -485,10 +492,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) * Discard request come in as REQ_TYPE_FS but we turn them into * block PC requests to make life easier. */ - if (rq->cmd_flags & REQ_DISCARD) - ret = sd_prepare_discard(rq); - - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { + if (rq->cmd_flags & REQ_DISCARD) { + ret = scsi_setup_discard_cmnd(sdp, rq); + goto out; + } else if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { ret = scsi_setup_blk_pc_cmnd(sdp, rq); goto out; } else if (rq->cmd_type != REQ_TYPE_FS) { @@ -1163,6 +1170,15 @@ static int sd_done(struct scsi_cmnd *SCpnt) int sense_valid = 0; int sense_deferred = 0; + /* + * If this is a discard request that originated from the kernel + * we need to free our payload here. Note that we need to check + * the request flag as the normal payload rules apply for + * pass-through UNMAP / WRITE SAME requests. + */ + if (SCpnt->request->cmd_flags & REQ_DISCARD) + __free_page(bio_page(SCpnt->request->bio)); + if (result) { sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); if (sense_valid) -- cgit From 28018c242a4ec7017bbbf81d2d3952f820a27118 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 1 Jul 2010 19:49:17 +0900 Subject: block: implement an unprep function corresponding directly to prep Reviewed-by: FUJITA Tomonori Signed-off-by: Jens Axboe --- drivers/scsi/scsi_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 5f1160841b0e..ee836193f531 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -85,7 +85,7 @@ static void scsi_unprep_request(struct request *req) { struct scsi_cmnd *cmd = req->special; - req->cmd_flags &= ~REQ_DONTPREP; + blk_unprep_request(req); req->special = NULL; scsi_put_command(cmd); -- cgit From f1126e950d28ff875d96ed6a04a9ff96c7bfc357 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 1 Jul 2010 19:49:18 +0900 Subject: scsi: add sd_unprep_fn to free discard page This fixes discard page leak by using q->unprep_rq_fn facility. q->unprep_rq_fn is called when all the data buffer (req->bio and scsi_data_buffer) in the request is freed. sd_unprep() uses rq->buffer to free discard page allocated in sd_prepare_discard(). Signed-off-by: FUJITA Tomonori Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 86da819c70eb..2d4e3a865f39 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -425,6 +425,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) sector_t sector = bio->bi_sector; unsigned int nr_sectors = bio_sectors(bio); unsigned int len; + int ret; struct page *page; if (sdkp->device->sector_size == 4096) { @@ -465,7 +466,15 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) } blk_add_request_payload(rq, page, len); - return scsi_setup_blk_pc_cmnd(sdp, rq); + ret = scsi_setup_blk_pc_cmnd(sdp, rq); + rq->buffer = page_address(page); + return ret; +} + +static void sd_unprep_fn(struct request_queue *q, struct request *rq) +{ + if (rq->cmd_flags & REQ_DISCARD) + __free_page(virt_to_page(rq->buffer)); } /** @@ -2242,6 +2251,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie) sd_revalidate_disk(gd); blk_queue_prep_rq(sdp->request_queue, sd_prep_fn); + blk_queue_unprep_rq(sdp->request_queue, sd_unprep_fn); gd->driverfs_dev = &sdp->sdev_gendev; gd->flags = GENHD_FL_EXT_DEVT; -- cgit From 802447c1c0513a0ea0e29d6bda23b19ac0686654 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 1 Jul 2010 19:49:19 +0900 Subject: scsi: remove unused free discard page in sd_done - sd_done isn't called for pc request so we never call the code. - we use sd_unprep to free discard page now. Signed-off-by: FUJITA Tomonori Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 2d4e3a865f39..aa6b48ba78b1 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1179,15 +1179,6 @@ static int sd_done(struct scsi_cmnd *SCpnt) int sense_valid = 0; int sense_deferred = 0; - /* - * If this is a discard request that originated from the kernel - * we need to free our payload here. Note that we need to check - * the request flag as the normal payload rules apply for - * pass-through UNMAP / WRITE SAME requests. - */ - if (SCpnt->request->cmd_flags & REQ_DISCARD) - __free_page(bio_page(SCpnt->request->bio)); - if (result) { sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); if (sense_valid) -- cgit From 90467c294aba7f911bdae72ed86995cf1de4d364 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sat, 3 Jul 2010 17:45:34 +0900 Subject: scsi: stop using q->prepare_flush_fn scsi-ml builds flush requests via q->prepare_flush_fn(), however, builds discard requests via q->prep_rq_fn. Using two different mechnisms for the similar requests (building commands in SCSI ULD) doesn't make sense. Handing both via q->prep_rq_fn makes the code design simpler. Signed-off-by: FUJITA Tomonori Cc: James Bottomley Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index aa6b48ba78b1..e8c295e01466 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -471,6 +471,18 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) return ret; } +static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq) +{ + /* for now, we use REQ_TYPE_BLOCK_PC. */ + rq->cmd_type = REQ_TYPE_BLOCK_PC; + rq->timeout = SD_TIMEOUT; + rq->retries = SD_MAX_RETRIES; + rq->cmd[0] = SYNCHRONIZE_CACHE; + rq->cmd_len = 10; + + return scsi_setup_blk_pc_cmnd(sdp, rq); +} + static void sd_unprep_fn(struct request_queue *q, struct request *rq) { if (rq->cmd_flags & REQ_DISCARD) @@ -504,6 +516,9 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) if (rq->cmd_flags & REQ_DISCARD) { ret = scsi_setup_discard_cmnd(sdp, rq); goto out; + } else if (rq->cmd_flags & REQ_FLUSH) { + ret = scsi_setup_flush_cmnd(sdp, rq); + goto out; } else if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { ret = scsi_setup_blk_pc_cmnd(sdp, rq); goto out; @@ -1053,15 +1068,6 @@ static int sd_sync_cache(struct scsi_disk *sdkp) return 0; } -static void sd_prepare_flush(struct request_queue *q, struct request *rq) -{ - rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->timeout = SD_TIMEOUT; - rq->retries = SD_MAX_RETRIES; - rq->cmd[0] = SYNCHRONIZE_CACHE; - rq->cmd_len = 10; -} - static void sd_rescan(struct device *dev) { struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); @@ -2129,7 +2135,7 @@ static int sd_revalidate_disk(struct gendisk *disk) else ordered = QUEUE_ORDERED_DRAIN; - blk_queue_ordered(sdkp->disk->queue, ordered, sd_prepare_flush); + blk_queue_ordered(sdkp->disk->queue, ordered, NULL); set_capacity(disk, sdkp->capacity); kfree(buffer); -- cgit From 00fff26539bfe3fad21c164fc4002d9ede056fb0 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sat, 3 Jul 2010 17:45:40 +0900 Subject: block: remove q->prepare_flush_fn completely This removes q->prepare_flush_fn completely (changes the blk_queue_ordered API). Signed-off-by: FUJITA Tomonori Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e8c295e01466..d9a4314a1948 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2135,7 +2135,7 @@ static int sd_revalidate_disk(struct gendisk *disk) else ordered = QUEUE_ORDERED_DRAIN; - blk_queue_ordered(sdkp->disk->queue, ordered, NULL); + blk_queue_ordered(sdkp->disk->queue, ordered); set_capacity(disk, sdkp->capacity); kfree(buffer); -- cgit From 82b6d57fb11644fe25c8a1346627ad0027673dae Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sat, 3 Jul 2010 08:07:04 -0600 Subject: scsi: need to reset unprep_rq_fn in sd_remove This is for block's for-2.6.36. We need to reset q->unprep_rq_fn in sd_remove. Otherwise we hit kernel oops if we access to a scsi disk device via sg after removing scsi disk module. Signed-off-by: FUJITA Tomonori Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index d9a4314a1948..0994ab63b598 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2384,6 +2384,7 @@ static int sd_remove(struct device *dev) async_synchronize_full(); sdkp = dev_get_drvdata(dev); blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn); + blk_queue_unprep_rq(sdkp->device->request_queue, NULL); device_del(&sdkp->dev); del_gendisk(sdkp->disk); sd_shutdown(dev); -- cgit From 610a63498f7f366031a6327eaaa9963ffa110b2b Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 8 Jul 2010 10:16:17 +0200 Subject: scsi: fix discard page leak We leak a page allocated for discard on some error conditions (e.g. scsi_prep_state_check returns BLKPREP_DEFER in scsi_setup_blk_pc_cmnd). We unprep on requests that weren't prepped in the error path of scsi_init_io. It makes the error path to clean up scsi commands messy. Let's strictly apply the rule that we can't unprep on a request that wasn't prepped. Calling just scsi_put_command() in the error path of scsi_init_io() is enough. We don't set REQ_DONTPREP yet. scsi_setup_discard_cmnd can safely free a page on the error case with the above rule. Signed-off-by: FUJITA Tomonori Signed-off-by: Jens Axboe --- drivers/scsi/scsi_lib.c | 7 ++----- drivers/scsi/sd.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ee836193f531..b8de389636f8 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1011,11 +1011,8 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) err_exit: scsi_release_buffers(cmd); - if (error == BLKPREP_KILL) - scsi_put_command(cmd); - else /* BLKPREP_DEFER */ - scsi_unprep_request(cmd->request); - + scsi_put_command(cmd); + cmd->request->special = NULL; return error; } EXPORT_SYMBOL(scsi_init_io); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 0994ab63b598..1d0c4b7c3b69 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -468,6 +468,10 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) blk_add_request_payload(rq, page, len); ret = scsi_setup_blk_pc_cmnd(sdp, rq); rq->buffer = page_address(page); + if (ret != BLKPREP_OK) { + __free_page(page); + rq->buffer = NULL; + } return ret; } @@ -485,8 +489,10 @@ static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq) static void sd_unprep_fn(struct request_queue *q, struct request *rq) { - if (rq->cmd_flags & REQ_DISCARD) - __free_page(virt_to_page(rq->buffer)); + if (rq->cmd_flags & REQ_DISCARD) { + free_page((unsigned long)rq->buffer); + rq->buffer = NULL; + } } /** -- cgit From 8a6cfeb6deca3a8fefd639d898b0d163c0b5d368 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 8 Jul 2010 10:18:46 +0200 Subject: block: push down BKL into .locked_ioctl As a preparation for the removal of the big kernel lock in the block layer, this removes the BKL from the common ioctl handling code, moving it into every single driver still using it. Signed-off-by: Arnd Bergmann Acked-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 17 ++++++++++++----- drivers/scsi/sr.c | 18 +++++++++++++----- 2 files changed, 25 insertions(+), 10 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 1d0c4b7c3b69..633ac32b25c1 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -924,6 +925,7 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, SCSI_LOG_IOCTL(1, printk("sd_ioctl: disk=%s, cmd=0x%x\n", disk->disk_name, cmd)); + lock_kernel(); /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it @@ -933,7 +935,7 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, error = scsi_nonblockable_ioctl(sdp, cmd, p, (mode & FMODE_NDELAY) != 0); if (!scsi_block_when_processing_errors(sdp) || !error) - return error; + goto out; /* * Send SCSI addressing ioctls directly to mid level, send other @@ -943,13 +945,18 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, switch (cmd) { case SCSI_IOCTL_GET_IDLUN: case SCSI_IOCTL_GET_BUS_NUMBER: - return scsi_ioctl(sdp, cmd, p); + error = scsi_ioctl(sdp, cmd, p); + break; default: error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p); if (error != -ENOTTY) - return error; + break; + error = scsi_ioctl(sdp, cmd, p); + break; } - return scsi_ioctl(sdp, cmd, p); +out: + unlock_kernel(); + return error; } static void set_media_not_present(struct scsi_disk *sdkp) @@ -1123,7 +1130,7 @@ static const struct block_device_operations sd_fops = { .owner = THIS_MODULE, .open = sd_open, .release = sd_release, - .locked_ioctl = sd_ioctl, + .ioctl = sd_ioctl, .getgeo = sd_getgeo, #ifdef CONFIG_COMPAT .compat_ioctl = sd_compat_ioctl, diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 0a90abc7f140..d42fa6468f41 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -493,6 +494,8 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, void __user *argp = (void __user *)arg; int ret; + lock_kernel(); + /* * Send SCSI addressing ioctls directly to mid level, send other * ioctls to cdrom/block level. @@ -500,12 +503,13 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, switch (cmd) { case SCSI_IOCTL_GET_IDLUN: case SCSI_IOCTL_GET_BUS_NUMBER: - return scsi_ioctl(sdev, cmd, argp); + ret = scsi_ioctl(sdev, cmd, argp); + goto out; } ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg); if (ret != -ENOSYS) - return ret; + goto out; /* * ENODEV means that we didn't recognise the ioctl, or that we @@ -516,8 +520,12 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, ret = scsi_nonblockable_ioctl(sdev, cmd, argp, (mode & FMODE_NDELAY) != 0); if (ret != -ENODEV) - return ret; - return scsi_ioctl(sdev, cmd, argp); + goto out; + ret = scsi_ioctl(sdev, cmd, argp); + +out: + unlock_kernel(); + return ret; } static int sr_block_media_changed(struct gendisk *disk) @@ -531,7 +539,7 @@ static const struct block_device_operations sr_bdops = .owner = THIS_MODULE, .open = sr_block_open, .release = sr_block_release, - .locked_ioctl = sr_block_ioctl, + .ioctl = sr_block_ioctl, .media_changed = sr_block_media_changed, /* * No compat_ioctl for now because sr_block_ioctl never -- cgit From 6e9624b8caec290d28b4c6d9ec75749df6372b87 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 7 Aug 2010 18:25:34 +0200 Subject: block: push down BKL into .open and .release The open and release block_device_operations are currently called with the BKL held. In order to change that, we must first make sure that all drivers that currently rely on this have no regressions. This blindly pushes the BKL into all .open and .release operations for all block drivers to prepare for the next step. The drivers can subsequently replace the BKL with their own locks or remove it completely when it can be shown that it is not needed. The functions blkdev_get and blkdev_put are the only remaining users of the big kernel lock in the block layer, besides a few uses in the ioctl code, none of which need to serialize with blkdev_{get,put}. Most of these two functions is also under the protection of bdev->bd_mutex, including the actual calls to ->open and ->release, and the common code does not access any global data structures that need the BKL. Signed-off-by: Arnd Bergmann Acked-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 5 +++++ drivers/scsi/sr.c | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 633ac32b25c1..01680c7c8507 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -795,6 +795,7 @@ static int sd_open(struct block_device *bdev, fmode_t mode) SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_open\n")); + lock_kernel(); sdev = sdkp->device; /* @@ -838,10 +839,12 @@ static int sd_open(struct block_device *bdev, fmode_t mode) scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); } + unlock_kernel(); return 0; error_out: scsi_disk_put(sdkp); + unlock_kernel(); return retval; } @@ -863,6 +866,7 @@ static int sd_release(struct gendisk *disk, fmode_t mode) SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_release\n")); + lock_kernel(); if (!--sdkp->openers && sdev->removable) { if (scsi_block_when_processing_errors(sdev)) scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); @@ -873,6 +877,7 @@ static int sd_release(struct gendisk *disk, fmode_t mode) * XXX is followed by a "rmmod sd_mod"? */ scsi_disk_put(sdkp); + unlock_kernel(); return 0; } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index d42fa6468f41..ba9c3e0387ce 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -467,22 +467,27 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq) static int sr_block_open(struct block_device *bdev, fmode_t mode) { - struct scsi_cd *cd = scsi_cd_get(bdev->bd_disk); + struct scsi_cd *cd; int ret = -ENXIO; + lock_kernel(); + cd = scsi_cd_get(bdev->bd_disk); if (cd) { ret = cdrom_open(&cd->cdi, bdev, mode); if (ret) scsi_cd_put(cd); } + unlock_kernel(); return ret; } static int sr_block_release(struct gendisk *disk, fmode_t mode) { struct scsi_cd *cd = scsi_cd(disk); + lock_kernel(); cdrom_release(&cd->cdi, mode); scsi_cd_put(cd); + unlock_kernel(); return 0; } -- cgit From 409f3499a2cfcd1e9c2857c53af7fcce069f027f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 7 Jul 2010 16:51:29 +0200 Subject: scsi/sd: remove big kernel lock Every user of the BKL in the sd driver is the result of the pushdown from the block layer into the open/close/ioctl functions. The only place that used to rely on the BKL is the sdkp->openers variable, which gets converted into an atomic_t. Nothing else seems to rely on the BKL, since the functions do not touch global data without holding another lock, and the open/close functions are still protected from concurrent execution using the bdev->bd_mutex. Signed-off-by: Arnd Bergmann Cc: linux-scsi@vger.kernel.org Cc: "James E.J. Bottomley" Acked-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 17 +++++++---------- drivers/scsi/sd.h | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 01680c7c8507..fc5d69a84af5 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -783,6 +783,8 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) * or from within the kernel (e.g. as a result of a mount(1) ). * In the latter case @inode and @filp carry an abridged amount * of information as noted above. + * + * Locking: called with bdev->bd_mutex held. **/ static int sd_open(struct block_device *bdev, fmode_t mode) { @@ -795,7 +797,6 @@ static int sd_open(struct block_device *bdev, fmode_t mode) SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_open\n")); - lock_kernel(); sdev = sdkp->device; /* @@ -834,17 +835,15 @@ static int sd_open(struct block_device *bdev, fmode_t mode) if (!scsi_device_online(sdev)) goto error_out; - if (!sdkp->openers++ && sdev->removable) { + if ((atomic_inc_return(&sdkp->openers) == 1) && sdev->removable) { if (scsi_block_when_processing_errors(sdev)) scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); } - unlock_kernel(); return 0; error_out: scsi_disk_put(sdkp); - unlock_kernel(); return retval; } @@ -858,6 +857,8 @@ error_out: * * Note: may block (uninterruptible) if error recovery is underway * on this disk. + * + * Locking: called with bdev->bd_mutex held. **/ static int sd_release(struct gendisk *disk, fmode_t mode) { @@ -866,8 +867,7 @@ static int sd_release(struct gendisk *disk, fmode_t mode) SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_release\n")); - lock_kernel(); - if (!--sdkp->openers && sdev->removable) { + if (atomic_dec_return(&sdkp->openers) && sdev->removable) { if (scsi_block_when_processing_errors(sdev)) scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); } @@ -877,7 +877,6 @@ static int sd_release(struct gendisk *disk, fmode_t mode) * XXX is followed by a "rmmod sd_mod"? */ scsi_disk_put(sdkp); - unlock_kernel(); return 0; } @@ -930,7 +929,6 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, SCSI_LOG_IOCTL(1, printk("sd_ioctl: disk=%s, cmd=0x%x\n", disk->disk_name, cmd)); - lock_kernel(); /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it @@ -960,7 +958,6 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, break; } out: - unlock_kernel(); return error; } @@ -2346,7 +2343,7 @@ static int sd_probe(struct device *dev) sdkp->driver = &sd_template; sdkp->disk = gd; sdkp->index = index; - sdkp->openers = 0; + atomic_set(&sdkp->openers, 0); sdkp->previous_state = 1; if (!sdp->request_queue->rq_timeout) { diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 43d3caf268ef..f81a9309e6de 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -47,7 +47,7 @@ struct scsi_disk { struct scsi_device *device; struct device dev; struct gendisk *disk; - unsigned int openers; /* protected by BKL for now, yuck */ + atomic_t openers; sector_t capacity; /* size in 512-byte sectors */ u32 index; unsigned short hw_sector_size; -- cgit From 6a32a8aed509e71137043d464db4a7fcd88c903e Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Wed, 21 Jul 2010 10:29:37 +0900 Subject: scsi: convert discard to REQ_TYPE_FS from REQ_TYPE_BLOCK_PC Jens, any reason why this isn't included in your for-2.6.36 yet? = From: FUJITA Tomonori Subject: [PATCH resend] scsi: convert discard to REQ_TYPE_FS from REQ_TYPE_BLOCK_PC The block layer (file systems) sends discard requests as REQ_TYPE_FS (the role of REQ_TYPE_FS is that setting up commands and interpreting the results). But SCSI-ml treats discard requests as REQ_TYPE_BLOCK_PC. scsi-ml can handle discard requests as REQ_TYPE_FS easily. scsi_setup_discard_cmnd() sets up struct request and the bio nicely. Only remaining issue is that discard requests can't be completed partially so we need to modify sd_done. This conversion also fixes the problem that discard requests aren't retried when possible (e.g. UNIT ATTENTION). Signed-off-by: FUJITA Tomonori Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index fc5d69a84af5..e63b85ac8cd1 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -434,7 +434,6 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) nr_sectors >>= 3; } - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = SD_TIMEOUT; memset(rq->cmd, 0, rq->cmd_len); @@ -1200,6 +1199,12 @@ static int sd_done(struct scsi_cmnd *SCpnt) int sense_valid = 0; int sense_deferred = 0; + if (SCpnt->request->cmd_flags & REQ_DISCARD) { + if (!result) + scsi_set_resid(SCpnt, 0); + return good_bytes; + } + if (result) { sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); if (sense_valid) -- cgit From e96f6abe02fc3320d669985443e8c68ff8e83294 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 9 Jul 2010 09:38:26 +0900 Subject: scsi: use REQ_TYPE_FS for flush request scsi-ml uses REQ_TYPE_BLOCK_PC for flush requests from file systems. The definition of REQ_TYPE_BLOCK_PC is that we don't retry requests even when we can (e.g. UNIT ATTENTION) and we send the response to the callers (then the callers can decide what they want). We need a workaround such as the commit 77a4229719e511a0d38d9c355317ae1469adeb54 to retry BLOCK_PC flush requests. We will need the similar workaround for discard requests too since SCSI-ml handle them as BLOCK_PC internally. This uses REQ_TYPE_FS for flush requests from file systems instead of REQ_TYPE_BLOCK_PC. scsi-ml retries only REQ_TYPE_FS requests that have data to transfer when we can retry them (e.g. UNIT_ATTENTION). However, we also need to retry REQ_TYPE_FS requests without data because the callers don't. This also changes scsi_check_sense() to retry all the REQ_TYPE_FS requests when appropriate. Thanks to scsi_noretry_cmd(), REQ_TYPE_BLOCK_PC requests don't be retried as before. Note that basically, this reverts the commit 77a4229719e511a0d38d9c355317ae1469adeb54 since now we use REQ_TYPE_FS for flush requests. Signed-off-by: FUJITA Tomonori Signed-off-by: Jens Axboe --- drivers/scsi/scsi_error.c | 19 ++++--------------- drivers/scsi/sd.c | 2 -- 2 files changed, 4 insertions(+), 17 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 1b88af89d0c7..2768bf6ffe59 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -307,20 +307,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) (sshdr.asc == 0x04) && (sshdr.ascq == 0x02)) return FAILED; - if (scmd->request->cmd_flags & REQ_HARDBARRIER) - /* - * barrier requests should always retry on UA - * otherwise block will get a spurious error - */ - return NEEDS_RETRY; - else - /* - * for normal (non barrier) commands, pass the - * UA upwards for a determination in the - * completion functions - */ - return SUCCESS; - + return NEEDS_RETRY; /* these three are not supported */ case COPY_ABORTED: case VOLUME_OVERFLOW: @@ -1336,7 +1323,9 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd) * assume caller has checked sense and determinted * the check condition was retryable. */ - return (scmd->request->cmd_flags & REQ_FAILFAST_DEV); + if (scmd->request->cmd_flags & REQ_FAILFAST_DEV || + scmd->request->cmd_type == REQ_TYPE_BLOCK_PC) + return 1; } return 0; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e63b85ac8cd1..108daead7ae8 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -477,8 +477,6 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq) { - /* for now, we use REQ_TYPE_BLOCK_PC. */ - rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = SD_TIMEOUT; rq->retries = SD_MAX_RETRIES; rq->cmd[0] = SYNCHRONIZE_CACHE; -- cgit From 3eb3a92851857e6de92ad0c57bf7046ac4f58671 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 29 Jul 2010 10:10:16 +0200 Subject: [SCSI] Return NEEDS_RETRY for eh commands with status BUSY When the transport is busy and we're sending an EH command drivers occasionally return 'BUSY'. As this in most cases is the TUR command sent as part of the error recovery this is a sure way to make the error recovery escalate. Returning 'NEEDS_RETRY' here will just retry the TUR command and eventually abort the original command, thus making error handling far smoother. Signed-off-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 2bf98469dc4c..cfd01ef8a9d4 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -481,6 +481,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd) scsi_handle_queue_full(scmd->device); /* fall through */ case BUSY: + return NEEDS_RETRY; default: return FAILED; } -- cgit From 3deee42088ddcf5b23021aa089b53444797e565d Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Thu, 5 Aug 2010 17:50:37 -0700 Subject: [SCSI] tgt: fix warning Using scsi_tgt_lib in a new target module, we were getting the following warning and a stack traceback on every I/O completion: WARNING: at block/blk-core.c:1108 Which is claiming we may be leaking a bio. We don't leak bios (blk_rq_unmap_user should free them). Set rq->bio to NULL before calling scsi_host_put_command(). This was as advised by Fujita Tomonori. Signed-off-by: Joe Eykholt Acked-by: FUJITA Tomonori Signed-off-by: James Bottomley --- drivers/scsi/scsi_tgt_lib.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index 66241dd525ae..c399be979921 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -185,6 +185,7 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work) dprintk("cmd %p %d %u\n", cmd, cmd->sc_data_direction, rq_data_dir(cmd->request)); scsi_unmap_user_pages(tcmd); + tcmd->rq->bio = NULL; scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd); } -- cgit From 67110dfd45442e70753c575cf0509eaed237b749 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 6 Aug 2010 15:17:24 -0500 Subject: [SCSI] make error handling more robust in the face of reservations commit 5f91bb050ecc4ff1d8d3d07edbe550c8f431c5e1 Author: Michael Reed Date: Mon Aug 10 11:59:28 2009 -0500 [SCSI] reservation conflict after timeout causes device to be taken offline Flipped us from always returning failed to always returning success in the name of fixing the problem where reservation conflict returns from test unit ready cause the device always to be taken offline. Unfortuantely, it also introduced a problem whereby for commands other than test unit ready, the eh dispatcher thinks they succeeded when reservation conflict is returned, whereas in reality they failed. Fix this by only returning success for the test unit ready case. Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index cfd01ef8a9d4..0bd88381c1e1 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -473,10 +473,12 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd) */ return SUCCESS; case RESERVATION_CONFLICT: - /* - * let issuer deal with this, it could be just fine - */ - return SUCCESS; + if (scmd->cmnd[0] == TEST_UNIT_READY) + /* it is a success, we probed the device and + * found it */ + return SUCCESS; + /* otherwise, we failed to send the command */ + return FAILED; case QUEUE_FULL: scsi_handle_queue_full(scmd->device); /* fall through */ -- cgit From 3c3e210877e89aa3bfbda22551876986c035c433 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Mon, 9 Aug 2010 05:14:07 -0700 Subject: [SCSI] qla4xxx: fix compilation warning Fix following warning: drivers/scsi/qla4xxx/ql4_nx.c: In function 'qla4_8xxx_get_flash_info': drivers/scsi/qla4xxx/ql4_nx.c:1952: warning: 'mid' may be used uninitialized in this function drivers/scsi/qla4xxx/ql4_nx.c:1952: note: 'mid' was declared here drivers/scsi/qla4xxx/ql4_nx.c:1952: warning: 'fid' may be used uninitialized in this function drivers/scsi/qla4xxx/ql4_nx.c:1952: note: 'fid' was declared here Signed-off-by: Vikas Chaudhary Reported-by: Stephen Rothwell Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_nx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 1b85235efd8c..e031a734836e 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -1953,7 +1953,8 @@ qla4_8xxx_get_fdt_info(struct scsi_qla_host *ha) uint16_t cnt, chksum; uint16_t *wptr; struct qla_fdt_layout *fdt; - uint16_t mid, fid; + uint16_t mid = 0; + uint16_t fid = 0; struct ql82xx_hw_data *hw = &ha->hw; hw->flash_conf_off = FARX_ACCESS_FLASH_CONF; -- cgit From d6d1b650ae6acce73d55dd0246de22180303ae73 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 11 Aug 2010 23:04:27 -0600 Subject: param: simple locking for sysfs-writable charp parameters Since the writing to sysfs can free the old one, we need to block that when we access the charp variables. Signed-off-by: Rusty Russell Reviewed-by: Takashi Iwai Tested-by: Phil Carmody Cc: Jeff Dike Cc: Dan Williams Cc: John W. Linville Cc: Jing Huang Cc: James E.J. Bottomley Cc: Greg Kroah-Hartman Cc: Johannes Berg Cc: David S. Miller Cc: user-mode-linux-devel@lists.sourceforge.net Cc: libertas-dev@lists.infradead.org Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-scsi@vger.kernel.org Cc: linux-usb@vger.kernel.org --- drivers/scsi/bfa/bfad.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 915a29d6c7ad..ca04cc9d332f 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -788,6 +788,7 @@ bfad_drv_init(struct bfad_s *bfad) memset(&driver_info, 0, sizeof(driver_info)); strncpy(driver_info.version, BFAD_DRIVER_VERSION, sizeof(driver_info.version) - 1); + __kernel_param_lock(); if (host_name) strncpy(driver_info.host_machine_name, host_name, sizeof(driver_info.host_machine_name) - 1); @@ -797,6 +798,7 @@ bfad_drv_init(struct bfad_s *bfad) if (os_patch) strncpy(driver_info.host_os_patch, os_patch, sizeof(driver_info.host_os_patch) - 1); + __kernel_param_unlock(); strncpy(driver_info.os_device_name, bfad->pci_name, sizeof(driver_info.os_device_name - 1)); -- cgit From ef3f7cc41280e9611a837df1fedf3f6d4d921a75 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 10 Aug 2010 18:01:10 -0700 Subject: osst: fix read buffer overflow Check whether index is within bounds before testing the element. Signed-off-by: Roel Kluin Cc: Willem Riede Cc: James E.J. Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/osst.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index d64b7178fa08..278b352ae78d 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -5868,7 +5868,8 @@ static int osst_probe(struct device *dev) } /* find a free minor number */ - for (i=0; os_scsi_tapes[i] && i= osst_max_dev) panic ("Scsi_devices corrupt (osst)"); dev_num = i; -- cgit From 2c076eea6d3005c54f6e7be5938477fdc7027686 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 10 Aug 2010 18:01:10 -0700 Subject: gdth: unmap ccb_phys when scsi_add_host() fails in gdth_eisa_probe_one() unmap ccb_phys as well when scsi_add_host() fails Signed-off-by: Roel Kluin Cc: Achim Leubner Cc: James E.J. Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/gdth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index f672d6213eea..b860d650a563 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -4914,7 +4914,7 @@ static int __init gdth_eisa_probe_one(u16 eisa_slot) error = scsi_add_host(shp, NULL); if (error) - goto out_free_coal_stat; + goto out_free_ccb_phys; list_add_tail(&ha->list, &gdth_instances); gdth_timer_init(); -- cgit From 085267acd0ca29623c8239a38639d43d6d21e972 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 10 Aug 2010 18:01:11 -0700 Subject: NCR5380: bit MR_DMA_MODE set twice in NCR5380_transfer_dma() Besides keeping the line short, the second setting of the MR_DMA_MODE bit was removed. Signed-off-by: Roel Kluin Cc: James Bottomley Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/NCR5380.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index f92da9fd5f20..5d2f148889ad 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -1857,7 +1857,9 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase #endif /* KLL May need eop and parity in 53c400 */ if (hostdata->flags & FLAG_NCR53C400) - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE | MR_MONITOR_BSY); + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | + MR_ENABLE_PAR_CHECK | MR_ENABLE_PAR_INTR | + MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); else NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); #endif /* def REAL_DMA */ -- cgit From 95cc7baa7f19e191b4790d144b7cbe47369cfe32 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 10 Aug 2010 18:01:13 -0700 Subject: drivers/scsi: remove unnecessary NULL test At the point where cmnd is initialized, it is tested for NULL, so it doesn't have to be tested again here. A simplified version of the semantic match that detects this problem is as follows (http://coccinelle.lip6.fr/): // @match exists@ expression x, E; identifier fld; @@ * x->fld ... when != \(x = E\|&x\) * x == NULL // Signed-off-by: Julia Lawall Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/initio.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index a7714160fbc3..108797761b95 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -2817,7 +2817,6 @@ static void i91uSCBPost(u8 * host_mem, u8 * cblk_mem) } cmnd->result = cblk->tastat | (cblk->hastat << 16); - WARN_ON(cmnd == NULL); i91u_unmap_scb(host->pci_dev, cmnd); cmnd->scsi_done(cmnd); /* Notify system DONE */ initio_release_scb(host, cblk); /* Release SCB for current channel */ -- cgit From c94babbaf85c3162bd53a722ceeea32a0982d436 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 10 Aug 2010 18:01:15 -0700 Subject: g_NCR5380: remove misleading pnp error message Remove misleading error message that appears after pnp card has been detected correctly. Signed-off-by: Ondrej Zary Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/g_NCR5380.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 75585a52c88b..6bc0015662e0 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -322,10 +322,8 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt) while ((dev = pnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) { if (count >= NO_OVERRIDES) break; - if (pnp_device_attach(dev) < 0) { - printk(KERN_ERR "dtc436e probe: attach failed\n"); + if (pnp_device_attach(dev) < 0) continue; - } if (pnp_activate_dev(dev) < 0) { printk(KERN_ERR "dtc436e probe: activate failed\n"); pnp_device_detach(dev); -- cgit From 702a98c63355b74aec50897870eb1c89b5009cfb Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 10 Aug 2010 18:01:16 -0700 Subject: g_NCR5380: fix broken MMIO compilation The ifdefs are broken so the MMIO code is never compiled and so it's broken too. Fix them all. Untested as I don't have the hardware. Signed-off-by: Ondrej Zary Reviewed-by: Andy Walls Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/g_NCR5380.c | 43 +++++++++++++++++++++++-------------------- drivers/scsi/g_NCR5380.h | 6 +++--- 2 files changed, 26 insertions(+), 23 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 6bc0015662e0..427a56d3117e 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -285,9 +285,12 @@ static int __init do_DTC3181E_setup(char *str) int __init generic_NCR5380_detect(struct scsi_host_template * tpnt) { static int current_override = 0; - int count, i; + int count; unsigned int *ports; +#ifndef SCSI_G_NCR5380_MEM + int i; unsigned long region_size = 16; +#endif static unsigned int __initdata ncr_53c400a_ports[] = { 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 }; @@ -296,7 +299,7 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt) }; int flags = 0; struct Scsi_Host *instance; -#ifdef CONFIG_SCSI_G_NCR5380_MEM +#ifdef SCSI_G_NCR5380_MEM unsigned long base; void __iomem *iomem; #endif @@ -315,7 +318,7 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt) overrides[0].board = BOARD_NCR53C400A; else if (dtc_3181e != NCR_NOT_SET) overrides[0].board = BOARD_DTC3181E; - +#ifndef SCSI_G_NCR5380_MEM if (!current_override && isapnp_present()) { struct pnp_dev *dev = NULL; count = 0; @@ -347,7 +350,7 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt) count++; } } - +#endif tpnt->proc_name = "g_NCR5380"; for (count = 0; current_override < NO_OVERRIDES; ++current_override) { @@ -372,7 +375,7 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt) break; } -#ifndef CONFIG_SCSI_G_NCR5380_MEM +#ifndef SCSI_G_NCR5380_MEM if (ports) { /* wakeup sequence for the NCR53C400A and DTC3181E */ @@ -434,7 +437,7 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt) #endif instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); if (instance == NULL) { -#ifndef CONFIG_SCSI_G_NCR5380_MEM +#ifndef SCSI_G_NCR5380_MEM release_region(overrides[current_override].NCR5380_map_name, region_size); #else iounmap(iomem); @@ -444,10 +447,10 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt) } instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name; -#ifndef CONFIG_SCSI_G_NCR5380_MEM +#ifndef SCSI_G_NCR5380_MEM instance->n_io_port = region_size; #else - ((struct NCR5380_hostdata *)instance->hostdata).iomem = iomem; + ((struct NCR5380_hostdata *)instance->hostdata)->iomem = iomem; #endif NCR5380_init(instance, flags); @@ -515,10 +518,10 @@ int generic_NCR5380_release_resources(struct Scsi_Host *instance) free_irq(instance->irq, instance); NCR5380_exit(instance); -#ifndef CONFIG_SCSI_G_NCR5380_MEM +#ifndef SCSI_G_NCR5380_MEM release_region(instance->NCR5380_instance_name, instance->n_io_port); #else - iounmap(((struct NCR5380_hostdata *)instance->hostdata).iomem); + iounmap(((struct NCR5380_hostdata *)instance->hostdata)->iomem); release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); #endif @@ -588,14 +591,14 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, } while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY); -#ifndef CONFIG_SCSI_G_NCR5380_MEM +#ifndef SCSI_G_NCR5380_MEM { int i; for (i = 0; i < 128; i++) dst[start + i] = NCR5380_read(C400_HOST_BUFFER); } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ + /* implies SCSI_G_NCR5380_MEM */ memcpy_fromio(dst + start, iomem + NCR53C400_host_buffer, 128); #endif start += 128; @@ -608,14 +611,14 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, // FIXME - no timeout } -#ifndef CONFIG_SCSI_G_NCR5380_MEM +#ifndef SCSI_G_NCR5380_MEM { int i; for (i = 0; i < 128; i++) dst[start + i] = NCR5380_read(C400_HOST_BUFFER); } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ + /* implies SCSI_G_NCR5380_MEM */ memcpy_fromio(dst + start, iomem + NCR53C400_host_buffer, 128); #endif start += 128; @@ -674,13 +677,13 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, } while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) ; // FIXME - timeout -#ifndef CONFIG_SCSI_G_NCR5380_MEM +#ifndef SCSI_G_NCR5380_MEM { for (i = 0; i < 128; i++) NCR5380_write(C400_HOST_BUFFER, src[start + i]); } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ + /* implies SCSI_G_NCR5380_MEM */ memcpy_toio(iomem + NCR53C400_host_buffer, src + start, 128); #endif start += 128; @@ -690,13 +693,13 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) ; // FIXME - no timeout -#ifndef CONFIG_SCSI_G_NCR5380_MEM +#ifndef SCSI_G_NCR5380_MEM { for (i = 0; i < 128; i++) NCR5380_write(C400_HOST_BUFFER, src[start + i]); } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ + /* implies SCSI_G_NCR5380_MEM */ memcpy_toio(iomem + NCR53C400_host_buffer, src + start, 128); #endif start += 128; @@ -936,7 +939,7 @@ module_param(ncr_53c400a, int, 0); module_param(dtc_3181e, int, 0); MODULE_LICENSE("GPL"); - +#ifndef SCSI_G_NCR5380_MEM static struct isapnp_device_id id_table[] __devinitdata = { { ISAPNP_ANY_ID, ISAPNP_ANY_ID, @@ -946,7 +949,7 @@ static struct isapnp_device_id id_table[] __devinitdata = { }; MODULE_DEVICE_TABLE(isapnp, id_table); - +#endif __setup("ncr5380=", do_NCR5380_setup); __setup("ncr53c400=", do_NCR53C400_setup); diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h index df0b3f69ef63..921764c9ab24 100644 --- a/drivers/scsi/g_NCR5380.h +++ b/drivers/scsi/g_NCR5380.h @@ -63,7 +63,7 @@ static const char* generic_NCR5380_info(struct Scsi_Host *); #define __STRVAL(x) #x #define STRVAL(x) __STRVAL(x) -#ifndef CONFIG_SCSI_G_NCR5380_MEM +#ifndef SCSI_G_NCR5380_MEM #define NCR5380_map_config port #define NCR5380_map_type int @@ -91,7 +91,7 @@ static const char* generic_NCR5380_info(struct Scsi_Host *); NCR5380_map_name = (NCR5380_map_type)((instance)->NCR5380_instance_name) #else -/* therefore CONFIG_SCSI_G_NCR5380_MEM */ +/* therefore SCSI_G_NCR5380_MEM */ #define NCR5380_map_config memory #define NCR5380_map_type unsigned long @@ -114,7 +114,7 @@ static const char* generic_NCR5380_info(struct Scsi_Host *); register void __iomem *iomem #define NCR5380_setup(instance) \ - iomem = (((struct NCR5380_hostdata *)(instance)->hostdata).iomem) + iomem = (((struct NCR5380_hostdata *)(instance)->hostdata)->iomem) #endif -- cgit From d8187b945aa4ed9ea298518e3dac691ea09724e5 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 10 Aug 2010 18:01:17 -0700 Subject: dc395x: decrease iteration for tag_number of max_command in start_scsi() The tag_number reaches dcb->max_command + 1 after the loop, but when the tag_number equals dcb->max_command an error message is already issued. The last iteration therefore appears obsolete. Signed-off-by: Roel Kluin Cc: Oliver Neukum Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/dc395x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index bd977be7544e..54f50b07dac7 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -1597,7 +1597,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, u32 tag_mask = 1; u8 tag_number = 0; while (tag_mask & dcb->tag_mask - && tag_number <= dcb->max_command) { + && tag_number < dcb->max_command) { tag_mask = tag_mask << 1; tag_number++; } -- cgit From 85bc081f44d53e3ac268c59275cc3b9b5afae04a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 10 Aug 2010 18:01:18 -0700 Subject: drivers/scsi/aic94xx/aic94xx_init.c: correct the size argument to kmalloc In each case, the destination of the allocation has type struct **, so the elements of the array should have pointer type, not structure type. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @disable sizeof_type_expr@ type T; T **x; @@ x = <+...sizeof( - T + *x )...+> // Signed-off-by: Julia Lawall Cc: Rolf Eike Beer Cc: Joe Perches Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/aic94xx/aic94xx_init.c | 4 ++-- drivers/scsi/ch.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 24ac2315c5c7..3b7e83d2dab4 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -688,9 +688,9 @@ static int asd_register_sas_ha(struct asd_ha_struct *asd_ha) { int i; struct asd_sas_phy **sas_phys = - kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_phy), GFP_KERNEL); + kcalloc(ASD_MAX_PHYS, sizeof(*sas_phys), GFP_KERNEL); struct asd_sas_port **sas_ports = - kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_port), GFP_KERNEL); + kcalloc(ASD_MAX_PHYS, sizeof(*sas_ports), GFP_KERNEL); if (!sas_phys || !sas_ports) { kfree(sas_phys); diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 4799d4391203..769b35f8b39f 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -352,7 +352,7 @@ ch_readconfig(scsi_changer *ch) } /* look up the devices of the data transfer elements */ - ch->dt = kmalloc(ch->counts[CHET_DT]*sizeof(struct scsi_device), + ch->dt = kcalloc(ch->counts[CHET_DT], sizeof(*ch->dt), GFP_KERNEL); if (!ch->dt) { -- cgit From d6e9fb46cd9e60946dc3e89ad8e32dd251dcc05d Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 10 Aug 2010 18:01:19 -0700 Subject: scsi: remove superfluous NULL pointer check from scsi_kill_request() Dan's list included: drivers/scsi/scsi_lib.c +1365 scsi_kill_request(9) warning: variable derefenced in initializer 'cmd' drivers/scsi/scsi_lib.c +1365 scsi_kill_request(9) warning: variable derefenced before check 'cmd' We dereference cmd (and possible OOPS if cmd == NULL) before starting the request so just remove the superfluous debugging code altogether. [ bart: the potential NULL pointer dereference was finally fixed in (much later than mine) commit 03b1470 but my patch is still valid ] Reported-by: Dan Carpenter Cc: Jonathan Corbet Cc: Eugene Teo Signed-off-by: Bartlomiej Zolnierkiewicz Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/scsi_lib.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index b8de389636f8..9ade720422c6 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1370,12 +1370,6 @@ static void scsi_kill_request(struct request *req, struct request_queue *q) blk_start_request(req); - if (unlikely(cmd == NULL)) { - printk(KERN_CRIT "impossible request in %s.\n", - __func__); - BUG(); - } - sdev = cmd->device; starget = scsi_target(sdev); shost = sdev->host; -- cgit From 439d77f70f18ebe2b28757b141e67a25575fe363 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 10 Aug 2010 18:01:20 -0700 Subject: scsi/sd.c: quiet all sparse noise In sd_store_cache_type the symbol 'len' is declared twice. Remove the second declaration to quiet the following sparse warning. warning: symbol 'len' shadows an earlier one In sd_probe the variable 'index' is declared as a u32. This variable is used in a call to ida_get_new which is expecting an int *. Make the variable an int to quiet the following sparse warning. warning: incorrect type in argument 2 (different signedness) There are 4 symbols in the file that are not exported and produce the following sparse warnings. warning: symbol 'sd_cdb_cache' was not declared. Should it be static? warning: symbol 'sd_cdb_pool' was not declared. Should it be static? warning: symbol 'sd_read_protection_type' was not declared. Should it be static? warning: symbol 'sd_read_app_tag_own' was not declared. Should it be static? Make them static to quiet the warnings. Signed-off-by: H Hartley Sweeten Cc: James E.J. Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/sd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8e2e893db9e7..2714becc2eaf 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -119,8 +119,8 @@ static DEFINE_IDA(sd_index_ida); * object after last put) */ static DEFINE_MUTEX(sd_ref_mutex); -struct kmem_cache *sd_cdb_cache; -mempool_t *sd_cdb_pool; +static struct kmem_cache *sd_cdb_cache; +static mempool_t *sd_cdb_pool; static const char *sd_cache_types[] = { "write through", "none", "write back", @@ -147,7 +147,7 @@ sd_store_cache_type(struct device *dev, struct device_attribute *attr, return -EINVAL; for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) { - const int len = strlen(sd_cache_types[i]); + len = strlen(sd_cache_types[i]); if (strncmp(sd_cache_types[i], buf, len) == 0 && buf[len] == '\n') { ct = i; @@ -1423,7 +1423,7 @@ sd_spinup_disk(struct scsi_disk *sdkp) /* * Determine whether disk supports Data Integrity Field. */ -void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer) +static void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer) { struct scsi_device *sdp = sdkp->device; u8 type; @@ -1969,7 +1969,7 @@ defaults: * The ATO bit indicates whether the DIF application tag is available * for use by the operating system. */ -void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer) +static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer) { int res, offset; struct scsi_device *sdp = sdkp->device; @@ -2315,7 +2315,7 @@ static int sd_probe(struct device *dev) struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp; struct gendisk *gd; - u32 index; + int index; int error; error = -ENODEV; -- cgit From ae68230c2da8e5be712acd50dd9115918fa28839 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 10 Aug 2010 18:01:21 -0700 Subject: drivers/scsi/qla2xxx/qla_os.c: fix continuation line formats String constants that are continued on subsequent lines with \ will cause spurious whitespace in the resulting output. Signed-off-by: Joe Perches Cc: James E.J. Bottomley Cc: Giridhar Malavali Cc: Anirban Chakraborty Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/qla2xxx/qla_os.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index ff2172da7c19..8c80b49ac1c4 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -115,8 +115,8 @@ int ql2xmaxqueues = 1; module_param(ql2xmaxqueues, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xmaxqueues, "Enables MQ settings " - "Default is 1 for single queue. Set it to number \ - of queues in MQ mode."); + "Default is 1 for single queue. Set it to number " + "of queues in MQ mode."); int ql2xmultique_tag; module_param(ql2xmultique_tag, int, S_IRUGO|S_IRUSR); -- cgit From 6d154db6b3fc3c4dc3fbf7c32df0ad9d7aeaa18c Mon Sep 17 00:00:00 2001 From: Yong Zhang Date: Tue, 10 Aug 2010 18:01:22 -0700 Subject: scsi: bfa: correct onstack wait_queue_head declaration Use DECLARE_WAIT_QUEUE_HEAD_ONSTACK to make lockdep happy Signed-off-by: Yong Zhang Cc: Jing Huang Cc: James E.J. Bottomley Cc: Roel Kluin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/bfa/bfad_im.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 678120b70460..6ef87f6fcdbb 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -291,7 +291,7 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd) struct bfa_tskim_s *tskim; struct bfad_itnim_s *itnim; struct bfa_itnim_s *bfa_itnim; - DECLARE_WAIT_QUEUE_HEAD(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); int rc = SUCCESS; unsigned long flags; enum bfi_tskim_status task_status; @@ -353,7 +353,7 @@ bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd) struct bfad_itnim_s *itnim; unsigned long flags; u32 i, rc, err_cnt = 0; - DECLARE_WAIT_QUEUE_HEAD(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); enum bfi_tskim_status task_status; spin_lock_irqsave(&bfad->bfad_lock, flags); -- cgit From 87da32356bcee42569666bef1479d0e599a556f8 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 10 Aug 2010 18:01:22 -0700 Subject: drivers/scsi/ch.c: don't use vprintk as macro It's an exported symbol of kernel/printk.c Rename vprintk and dprintk macros to more common VPRINTK and DPRINTK Add do { } while(0) around macros Add level to VPRINTK so KERN_CONT can be used a couple of times. Signed-off-by: Joe Perches Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/ch.c | 87 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 43 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 769b35f8b39f..d6532187f616 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -84,10 +84,16 @@ static const char * vendor_labels[CH_TYPES-4] = { }; // module_param_string_array(vendor_labels, NULL, 0444); -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "%s: " fmt, ch->name , ## arg) -#define vprintk(fmt, arg...) if (verbose) \ - printk(KERN_INFO "%s: " fmt, ch->name , ## arg) +#define DPRINTK(fmt, arg...) \ +do { \ + if (debug) \ + printk(KERN_DEBUG "%s: " fmt, ch->name, ##arg); \ +} while (0) +#define VPRINTK(level, fmt, arg...) \ +do { \ + if (verbose) \ + printk(level "%s: " fmt, ch->name, ##arg); \ +} while (0) /* ------------------------------------------------------------------- */ @@ -186,7 +192,7 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, retry: errno = 0; if (debug) { - dprintk("command: "); + DPRINTK("command: "); __scsi_print_command(cmd); } @@ -194,7 +200,7 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, buflength, &sshdr, timeout * HZ, MAX_RETRIES, NULL); - dprintk("result: 0x%x\n",result); + DPRINTK("result: 0x%x\n",result); if (driver_byte(result) & DRIVER_SENSE) { if (debug) scsi_print_sense_hdr(ch->name, &sshdr); @@ -250,7 +256,7 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data) cmd[9] = 255; if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) { if (((buffer[16] << 8) | buffer[17]) != elem) { - dprintk("asked for element 0x%02x, got 0x%02x\n", + DPRINTK("asked for element 0x%02x, got 0x%02x\n", elem,(buffer[16] << 8) | buffer[17]); kfree(buffer); return -EIO; @@ -259,10 +265,10 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data) } else { if (ch->voltags) { ch->voltags = 0; - vprintk("device has no volume tag support\n"); + VPRINTK(KERN_INFO, "device has no volume tag support\n"); goto retry; } - dprintk("READ ELEMENT STATUS for element 0x%x failed\n",elem); + DPRINTK("READ ELEMENT STATUS for element 0x%x failed\n",elem); } kfree(buffer); return result; @@ -274,12 +280,12 @@ ch_init_elem(scsi_changer *ch) int err; u_char cmd[6]; - vprintk("INITIALIZE ELEMENT STATUS, may take some time ...\n"); + VPRINTK(KERN_INFO, "INITIALIZE ELEMENT STATUS, may take some time ...\n"); memset(cmd,0,sizeof(cmd)); cmd[0] = INITIALIZE_ELEMENT_STATUS; cmd[1] = ch->device->lun << 5; err = ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE); - vprintk("... finished\n"); + VPRINTK(KERN_INFO, "... finished\n"); return err; } @@ -322,20 +328,20 @@ ch_readconfig(scsi_changer *ch) (buffer[buffer[3]+18] << 8) | buffer[buffer[3]+19]; ch->counts[CHET_DT] = (buffer[buffer[3]+20] << 8) | buffer[buffer[3]+21]; - vprintk("type #1 (mt): 0x%x+%d [medium transport]\n", + VPRINTK(KERN_INFO, "type #1 (mt): 0x%x+%d [medium transport]\n", ch->firsts[CHET_MT], ch->counts[CHET_MT]); - vprintk("type #2 (st): 0x%x+%d [storage]\n", + VPRINTK(KERN_INFO, "type #2 (st): 0x%x+%d [storage]\n", ch->firsts[CHET_ST], ch->counts[CHET_ST]); - vprintk("type #3 (ie): 0x%x+%d [import/export]\n", + VPRINTK(KERN_INFO, "type #3 (ie): 0x%x+%d [import/export]\n", ch->firsts[CHET_IE], ch->counts[CHET_IE]); - vprintk("type #4 (dt): 0x%x+%d [data transfer]\n", + VPRINTK(KERN_INFO, "type #4 (dt): 0x%x+%d [data transfer]\n", ch->firsts[CHET_DT], ch->counts[CHET_DT]); } else { - vprintk("reading element address assigment page failed!\n"); + VPRINTK(KERN_INFO, "reading element address assigment page failed!\n"); } /* vendor specific element types */ @@ -346,7 +352,7 @@ ch_readconfig(scsi_changer *ch) continue; ch->firsts[CHET_V1+i] = vendor_firsts[i]; ch->counts[CHET_V1+i] = vendor_counts[i]; - vprintk("type #%d (v%d): 0x%x+%d [%s, vendor specific]\n", + VPRINTK(KERN_INFO, "type #%d (v%d): 0x%x+%d [%s, vendor specific]\n", i+5,i+1,vendor_firsts[i],vendor_counts[i], vendor_labels[i]); } @@ -366,21 +372,19 @@ ch_readconfig(scsi_changer *ch) if (elem < CH_DT_MAX && -1 != dt_id[elem]) { id = dt_id[elem]; lun = dt_lun[elem]; - vprintk("dt 0x%x: [insmod option] ", + VPRINTK(KERN_INFO, "dt 0x%x: [insmod option] ", elem+ch->firsts[CHET_DT]); } else if (0 != ch_read_element_status (ch,elem+ch->firsts[CHET_DT],data)) { - vprintk("dt 0x%x: READ ELEMENT STATUS failed\n", + VPRINTK(KERN_INFO, "dt 0x%x: READ ELEMENT STATUS failed\n", elem+ch->firsts[CHET_DT]); } else { - vprintk("dt 0x%x: ",elem+ch->firsts[CHET_DT]); + VPRINTK(KERN_INFO, "dt 0x%x: ",elem+ch->firsts[CHET_DT]); if (data[6] & 0x80) { - if (verbose) - printk("not this SCSI bus\n"); + VPRINTK(KERN_CONT, "not this SCSI bus\n"); ch->dt[elem] = NULL; } else if (0 == (data[6] & 0x30)) { - if (verbose) - printk("ID/LUN unknown\n"); + VPRINTK(KERN_CONT, "ID/LUN unknown\n"); ch->dt[elem] = NULL; } else { id = ch->device->id; @@ -390,22 +394,19 @@ ch_readconfig(scsi_changer *ch) } } if (-1 != id) { - if (verbose) - printk("ID %i, LUN %i, ",id,lun); + VPRINTK(KERN_CONT, "ID %i, LUN %i, ",id,lun); ch->dt[elem] = scsi_device_lookup(ch->device->host, ch->device->channel, id,lun); if (!ch->dt[elem]) { /* should not happen */ - if (verbose) - printk("Huh? device not found!\n"); + VPRINTK(KERN_CONT, "Huh? device not found!\n"); } else { - if (verbose) - printk("name: %8.8s %16.16s %4.4s\n", - ch->dt[elem]->vendor, - ch->dt[elem]->model, - ch->dt[elem]->rev); + VPRINTK(KERN_CONT, "name: %8.8s %16.16s %4.4s\n", + ch->dt[elem]->vendor, + ch->dt[elem]->model, + ch->dt[elem]->rev); } } } @@ -422,7 +423,7 @@ ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate) { u_char cmd[10]; - dprintk("position: 0x%x\n",elem); + DPRINTK("position: 0x%x\n",elem); if (0 == trans) trans = ch->firsts[CHET_MT]; memset(cmd,0,sizeof(cmd)); @@ -441,7 +442,7 @@ ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate) { u_char cmd[12]; - dprintk("move: 0x%x => 0x%x\n",src,dest); + DPRINTK("move: 0x%x => 0x%x\n",src,dest); if (0 == trans) trans = ch->firsts[CHET_MT]; memset(cmd,0,sizeof(cmd)); @@ -463,7 +464,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src, { u_char cmd[12]; - dprintk("exchange: 0x%x => 0x%x => 0x%x\n", + DPRINTK("exchange: 0x%x => 0x%x => 0x%x\n", src,dest1,dest2); if (0 == trans) trans = ch->firsts[CHET_MT]; @@ -511,7 +512,7 @@ ch_set_voltag(scsi_changer *ch, u_int elem, if (!buffer) return -ENOMEM; - dprintk("%s %s voltag: 0x%x => \"%s\"\n", + DPRINTK("%s %s voltag: 0x%x => \"%s\"\n", clear ? "clear" : "set", alternate ? "alternate" : "primary", elem, tag); @@ -550,7 +551,7 @@ static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest) } put_user(data[2], dest+i); if (data[2] & CESTATUS_EXCEPT) - vprintk("element 0x%x: asc=0x%x, ascq=0x%x\n", + VPRINTK(KERN_INFO, "element 0x%x: asc=0x%x, ascq=0x%x\n", ch->firsts[type]+i, (int)data[4],(int)data[5]); retval = ch_read_element_status @@ -660,7 +661,7 @@ static long ch_ioctl(struct file *file, return -EFAULT; if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) { - dprintk("CHIOPOSITION: invalid parameter\n"); + DPRINTK("CHIOPOSITION: invalid parameter\n"); return -EBADSLT; } mutex_lock(&ch->lock); @@ -680,7 +681,7 @@ static long ch_ioctl(struct file *file, if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) || 0 != ch_checkrange(ch, mv.cm_totype, mv.cm_tounit )) { - dprintk("CHIOMOVE: invalid parameter\n"); + DPRINTK("CHIOMOVE: invalid parameter\n"); return -EBADSLT; } @@ -703,7 +704,7 @@ static long ch_ioctl(struct file *file, if (0 != ch_checkrange(ch, mv.ce_srctype, mv.ce_srcunit ) || 0 != ch_checkrange(ch, mv.ce_fdsttype, mv.ce_fdstunit) || 0 != ch_checkrange(ch, mv.ce_sdsttype, mv.ce_sdstunit)) { - dprintk("CHIOEXCHANGE: invalid parameter\n"); + DPRINTK("CHIOEXCHANGE: invalid parameter\n"); return -EBADSLT; } @@ -796,7 +797,7 @@ static long ch_ioctl(struct file *file, } } else if (ch->voltags) { ch->voltags = 0; - vprintk("device has no volume tag support\n"); + VPRINTK(KERN_INFO, "device has no volume tag support\n"); goto voltag_retry; } kfree(buffer); @@ -824,7 +825,7 @@ static long ch_ioctl(struct file *file, return -EFAULT; if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) { - dprintk("CHIOSVOLTAG: invalid parameter\n"); + DPRINTK("CHIOSVOLTAG: invalid parameter\n"); return -EBADSLT; } elem = ch->firsts[csv.csv_type] + csv.csv_unit; -- cgit From 6de61f9d2491970a204da9111e2d25e0d9f284d6 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 10 Aug 2010 18:01:23 -0700 Subject: bfa: wrong fcport H2I message tested in bfa_fcport_isr() It appears that the wrong fcport H2I message was tested Signed-off-by: Roel Kluin Acked-by: Jing Huang Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/bfa/bfa_fcport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c index f0933d8d1eda..76867b5577fa 100644 --- a/drivers/scsi/bfa/bfa_fcport.c +++ b/drivers/scsi/bfa/bfa_fcport.c @@ -1310,7 +1310,7 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) break; case BFI_FCPORT_I2H_DISABLE_RSP: - if (fcport->msgtag == i2hmsg.penable_rsp->msgtag) + if (fcport->msgtag == i2hmsg.pdisable_rsp->msgtag) bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP); break; -- cgit From b2045240058381088e6e367e5f54b2a8bed931e1 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 10 Aug 2010 18:01:24 -0700 Subject: scsi: fix pmcraid build errors pmcraid should depend on NET since it uses netlink interfaces. This fixes multiple build errors when CONFIG_NET is not enabled: ERROR: "genl_register_family" [drivers/scsi/pmcraid.ko] undefined! ERROR: "genl_unregister_family" [drivers/scsi/pmcraid.ko] undefined! ERROR: "nla_put" [drivers/scsi/pmcraid.ko] undefined! ERROR: "init_net" [drivers/scsi/pmcraid.ko] undefined! ERROR: "__alloc_skb" [drivers/scsi/pmcraid.ko] undefined! ERROR: "netlink_broadcast" [drivers/scsi/pmcraid.ko] undefined! ERROR: "kfree_skb" [drivers/scsi/pmcraid.ko] undefined! ERROR: "skb_put" [drivers/scsi/pmcraid.ko] undefined! Signed-off-by: Randy Dunlap Cc: Anil Ravindranath Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 158284f05732..6466231f338b 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1853,7 +1853,7 @@ config ZFCP_DIF config SCSI_PMCRAID tristate "PMC SIERRA Linux MaxRAID adapter support" - depends on PCI && SCSI + depends on PCI && SCSI && NET ---help--- This driver supports the PMC SIERRA MaxRAID adapters. -- cgit From 5c90ad905b401c6675dcb6c9fed7c09c9240205c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 10 Aug 2010 18:01:25 -0700 Subject: scsi: fix bnx2i build errors bnx2i should depend on NET since it selects SCSI_ISCSI_ATTRS, which depends on NET. Also move the dependencies together. The "depends" change fixes multiple build errors when CONFIG_NET is not enabled: ERROR: "skb_trim" [drivers/scsi/scsi_transport_iscsi.ko] undefined! ERROR: "netlink_kernel_create" [drivers/scsi/scsi_transport_iscsi.ko] undefined! ERROR: "netlink_kernel_release" [drivers/scsi/scsi_transport_iscsi.ko] undefined! ERROR: "skb_pull" [drivers/scsi/scsi_transport_iscsi.ko] undefined! ERROR: "init_net" [drivers/scsi/scsi_transport_iscsi.ko] undefined! ERROR: "__alloc_skb" [drivers/scsi/scsi_transport_iscsi.ko] undefined! ERROR: "netlink_broadcast" [drivers/scsi/scsi_transport_iscsi.ko] undefined! ERROR: "kfree_skb" [drivers/scsi/scsi_transport_iscsi.ko] undefined! ERROR: "skb_put" [drivers/scsi/scsi_transport_iscsi.ko] undefined! Signed-off-by: Randy Dunlap Cc: Anil Veerabhadrappa Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/bnx2i/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/bnx2i/Kconfig b/drivers/scsi/bnx2i/Kconfig index 1e9f7141102b..45a6154ce972 100644 --- a/drivers/scsi/bnx2i/Kconfig +++ b/drivers/scsi/bnx2i/Kconfig @@ -1,10 +1,11 @@ config SCSI_BNX2_ISCSI tristate "Broadcom NetXtreme II iSCSI support" + depends on NET + depends on PCI select SCSI_ISCSI_ATTRS select NETDEVICES select NETDEV_1000 select CNIC - depends on PCI ---help--- This driver supports iSCSI offload for the Broadcom NetXtreme II devices. -- cgit From a737b88df8d0b4476ae53daaa6db137df0541203 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 10 Aug 2010 18:01:26 -0700 Subject: scsi: remove private BIT macros A couple of scsi drivers define a BIT() macro, duplicating the one in bitops.h. Cc: Jing Huang Cc: Robert Love Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/bfa/include/protocol/fcp.h | 4 +--- drivers/scsi/fnic/fnic.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/bfa/include/protocol/fcp.h b/drivers/scsi/bfa/include/protocol/fcp.h index 9ade68ad2853..74ea63ce84b7 100644 --- a/drivers/scsi/bfa/include/protocol/fcp.h +++ b/drivers/scsi/bfa/include/protocol/fcp.h @@ -18,6 +18,7 @@ #ifndef __FCPPROTO_H__ #define __FCPPROTO_H__ +#include #include #pragma pack(1) @@ -102,9 +103,6 @@ enum { /* * Task management flags field - only one bit shall be set */ -#ifndef BIT -#define BIT(_x) (1 << (_x)) -#endif enum fcp_tm_cmnd{ FCP_TM_ABORT_TASK_SET = BIT(1), FCP_TM_CLEAR_TASK_SET = BIT(2), diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 19338e0ba2c5..cbb20b13b228 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include "fnic_io.h" @@ -49,7 +50,6 @@ /* * Tag bits used for special requests. */ -#define BIT(nr) (1UL << (nr)) #define FNIC_TAG_ABORT BIT(30) /* tag bit indicating abort */ #define FNIC_TAG_DEV_RST BIT(29) /* indicates device reset */ #define FNIC_TAG_MASK (BIT(24) - 1) /* mask for lookup */ -- cgit From 3094141c6532a4f748425c21c091001f218da8ae Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 10 Aug 2010 18:01:27 -0700 Subject: drivers/scsi: use memdup_user Use memdup_user when user data is immediately copied into the allocated region. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression from,to,size,flag; position p; identifier l1,l2; @@ - to = \(kmalloc@p\|kzalloc@p\)(size,flag); + to = memdup_user(from,size); if ( - to==NULL + IS_ERR(to) || ...) { <+... when != goto l1; - -ENOMEM + PTR_ERR(to) ...+> } - if (copy_from_user(to, from, size) != 0) { - <+... when != goto l2; - -EFAULT - ...+> - } // Signed-off-by: Julia Lawall Cc: Doug Gilbert Cc: Boaz Harrosh Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/sg.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 2968c6b83ddb..78d616315d8e 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1686,14 +1686,9 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd) int len, size = sizeof(struct sg_iovec) * iov_count; struct iovec *iov; - iov = kmalloc(size, GFP_ATOMIC); - if (!iov) - return -ENOMEM; - - if (copy_from_user(iov, hp->dxferp, size)) { - kfree(iov); - return -EFAULT; - } + iov = memdup_user(hp->dxferp, size); + if (IS_ERR(iov)) + return PTR_ERR(iov); len = iov_length(iov, iov_count); if (hp->dxfer_len < len) { -- cgit From ecc3099002c1cc87e9e4b3dc5fdf7821828f6733 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Aug 2010 18:01:27 -0700 Subject: drivers: scsi: use newly introduced hex_to_bin() method Signed-off-by: Andy Shevchenko Cc: Adaptec OEM Raid Solutions Cc: "James E.J. Bottomley" Cc: James Smart Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/aacraid/rx.c | 5 ++--- drivers/scsi/lpfc/lpfc_attr.c | 23 +++++++++++------------ drivers/scsi/scsi_transport_fc.c | 12 ++++++------ 3 files changed, 19 insertions(+), 21 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 04057ab72a8b..84d77fd86e5b 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -352,9 +352,8 @@ static int aac_rx_check_health(struct aac_dev *dev) pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS), post, paddr); if (likely((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X')))) { - ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10); - ret <<= 4; - ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10); + ret = (hex_to_bin(buffer[2]) << 4) + + hex_to_bin(buffer[3]); } pci_free_consistent(dev->pdev, 512, buffer, baddr); return ret; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 162704cf6a96..ad05b266e950 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -1795,12 +1796,11 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr, /* Validate and store the new name */ for (i=0, j=0; i < 16; i++) { - if ((*buf >= 'a') && (*buf <= 'f')) - j = ((j << 4) | ((*buf++ -'a') + 10)); - else if ((*buf >= 'A') && (*buf <= 'F')) - j = ((j << 4) | ((*buf++ -'A') + 10)); - else if ((*buf >= '0') && (*buf <= '9')) - j = ((j << 4) | (*buf++ -'0')); + int value; + + value = hex_to_bin(*buf++); + if (value >= 0) + j = (j << 4) | value; else return -EINVAL; if (i % 2) { @@ -1888,12 +1888,11 @@ lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr, /* Validate and store the new name */ for (i=0, j=0; i < 16; i++) { - if ((*buf >= 'a') && (*buf <= 'f')) - j = ((j << 4) | ((*buf++ -'a') + 10)); - else if ((*buf >= 'A') && (*buf <= 'F')) - j = ((j << 4) | ((*buf++ -'A') + 10)); - else if ((*buf >= '0') && (*buf <= '9')) - j = ((j << 4) | (*buf++ -'0')); + int value; + + value = hex_to_bin(*buf++); + if (value >= 0) + j = (j << 4) | value; else return -EINVAL; if (i % 2) { diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index edb6b362a8fa..d7e470a06180 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1730,12 +1731,11 @@ fc_parse_wwn(const char *ns, u64 *nm) /* Validate and store the new name */ for (i=0, j=0; i < 16; i++) { - if ((*ns >= 'a') && (*ns <= 'f')) - j = ((j << 4) | ((*ns++ -'a') + 10)); - else if ((*ns >= 'A') && (*ns <= 'F')) - j = ((j << 4) | ((*ns++ -'A') + 10)); - else if ((*ns >= '0') && (*ns <= '9')) - j = ((j << 4) | (*ns++ -'0')); + int value; + + value = hex_to_bin(*ns++); + if (value >= 0) + j = (j << 4) | value; else return -EINVAL; if (i % 2) { -- cgit From d80e0d96a328cc864a1cb359f545a6ed0c61812d Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Aug 2010 18:03:24 -0700 Subject: scsi: 53c700: remove dma_is_consistent usage This driver is the only user of dma_is_consistent(). We plan to remove this API. The driver uses the API in the following way: BUG_ON(!dma_is_consistent(hostdata->dev, pScript) && L1_CACHE_BYTES < dma_get_cache_alignment()); The above code tries to see if L1_CACHE_BYTES is greater than dma_get_cache_alignment() on sysmtes that can not allocate coherent memory (some old systems can't). James Bottomley exmplained that this is necesary because the driver packs the set of mailboxes into a single coherent area and separates the different usages by a L1 cache stride. So it's fatal if the dma He also pointed out that we can kill this checking because we don't hit this BUG_ON on all architectures that actually use the driver. (akpm: stolen from the scsi tree because dma-mapping-remove-dma_is_consistent-api.patch needs it) Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/53c700.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 80dc3ac12cde..89fc1c8af86b 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -309,9 +309,6 @@ NCR_700_detect(struct scsi_host_template *tpnt, hostdata->msgin = memory + MSGIN_OFFSET; hostdata->msgout = memory + MSGOUT_OFFSET; hostdata->status = memory + STATUS_OFFSET; - /* all of these offsets are L1_CACHE_BYTES separated. It is fatal - * if this isn't sufficient separation to avoid dma flushing issues */ - BUG_ON(!dma_is_consistent(hostdata->dev, pScript) && L1_CACHE_BYTES < dma_get_cache_alignment()); hostdata->slots = (struct NCR_700_command_slot *)(memory + SLOTS_OFFSET); hostdata->dev = dev; -- cgit