diff options
Diffstat (limited to 'drivers/scsi/be2iscsi')
-rw-r--r-- | drivers/scsi/be2iscsi/be.h | 21 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_cmds.c | 88 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_cmds.h | 14 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_iscsi.c | 136 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_iscsi.h | 2 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_main.c | 488 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_main.h | 27 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_mgmt.c | 139 | ||||
-rw-r--r-- | drivers/scsi/be2iscsi/be_mgmt.h | 6 |
9 files changed, 547 insertions, 374 deletions
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index a93a504..136b49c 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -24,6 +24,10 @@ #define FW_VER_LEN 32 #define MCC_Q_LEN 128 #define MCC_CQ_LEN 256 +#define MAX_MCC_CMD 16 +/* BladeEngine Generation numbers */ +#define BE_GEN2 2 +#define BE_GEN3 3 struct be_dma_mem { void *va; @@ -57,6 +61,11 @@ static inline void *queue_head_node(struct be_queue_info *q) return q->dma_mem.va + q->head * q->entry_size; } +static inline void *queue_get_wrb(struct be_queue_info *q, unsigned int wrb_num) +{ + return q->dma_mem.va + wrb_num * q->entry_size; +} + static inline void *queue_tail_node(struct be_queue_info *q) { return q->dma_mem.va + q->tail * q->entry_size; @@ -104,15 +113,19 @@ struct be_ctrl_info { spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ spinlock_t mcc_cq_lock; - /* MCC Async callback */ - void (*async_cb) (void *adapter, bool link_up); - void *adapter_ctxt; + wait_queue_head_t mcc_wait[MAX_MCC_CMD + 1]; + unsigned int mcc_tag[MAX_MCC_CMD]; + unsigned int mcc_numtag[MAX_MCC_CMD + 1]; + unsigned short mcc_alloc_index; + unsigned short mcc_free_index; + unsigned int mcc_tag_available; }; #include "be_cmds.h" #define PAGE_SHIFT_4K 12 #define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K) +#define mcc_timeout 120000 /* 5s timeout */ /* Returns number of pages spanned by the data starting at the given addr */ #define PAGES_4K_SPANNED(_address, size) \ diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index f008708..6709857 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -19,7 +19,7 @@ #include "be_mgmt.h" #include "be_main.h" -static void be_mcc_notify(struct beiscsi_hba *phba) +void be_mcc_notify(struct beiscsi_hba *phba) { struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; u32 val = 0; @@ -29,6 +29,52 @@ static void be_mcc_notify(struct beiscsi_hba *phba) iowrite32(val, phba->db_va + DB_MCCQ_OFFSET); } +unsigned int alloc_mcc_tag(struct beiscsi_hba *phba) +{ + unsigned int tag = 0; + unsigned int num = 0; + +mcc_tag_rdy: + if (phba->ctrl.mcc_tag_available) { + tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index]; + phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0; + phba->ctrl.mcc_numtag[tag] = 0; + } else { + udelay(100); + num++; + if (num < mcc_timeout) + goto mcc_tag_rdy; + } + if (tag) { + phba->ctrl.mcc_tag_available--; + if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1)) + phba->ctrl.mcc_alloc_index = 0; + else + phba->ctrl.mcc_alloc_index++; + } + return tag; +} + +void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag) +{ + spin_lock(&ctrl->mbox_lock); + tag = tag & 0x000000FF; + ctrl->mcc_tag[ctrl->mcc_free_index] = tag; + if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1)) + ctrl->mcc_free_index = 0; + else + ctrl->mcc_free_index++; + ctrl->mcc_tag_available++; + spin_unlock(&ctrl->mbox_lock); +} + +bool is_link_state_evt(u32 trailer) +{ + return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & + ASYNC_TRAILER_EVENT_CODE_MASK) == + ASYNC_EVENT_CODE_LINK_STATE); +} + static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl) { if (compl->flags != 0) { @@ -64,12 +110,30 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl, return 0; } - -static inline bool is_link_state_evt(u32 trailer) +int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl, + struct be_mcc_compl *compl) { - return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & - ASYNC_TRAILER_EVENT_CODE_MASK) == - ASYNC_EVENT_CODE_LINK_STATE); + u16 compl_status, extd_status; + unsigned short tag; + + be_dws_le_to_cpu(compl, 4); + + compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & + CQE_STATUS_COMPL_MASK; + /* The ctrl.mcc_numtag[tag] is filled with + * [31] = valid, [30:24] = Rsvd, [23:16] = wrb, [15:8] = extd_status, + * [7:0] = compl_status + */ + tag = (compl->tag0 & 0x000000FF); + extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & + CQE_STATUS_EXTD_MASK; + + ctrl->mcc_numtag[tag] = 0x80000000; + ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000); + ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8; + ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF); + wake_up_interruptible(&ctrl->mcc_wait[tag]); + return 0; } static struct be_mcc_compl *be_mcc_compl_get(struct beiscsi_hba *phba) @@ -89,7 +153,7 @@ static void be2iscsi_fail_session(struct iscsi_cls_session *cls_session) iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); } -static void beiscsi_async_link_state_process(struct beiscsi_hba *phba, +void beiscsi_async_link_state_process(struct beiscsi_hba *phba, struct be_async_event_link_state *evt) { switch (evt->port_link_status) { @@ -97,13 +161,13 @@ static void beiscsi_async_link_state_process(struct beiscsi_hba *phba, SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d \n", evt->physical_port); phba->state |= BE_ADAPTER_LINK_DOWN; + iscsi_host_for_each_session(phba->shost, + be2iscsi_fail_session); break; case ASYNC_EVENT_LINK_UP: phba->state = BE_ADAPTER_UP; SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d \n", evt->physical_port); - iscsi_host_for_each_session(phba->shost, - be2iscsi_fail_session); break; default: SE_DEBUG(DBG_LVL_1, "Unexpected Async Notification %d on" @@ -162,7 +226,6 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba) /* Wait till no more pending mcc requests are present */ static int be_mcc_wait_compl(struct beiscsi_hba *phba) { -#define mcc_timeout 120000 /* 5s timeout */ int i, status; for (i = 0; i < mcc_timeout; i++) { status = beiscsi_process_mcc(phba); @@ -372,9 +435,10 @@ struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba) BUG_ON(atomic_read(&mccq->used) >= mccq->len); wrb = queue_head_node(mccq); + memset(wrb, 0, sizeof(*wrb)); + wrb->tag0 = (mccq->head & 0x000000FF) << 16; queue_head_inc(mccq); atomic_inc(&mccq->used); - memset(wrb, 0, sizeof(*wrb)); return wrb; } diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 5de8acb..49fcc78 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -425,14 +425,20 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba, int be_poll_mcc(struct be_ctrl_info *ctrl); unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba); -int be_cmd_get_mac_addr(struct beiscsi_hba *phba, u8 *mac_addr); - +unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba); +void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag); /*ISCSI Functuions */ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl); struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem); struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba); int be_mcc_notify_wait(struct beiscsi_hba *phba); +void be_mcc_notify(struct beiscsi_hba *phba); +unsigned int alloc_mcc_tag(struct beiscsi_hba *phba); +void beiscsi_async_link_state_process(struct beiscsi_hba *phba, + struct be_async_event_link_state *evt); +int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl, + struct be_mcc_compl *compl); int be_mbox_notify(struct be_ctrl_info *ctrl); @@ -448,6 +454,8 @@ int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl, int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem, struct be_queue_info *wrbq); +bool is_link_state_evt(u32 trailer); + struct be_default_pdu_context { u32 dw[4]; } __packed; diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index d587b03..29a3aaf 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -101,6 +101,7 @@ void beiscsi_session_destroy(struct iscsi_cls_session *cls_session) struct iscsi_session *sess = cls_session->dd_data; struct beiscsi_session *beiscsi_sess = sess->dd_data; + SE_DEBUG(DBG_LVL_8, "In beiscsi_session_destroy\n"); pci_pool_destroy(beiscsi_sess->bhs_pool); iscsi_session_teardown(cls_session); } @@ -224,6 +225,7 @@ int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, struct beiscsi_conn *beiscsi_conn = conn->dd_data; int len = 0; + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_param, param= %d\n", param); beiscsi_ep = beiscsi_conn->ep; if (!beiscsi_ep) { SE_DEBUG(DBG_LVL_1, @@ -254,6 +256,7 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, struct iscsi_session *session = conn->session; int ret; + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_set_param, param= %d\n", param); ret = iscsi_set_param(cls_conn, param, buf, buflen); if (ret) return ret; @@ -271,8 +274,8 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, conn->max_recv_dlength = 65536; break; case ISCSI_PARAM_MAX_BURST: - if (session->first_burst > 262144) - session->first_burst = 262144; + if (session->max_burst > 262144) + session->max_burst = 262144; break; default: return 0; @@ -293,12 +296,41 @@ 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; + SE_DEBUG(DBG_LVL_8, "In beiscsi_get_host_param, param= %d\n", param); switch (param) { case ISCSI_HOST_PARAM_HWADDRESS: - be_cmd_get_mac_addr(phba, phba->mac_address); - len = 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 -1; + } 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 -1; + } 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); + } break; default: return iscsi_host_get_param(shost, param, buf); @@ -378,6 +410,7 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn) struct beiscsi_endpoint *beiscsi_ep; struct beiscsi_offload_params params; + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_start\n"); memset(¶ms, 0, sizeof(struct beiscsi_offload_params)); beiscsi_ep = beiscsi_conn->ep; if (!beiscsi_ep) @@ -422,8 +455,14 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, { struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; struct beiscsi_hba *phba = beiscsi_ep->phba; + struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + struct be_mcc_wrb *wrb; + struct tcp_connect_and_offload_out *ptcpcnct_out; + unsigned short status, extd_status; + unsigned int tag, wrb_num; int ret = -1; + SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn\n"); beiscsi_ep->ep_cid = beiscsi_get_cid(phba); if (beiscsi_ep->ep_cid == 0xFFFF) { SE_DEBUG(DBG_LVL_1, "No free cid available\n"); @@ -431,15 +470,44 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, } SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d ", beiscsi_ep->ep_cid); - phba->ep_array[beiscsi_ep->ep_cid] = ep; - if (beiscsi_ep->ep_cid > - (phba->fw_config.iscsi_cid_start + phba->params.cxns_per_ctrl)) { + phba->ep_array[beiscsi_ep->ep_cid - + phba->fw_config.iscsi_cid_start] = ep; + if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start + + phba->params.cxns_per_ctrl * 2)) { SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); return ret; } beiscsi_ep->cid_vld = 0; - return mgmt_open_connection(phba, dst_addr, beiscsi_ep); + tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep); + if (!tag) { + SE_DEBUG(DBG_LVL_1, + "mgmt_invalidate_connection Failed for cid=%d \n", + beiscsi_ep->ep_cid); + } 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, "mgmt_open_connection Failed" + " status = %d extd_status = %d \n", + status, extd_status); + free_mcc_tag(&phba->ctrl, tag); + return -1; + } else { + wrb = queue_get_wrb(mccq, wrb_num); + free_mcc_tag(&phba->ctrl, tag); + + ptcpcnct_out = embedded_payload(wrb); + beiscsi_ep = ep->dd_data; + beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle; + beiscsi_ep->cid_vld = 1; + SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); + } + return 0; } /** @@ -459,14 +527,12 @@ static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid) * beiscsi_free_ep - free endpoint * @ep: pointer to iscsi endpoint structure */ -static void beiscsi_free_ep(struct iscsi_endpoint *ep) +static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep) { - struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; struct beiscsi_hba *phba = beiscsi_ep->phba; beiscsi_put_cid(phba, beiscsi_ep->ep_cid); beiscsi_ep->phba = NULL; - iscsi_destroy_endpoint(ep); } /** @@ -495,9 +561,9 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, return ERR_PTR(ret); } - if (phba->state) { + if (phba->state != BE_ADAPTER_UP) { ret = -EBUSY; - SE_DEBUG(DBG_LVL_1, "The Adapet state is Not UP \n"); + SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP \n"); return ERR_PTR(ret); } @@ -509,9 +575,9 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, beiscsi_ep = ep->dd_data; beiscsi_ep->phba = phba; - + beiscsi_ep->openiscsi_ep = ep; if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) { - SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); + SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn \n"); ret = -ENOMEM; goto free_ep; } @@ -519,7 +585,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, return ep; free_ep: - beiscsi_free_ep(ep); + beiscsi_free_ep(beiscsi_ep); return ERR_PTR(ret); } @@ -546,20 +612,22 @@ int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) * @ep: The iscsi endpoint * @flag: The type of connection closure */ -static int beiscsi_close_conn(struct iscsi_endpoint *ep, int flag) +static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) { int ret = 0; - struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; + unsigned int tag; struct beiscsi_hba *phba = beiscsi_ep->phba; - if (MGMT_STATUS_SUCCESS != - mgmt_upload_connection(phba, beiscsi_ep->ep_cid, - CONNECTION_UPLOAD_GRACEFUL)) { + tag = mgmt_upload_connection(phba, beiscsi_ep->ep_cid, flag); + if (!tag) { SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x", beiscsi_ep->ep_cid); ret = -1; + } else { + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + free_mcc_tag(&phba->ctrl, tag); } - return ret; } @@ -574,19 +642,17 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) struct beiscsi_conn *beiscsi_conn; struct beiscsi_endpoint *beiscsi_ep; struct beiscsi_hba *phba; - int flag = 0; beiscsi_ep = ep->dd_data; phba = beiscsi_ep->phba; - SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect\n"); + SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n", + beiscsi_ep->ep_cid); if (beiscsi_ep->conn) { beiscsi_conn = beiscsi_ep->conn; iscsi_suspend_queue(beiscsi_conn->conn); - beiscsi_close_conn(ep, flag); } - beiscsi_free_ep(ep); } /** @@ -619,23 +685,31 @@ void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) struct iscsi_session *session = conn->session; struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session); struct beiscsi_hba *phba = iscsi_host_priv(shost); - unsigned int status; + unsigned int tag; unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; - SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop\n"); beiscsi_ep = beiscsi_conn->ep; if (!beiscsi_ep) { SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n"); return; } - status = mgmt_invalidate_connection(phba, beiscsi_ep, + SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop ep_cid = %d\n", + beiscsi_ep->ep_cid); + tag = mgmt_invalidate_connection(phba, beiscsi_ep, beiscsi_ep->ep_cid, 1, savecfg_flag); - if (status != MGMT_STATUS_SUCCESS) { + if (!tag) { SE_DEBUG(DBG_LVL_1, "mgmt_invalidate_connection Failed for cid=%d \n", beiscsi_ep->ep_cid); + } else { + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + free_mcc_tag(&phba->ctrl, tag); } + beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL); + beiscsi_free_ep(beiscsi_ep); + iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); iscsi_conn_stop(cls_conn, flag); } diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h index f92ffc5..1f512c2 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.h +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 1a557fa..7c22616 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -40,7 +40,6 @@ static unsigned int be_iopoll_budget = 10; static unsigned int be_max_phys_size = 64; static unsigned int enable_msix = 1; -static unsigned int ring_mode; MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR); @@ -62,10 +61,10 @@ static int beiscsi_slave_configure(struct scsi_device *sdev) /*------------------- PCI Driver operations and data ----------------- */ static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = { { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, + { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) }, { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) }, { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) }, { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID3) }, - { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID4) }, { 0 } }; MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); @@ -112,6 +111,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) memset(phba, 0, sizeof(*phba)); phba->shost = shost; phba->pcidev = pci_dev_get(pcidev); + pci_set_drvdata(pcidev, phba); if (iscsi_host_add(shost, &phba->pcidev->dev)) goto free_devices; @@ -143,6 +143,7 @@ static int beiscsi_map_pci_bars(struct beiscsi_hba *phba, struct pci_dev *pcidev) { u8 __iomem *addr; + int pcicfg_reg; addr = ioremap_nocache(pci_resource_start(pcidev, 2), pci_resource_len(pcidev, 2)); @@ -159,13 +160,19 @@ static int beiscsi_map_pci_bars(struct beiscsi_hba *phba, phba->db_va = addr; phba->db_pa.u.a64.address = pci_resource_start(pcidev, 4); - addr = ioremap_nocache(pci_resource_start(pcidev, 1), - pci_resource_len(pcidev, 1)); + if (phba->generation == BE_GEN2) + pcicfg_reg = 1; + else + pcicfg_reg = 0; + + addr = ioremap_nocache(pci_resource_start(pcidev, pcicfg_reg), + pci_resource_len(pcidev, pcicfg_reg)); + if (addr == NULL) goto pci_map_err; phba->ctrl.pcicfg = addr; phba->pci_va = addr; - phba->pci_pa.u.a64.address = pci_resource_start(pcidev, 1); + phba->pci_pa.u.a64.address = pci_resource_start(pcidev, pcicfg_reg); return 0; pci_map_err: @@ -230,29 +237,27 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev) static void beiscsi_get_params(struct beiscsi_hba *phba) { - phba->params.ios_per_ctrl = BE2_IO_DEPTH; - phba->params.cxns_per_ctrl = BE2_MAX_SESSIONS; - phba->params.asyncpdus_per_ctrl = BE2_ASYNCPDUS; - phba->params.icds_per_ctrl = BE2_MAX_ICDS / 2; + phba->params.ios_per_ctrl = (phba->fw_config.iscsi_icd_count + - (phba->fw_config.iscsi_cid_count + + BE2_TMFS + + BE2_NOPOUT_REQ)); + phba->params.cxns_per_ctrl = phba->fw_config.iscsi_cid_count; + phba->params.asyncpdus_per_ctrl = phba->fw_config.iscsi_cid_count;; + phba->params.icds_per_ctrl = phba->fw_config.iscsi_icd_count;; phba->params.num_sge_per_io = BE2_SGE; phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ; phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ; phba->params.eq_timer = 64; phba->params.num_eq_entries = - (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) / - 512) + 1) * 512; + (((BE2_CMDS_PER_CXN * 2 + phba->fw_config.iscsi_cid_count * 2 + + BE2_TMFS) / 512) + 1) * 512; phba->params.num_eq_entries = (phba->params.num_eq_entries < 1024) ? 1024 : phba->params.num_eq_entries; SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d \n", - phba->params.num_eq_entries); + phba->params.num_eq_entries); phba->params.num_cq_entries = - (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) / - 512) + 1) * 512; - SE_DEBUG(DBG_LVL_8, - "phba->params.num_cq_entries=%d BE2_CMDS_PER_CXN=%d" - "BE2_LOGOUTS=%d BE2_TMFS=%d BE2_ASYNCPDUS=%d \n", - phba->params.num_cq_entries, BE2_CMDS_PER_CXN, - BE2_LOGOUTS, BE2_TMFS, BE2_ASYNCPDUS); + (((BE2_CMDS_PER_CXN * 2 + phba->fw_config.iscsi_cid_count * 2 + + BE2_TMFS) / 512) + 1) * 512; phba->params.wrbs_per_cxn = 256; } @@ -443,7 +448,7 @@ static irqreturn_t be_isr(int irq, void *dev_id) if (phba->todo_mcc_cq) queue_work(phba->wq, &phba->work_cqs); - if ((num_mcceq_processed) && (!num_ioeq_processed)) + if ((num_mcceq_processed) && (!num_ioeq_processed)) hwi_ring_eq_db(phba, eq->id, 0, (num_ioeq_processed + num_mcceq_processed) , 1, 1); @@ -561,6 +566,7 @@ beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn, SE_DEBUG(DBG_LVL_1, "In ISCSI_OP_REJECT\n"); break; case ISCSI_OP_LOGIN_RSP: + case ISCSI_OP_TEXT_RSP: task = conn->login_task; io_task = task->dd_data; login_hdr = (struct iscsi_hdr *)ppdu; @@ -631,29 +637,29 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) * alloc_wrb_handle - To allocate a wrb handle * @phba: The hba pointer * @cid: The cid to use for allocation - * @index: index allocation and wrb index * * This happens under session_lock until submission to chip */ -struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, - int index) +struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid) { struct hwi_wrb_context *pwrb_context; struct hwi_controller *phwi_ctrlr; - struct wrb_handle *pwrb_handle; + struct wrb_handle *pwrb_handle, *pwrb_handle_tmp; phwi_ctrlr = phba->phwi_ctrlr; pwrb_context = &phwi_ctrlr->wrb_context[cid]; - if (pwrb_context->wrb_handles_available) { + if (pwrb_context->wrb_handles_available >= 2) { pwrb_handle = pwrb_context->pwrb_handle_base[ pwrb_context->alloc_index]; pwrb_context->wrb_handles_available--; - pwrb_handle->nxt_wrb_index = pwrb_handle->wrb_index; if (pwrb_context->alloc_index == (phba->params.wrbs_per_cxn - 1)) pwrb_context->alloc_index = 0; else pwrb_context->alloc_index++; + pwrb_handle_tmp = pwrb_context->pwrb_handle_base[ + pwrb_context->alloc_index]; + pwrb_handle->nxt_wrb_index = pwrb_handle_tmp->wrb_index; } else pwrb_handle = NULL; return pwrb_handle; @@ -671,9 +677,7 @@ static void free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context, struct wrb_handle *pwrb_handle) { - if (!ring_mode) - pwrb_context->pwrb_handle_base[pwrb_context->free_index] = - pwrb_handle; + pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle; pwrb_context->wrb_handles_available++; if (pwrb_context->free_index == (phba->params.wrbs_per_cxn - 1)) pwrb_context->free_index = 0; @@ -790,6 +794,7 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn, memcpy(task->sc->sense_buffer, sense, min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE)); } + if (io_task->cmd_bhs->iscsi_hdr.flags & ISCSI_FLAG_CMD_READ) { if (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32] & SOL_RES_CNT_MASK) @@ -811,6 +816,7 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn, struct iscsi_conn *conn = beiscsi_conn->conn; hdr = (struct iscsi_logout_rsp *)task->hdr; + hdr->opcode = ISCSI_OP_LOGOUT_RSP; hdr->t2wait = 5; hdr->t2retain = 0; hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] @@ -825,6 +831,9 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn, & SOL_EXP_CMD_SN_MASK) + ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd) / 32] & SOL_CMD_WND_MASK) >> 24) - 1); + hdr->dlength[0] = 0; + hdr->dlength[1] = 0; + hdr->dlength[2] = 0; hdr->hlength = 0; hdr->itt = io_task->libiscsi_itt; __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); @@ -839,6 +848,7 @@ be_complete_tmf(struct beiscsi_conn *beiscsi_conn, struct beiscsi_io_task *io_task = task->dd_data; hdr = (struct iscsi_tm_rsp *)task->hdr; + hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP; hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] & SOL_FLAGS_MASK) >> 24) | 0x80; hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) / @@ -859,7 +869,6 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, { struct hwi_wrb_context *pwrb_context; struct wrb_handle *pwrb_handle = NULL; - struct sgl_handle *psgl_handle = NULL; struct hwi_controller *phwi_ctrlr; struct iscsi_task *task; struct beiscsi_io_task *io_task; @@ -867,22 +876,14 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, struct iscsi_session *session = conn->session; phwi_ctrlr = phba->phwi_ctrlr; - if (ring_mode) { - psgl_handle = phba->sgl_hndl_array[((psol-> - dw[offsetof(struct amap_sol_cqe_ring, icd_index) / - 32] & SOL_ICD_INDEX_MASK) >> 6)]; - pwrb_context = &phwi_ctrlr->wrb_context[psgl_handle->cid]; - task = psgl_handle->task; - pwrb_handle = NULL; - } else { - pwrb_context = &phwi_ctrlr->wrb_context[((psol-> + pwrb_context = &phwi_ctrlr->wrb_context[((psol-> dw[offsetof(struct amap_sol_cqe, cid) / 32] & - SOL_CID_MASK) >> 6)]; - pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> + SOL_CID_MASK) >> 6) - + phba->fw_config.iscsi_cid_start]; + pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> dw[offsetof(struct amap_sol_cqe, wrb_index) / 32] & SOL_WRB_INDEX_MASK) >> 16)]; - task = pwrb_handle->pio_handle; - } + task = pwrb_handle->pio_handle; io_task = task->dd_data; spin_lock(&phba->mgmt_sgl_lock); @@ -923,31 +924,23 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, struct iscsi_wrb *pwrb = NULL; struct hwi_controller *phwi_ctrlr; struct iscsi_task *task; - struct sgl_handle *psgl_handle = NULL; unsigned int type; struct iscsi_conn *conn = beiscsi_conn->conn; struct iscsi_session *session = conn->session; phwi_ctrlr = phba->phwi_ctrlr; - if (ring_mode) { - psgl_handle = phba->sgl_hndl_array[((psol-> - dw[offsetof(struct amap_sol_cqe_ring, icd_index) / - 32] & SOL_ICD_INDEX_MASK) >> 6)]; - task = psgl_handle->task; - type = psgl_handle->type; - } else { - pwrb_context = &phwi_ctrlr-> - wrb_context[((psol->dw[offsetof + pwrb_context = &phwi_ctrlr->wrb_context[((psol->dw[offsetof (struct amap_sol_cqe, cid) / 32] - & SOL_CID_MASK) >> 6)]; - pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> + & SOL_CID_MASK) >> 6) - + phba->fw_config.iscsi_cid_start]; + pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> dw[offsetof(struct amap_sol_cqe, wrb_index) / 32] & SOL_WRB_INDEX_MASK) >> 16)]; - task = pwrb_handle->pio_handle; - pwrb = pwrb_handle->pwrb; - type = (pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] & - WRB_TYPE_MASK) >> 28; - } + task = pwrb_handle->pio_handle; + pwrb = pwrb_handle->pwrb; + type = (pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] & + WRB_TYPE_MASK) >> 28; + spin_lock_bh(&session->lock); switch (type) { case HWH_TYPE_IO: @@ -978,15 +971,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, break; default: - if (ring_mode) - shost_printk(KERN_WARNING, phba->shost, - "In hwi_complete_cmd, unknown type = %d" - "icd_index 0x%x CID 0x%x\n", type, - ((psol->dw[offsetof(struct amap_sol_cqe_ring, - icd_index) / 32] & SOL_ICD_INDEX_MASK) >> 6), - psgl_handle->cid); - else - shost_printk(KERN_WARNING, phba->shost, + shost_printk(KERN_WARNING, phba->shost, "In hwi_complete_cmd, unknown type = %d" "wrb_index 0x%x CID 0x%x\n", type, ((psol->dw[offsetof(struct amap_iscsi_wrb, @@ -1077,7 +1062,8 @@ hwi_get_async_handle(struct beiscsi_hba *phba, WARN_ON(!pasync_handle); - pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid; + pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start; pasync_handle->is_header = is_header; pasync_handle->buffer_len = ((pdpdu_cqe-> dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32] @@ -1327,9 +1313,10 @@ hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn, } status = beiscsi_process_async_pdu(beiscsi_conn, phba, - beiscsi_conn->beiscsi_conn_cid, - phdr, hdr_len, pfirst_buffer, - buf_len); + (beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start), + phdr, hdr_len, pfirst_buffer, + buf_len); if (status == 0) hwi_free_async_msg(phba, cri); @@ -1422,6 +1409,48 @@ static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn, hwi_post_async_buffers(phba, pasync_handle->is_header); } +static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba) +{ + struct be_queue_info *mcc_cq; + struct be_mcc_compl *mcc_compl; + unsigned int num_processed = 0; + + mcc_cq = &phba->ctrl.mcc_obj.cq; + mcc_compl = queue_tail_node(mcc_cq); + mcc_compl->flags = le32_to_cpu(mcc_compl->flags); + while (mcc_compl->flags & CQE_FLAGS_VALID_MASK) { + + if (num_processed >= 32) { + hwi_ring_cq_db(phba, mcc_cq->id, + num_processed, 0, 0); + num_processed = 0; + } + if (mcc_compl->flags & CQE_FLAGS_ASYNC_MASK) { + /* Interpret flags as an async trailer */ + if (is_link_state_evt(mcc_compl->flags)) + /* Interpret compl as a async link evt */ + beiscsi_async_link_state_process(phba, + (struct be_async_event_link_state *) mcc_compl); + else + SE_DEBUG(DBG_LVL_1, + " Unsupported Async Event, flags" + " = 0x%08x \n", mcc_compl->flags); + } else if (mcc_compl->flags & CQE_FLAGS_COMPLETED_MASK) { + be_mcc_compl_process_isr(&phba->ctrl, mcc_compl); + atomic_dec(&phba->ctrl.mcc_obj.q.used); + } + + mcc_compl->flags = 0; + queue_tail_inc(mcc_cq); + mcc_compl = queue_tail_node(mcc_cq); + mcc_compl->flags = le32_to_cpu(mcc_compl->flags); + num_processed++; + } + + if (num_processed > 0) + hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 1, 0); + +} static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) { @@ -1431,7 +1460,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) unsigned int num_processed = 0; unsigned int tot_nump = 0; struct beiscsi_conn *beiscsi_conn; - struct sgl_handle *psgl_handle = NULL; + struct beiscsi_endpoint *beiscsi_ep; + struct iscsi_endpoint *ep; struct beiscsi_hba *phba; cq = pbe_eq->cq; @@ -1442,32 +1472,13 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) CQE_VALID_MASK) { be_dws_le_to_cpu(sol, sizeof(struct sol_cqe)); - if (ring_mode) { - psgl_handle = phba->sgl_hndl_array[((sol-> - dw[offsetof(struct amap_sol_cqe_ring, - icd_index) / 32] & SOL_ICD_INDEX_MASK) - >> 6)]; - beiscsi_conn = phba->conn_table[psgl_handle->cid]; - if (!beiscsi_conn || !beiscsi_conn->ep) { - shost_printk(KERN_WARNING, phba->shost, - "Connection table empty for cid = %d\n", - psgl_handle->cid); - return 0; - } + ep = phba->ep_array[(u32) ((sol-> + dw[offsetof(struct amap_sol_cqe, cid) / 32] & + SOL_CID_MASK) >> 6) - + phba->fw_config.iscsi_cid_start]; - } else { - beiscsi_conn = phba->conn_table[(u32) (sol-> - dw[offsetof(struct amap_sol_cqe, cid) / 32] & - SOL_CID_MASK) >> 6]; - - if (!beiscsi_conn || !beiscsi_conn->ep) { - shost_printk(KERN_WARNING, phba->shost, - "Connection table empty for cid = %d\n", - (u32)(sol->dw[offsetof(struct amap_sol_cqe, - cid) / 32] & SOL_CID_MASK) >> 6); - return 0; - } - } + beiscsi_ep = ep->dd_data; + beiscsi_conn = beiscsi_ep->conn; if (num_processed >= 32) { hwi_ring_cq_db(phba, cq->id, @@ -1511,21 +1522,13 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) case CMD_CXN_KILLED_ITT_INVALID: case CMD_CXN_KILLED_SEQ_OUTOFORDER: case CMD_CXN_KILLED_INVALID_DATASN_RCVD: - if (ring_mode) { - SE_DEBUG(DBG_LVL_1, - "CQ Error notification for cmd.. " - "code %d cid 0x%x\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, psgl_handle->cid); - } else { - SE_DEBUG(DBG_LVL_1, + SE_DEBUG(DBG_LVL_1, "CQ Error notification for cmd.. " "code %d cid 0x%x\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, (sol->dw[offsetof(struct amap_sol_cqe, cid) / 32] & SOL_CID_MASK)); - } break; case UNSOL_DATA_DIGEST_ERROR_NOTIFY: SE_DEBUG(DBG_LVL_1, @@ -1547,37 +1550,23 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) case CXN_KILLED_OVER_RUN_RESIDUAL: case CXN_KILLED_UNDER_RUN_RESIDUAL: case CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN: - if (ring_mode) { - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID " - "0x%x...\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, psgl_handle->cid); - } else { - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID " + SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID " "0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, - sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & CQE_CID_MASK); - } + (sol->dw[offsetof(struct amap_sol_cqe, cid) / + 32] & CQE_CID_MASK)); iscsi_conn_failure(beiscsi_conn->conn, ISCSI_ERR_CONN_FAILED); break; case CXN_KILLED_RST_SENT: case CXN_KILLED_RST_RCVD: - if (ring_mode) { - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset" - "received/sent on CID 0x%x...\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, psgl_handle->cid); - } else { - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset" + SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset" "received/sent on CID 0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, - sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & CQE_CID_MASK); - } + (sol->dw[offsetof(struct amap_sol_cqe, cid) / + 32] & CQE_CID_MASK)); iscsi_conn_failure(beiscsi_conn->conn, ISCSI_ERR_CONN_FAILED); break; @@ -1586,8 +1575,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) "received on CID 0x%x...\n", sol->dw[offsetof(struct amap_sol_cqe, code) / 32] & CQE_CODE_MASK, - sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & CQE_CID_MASK); + (sol->dw[offsetof(struct amap_sol_cqe, cid) / + 32] & CQE_CID_MASK)); break; } @@ -1604,7 +1593,7 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) return tot_nump; } -static void beiscsi_process_all_cqs(struct work_struct *work) +void beiscsi_process_all_cqs(struct work_struct *work) { unsigned long flags; struct hwi_controller *phwi_ctrlr; @@ -1624,6 +1613,7 @@ static void beiscsi_process_all_cqs(struct work_struct *work) spin_lock_irqsave(&phba->isr_lock, flags); phba->todo_mcc_cq = 0; spin_unlock_irqrestore(&phba->isr_lock, flags); + beiscsi_process_mcc_isr(phba); } if (phba->todo_cq) { @@ -1668,7 +1658,8 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, io_task->bhs_pa.u.a32.address_hi); l_sg = sg; - for (index = 0; (index < num_sg) && (index < 2); index++, sg_next(sg)) { + for (index = 0; (index < num_sg) && (index < 2); index++, + sg = sg_next(sg)) { if (index == 0) { sg_len = sg_dma_len(sg); addr = (u64) sg_dma_address(sg); @@ -1679,11 +1670,7 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb, sg_len); sge_len = sg_len; - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, - 1); } else { - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, - 0); AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_r2t_offset, pwrb, sge_len); sg_len = sg_dma_len(sg); @@ -1706,13 +1693,27 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, io_task->bhs_pa.u.a32.address_lo); - if (num_sg == 2) - AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, 1); + if (num_sg == 1) { + AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, + 1); + AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, + 0); + } else if (num_sg == 2) { + AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, + 0); + AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, + 1); + } else { + AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, + 0); + AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, + 0); + } sg = l_sg; psgl++; psgl++; offset = 0; - for (index = 0; index < num_sg; index++, sg_next(sg), psgl++) { + for (index = 0; index < num_sg; index++, sg = sg_next(sg), psgl++) { sg_len = sg_dma_len(sg); addr = (u64) sg_dma_address(sg); AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, @@ -2048,10 +2049,9 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba) } idx = 0; pwrb = mem_descr_wrb->mem_array[idx].virtual_address; - num_cxn_wrb = - ((mem_descr_wrb->mem_array[idx].size) / (sizeof(struct iscsi_wrb)) * - phba->params.wrbs_per_cxn); - + num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) / + ((sizeof(struct iscsi_wrb) * + phba->params.wrbs_per_cxn)); for (index = 0; index < phba->params.cxns_per_ctrl; index += 2) { pwrb_context = &phwi_ctrlr->wrb_context[index]; if (num_cxn_wrb) { @@ -2064,9 +2064,9 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba) } else { idx++; pwrb = mem_descr_wrb->mem_array[idx].virtual_address; - num_cxn_wrb = ((mem_descr_wrb->mem_array[idx].size) / - (sizeof(struct iscsi_wrb)) * - phba->params.wrbs_per_cxn); + num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) / + ((sizeof(struct iscsi_wrb) * + phba->params.wrbs_per_cxn)); for (j = 0; j < phba->params.wrbs_per_cxn; j++) { pwrb_handle = pwrb_context->pwrb_handle_base[j]; pwrb_handle->pwrb = pwrb; @@ -2383,7 +2383,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba, &paddr); if (!cq_vaddress) goto create_cq_error; - ret = be_fill_queue(cq, phba->params.icds_per_ctrl / 2, + ret = be_fill_queue(cq, phba->params.num_cq_entries, sizeof(struct sol_cqe), cq_vaddress); if (ret) { shost_printk(KERN_ERR, phba->shost, @@ -2634,7 +2634,8 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba, "wrbq create failed."); return status; } - phwi_ctrlr->wrb_context[i].cid = phwi_context->be_wrbq[i].id; + phwi_ctrlr->wrb_context[i * 2].cid = phwi_context->be_wrbq[i]. + id; } kfree(pwrb_arr); return 0; @@ -2803,17 +2804,6 @@ static int hwi_init_port(struct beiscsi_hba *phba) goto error; } - if (phba->fw_config.iscsi_features == 0x1) - ring_mode = 1; - else - ring_mode = 0; - status = mgmt_get_fw_config(ctrl, phba); - if (status != 0) { - shost_printk(KERN_ERR, phba->shost, - "Error getting fw config\n"); - goto error; - } - status = beiscsi_create_cqs(phba, phwi_context); if (status != 0) { shost_printk(KERN_ERR, phba->shost, "CQ not created\n"); @@ -2941,17 +2931,6 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) phba->io_sgl_hndl_avbl = 0; phba->eh_sgl_hndl_avbl = 0; - if (ring_mode) { - phba->sgl_hndl_array = kzalloc(sizeof(struct sgl_handle *) * - phba->params.icds_per_ctrl, - GFP_KERNEL); - if (!phba->sgl_hndl_array) { - shost_printk(KERN_ERR, phba->shost, - "Mem Alloc Failed. Failing to load\n"); - return -ENOMEM; - } - } - mem_descr_sglh = phba->init_mem; mem_descr_sglh += HWI_MEM_SGLH; if (1 == mem_descr_sglh->num_elements) { @@ -2959,8 +2938,6 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) phba->params.ios_per_ctrl, GFP_KERNEL); if (!phba->io_sgl_hndl_base) { - if (ring_mode) - kfree(phba->sgl_hndl_array); shost_printk(KERN_ERR, phba->shost, "Mem Alloc Failed. Failing to load\n"); return -ENOMEM; @@ -3032,7 +3009,7 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, pfrag, 0); pfrag += phba->params.num_sge_per_io; psgl_handle->sgl_index = - phba->fw_config.iscsi_cid_start + arr_index++; + phba->fw_config.iscsi_icd_start + arr_index++; } idx++; } @@ -3047,7 +3024,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) { int i, new_cid; - phba->cid_array = kmalloc(sizeof(void *) * phba->params.cxns_per_ctrl, + phba->cid_array = kzalloc(sizeof(void *) * phba->params.cxns_per_ctrl, GFP_KERNEL); if (!phba->cid_array) { shost_printk(KERN_ERR, phba->shost, @@ -3055,7 +3032,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) "hba_setup_cid_tbls\n"); return -ENOMEM; } - phba->ep_array = kmalloc(sizeof(struct iscsi_endpoint *) * + phba->ep_array = kzalloc(sizeof(struct iscsi_endpoint *) * phba->params.cxns_per_ctrl * 2, GFP_KERNEL); if (!phba->ep_array) { shost_printk(KERN_ERR, phba->shost, @@ -3064,7 +3041,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) kfree(phba->cid_array); return -ENOMEM; } - new_cid = phba->fw_config.iscsi_icd_start; + new_cid = phba->fw_config.iscsi_cid_start; for (i = 0; i < phba->params.cxns_per_ctrl; i++) { phba->cid_array[i] = new_cid; new_cid += 2; @@ -3145,8 +3122,6 @@ static int beiscsi_init_port(struct beiscsi_hba *phba) if (hba_setup_cid_tbls(phba)) { shost_printk(KERN_ERR, phba->shost, "Failed in hba_setup_cid_tbls\n"); - if (ring_mode) - kfree(phba->sgl_hndl_array); kfree(phba->io_sgl_hndl_base); kfree(phba->eh_sgl_hndl_base); goto do_cleanup_ctrlr; @@ -3166,6 +3141,7 @@ static void hwi_purge_eq(struct beiscsi_hba *phba) struct be_queue_info *eq; struct be_eq_entry *eqe = NULL; int i, eq_msix; + unsigned int num_processed; phwi_ctrlr = phba->phwi_ctrlr; phwi_context = phwi_ctrlr->phwi_ctxt; @@ -3177,13 +3153,17 @@ static void hwi_purge_eq(struct beiscsi_hba *phba) for (i = 0; i < (phba->num_cpus + eq_msix); i++) { eq = &phwi_context->be_eq[i].q; eqe = queue_tail_node(eq); - + num_processed = 0; while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] & EQE_VALID_MASK) { AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); queue_tail_inc(eq); eqe = queue_tail_node(eq); + num_processed++; } + + if (num_processed) + hwi_ring_eq_db(phba, eq->id, 1, num_processed, 1, 1); } } @@ -3195,10 +3175,9 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba) if (mgmt_status) shost_printk(KERN_WARNING, phba->shost, "mgmt_epfw_cleanup FAILED \n"); - hwi_cleanup(phba); + hwi_purge_eq(phba); - if (ring_mode) - kfree(phba->sgl_hndl_array); + hwi_cleanup(phba); kfree(phba->io_sgl_hndl_base); kfree(phba->eh_sgl_hndl_base); kfree(phba->cid_array); @@ -3219,7 +3198,8 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, * We can always use 0 here because it is reserved by libiscsi for * login/startup related tasks. */ - pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid, 0); + pwrb_handle = alloc_wrb_handle(phba, (beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start)); pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb; memset(pwrb, 0, sizeof(*pwrb)); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, @@ -3283,8 +3263,7 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_target_context_update_wrb)); doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; - if (!ring_mode) - doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) + doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; @@ -3328,8 +3307,9 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) io_task->bhs_pa.u.a64.address = paddr; io_task->libiscsi_itt = (itt_t)task->itt; io_task->pwrb_handle = alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid, - task->itt); + beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start + ); io_task->conn = beiscsi_conn; task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr; @@ -3343,7 +3323,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) goto free_hndls; } else { io_task->scsi_cmnd = NULL; - if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) { + if ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) { if (!beiscsi_conn->login_in_progress) { spin_lock(&phba->mgmt_sgl_lock); io_task->psgl_handle = (struct sgl_handle *) @@ -3370,21 +3350,16 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) itt = (itt_t) cpu_to_be32(((unsigned int)io_task->pwrb_handle-> wrb_index << 16) | (unsigned int) (io_task->psgl_handle->sgl_index)); - if (ring_mode) { - phba->sgl_hndl_array[io_task->psgl_handle->sgl_index - - phba->fw_config.iscsi_cid_start] = - io_task->psgl_handle; - io_task->psgl_handle->task = task; - io_task->psgl_handle->cid = beiscsi_conn->beiscsi_conn_cid; - } else - io_task->pwrb_handle->pio_handle = task; + io_task->pwrb_handle->pio_handle = task; io_task->cmd_bhs->iscsi_hdr.itt = itt; return 0; free_hndls: phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid]; + pwrb_context = &phwi_ctrlr->wrb_context[ + beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start]; free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); io_task->pwrb_handle = NULL; pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, @@ -3404,7 +3379,8 @@ static void beiscsi_cleanup_task(struct iscsi_task *task) struct hwi_controller *phwi_ctrlr; phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid]; + pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid + - phba->fw_config.iscsi_cid_start]; if (io_task->pwrb_handle) { free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); io_task->pwrb_handle = NULL; @@ -3460,18 +3436,12 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, ISCSI_OPCODE_SCSI_DATA_OUT); AMAP_SET_BITS(struct amap_pdu_data_out, final_bit, &io_task->cmd_bhs->iscsi_data_pdu, 1); - if (ring_mode) - io_task->psgl_handle->type = INI_WR_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_WR_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_WR_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); } else { - if (ring_mode) - io_task->psgl_handle->type = INI_RD_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_RD_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_RD_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0); } memcpy(&io_task->cmd_bhs->iscsi_data_pdu. @@ -3496,8 +3466,7 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; - if (!ring_mode) - doorbell |= (io_task->pwrb_handle->wrb_index & + doorbell |= (io_task->pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; @@ -3519,49 +3488,46 @@ static int beiscsi_mtask(struct iscsi_task *task) unsigned int doorbell = 0; unsigned int i, cid; struct iscsi_task *aborted_task; + unsigned int tag; cid = beiscsi_conn->beiscsi_conn_cid; pwrb = io_task->pwrb_handle->pwrb; + memset(pwrb, 0, sizeof(*pwrb)); AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, be32_to_cpu(task->cmdsn)); AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb, io_task->pwrb_handle->wrb_index); AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb, io_task->psgl_handle->sgl_index); - switch (task->hdr->opcode & ISCSI_OPCODE_MASK) { case ISCSI_OP_LOGIN: - if (ring_mode) - io_task->psgl_handle->type = TGT_DM_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - TGT_DM_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + TGT_DM_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1); hwi_write_buffer(pwrb, task); break; case ISCSI_OP_NOOP_OUT: - if (ring_mode) - io_task->psgl_handle->type = INI_RD_CMD; + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_RD_CMD); + if (task->hdr->ttt == ISCSI_RESERVED_TAG) + AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_RD_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 1); hwi_write_buffer(pwrb, task); break; case ISCSI_OP_TEXT: - if (ring_mode) - io_task->psgl_handle->type = INI_WR_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_WR_CMD); - AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + TGT_DM_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); hwi_write_buffer(pwrb, task); break; case ISCSI_OP_SCSI_TMFUNC: session = conn->session; i = ((struct iscsi_tm *)task->hdr)->rtt; phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[cid]; + pwrb_context = &phwi_ctrlr->wrb_context[cid - + phba->fw_config.iscsi_cid_start]; pwrb_handle = pwrb_context->pwrb_handle_basestd[be32_to_cpu(i) >> 16]; aborted_task = pwrb_handle->pio_handle; @@ -3572,22 +3538,25 @@ static int beiscsi_mtask(struct iscsi_task *task) if (!aborted_io_task->scsi_cmnd) return 0; - mgmt_invalidate_icds(phba, + tag = mgmt_invalidate_icds(phba, aborted_io_task->psgl_handle->sgl_index, cid); - if (ring_mode) - io_task->psgl_handle->type = INI_TMF_CMD; - else - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_TMF_CMD); + if (!tag) { + shost_printk(KERN_WARNING, phba->shost, + "mgmt_invalidate_icds could not be" + " submitted\n"); + } else { + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + free_mcc_tag(&phba->ctrl, tag); + } + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_TMF_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); hwi_write_buffer(pwrb, task); break; case ISCSI_OP_LOGOUT: AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); - if (ring_mode) - io_task->psgl_handle->type = HWH_TYPE_LOGOUT; - else AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, HWH_TYPE_LOGOUT); hwi_write_buffer(pwrb, task); @@ -3600,14 +3569,13 @@ static int beiscsi_mtask(struct iscsi_task *task) } AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, - be32_to_cpu(task->data_count)); + task->data_count); AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, io_task->pwrb_handle->nxt_wrb_index); be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); doorbell |= cid & DB_WRB_POST_CID_MASK; - if (!ring_mode) - doorbell |= (io_task->pwrb_handle->wrb_index & + doorbell |= (io_task->pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET); @@ -3649,7 +3617,6 @@ static int beiscsi_task_xmit(struct iscsi_task *task) return beiscsi_iotask(task, sg, num_sg, xferlen, writedir); } - static void beiscsi_remove(struct pci_dev *pcidev) { struct beiscsi_hba *phba = NULL; @@ -3734,7 +3701,20 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, } SE_DEBUG(DBG_LVL_8, " phba = %p \n", phba); - pci_set_drvdata(pcidev, phba); + switch (pcidev->device) { + case BE_DEVICE_ID1: + case OC_DEVICE_ID1: + case OC_DEVICE_ID2: + phba->generation = BE_GEN2; + break; + case BE_DEVICE_ID2: + case OC_DEVICE_ID3: + phba->generation = BE_GEN3; + break; + default: + phba->generation = 0; + } + if (enable_msix) num_cpus = find_num_cpus(); else @@ -3754,7 +3734,15 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, spin_lock_init(&phba->io_sgl_lock); spin_lock_init(&phba->mgmt_sgl_lock); spin_lock_init(&phba->isr_lock); + ret = mgmt_get_fw_config(&phba->ctrl, phba); + if (ret != 0) { + shost_printk(KERN_ERR, phba->shost, + "Error getting fw config\n"); + goto free_port; + } + phba->shost->max_id = phba->fw_config.iscsi_cid_count; beiscsi_get_params(phba); + phba->shost->can_queue = phba->params.ios_per_ctrl; ret = beiscsi_init_port(phba); if (ret < 0) { shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" @@ -3762,6 +3750,15 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, goto free_port; } + for (i = 0; i < MAX_MCC_CMD ; i++) { + init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]); + phba->ctrl.mcc_tag[i] = i + 1; + phba->ctrl.mcc_numtag[i + 1] = 0; + phba->ctrl.mcc_tag_available++; + } + + phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0; + snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_q_irq%u", phba->shost->host_no); phba->wq = create_workqueue(phba->wq_name); @@ -3836,7 +3833,7 @@ disable_pci: struct iscsi_transport beiscsi_iscsi_transport = { .owner = THIS_MODULE, .name = DRV_NAME, - .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | + .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | CAP_TEXT_NEGO | CAP_MULTI_R2T | CAP_DATADGST | CAP_DATA_PATH_OFFLOAD, .param_mask = ISCSI_MAX_RECV_DLENGTH | ISCSI_MAX_XMIT_DLENGTH | @@ -3859,7 +3856,7 @@ struct iscsi_transport beiscsi_iscsi_transport = { ISCSI_USERNAME | ISCSI_PASSWORD | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | - ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO | + ISCSI_LU_RESET_TMO | ISCSI_PING_TMO | ISCSI_RECV_TMO | ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | @@ -3905,7 +3902,7 @@ static int __init beiscsi_module_init(void) SE_DEBUG(DBG_LVL_1, "beiscsi_module_init - Unable to register beiscsi" "transport.\n"); - ret = -ENOMEM; + return -ENOMEM; } SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p \n", &beiscsi_iscsi_transport); @@ -3917,7 +3914,6 @@ static int __init beiscsi_module_init(void) "beiscsi pci driver.\n"); goto unregister_iscsi_transport; } - ring_mode = 0; return 0; unregister_iscsi_transport: diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 25e6b20..c53a80a 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -40,31 +40,29 @@ #define DRV_DESC BE_NAME " " "Driver" #define BE_VENDOR_ID 0x19A2 +/* DEVICE ID's for BE2 */ #define BE_DEVICE_ID1 0x212 #define OC_DEVICE_ID1 0x702 #define OC_DEVICE_ID2 0x703 + +/* DEVICE ID's for BE3 */ +#define BE_DEVICE_ID2 0x222 #define OC_DEVICE_ID3 0x712 -#define OC_DEVICE_ID4 0x222 -#define BE2_MAX_SESSIONS 64 +#define BE2_IO_DEPTH 1024 +#define BE2_MAX_SESSIONS 256 #define BE2_CMDS_PER_CXN 128 -#define BE2_LOGOUTS BE2_MAX_SESSIONS #define BE2_TMFS 16 #define BE2_NOPOUT_REQ 16 -#define BE2_ASYNCPDUS BE2_MAX_SESSIONS -#define BE2_MAX_ICDS 2048 #define BE2_SGE 32 #define BE2_DEFPDU_HDR_SZ 64 #define BE2_DEFPDU_DATA_SZ 8192 -#define BE2_IO_DEPTH \ - (BE2_MAX_ICDS / 2 - (BE2_LOGOUTS + BE2_TMFS + BE2_NOPOUT_REQ)) #define MAX_CPUS 31 -#define BEISCSI_SGLIST_ELEMENTS BE2_SGE +#define BEISCSI_SGLIST_ELEMENTS 30 -#define BEISCSI_MAX_CMNDS 1024 /* Max IO's per Ctrlr sht->can_queue */ #define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */ -#define BEISCSI_MAX_SECTORS 2048 /* scsi_host->max_sectors */ +#define BEISCSI_MAX_SECTORS 256 /* 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 */ @@ -330,6 +328,7 @@ struct beiscsi_hba { struct workqueue_struct *wq; /* The actuak work queue */ struct work_struct work_cqs; /* The work being queued */ struct be_ctrl_info ctrl; + unsigned int generation; }; struct beiscsi_session { @@ -656,11 +655,12 @@ struct amap_iscsi_wrb { } __packed; -struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, - int index); +struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid); void free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle); +void beiscsi_process_all_cqs(struct work_struct *work); + struct pdu_nop_out { u32 dw[12]; }; @@ -802,7 +802,6 @@ struct hwi_controller { struct be_ring default_pdu_hdr; struct be_ring default_pdu_data; struct hwi_context_memory *phwi_ctxt; - unsigned short cq_errors[CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN]; }; enum hwh_type_enum { diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 79c2bd5..317bcd0 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -48,6 +48,14 @@ unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl, pfw_cfg->ulp[0].sq_base; phba->fw_config.iscsi_cid_count = pfw_cfg->ulp[0].sq_count; + if (phba->fw_config.iscsi_cid_count > (BE2_MAX_SESSIONS / 2)) { + SE_DEBUG(DBG_LVL_8, + "FW reported MAX CXNS as %d \t" + "Max Supported = %d.\n", + phba->fw_config.iscsi_cid_count, + BE2_MAX_SESSIONS); + phba->fw_config.iscsi_cid_count = BE2_MAX_SESSIONS / 2; + } } else { shost_printk(KERN_WARNING, phba->shost, "Failed in mgmt_get_fw_config \n"); @@ -77,6 +85,7 @@ unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl, } nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes); req = nonemb_cmd.va; + memset(req, 0, sizeof(*req)); spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); @@ -140,10 +149,17 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, { struct be_dma_mem nonemb_cmd; struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct be_sge *sge = nonembedded_sgl(wrb); + struct be_mcc_wrb *wrb; + struct be_sge *sge; struct invalidate_commands_params_in *req; - int status = 0; + unsigned int tag = 0; + + spin_lock(&ctrl->mbox_lock); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev, sizeof(struct invalidate_commands_params_in), @@ -156,8 +172,10 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, } nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); req = nonemb_cmd.va; - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + memset(req, 0, sizeof(*req)); + wrb = wrb_from_mccq(phba); + sge = nonembedded_sgl(wrb); + wrb->tag0 |= tag; be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, @@ -172,14 +190,12 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF); sge->len = cpu_to_le32(nonemb_cmd.size); - status = be_mcc_notify_wait(phba); - if (status) - SE_DEBUG(DBG_LVL_1, "ICDS Invalidation Failed\n"); + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); if (nonemb_cmd.va) pci_free_consistent(ctrl->pdev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); - return status; + return tag; } unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, @@ -189,13 +205,19 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, unsigned short savecfg_flag) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct iscsi_invalidate_connection_params_in *req = - embedded_payload(wrb); - int status = 0; + struct be_mcc_wrb *wrb; + struct iscsi_invalidate_connection_params_in *req; + unsigned int tag = 0; spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + wrb = wrb_from_mccq(phba); + wrb->tag0 |= tag; + req = embedded_payload(wrb); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, @@ -208,35 +230,37 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, else req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE; req->save_cfg = savecfg_flag; - status = be_mcc_notify_wait(phba); - if (status) - SE_DEBUG(DBG_LVL_1, "Invalidation Failed\n"); - + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return status; + return tag; } unsigned char mgmt_upload_connection(struct beiscsi_hba *phba, unsigned short cid, unsigned int upload_flag) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct tcp_upload_params_in *req = embedded_payload(wrb); - int status = 0; + struct be_mcc_wrb *wrb; + struct tcp_upload_params_in *req; + unsigned int tag = 0; spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + 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_COMMON_TCP_UPLOAD, OPCODE_COMMON_TCP_UPLOAD, sizeof(*req)); req->id = (unsigned short)cid; req->upload_type = (unsigned char)upload_flag; - status = be_mcc_notify_wait(phba); - if (status) - SE_DEBUG(DBG_LVL_1, "mgmt_upload_connection Failed\n"); + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return status; + return tag; } int mgmt_open_connection(struct beiscsi_hba *phba, @@ -248,13 +272,13 @@ int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr_in *daddr_in = (struct sockaddr_in *)dst_addr; struct sockaddr_in6 *daddr_in6 = (struct sockaddr_in6 *)dst_addr; struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct tcp_connect_and_offload_in *req = embedded_payload(wrb); + struct be_mcc_wrb *wrb; + struct tcp_connect_and_offload_in *req; unsigned short def_hdr_id; unsigned short def_data_id; struct phys_addr template_address = { 0, 0 }; struct phys_addr *ptemplate_address; - int status = 0; + unsigned int tag = 0; unsigned int i; unsigned short cid = beiscsi_ep->ep_cid; @@ -266,7 +290,14 @@ int mgmt_open_connection(struct beiscsi_hba *phba, ptemplate_address = &template_address; ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address); spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + 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, @@ -311,46 +342,36 @@ int mgmt_open_connection(struct beiscsi_hba *phba, req->do_offload = 1; req->dataout_template_pa.lo = ptemplate_address->lo; req->dataout_template_pa.hi = ptemplate_address->hi; - status = be_mcc_notify_wait(phba); - if (!status) { - struct iscsi_endpoint *ep; - struct tcp_connect_and_offload_out *ptcpcnct_out = - embedded_payload(wrb); - - ep = phba->ep_array[ptcpcnct_out->cid]; - beiscsi_ep = ep->dd_data; - beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle; - beiscsi_ep->cid_vld = 1; - SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); - } else - SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed\n"); + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return status; + return tag; } -int be_cmd_get_mac_addr(struct beiscsi_hba *phba, u8 *mac_addr) +unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct be_cmd_req_get_mac_addr *req = embedded_payload(wrb); - int status; + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_mac_addr *req; + unsigned int tag = 0; SE_DEBUG(DBG_LVL_8, "In be_cmd_get_mac_addr\n"); spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); + 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, OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, sizeof(*req)); - status = be_mcc_notify_wait(phba); - if (!status) { - struct be_cmd_resp_get_mac_addr *resp = embedded_payload(wrb); - - memcpy(mac_addr, resp->mac_address, ETH_ALEN); - } - + be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - return status; + return tag; } diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index 24eaff9..ecead6a 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2009 ServerEngines + * Copyright (C) 2005 - 2010 ServerEngines * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -231,6 +231,7 @@ struct beiscsi_endpoint { struct beiscsi_hba *phba; struct beiscsi_sess *sess; struct beiscsi_conn *conn; + struct iscsi_endpoint *openiscsi_ep; unsigned short ip_type; char dst6_addr[ISCSI_ADDRESS_BUF_LEN]; unsigned long dst_addr; @@ -249,7 +250,4 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, unsigned short issue_reset, unsigned short savecfg_flag); -unsigned char mgmt_fw_cmd(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba, - char *buf, unsigned int len); #endif |