* [PATCH 2/2 2.6.29-rc] cxgb3i - add handling of chip reset
@ 2009-02-25 1:28 Karen Xie
2009-02-25 17:21 ` Mike Christie
2009-02-25 17:29 ` Mike Christie
0 siblings, 2 replies; 5+ messages in thread
From: Karen Xie @ 2009-02-25 1:28 UTC (permalink / raw)
To: open-iscsi, linux-scsi; +Cc: michaelc, James.Bottomley, kxie
[PATCH 2/2 2.6.29-rc] cxgb3i - add support of chip reset
From: Karen Xie <kxie@chelsio.com>
The cxgb3 driver would reset the chip due to an EEH event or a fatal error
and notifies the upper layer modules (iscsi, rdma).
Upon receiving the notification the cxgb3i driver would
- close all the iscsi tcp connections and mark the associated sessions as
failed due to connection error,
- re-initialize its offload functions,
- re-initialize the chip's ddp functions.
The iscsi error recovery mechanism will re-establish the tcp connection after
reset.
This patch requires the the following cxgb3 patch in the linux-next git tree
(http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git;a=commitdiff;h=cb0bc205959bf8c60acae9c71f3da0597e756f8e).
Signed-off-by: Karen Xie <kxie@chelsio.com>
---
drivers/scsi/cxgb3i/cxgb3i.h | 10 +
drivers/scsi/cxgb3i/cxgb3i_ddp.c | 258 +++++++++++++++++-----------------
drivers/scsi/cxgb3i/cxgb3i_ddp.h | 5 -
drivers/scsi/cxgb3i/cxgb3i_init.c | 25 +++
drivers/scsi/cxgb3i/cxgb3i_iscsi.c | 145 +++++++++++++------
drivers/scsi/cxgb3i/cxgb3i_offload.c | 102 +++++++++----
drivers/scsi/cxgb3i/cxgb3i_offload.h | 10 +
drivers/scsi/cxgb3i/cxgb3i_pdu.c | 11 +
drivers/scsi/cxgb3i/cxgb3i_pdu.h | 2
9 files changed, 338 insertions(+), 230 deletions(-)
diff --git a/drivers/scsi/cxgb3i/cxgb3i.h b/drivers/scsi/cxgb3i/cxgb3i.h
index a7cf550..e13c98a 100644
--- a/drivers/scsi/cxgb3i/cxgb3i.h
+++ b/drivers/scsi/cxgb3i/cxgb3i.h
@@ -66,10 +66,12 @@ struct cxgb3i_hba {
* @pdev: pointer to pci dev
* @hba_cnt: # of hbas (the same as # of ports)
* @hba: all the hbas on this adapter
+ * @flag: bit flag for adapter event/status
* @tx_max_size: max. tx packet size supported
* @rx_max_size: max. rx packet size supported
* @tag_format: ddp tag format settings
*/
+#define CXGB3I_ADAPTER_FLAG_RESET 0x1
struct cxgb3i_adapter {
struct list_head list_head;
spinlock_t lock;
@@ -78,6 +80,7 @@ struct cxgb3i_adapter {
unsigned char hba_cnt;
struct cxgb3i_hba *hba[MAX_NPORTS];
+ unsigned int flags;
unsigned int tx_max_size;
unsigned int rx_max_size;
@@ -137,10 +140,9 @@ struct cxgb3i_task_data {
int cxgb3i_iscsi_init(void);
void cxgb3i_iscsi_cleanup(void);
-struct cxgb3i_adapter *cxgb3i_adapter_add(struct t3cdev *);
-void cxgb3i_adapter_remove(struct t3cdev *);
-int cxgb3i_adapter_ulp_init(struct cxgb3i_adapter *);
-void cxgb3i_adapter_ulp_cleanup(struct cxgb3i_adapter *);
+struct cxgb3i_adapter *cxgb3i_adapter_find_by_tdev(struct t3cdev *);
+void cxgb3i_adapter_open(struct t3cdev *);
+void cxgb3i_adapter_close(struct t3cdev *);
struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *);
struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *,
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c
index a83d36e..012956b 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.c
@@ -66,9 +66,6 @@ static unsigned char ddp_page_order[DDP_PGIDX_MAX] = {0, 1, 2, 4};
static unsigned char ddp_page_shift[DDP_PGIDX_MAX] = {12, 13, 14, 16};
static unsigned char page_idx = DDP_PGIDX_MAX;
-static LIST_HEAD(cxgb3i_ddp_list);
-static DEFINE_RWLOCK(cxgb3i_ddp_rwlock);
-
/*
* functions to program the pagepod in h/w
*/
@@ -113,22 +110,30 @@ static int set_ddp_map(struct cxgb3i_ddp_info *ddp, struct pagepod_hdr *hdr,
return 0;
}
-static int clear_ddp_map(struct cxgb3i_ddp_info *ddp, unsigned int idx,
- unsigned int npods)
+static int clear_ddp_map(struct cxgb3i_ddp_info *ddp, unsigned int tag,
+ unsigned int idx, unsigned int npods)
{
unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit;
int i;
+ int cnt = 0;
for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) {
struct sk_buff *skb = ddp->gl_skb[idx];
+ if (!skb) {
+ ddp_log_error("ddp tag 0x%x, 0x%x, %d/%u, skb NULL.\n",
+ tag, idx, i, npods);
+ continue;
+ }
+
+ cnt++;
ddp->gl_skb[idx] = NULL;
memset((skb->head + sizeof(struct ulp_mem_io)), 0, PPOD_SIZE);
ulp_mem_io_set_hdr(skb, pm_addr);
skb->priority = CPL_PRIORITY_CONTROL;
cxgb3_ofld_send(ddp->tdev, skb);
}
- return 0;
+ return cnt;
}
static inline int ddp_find_unused_entries(struct cxgb3i_ddp_info *ddp,
@@ -439,14 +444,15 @@ EXPORT_SYMBOL_GPL(cxgb3i_ddp_tag_reserve);
* @tag: ddp tag
* ddp cleanup for a given ddp tag and release all the resources held
*/
-void cxgb3i_ddp_tag_release(struct t3cdev *tdev, u32 tag)
+int cxgb3i_ddp_tag_release(struct t3cdev *tdev, u32 tag)
{
struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi;
u32 idx;
+ int err = -EINVAL;
if (!ddp) {
ddp_log_error("release ddp tag 0x%x, ddp NULL.\n", tag);
- return;
+ return err;
}
idx = (tag >> PPOD_IDX_SHIFT) & ddp->idx_mask;
@@ -457,17 +463,26 @@ void cxgb3i_ddp_tag_release(struct t3cdev *tdev, u32 tag)
if (!gl) {
ddp_log_error("release ddp 0x%x, idx 0x%x, gl NULL.\n",
tag, idx);
- return;
+ return err;
}
npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT;
+ if (!npods) {
+ ddp_log_error("release ddp 0x%x, 0x%x, gl elem %u.\n",
+ tag, idx, gl->nelem);
+ return err;
+ }
ddp_log_debug("ddp tag 0x%x, release idx 0x%x, npods %u.\n",
tag, idx, npods);
- clear_ddp_map(ddp, idx, npods);
+ if (clear_ddp_map(ddp, tag, idx, npods) == npods)
+ err = 0;
ddp_unmark_entries(ddp, idx, npods);
cxgb3i_ddp_release_gl(gl, ddp->pdev);
- } else
+ } else {
ddp_log_error("ddp tag 0x%x, idx 0x%x > max 0x%x.\n",
tag, idx, ddp->nppods);
+ return err;
+ }
+ return err;
}
EXPORT_SYMBOL_GPL(cxgb3i_ddp_tag_release);
@@ -565,7 +580,87 @@ int cxgb3i_setup_conn_digest(struct t3cdev *tdev, unsigned int tid,
}
EXPORT_SYMBOL_GPL(cxgb3i_setup_conn_digest);
-static int ddp_init(struct t3cdev *tdev)
+
+/**
+ * cxgb3i_adapter_ddp_info - initialize the adapter's ddp resource
+ * @tdev: t3cdev adapter
+ * @tformat: tag format
+ * @txsz: max tx pdu payload size, filled in by this func.
+ * @rxsz: max rx pdu payload size, filled in by this func.
+ * setup the tag format for a given iscsi entity
+ */
+int cxgb3i_adapter_ddp_info(struct t3cdev *tdev,
+ struct cxgb3i_tag_format *tformat,
+ unsigned int *txsz, unsigned int *rxsz)
+{
+ struct cxgb3i_ddp_info *ddp;
+ unsigned char idx_bits;
+
+ if (!tformat)
+ return -EINVAL;
+
+ if (!tdev->ulp_iscsi)
+ return -EINVAL;
+
+ ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi;
+
+ idx_bits = 32 - tformat->sw_bits;
+ tformat->rsvd_bits = ddp->idx_bits;
+ tformat->rsvd_shift = PPOD_IDX_SHIFT;
+ tformat->rsvd_mask = (1 << tformat->rsvd_bits) - 1;
+
+ ddp_log_info("tag format: sw %u, rsvd %u,%u, mask 0x%x.\n",
+ tformat->sw_bits, tformat->rsvd_bits,
+ tformat->rsvd_shift, tformat->rsvd_mask);
+
+ *txsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
+ ddp->max_txsz - ISCSI_PDU_NONPAYLOAD_LEN);
+ *rxsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
+ ddp->max_rxsz - ISCSI_PDU_NONPAYLOAD_LEN);
+ ddp_log_info("max payload size: %u/%u, %u/%u.\n",
+ *txsz, ddp->max_txsz, *rxsz, ddp->max_rxsz);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_info);
+
+/**
+ * ddp_release - release the cxgb3 adapter's ddp resource
+ * @tdev: t3cdev adapter
+ * release all the resource held by the ddp pagepod manager for a given
+ * adapter if needed
+ */
+static void ddp_release(struct t3cdev *tdev)
+{
+ int i = 0;
+ struct cxgb3i_ddp_info *ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi;
+
+ ddp_log_info("t3dev 0x%p, release ddp 0x%p.\n", tdev, ddp);
+
+ if (ddp) {
+ tdev->ulp_iscsi = NULL;
+ while (i < ddp->nppods) {
+ struct cxgb3i_gather_list *gl = ddp->gl_map[i];
+ if (gl) {
+ int npods = (gl->nelem + PPOD_PAGES_MAX - 1)
+ >> PPOD_PAGES_SHIFT;
+ ddp_log_info("t3dev 0x%p, ddp %d + %d.\n",
+ tdev, i, npods);
+ kfree(gl);
+ ddp_free_gl_skb(ddp, i, npods);
+ i += npods;
+ } else
+ i++;
+ }
+ cxgb3i_free_big_mem(ddp);
+ }
+}
+
+/**
+ * ddp_init - initialize the cxgb3 adapter's ddp resource
+ * @tdev: t3cdev adapter
+ * initialize the ddp pagepod manager for a given adapter
+ */
+static void ddp_init(struct t3cdev *tdev)
{
struct cxgb3i_ddp_info *ddp;
struct ulp_iscsi_info uinfo;
@@ -573,6 +668,12 @@ static int ddp_init(struct t3cdev *tdev)
int i, err;
static int vers_printed;
+ if (tdev->ulp_iscsi) {
+ ddp_log_warn("t3dev 0x%p, ddp 0x%p already set up.\n",
+ tdev, tdev->ulp_iscsi);
+ return;
+ }
+
if (!vers_printed) {
printk(KERN_INFO "%s", version);
vers_printed = 1;
@@ -582,7 +683,7 @@ static int ddp_init(struct t3cdev *tdev)
if (err < 0) {
ddp_log_error("%s, failed to get iscsi param err=%d.\n",
tdev->name, err);
- return err;
+ return;
}
ppmax = (uinfo.ulimit - uinfo.llimit + 1) >> PPOD_SIZE_SHIFT;
@@ -599,7 +700,7 @@ static int ddp_init(struct t3cdev *tdev)
if (!ddp) {
ddp_log_warn("%s unable to alloc ddp 0x%d, ddp disabled.\n",
tdev->name, ppmax);
- return 0;
+ return;
}
ddp->gl_map = (struct cxgb3i_gather_list **)(ddp + 1);
ddp->gl_skb = (struct sk_buff **)(((char *)ddp->gl_map) +
@@ -633,141 +734,46 @@ static int ddp_init(struct t3cdev *tdev)
tdev->ulp_iscsi = ddp;
- /* add to the list */
- write_lock(&cxgb3i_ddp_rwlock);
- list_add_tail(&ddp->list, &cxgb3i_ddp_list);
- write_unlock(&cxgb3i_ddp_rwlock);
-
- ddp_log_info("nppods %u (0x%x ~ 0x%x), bits %u, mask 0x%x,0x%x "
- "pkt %u/%u, %u/%u.\n",
- ppmax, ddp->llimit, ddp->ulimit, ddp->idx_bits,
- ddp->idx_mask, ddp->rsvd_tag_mask,
- ddp->max_txsz, uinfo.max_txsz,
+ ddp_log_info("tdev 0x%p, nppods %u, bits %u, mask 0x%x,0x%x pkt %u/%u,"
+ " %u/%u.\n",
+ tdev, ppmax, ddp->idx_bits, ddp->idx_mask,
+ ddp->rsvd_tag_mask, ddp->max_txsz, uinfo.max_txsz,
ddp->max_rxsz, uinfo.max_rxsz);
- return 0;
+ return;
free_ddp_map:
cxgb3i_free_big_mem(ddp);
- return err;
}
-/**
- * cxgb3i_adapter_ddp_init - initialize the adapter's ddp resource
- * @tdev: t3cdev adapter
- * @tformat: tag format
- * @txsz: max tx pdu payload size, filled in by this func.
- * @rxsz: max rx pdu payload size, filled in by this func.
- * initialize the ddp pagepod manager for a given adapter if needed and
- * setup the tag format for a given iscsi entity
- */
-int cxgb3i_adapter_ddp_init(struct t3cdev *tdev,
- struct cxgb3i_tag_format *tformat,
- unsigned int *txsz, unsigned int *rxsz)
-{
- struct cxgb3i_ddp_info *ddp;
- unsigned char idx_bits;
-
- if (!tformat)
- return -EINVAL;
-
- if (!tdev->ulp_iscsi) {
- int err = ddp_init(tdev);
- if (err < 0)
- return err;
- }
- ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi;
-
- idx_bits = 32 - tformat->sw_bits;
- tformat->rsvd_bits = ddp->idx_bits;
- tformat->rsvd_shift = PPOD_IDX_SHIFT;
- tformat->rsvd_mask = (1 << tformat->rsvd_bits) - 1;
-
- ddp_log_info("tag format: sw %u, rsvd %u,%u, mask 0x%x.\n",
- tformat->sw_bits, tformat->rsvd_bits,
- tformat->rsvd_shift, tformat->rsvd_mask);
-
- *txsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
- ddp->max_txsz - ISCSI_PDU_NONPAYLOAD_LEN);
- *rxsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
- ddp->max_rxsz - ISCSI_PDU_NONPAYLOAD_LEN);
- ddp_log_info("max payload size: %u/%u, %u/%u.\n",
- *txsz, ddp->max_txsz, *rxsz, ddp->max_rxsz);
- return 0;
-}
-EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_init);
-
-static void ddp_release(struct cxgb3i_ddp_info *ddp)
-{
- int i = 0;
- struct t3cdev *tdev = ddp->tdev;
-
- tdev->ulp_iscsi = NULL;
- while (i < ddp->nppods) {
- struct cxgb3i_gather_list *gl = ddp->gl_map[i];
- if (gl) {
- int npods = (gl->nelem + PPOD_PAGES_MAX - 1)
- >> PPOD_PAGES_SHIFT;
-
- kfree(gl);
- ddp_free_gl_skb(ddp, i, npods);
- } else
- i++;
- }
- cxgb3i_free_big_mem(ddp);
-}
-
-/**
- * cxgb3i_adapter_ddp_cleanup - release the adapter's ddp resource
- * @tdev: t3cdev adapter
- * release all the resource held by the ddp pagepod manager for a given
- * adapter if needed
- */
-void cxgb3i_adapter_ddp_cleanup(struct t3cdev *tdev)
-{
- struct cxgb3i_ddp_info *ddp;
-
- /* remove from the list */
- write_lock(&cxgb3i_ddp_rwlock);
- list_for_each_entry(ddp, &cxgb3i_ddp_list, list) {
- if (ddp->tdev == tdev) {
- list_del(&ddp->list);
- break;
- }
- }
- write_unlock(&cxgb3i_ddp_rwlock);
-
- if (ddp)
- ddp_release(ddp);
-}
-EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_cleanup);
+static struct cxgb3_client t3c_ddp_client = {
+ .name = "iscsiddp_cxgb3",
+ .add = ddp_init,
+ .remove = ddp_release,
+};
/**
* cxgb3i_ddp_init_module - module init entry point
- * initialize any driver wide global data structures
+ * initialize any driver wide global data structures and register with the
+ * cxgb3 module
*/
static int __init cxgb3i_ddp_init_module(void)
{
page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE);
ddp_log_info("system PAGE_SIZE %lu, ddp idx %u.\n",
PAGE_SIZE, page_idx);
+
+ cxgb3_register_client(&t3c_ddp_client);
return 0;
}
/**
* cxgb3i_ddp_exit_module - module cleanup/exit entry point
- * go through the ddp list and release any resource held.
+ * go through the ddp list, unregister with the cxgb3 module and release
+ * any resource held.
*/
static void __exit cxgb3i_ddp_exit_module(void)
{
- struct cxgb3i_ddp_info *ddp;
-
- /* release all ddp manager if there is any */
- write_lock(&cxgb3i_ddp_rwlock);
- list_for_each_entry(ddp, &cxgb3i_ddp_list, list) {
- list_del(&ddp->list);
- ddp_release(ddp);
- }
- write_unlock(&cxgb3i_ddp_rwlock);
+ cxgb3_unregister_client(&t3c_ddp_client);
}
module_init(cxgb3i_ddp_init_module);
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.h b/drivers/scsi/cxgb3i/cxgb3i_ddp.h
index 3faae78..40224ad 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_ddp.h
+++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.h
@@ -286,7 +286,7 @@ static inline u32 cxgb3i_tag_nonrsvd_bits(struct cxgb3i_tag_format *tformat,
int cxgb3i_ddp_tag_reserve(struct t3cdev *, unsigned int tid,
struct cxgb3i_tag_format *, u32 *tag,
struct cxgb3i_gather_list *, gfp_t gfp);
-void cxgb3i_ddp_tag_release(struct t3cdev *, u32 tag);
+int cxgb3i_ddp_tag_release(struct t3cdev *, u32 tag);
struct cxgb3i_gather_list *cxgb3i_ddp_make_gl(unsigned int xferlen,
struct scatterlist *sgl,
@@ -303,7 +303,6 @@ int cxgb3i_setup_conn_pagesize(struct t3cdev *, unsigned int tid, int reply,
int cxgb3i_setup_conn_digest(struct t3cdev *, unsigned int tid,
int hcrc, int dcrc, int reply);
int cxgb3i_ddp_find_page_index(unsigned long pgsz);
-int cxgb3i_adapter_ddp_init(struct t3cdev *, struct cxgb3i_tag_format *,
+int cxgb3i_adapter_ddp_info(struct t3cdev *, struct cxgb3i_tag_format *,
unsigned int *txsz, unsigned int *rxsz);
-void cxgb3i_adapter_ddp_cleanup(struct t3cdev *);
#endif
diff --git a/drivers/scsi/cxgb3i/cxgb3i_init.c b/drivers/scsi/cxgb3i/cxgb3i_init.c
index 1ce9f24..833dbfa 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_init.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_init.c
@@ -26,6 +26,7 @@ MODULE_VERSION(DRV_MODULE_VERSION);
static void open_s3_dev(struct t3cdev *);
static void close_s3_dev(struct t3cdev *);
+static void s3_err_handler(struct t3cdev *tdev, u32 status, u32 error);
static cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS];
static struct cxgb3_client t3c_client = {
@@ -33,6 +34,7 @@ static struct cxgb3_client t3c_client = {
.handlers = cxgb3i_cpl_handlers,
.add = open_s3_dev,
.remove = close_s3_dev,
+ .err_handler = s3_err_handler,
};
/**
@@ -49,7 +51,7 @@ static void open_s3_dev(struct t3cdev *t3dev)
}
cxgb3i_sdev_add(t3dev, &t3c_client);
- cxgb3i_adapter_add(t3dev);
+ cxgb3i_adapter_open(t3dev);
}
/**
@@ -58,10 +60,29 @@ static void open_s3_dev(struct t3cdev *t3dev)
*/
static void close_s3_dev(struct t3cdev *t3dev)
{
- cxgb3i_adapter_remove(t3dev);
+ cxgb3i_adapter_close(t3dev);
cxgb3i_sdev_remove(t3dev);
}
+static void s3_err_handler(struct t3cdev *tdev, u32 status, u32 error)
+{
+ struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(tdev);
+
+ cxgb3i_log_info("snic 0x%p, tdev 0x%p, status 0x%x, err 0x%x.\n",
+ snic, tdev, status, error);
+ if (!snic)
+ return;
+
+ switch (status) {
+ case OFFLOAD_STATUS_DOWN:
+ snic->flags |= CXGB3I_ADAPTER_FLAG_RESET;
+ break;
+ case OFFLOAD_STATUS_UP:
+ snic->flags &= ~CXGB3I_ADAPTER_FLAG_RESET;
+ break;
+ }
+}
+
/**
* cxgb3i_init_module - module init entry point
*
diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
index fa2a44f..28bdf0a 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
@@ -53,36 +53,90 @@ static LIST_HEAD(cxgb3i_snic_list);
static DEFINE_RWLOCK(cxgb3i_snic_rwlock);
/**
- * cxgb3i_adapter_add - init a s3 adapter structure and any h/w settings
- * @t3dev: t3cdev adapter
- * return the resulting cxgb3i_adapter struct
+ * cxgb3i_adpater_find_by_tdev - find the cxgb3i_adapter structure with a
+ * given t3cdev
+ * @tdev: t3cdev pointer
*/
-struct cxgb3i_adapter *cxgb3i_adapter_add(struct t3cdev *t3dev)
+struct cxgb3i_adapter *cxgb3i_adapter_find_by_tdev(struct t3cdev *tdev)
{
struct cxgb3i_adapter *snic;
- struct adapter *adapter = tdev2adap(t3dev);
+
+ read_lock(&cxgb3i_snic_rwlock);
+ list_for_each_entry(snic, &cxgb3i_snic_list, list_head) {
+ if (snic->tdev == tdev) {
+ read_unlock(&cxgb3i_snic_rwlock);
+ return snic;
+ }
+ }
+ read_unlock(&cxgb3i_snic_rwlock);
+ return NULL;
+}
+
+/**
+ * cxgb3i_adapter_remove - release all the resources held and cleanup any
+ * h/w settings
+ * @t3dev: t3cdev adapter
+ */
+void cxgb3i_adapter_close(struct t3cdev *t3dev)
+{
+ struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(t3dev);
int i;
- snic = kzalloc(sizeof(*snic), GFP_KERNEL);
- if (!snic) {
- cxgb3i_api_debug("cxgb3 %s, OOM.\n", t3dev->name);
- return NULL;
+ if (!snic || snic->flags & CXGB3I_ADAPTER_FLAG_RESET) {
+ cxgb3i_log_info("t3dev 0x%p close, snic 0x%p, f 0x%x.\n",
+ t3dev, snic, snic ? snic->flags : 0);
+ return;
}
- spin_lock_init(&snic->lock);
- snic->tdev = t3dev;
+ /* remove from the list */
+ write_lock(&cxgb3i_snic_rwlock);
+ list_del(&snic->list_head);
+ write_unlock(&cxgb3i_snic_rwlock);
+
+ for (i = 0; i < snic->hba_cnt; i++) {
+ if (snic->hba[i]) {
+ cxgb3i_hba_host_remove(snic->hba[i]);
+ snic->hba[i] = NULL;
+ }
+ }
+ cxgb3i_log_info("t3dev 0x%p close, snic 0x%p, %u scsi hosts removed.\n",
+ t3dev, snic, snic->hba_cnt);
+ kfree(snic);
+}
+
+/**
+ * cxgb3i_adapter_open - initiate or update a s3 adapter structure and
+ * any h/w settings
+ * @t3dev: t3cdev adapter
+ */
+static inline int adapter_update(struct cxgb3i_adapter *snic)
+{
+ cxgb3i_log_info("snic 0x%p, t3dev 0x%p, updating.\n",
+ snic, snic->tdev);
+ return cxgb3i_adapter_ddp_info(snic->tdev, &snic->tag_format,
+ &snic->tx_max_size,
+ &snic->rx_max_size);
+}
+
+static int adapter_add(struct cxgb3i_adapter *snic)
+{
+ struct t3cdev *t3dev = snic->tdev;
+ struct adapter *adapter = tdev2adap(t3dev);
+ int i, err;
+
snic->pdev = adapter->pdev;
snic->tag_format.sw_bits = sw_tag_idx_bits + sw_tag_age_bits;
- if (cxgb3i_adapter_ddp_init(t3dev, &snic->tag_format,
+ err = cxgb3i_adapter_ddp_info(t3dev, &snic->tag_format,
&snic->tx_max_size,
- &snic->rx_max_size) < 0)
- goto free_snic;
+ &snic->rx_max_size);
+ if (err < 0)
+ return err;
for_each_port(adapter, i) {
snic->hba[i] = cxgb3i_hba_host_add(snic, adapter->port[i]);
if (!snic->hba[i])
- goto ulp_cleanup;
+ return -EINVAL;
}
snic->hba_cnt = adapter->params.nports;
@@ -91,46 +145,35 @@ struct cxgb3i_adapter *cxgb3i_adapter_add(struct t3cdev *t3dev)
list_add_tail(&snic->list_head, &cxgb3i_snic_list);
write_unlock(&cxgb3i_snic_rwlock);
- return snic;
-
-ulp_cleanup:
- cxgb3i_adapter_ddp_cleanup(t3dev);
-free_snic:
- kfree(snic);
- return NULL;
+ cxgb3i_log_info("t3dev 0x%p open, snic 0x%p, %u scsi hosts added.\n",
+ t3dev, snic, snic->hba_cnt);
+ return 0;
}
-/**
- * cxgb3i_adapter_remove - release all the resources held and cleanup any
- * h/w settings
- * @t3dev: t3cdev adapter
- */
-void cxgb3i_adapter_remove(struct t3cdev *t3dev)
+void cxgb3i_adapter_open(struct t3cdev *t3dev)
{
- int i;
- struct cxgb3i_adapter *snic;
+ struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(t3dev);
+ int err;
- /* remove from the list */
- write_lock(&cxgb3i_snic_rwlock);
- list_for_each_entry(snic, &cxgb3i_snic_list, list_head) {
- if (snic->tdev == t3dev) {
- list_del(&snic->list_head);
- break;
- }
+ if (snic)
+ err = adapter_update(snic);
+ else {
+ snic = kzalloc(sizeof(*snic), GFP_KERNEL);
+ if (snic) {
+ spin_lock_init(&snic->lock);
+ snic->tdev = t3dev;
+ err = adapter_add(snic);
+ } else
+ err = -ENOMEM;
}
- write_unlock(&cxgb3i_snic_rwlock);
- if (snic) {
- for (i = 0; i < snic->hba_cnt; i++) {
- if (snic->hba[i]) {
- cxgb3i_hba_host_remove(snic->hba[i]);
- snic->hba[i] = NULL;
- }
+ if (err < 0) {
+ cxgb3i_log_info("snic 0x%p, f 0x%x, t3dev 0x%p open, err %d.\n",
+ snic, snic ? snic->flags : 0, t3dev, err);
+ if (snic) {
+ snic->flags &= ~CXGB3I_ADAPTER_FLAG_RESET;
+ cxgb3i_adapter_close(t3dev);
}
-
- /* release ddp resources */
- cxgb3i_adapter_ddp_cleanup(snic->tdev);
- kfree(snic);
}
}
@@ -173,7 +216,8 @@ struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *snic,
sizeof(struct cxgb3i_hba),
CXGB3I_SCSI_QDEPTH_DFLT);
if (!shost) {
- cxgb3i_log_info("iscsi_host_alloc failed.\n");
+ cxgb3i_log_info("snic 0x%p, ndev 0x%p, host_alloc failed.\n",
+ snic, ndev);
return NULL;
}
@@ -191,7 +235,8 @@ struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *snic,
pci_dev_get(snic->pdev);
err = iscsi_host_add(shost, &snic->pdev->dev);
if (err) {
- cxgb3i_log_info("iscsi_host_add failed.\n");
+ cxgb3i_log_info("snic 0x%p, ndev 0x%p, host_add failed.\n",
+ snic, ndev);
goto pci_dev_put;
}
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c
index de3b3b6..bd3d0af 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c
@@ -94,29 +94,30 @@ static int c3cn_get_port(struct s3_conn *c3cn, struct cxgb3i_sdev_data *cdata)
if (!cdata)
goto error_out;
- if (c3cn->saddr.sin_port != 0) {
- idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base;
- if (idx < 0 || idx >= cxgb3_max_connect)
- return 0;
- if (!test_and_set_bit(idx, cdata->sport_map))
- return -EADDRINUSE;
+ if (c3cn->saddr.sin_port) {
+ cxgb3i_log_error("connect, sin_port NON-ZERO %u.\n",
+ c3cn->saddr.sin_port);
+ return -EADDRINUSE;
}
- /* the sport_map_next may not be accurate but that is okay, sport_map
- should be */
- start = idx = cdata->sport_map_next;
+ spin_lock_bh(&cdata->lock);
+ start = idx = cdata->sport_next;
do {
if (++idx >= cxgb3_max_connect)
idx = 0;
- if (!(test_and_set_bit(idx, cdata->sport_map))) {
+ if (!cdata->sport_conn[idx]) {
c3cn->saddr.sin_port = htons(cxgb3_sport_base + idx);
- cdata->sport_map_next = idx;
+ cdata->sport_next = idx;
+ cdata->sport_conn[idx] = c3cn;
+ spin_unlock_bh(&cdata->lock);
+
c3cn_conn_debug("%s reserve port %u.\n",
cdata->cdev->name,
cxgb3_sport_base + idx);
return 0;
}
} while (idx != start);
+ spin_unlock_bh(&cdata->lock);
error_out:
return -EADDRNOTAVAIL;
@@ -124,15 +125,19 @@ error_out:
static void c3cn_put_port(struct s3_conn *c3cn)
{
- struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(c3cn->cdev);
+ if (!c3cn->cdev)
+ return;
if (c3cn->saddr.sin_port) {
+ struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(c3cn->cdev);
int idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base;
c3cn->saddr.sin_port = 0;
if (idx < 0 || idx >= cxgb3_max_connect)
return;
- clear_bit(idx, cdata->sport_map);
+ spin_lock_bh(&cdata->lock);
+ cdata->sport_conn[idx] = NULL;
+ spin_unlock_bh(&cdata->lock);
c3cn_conn_debug("%s, release port %u.\n",
cdata->cdev->name, cxgb3_sport_base + idx);
}
@@ -187,7 +192,7 @@ static void c3cn_closed(struct s3_conn *c3cn)
c3cn_put_port(c3cn);
c3cn_release_offload_resources(c3cn);
c3cn_set_state(c3cn, C3CN_STATE_CLOSED);
- cxgb3i_conn_closing(c3cn);
+ cxgb3i_conn_closing(c3cn, c3cn_flag(c3cn, C3CN_OFFLOAD_DOWN));
}
/*
@@ -886,7 +891,7 @@ static void process_peer_close(struct s3_conn *c3cn, struct sk_buff *skb)
c3cn->cdev->name, c3cn->tid, c3cn->state);
}
- cxgb3i_conn_closing(c3cn);
+ cxgb3i_conn_closing(c3cn, 0);
out:
__kfree_skb(skb);
}
@@ -1305,11 +1310,7 @@ static void c3cn_release_offload_resources(struct s3_conn *c3cn)
struct t3cdev *cdev = c3cn->cdev;
unsigned int tid = c3cn->tid;
- if (!cdev)
- return;
-
c3cn->qset = 0;
-
c3cn_free_cpl_skbs(c3cn);
if (c3cn->wr_avail != c3cn->wr_max) {
@@ -1317,18 +1318,22 @@ static void c3cn_release_offload_resources(struct s3_conn *c3cn)
reset_wr_list(c3cn);
}
- if (c3cn->l2t) {
- l2t_release(L2DATA(cdev), c3cn->l2t);
- c3cn->l2t = NULL;
- }
-
- if (c3cn->state == C3CN_STATE_CONNECTING) /* we have ATID */
- s3_free_atid(cdev, tid);
- else { /* we have TID */
- cxgb3_remove_tid(cdev, (void *)c3cn, tid);
- c3cn_put(c3cn);
+ if (cdev) {
+ if (c3cn->l2t) {
+ l2t_release(L2DATA(cdev), c3cn->l2t);
+ c3cn->l2t = NULL;
+ }
+ if (c3cn->state == C3CN_STATE_CONNECTING)
+ /* we have ATID */
+ s3_free_atid(cdev, tid);
+ else {
+ /* we have TID */
+ cxgb3_remove_tid(cdev, (void *)c3cn, tid);
+ c3cn_put(c3cn);
+ }
}
+ c3cn->dst_cache = NULL;
c3cn->cdev = NULL;
}
@@ -1425,10 +1430,10 @@ void cxgb3i_c3cn_release(struct s3_conn *c3cn)
{
c3cn_conn_debug("c3cn 0x%p, s %u, f 0x%lx.\n",
c3cn, c3cn->state, c3cn->flags);
- if (likely(c3cn->state != C3CN_STATE_CONNECTING))
- c3cn_active_close(c3cn);
- else
+ if (unlikely(c3cn->state == C3CN_STATE_CONNECTING))
c3cn_set_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED);
+ else if (likely(c3cn->state != C3CN_STATE_CLOSED))
+ c3cn_active_close(c3cn);
c3cn_put(c3cn);
}
@@ -1657,7 +1662,6 @@ int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin)
c3cn_set_state(c3cn, C3CN_STATE_CLOSED);
ip_rt_put(rt);
c3cn_put_port(c3cn);
- c3cn->daddr.sin_port = 0;
return err;
}
@@ -1777,10 +1781,25 @@ out_err:
static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata)
{
struct adap_ports *ports = &cdata->ports;
+ struct s3_conn *c3cn;
int i;
+ for (i = 0; i < cxgb3_max_connect; i++) {
+ if (cdata->sport_conn[i]) {
+ c3cn = cdata->sport_conn[i];
+ cdata->sport_conn[i] = NULL;
+
+ spin_lock_bh(&c3cn->lock);
+ c3cn->cdev = NULL;
+ c3cn_set_flag(c3cn, C3CN_OFFLOAD_DOWN);
+ c3cn_closed(c3cn);
+ spin_unlock_bh(&c3cn->lock);
+ }
+ }
+
for (i = 0; i < ports->nports; i++)
NDEV2CDATA(ports->lldevs[i]) = NULL;
+
cxgb3i_free_big_mem(cdata);
}
@@ -1822,21 +1841,27 @@ void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client)
struct cxgb3i_sdev_data *cdata;
struct ofld_page_info rx_page_info;
unsigned int wr_len;
- int mapsize = DIV_ROUND_UP(cxgb3_max_connect,
- 8 * sizeof(unsigned long));
+ int mapsize = cxgb3_max_connect * sizeof(struct s3_conn *);
int i;
cdata = cxgb3i_alloc_big_mem(sizeof(*cdata) + mapsize, GFP_KERNEL);
- if (!cdata)
+ if (!cdata) {
+ cxgb3i_log_warn("t3dev 0x%p, offload up, OOM %d.\n",
+ cdev, mapsize);
return;
+ }
if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 ||
cdev->ctl(cdev, GET_PORTS, &cdata->ports) < 0 ||
- cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0)
+ cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0) {
+ cxgb3i_log_warn("t3dev 0x%p, offload up, ioctl failed.\n",
+ cdev);
goto free_cdata;
+ }
s3_init_wr_tab(wr_len);
+ spin_lock_init(&cdata->lock);
INIT_LIST_HEAD(&cdata->list);
cdata->cdev = cdev;
cdata->client = client;
@@ -1848,6 +1873,7 @@ void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client)
list_add_tail(&cdata->list, &cdata_list);
write_unlock(&cdata_rwlock);
+ cxgb3i_log_info("t3dev 0x%p, offload up, added.\n", cdev);
return;
free_cdata:
@@ -1862,6 +1888,8 @@ void cxgb3i_sdev_remove(struct t3cdev *cdev)
{
struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev);
+ cxgb3i_log_info("t3dev 0x%p, offload down, remove.\n", cdev);
+
write_lock(&cdata_rwlock);
list_del(&cdata->list);
write_unlock(&cdata_rwlock);
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.h b/drivers/scsi/cxgb3i/cxgb3i_offload.h
index 6344b9e..dab759d 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.h
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.h
@@ -135,6 +135,7 @@ enum c3cn_flags {
C3CN_ABORT_RPL_PENDING, /* expecting an abort reply */
C3CN_TX_DATA_SENT, /* already sent a TX_DATA WR */
C3CN_ACTIVE_CLOSE_NEEDED, /* need to be closed */
+ C3CN_OFFLOAD_DOWN /* offload function off */
};
/**
@@ -147,16 +148,17 @@ enum c3cn_flags {
* @cdev: t3cdev adapter
* @client: CPL client pointer
* @ports: array of adapter ports
- * @sport_map_next: next index into the port map
- * @sport_map: source port map
+ * @sport_next: next port
+ * @sport_conn: source port connection
*/
struct cxgb3i_sdev_data {
struct list_head list;
struct t3cdev *cdev;
struct cxgb3_client *client;
struct adap_ports ports;
- unsigned int sport_map_next;
- unsigned long sport_map[0];
+ spinlock_t lock;
+ unsigned int sport_next;
+ struct s3_conn *sport_conn[0];
};
#define NDEV2CDATA(ndev) (*(struct cxgb3i_sdev_data **)&(ndev)->ec_ptr)
#define CXGB3_SDEV_DATA(cdev) NDEV2CDATA((cdev)->lldev)
diff --git a/drivers/scsi/cxgb3i/cxgb3i_pdu.c b/drivers/scsi/cxgb3i/cxgb3i_pdu.c
index 17115c2..f104326 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_pdu.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_pdu.c
@@ -483,13 +483,18 @@ void cxgb3i_conn_tx_open(struct s3_conn *c3cn)
}
}
-void cxgb3i_conn_closing(struct s3_conn *c3cn)
+void cxgb3i_conn_closing(struct s3_conn *c3cn, int error)
{
struct iscsi_conn *conn;
read_lock(&c3cn->callback_lock);
conn = c3cn->user_data;
- if (conn && c3cn->state != C3CN_STATE_ESTABLISHED)
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ if (conn && c3cn->state != C3CN_STATE_ESTABLISHED) {
+ if (error)
+ iscsi_session_failure(conn->session,
+ ISCSI_ERR_CONN_FAILED);
+ else
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ }
read_unlock(&c3cn->callback_lock);
}
diff --git a/drivers/scsi/cxgb3i/cxgb3i_pdu.h b/drivers/scsi/cxgb3i/cxgb3i_pdu.h
index 0770b23..df4a876 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_pdu.h
+++ b/drivers/scsi/cxgb3i/cxgb3i_pdu.h
@@ -53,7 +53,7 @@ struct cpl_rx_data_ddp_norss {
#define ULP2_FLAG_DCRC_ERROR 0x20
#define ULP2_FLAG_PAD_ERROR 0x40
-void cxgb3i_conn_closing(struct s3_conn *c3cn);
+void cxgb3i_conn_closing(struct s3_conn *c3cn, int);
void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn);
void cxgb3i_conn_tx_open(struct s3_conn *c3cn);
#endif
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2 2.6.29-rc] cxgb3i - add handling of chip reset
2009-02-25 1:28 [PATCH 2/2 2.6.29-rc] cxgb3i - add handling of chip reset Karen Xie
@ 2009-02-25 17:21 ` Mike Christie
2009-02-25 18:00 ` Karen Xie
2009-02-25 17:29 ` Mike Christie
1 sibling, 1 reply; 5+ messages in thread
From: Mike Christie @ 2009-02-25 17:21 UTC (permalink / raw)
To: Karen Xie; +Cc: open-iscsi, linux-scsi, James.Bottomley
Karen Xie wrote:
> [PATCH 2/2 2.6.29-rc] cxgb3i - add support of chip reset
>
> From: Karen Xie <kxie@chelsio.com>
>
> The cxgb3 driver would reset the chip due to an EEH event or a fatal error
> and notifies the upper layer modules (iscsi, rdma).
> Upon receiving the notification the cxgb3i driver would
> - close all the iscsi tcp connections and mark the associated sessions as
> failed due to connection error,
> - re-initialize its offload functions,
> - re-initialize the chip's ddp functions.
>
> The iscsi error recovery mechanism will re-establish the tcp connection after
> reset.
>
> This patch requires the the following cxgb3 patch in the linux-next git tree
> (http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git;a=commitdiff;h=cb0bc205959bf8c60acae9c71f3da0597e756f8e).
>
>
> static inline int ddp_find_unused_entries(struct cxgb3i_ddp_info *ddp,
> @@ -439,14 +444,15 @@ EXPORT_SYMBOL_GPL(cxgb3i_ddp_tag_reserve);
> * @tag: ddp tag
> * ddp cleanup for a given ddp tag and release all the resources held
> */
> -void cxgb3i_ddp_tag_release(struct t3cdev *tdev, u32 tag)
> +int cxgb3i_ddp_tag_release(struct t3cdev *tdev, u32 tag)
> {
> struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi;
> u32 idx;
> + int err = -EINVAL;
>
> if (!ddp) {
> ddp_log_error("release ddp tag 0x%x, ddp NULL.\n", tag);
> - return;
> + return err;
> }
>
> idx = (tag >> PPOD_IDX_SHIFT) & ddp->idx_mask;
> @@ -457,17 +463,26 @@ void cxgb3i_ddp_tag_release(struct t3cdev *tdev, u32 tag)
> if (!gl) {
> ddp_log_error("release ddp 0x%x, idx 0x%x, gl NULL.\n",
> tag, idx);
> - return;
> + return err;
> }
> npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT;
> + if (!npods) {
> + ddp_log_error("release ddp 0x%x, 0x%x, gl elem %u.\n",
> + tag, idx, gl->nelem);
> + return err;
> + }
> ddp_log_debug("ddp tag 0x%x, release idx 0x%x, npods %u.\n",
> tag, idx, npods);
> - clear_ddp_map(ddp, idx, npods);
> + if (clear_ddp_map(ddp, tag, idx, npods) == npods)
> + err = 0;
> ddp_unmark_entries(ddp, idx, npods);
> cxgb3i_ddp_release_gl(gl, ddp->pdev);
If this fails, do we leak this memory?
When is ddp_release called? Would it be called to clean up in situati
this could fail?
> +/**
> + * cxgb3i_adapter_remove - release all the resources held and cleanup any
> + * h/w settings
The docbook comment for the function description should only be one
line. I think you did this in some other places.
>
> -void cxgb3i_conn_closing(struct s3_conn *c3cn)
> +void cxgb3i_conn_closing(struct s3_conn *c3cn, int error)
> {
> struct iscsi_conn *conn;
>
> read_lock(&c3cn->callback_lock);
> conn = c3cn->user_data;
> - if (conn && c3cn->state != C3CN_STATE_ESTABLISHED)
> - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
> + if (conn && c3cn->state != C3CN_STATE_ESTABLISHED) {
> + if (error)
> + iscsi_session_failure(conn->session,
> + ISCSI_ERR_CONN_FAILED);
> + else
> + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
> + }
> read_unlock(&c3cn->callback_lock);
If you have a ref to the conn, you can just use iscsi_conn_failure here.
I thought when you got the pci error event you were just going to use
the host session iter and loop over the session and fail them.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2 2.6.29-rc] cxgb3i - add handling of chip reset
2009-02-25 1:28 [PATCH 2/2 2.6.29-rc] cxgb3i - add handling of chip reset Karen Xie
2009-02-25 17:21 ` Mike Christie
@ 2009-02-25 17:29 ` Mike Christie
2009-02-25 18:06 ` Karen Xie
1 sibling, 1 reply; 5+ messages in thread
From: Mike Christie @ 2009-02-25 17:29 UTC (permalink / raw)
To: Karen Xie; +Cc: open-iscsi, linux-scsi, James.Bottomley
Some other comments about the host and snic allocation.
Karen Xie wrote:
> +/**
> + * cxgb3i_adapter_open - initiate or update a s3 adapter structure and
> + * any h/w settings
> + * @t3dev: t3cdev adapter
> + */
> +static inline int adapter_update(struct cxgb3i_adapter *snic)
The function name and comment got out of sync.
> -void cxgb3i_adapter_remove(struct t3cdev *t3dev)
> +void cxgb3i_adapter_open(struct t3cdev *t3dev)
> {
> - int i;
> - struct cxgb3i_adapter *snic;
> + struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(t3dev);
> + int err;
>
> - /* remove from the list */
> - write_lock(&cxgb3i_snic_rwlock);
> - list_for_each_entry(snic, &cxgb3i_snic_list, list_head) {
> - if (snic->tdev == t3dev) {
> - list_del(&snic->list_head);
> - break;
> - }
> + if (snic)
> + err = adapter_update(snic);
> + else {
> + snic = kzalloc(sizeof(*snic), GFP_KERNEL);
> + if (snic) {
> + spin_lock_init(&snic->lock);
> + snic->tdev = t3dev;
> + err = adapter_add(snic);
> + } else
> + err = -ENOMEM;
>
Does the snic represent the actual card. So if I had a dual ported card,
I would have one snic and then have multple shosts/cxgb3i_hba for each
port right?
It seemed strange because cxgb3i_hba_host_add sets the shost's parent to
the pci device, and we get the pci device from the snic->pdev. And so I
thought we see a pci device per port, so we would also should have a
snic per port?
^ permalink raw reply [flat|nested] 5+ messages in thread
* RE: [PATCH 2/2 2.6.29-rc] cxgb3i - add handling of chip reset
2009-02-25 17:21 ` Mike Christie
@ 2009-02-25 18:00 ` Karen Xie
0 siblings, 0 replies; 5+ messages in thread
From: Karen Xie @ 2009-02-25 18:00 UTC (permalink / raw)
To: Mike Christie; +Cc: open-iscsi, linux-scsi, James.Bottomley
-----Original Message-----
From: Mike Christie [mailto:michaelc@cs.wisc.edu]
Sent: Wednesday, February 25, 2009 9:22 AM
To: Karen Xie
Cc: open-iscsi@googlegroups.com; linux-scsi@vger.kernel.org;
James.Bottomley@HansenPartnership.com
Subject: Re: [PATCH 2/2 2.6.29-rc] cxgb3i - add handling of chip reset
Karen Xie wrote:
> [PATCH 2/2 2.6.29-rc] cxgb3i - add support of chip reset
>
> From: Karen Xie <kxie@chelsio.com>
>
> The cxgb3 driver would reset the chip due to an EEH event or a fatal
error
> and notifies the upper layer modules (iscsi, rdma).
> Upon receiving the notification the cxgb3i driver would
> - close all the iscsi tcp connections and mark the associated sessions
as
> failed due to connection error,
> - re-initialize its offload functions,
> - re-initialize the chip's ddp functions.
>
> The iscsi error recovery mechanism will re-establish the tcp
connection after
> reset.
>
> This patch requires the the following cxgb3 patch in the linux-next
git tree
>
(http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git;a=commitdi
ff;h=cb0bc205959bf8c60acae9c71f3da0597e756f8e).
>
>
> static inline int ddp_find_unused_entries(struct cxgb3i_ddp_info
*ddp,
> @@ -439,14 +444,15 @@ EXPORT_SYMBOL_GPL(cxgb3i_ddp_tag_reserve);
> * @tag: ddp tag
> * ddp cleanup for a given ddp tag and release all the resources held
> */
> -void cxgb3i_ddp_tag_release(struct t3cdev *tdev, u32 tag)
> +int cxgb3i_ddp_tag_release(struct t3cdev *tdev, u32 tag)
> {
> struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi;
> u32 idx;
> + int err = -EINVAL;
>
> if (!ddp) {
> ddp_log_error("release ddp tag 0x%x, ddp NULL.\n", tag);
> - return;
> + return err;
> }
>
> idx = (tag >> PPOD_IDX_SHIFT) & ddp->idx_mask;
> @@ -457,17 +463,26 @@ void cxgb3i_ddp_tag_release(struct t3cdev *tdev,
u32 tag)
> if (!gl) {
> ddp_log_error("release ddp 0x%x, idx 0x%x, gl
NULL.\n",
> tag, idx);
> - return;
> + return err;
> }
> npods = (gl->nelem + PPOD_PAGES_MAX - 1) >>
PPOD_PAGES_SHIFT;
> + if (!npods) {
> + ddp_log_error("release ddp 0x%x, 0x%x, gl elem
%u.\n",
> + tag, idx, gl->nelem);
> + return err;
> + }
> ddp_log_debug("ddp tag 0x%x, release idx 0x%x, npods
%u.\n",
> tag, idx, npods);
> - clear_ddp_map(ddp, idx, npods);
> + if (clear_ddp_map(ddp, tag, idx, npods) == npods)
> + err = 0;
> ddp_unmark_entries(ddp, idx, npods);
> cxgb3i_ddp_release_gl(gl, ddp->pdev);
If this fails, do we leak this memory?
[Karen] The only memory allocated is the gl structure, even if it is not
freed here, it will be freed at the cleanup of the ddp function.
When is ddp_release called? Would it be called to clean up in situati
this could fail?
[Karen] it is called in cleanup_task().
> +/**
> + * cxgb3i_adapter_remove - release all the resources held and cleanup
any
> + * h/w settings
The docbook comment for the function description should only be one
line. I think you did this in some other places.
[Karen] Thanks, I will fix them.
>
> -void cxgb3i_conn_closing(struct s3_conn *c3cn)
> +void cxgb3i_conn_closing(struct s3_conn *c3cn, int error)
> {
> struct iscsi_conn *conn;
>
> read_lock(&c3cn->callback_lock);
> conn = c3cn->user_data;
> - if (conn && c3cn->state != C3CN_STATE_ESTABLISHED)
> - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
> + if (conn && c3cn->state != C3CN_STATE_ESTABLISHED) {
> + if (error)
> + iscsi_session_failure(conn->session,
> + ISCSI_ERR_CONN_FAILED);
> + else
> + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
> + }
> read_unlock(&c3cn->callback_lock);
If you have a ref to the conn, you can just use iscsi_conn_failure here.
I thought when you got the pci error event you were just going to use
the host session iter and loop over the session and fail them.
[Karen] Yes, I could do it via iscsi_host_for_each_session() too.
^ permalink raw reply [flat|nested] 5+ messages in thread
* RE: [PATCH 2/2 2.6.29-rc] cxgb3i - add handling of chip reset
2009-02-25 17:29 ` Mike Christie
@ 2009-02-25 18:06 ` Karen Xie
0 siblings, 0 replies; 5+ messages in thread
From: Karen Xie @ 2009-02-25 18:06 UTC (permalink / raw)
To: Mike Christie; +Cc: open-iscsi, linux-scsi, James.Bottomley
-----Original Message-----
From: Mike Christie [mailto:michaelc@cs.wisc.edu]
Sent: Wednesday, February 25, 2009 9:30 AM
To: Karen Xie
Cc: open-iscsi@googlegroups.com; linux-scsi@vger.kernel.org;
James.Bottomley@HansenPartnership.com
Subject: Re: [PATCH 2/2 2.6.29-rc] cxgb3i - add handling of chip reset
Some other comments about the host and snic allocation.
Karen Xie wrote:
> +/**
> + * cxgb3i_adapter_open - initiate or update a s3 adapter structure
and
> + * any h/w settings
> + * @t3dev: t3cdev adapter
> + */
> +static inline int adapter_update(struct cxgb3i_adapter *snic)
The function name and comment got out of sync.
[Karen] Thanks, will fix it.
> -void cxgb3i_adapter_remove(struct t3cdev *t3dev)
> +void cxgb3i_adapter_open(struct t3cdev *t3dev)
> {
> - int i;
> - struct cxgb3i_adapter *snic;
> + struct cxgb3i_adapter *snic =
cxgb3i_adapter_find_by_tdev(t3dev);
> + int err;
>
> - /* remove from the list */
> - write_lock(&cxgb3i_snic_rwlock);
> - list_for_each_entry(snic, &cxgb3i_snic_list, list_head) {
> - if (snic->tdev == t3dev) {
> - list_del(&snic->list_head);
> - break;
> - }
> + if (snic)
> + err = adapter_update(snic);
> + else {
> + snic = kzalloc(sizeof(*snic), GFP_KERNEL);
> + if (snic) {
> + spin_lock_init(&snic->lock);
> + snic->tdev = t3dev;
> + err = adapter_add(snic);
> + } else
> + err = -ENOMEM;
>
Does the snic represent the actual card. So if I had a dual ported card,
I would have one snic and then have multple shosts/cxgb3i_hba for each
port right?
[Karen] Yes.
It seemed strange because cxgb3i_hba_host_add sets the shost's parent to
the pci device, and we get the pci device from the snic->pdev. And so I
thought we see a pci device per port, so we would also should have a
snic per port?
[Karen] Each port/cxgb3i_hba has a pointer point back to the
snic/adapter. So one snic per adapter, each snic contains one or more
ports, each port corresponds to one shost.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-02-25 18:13 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-02-25 1:28 [PATCH 2/2 2.6.29-rc] cxgb3i - add handling of chip reset Karen Xie
2009-02-25 17:21 ` Mike Christie
2009-02-25 18:00 ` Karen Xie
2009-02-25 17:29 ` Mike Christie
2009-02-25 18:06 ` Karen Xie
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox