diff options
Diffstat (limited to 'drivers/scsi/be2iscsi/be_cmds.c')
-rw-r--r-- | drivers/scsi/be2iscsi/be_cmds.c | 88 |
1 files changed, 76 insertions, 12 deletions
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index f008708f1b08..67098578fba4 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /** | 1 | /** |
2 | * Copyright (C) 2005 - 2009 ServerEngines | 2 | * Copyright (C) 2005 - 2010 ServerEngines |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
@@ -19,7 +19,7 @@ | |||
19 | #include "be_mgmt.h" | 19 | #include "be_mgmt.h" |
20 | #include "be_main.h" | 20 | #include "be_main.h" |
21 | 21 | ||
22 | static void be_mcc_notify(struct beiscsi_hba *phba) | 22 | void be_mcc_notify(struct beiscsi_hba *phba) |
23 | { | 23 | { |
24 | struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; | 24 | struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; |
25 | u32 val = 0; | 25 | u32 val = 0; |
@@ -29,6 +29,52 @@ static void be_mcc_notify(struct beiscsi_hba *phba) | |||
29 | iowrite32(val, phba->db_va + DB_MCCQ_OFFSET); | 29 | iowrite32(val, phba->db_va + DB_MCCQ_OFFSET); |
30 | } | 30 | } |
31 | 31 | ||
32 | unsigned int alloc_mcc_tag(struct beiscsi_hba *phba) | ||
33 | { | ||
34 | unsigned int tag = 0; | ||
35 | unsigned int num = 0; | ||
36 | |||
37 | mcc_tag_rdy: | ||
38 | if (phba->ctrl.mcc_tag_available) { | ||
39 | tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index]; | ||
40 | phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0; | ||
41 | phba->ctrl.mcc_numtag[tag] = 0; | ||
42 | } else { | ||
43 | udelay(100); | ||
44 | num++; | ||
45 | if (num < mcc_timeout) | ||
46 | goto mcc_tag_rdy; | ||
47 | } | ||
48 | if (tag) { | ||
49 | phba->ctrl.mcc_tag_available--; | ||
50 | if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1)) | ||
51 | phba->ctrl.mcc_alloc_index = 0; | ||
52 | else | ||
53 | phba->ctrl.mcc_alloc_index++; | ||
54 | } | ||
55 | return tag; | ||
56 | } | ||
57 | |||
58 | void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag) | ||
59 | { | ||
60 | spin_lock(&ctrl->mbox_lock); | ||
61 | tag = tag & 0x000000FF; | ||
62 | ctrl->mcc_tag[ctrl->mcc_free_index] = tag; | ||
63 | if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1)) | ||
64 | ctrl->mcc_free_index = 0; | ||
65 | else | ||
66 | ctrl->mcc_free_index++; | ||
67 | ctrl->mcc_tag_available++; | ||
68 | spin_unlock(&ctrl->mbox_lock); | ||
69 | } | ||
70 | |||
71 | bool is_link_state_evt(u32 trailer) | ||
72 | { | ||
73 | return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & | ||
74 | ASYNC_TRAILER_EVENT_CODE_MASK) == | ||
75 | ASYNC_EVENT_CODE_LINK_STATE); | ||
76 | } | ||
77 | |||
32 | static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl) | 78 | static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl) |
33 | { | 79 | { |
34 | if (compl->flags != 0) { | 80 | if (compl->flags != 0) { |
@@ -64,12 +110,30 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl, | |||
64 | return 0; | 110 | return 0; |
65 | } | 111 | } |
66 | 112 | ||
67 | 113 | int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl, | |
68 | static inline bool is_link_state_evt(u32 trailer) | 114 | struct be_mcc_compl *compl) |
69 | { | 115 | { |
70 | return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & | 116 | u16 compl_status, extd_status; |
71 | ASYNC_TRAILER_EVENT_CODE_MASK) == | 117 | unsigned short tag; |
72 | ASYNC_EVENT_CODE_LINK_STATE); | 118 | |
119 | be_dws_le_to_cpu(compl, 4); | ||
120 | |||
121 | compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & | ||
122 | CQE_STATUS_COMPL_MASK; | ||
123 | /* The ctrl.mcc_numtag[tag] is filled with | ||
124 | * [31] = valid, [30:24] = Rsvd, [23:16] = wrb, [15:8] = extd_status, | ||
125 | * [7:0] = compl_status | ||
126 | */ | ||
127 | tag = (compl->tag0 & 0x000000FF); | ||
128 | extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & | ||
129 | CQE_STATUS_EXTD_MASK; | ||
130 | |||
131 | ctrl->mcc_numtag[tag] = 0x80000000; | ||
132 | ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000); | ||
133 | ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8; | ||
134 | ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF); | ||
135 | wake_up_interruptible(&ctrl->mcc_wait[tag]); | ||
136 | return 0; | ||
73 | } | 137 | } |
74 | 138 | ||
75 | static struct be_mcc_compl *be_mcc_compl_get(struct beiscsi_hba *phba) | 139 | 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) | |||
89 | iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); | 153 | iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); |
90 | } | 154 | } |
91 | 155 | ||
92 | static void beiscsi_async_link_state_process(struct beiscsi_hba *phba, | 156 | void beiscsi_async_link_state_process(struct beiscsi_hba *phba, |
93 | struct be_async_event_link_state *evt) | 157 | struct be_async_event_link_state *evt) |
94 | { | 158 | { |
95 | switch (evt->port_link_status) { | 159 | switch (evt->port_link_status) { |
@@ -97,13 +161,13 @@ static void beiscsi_async_link_state_process(struct beiscsi_hba *phba, | |||
97 | SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d \n", | 161 | SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d \n", |
98 | evt->physical_port); | 162 | evt->physical_port); |
99 | phba->state |= BE_ADAPTER_LINK_DOWN; | 163 | phba->state |= BE_ADAPTER_LINK_DOWN; |
164 | iscsi_host_for_each_session(phba->shost, | ||
165 | be2iscsi_fail_session); | ||
100 | break; | 166 | break; |
101 | case ASYNC_EVENT_LINK_UP: | 167 | case ASYNC_EVENT_LINK_UP: |
102 | phba->state = BE_ADAPTER_UP; | 168 | phba->state = BE_ADAPTER_UP; |
103 | SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d \n", | 169 | SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d \n", |
104 | evt->physical_port); | 170 | evt->physical_port); |
105 | iscsi_host_for_each_session(phba->shost, | ||
106 | be2iscsi_fail_session); | ||
107 | break; | 171 | break; |
108 | default: | 172 | default: |
109 | SE_DEBUG(DBG_LVL_1, "Unexpected Async Notification %d on" | 173 | SE_DEBUG(DBG_LVL_1, "Unexpected Async Notification %d on" |
@@ -162,7 +226,6 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba) | |||
162 | /* Wait till no more pending mcc requests are present */ | 226 | /* Wait till no more pending mcc requests are present */ |
163 | static int be_mcc_wait_compl(struct beiscsi_hba *phba) | 227 | static int be_mcc_wait_compl(struct beiscsi_hba *phba) |
164 | { | 228 | { |
165 | #define mcc_timeout 120000 /* 5s timeout */ | ||
166 | int i, status; | 229 | int i, status; |
167 | for (i = 0; i < mcc_timeout; i++) { | 230 | for (i = 0; i < mcc_timeout; i++) { |
168 | status = beiscsi_process_mcc(phba); | 231 | status = beiscsi_process_mcc(phba); |
@@ -372,9 +435,10 @@ struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba) | |||
372 | 435 | ||
373 | BUG_ON(atomic_read(&mccq->used) >= mccq->len); | 436 | BUG_ON(atomic_read(&mccq->used) >= mccq->len); |
374 | wrb = queue_head_node(mccq); | 437 | wrb = queue_head_node(mccq); |
438 | memset(wrb, 0, sizeof(*wrb)); | ||
439 | wrb->tag0 = (mccq->head & 0x000000FF) << 16; | ||
375 | queue_head_inc(mccq); | 440 | queue_head_inc(mccq); |
376 | atomic_inc(&mccq->used); | 441 | atomic_inc(&mccq->used); |
377 | memset(wrb, 0, sizeof(*wrb)); | ||
378 | return wrb; | 442 | return wrb; |
379 | } | 443 | } |
380 | 444 | ||