diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-15 21:58:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-15 21:58:04 -0400 |
commit | 89a93f2f4834f8c126e8d9dd6b368d0b9e21ec3d (patch) | |
tree | e731456fec0cab1225ad3e806dc8d3efefa0a78b | |
parent | 260eddf4391f162a69d1d163729249635fa7a78f (diff) | |
parent | fe9233fb6914a0eb20166c967e3020f7f0fba2c9 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (102 commits)
[SCSI] scsi_dh: fix kconfig related build errors
[SCSI] sym53c8xx: Fix bogus sym_que_entry re-implementation of container_of
[SCSI] scsi_cmnd.h: remove double inclusion of linux/blkdev.h
[SCSI] make struct scsi_{host,target}_type static
[SCSI] fix locking in host use of blk_plug_device()
[SCSI] zfcp: Cleanup external header file
[SCSI] zfcp: Cleanup code in zfcp_erp.c
[SCSI] zfcp: zfcp_fsf cleanup.
[SCSI] zfcp: consolidate sysfs things into one file.
[SCSI] zfcp: Cleanup of code in zfcp_aux.c
[SCSI] zfcp: Cleanup of code in zfcp_scsi.c
[SCSI] zfcp: Move status accessors from zfcp to SCSI include file.
[SCSI] zfcp: Small QDIO cleanups
[SCSI] zfcp: Adapter reopen for large number of unsolicited status
[SCSI] zfcp: Fix error checking for ELS ADISC requests
[SCSI] zfcp: wait until adapter is finished with ERP during auto-port
[SCSI] ibmvfc: IBM Power Virtual Fibre Channel Adapter Client Driver
[SCSI] sg: Add target reset support
[SCSI] lib: Add support for the T10 (SCSI) Data Integrity Field CRC
[SCSI] sd: Move scsi_disk() accessor function to sd.h
...
106 files changed, 14368 insertions, 14158 deletions
diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt index d16011a8618e..709ca991a451 100644 --- a/Documentation/scsi/aacraid.txt +++ b/Documentation/scsi/aacraid.txt | |||
@@ -56,19 +56,33 @@ Supported Cards/Chipsets | |||
56 | 9005:0285:9005:02d1 Adaptec 5405 (Voodoo40) | 56 | 9005:0285:9005:02d1 Adaptec 5405 (Voodoo40) |
57 | 9005:0285:15d9:02d2 SMC AOC-USAS-S8i-LP | 57 | 9005:0285:15d9:02d2 SMC AOC-USAS-S8i-LP |
58 | 9005:0285:15d9:02d3 SMC AOC-USAS-S8iR-LP | 58 | 9005:0285:15d9:02d3 SMC AOC-USAS-S8iR-LP |
59 | 9005:0285:9005:02d4 Adaptec 2045 (Voodoo04 Lite) | 59 | 9005:0285:9005:02d4 Adaptec ASR-2045 (Voodoo04 Lite) |
60 | 9005:0285:9005:02d5 Adaptec 2405 (Voodoo40 Lite) | 60 | 9005:0285:9005:02d5 Adaptec ASR-2405 (Voodoo40 Lite) |
61 | 9005:0285:9005:02d6 Adaptec 2445 (Voodoo44 Lite) | 61 | 9005:0285:9005:02d6 Adaptec ASR-2445 (Voodoo44 Lite) |
62 | 9005:0285:9005:02d7 Adaptec 2805 (Voodoo80 Lite) | 62 | 9005:0285:9005:02d7 Adaptec ASR-2805 (Voodoo80 Lite) |
63 | 9005:0285:9005:02d8 Adaptec 5405G (Voodoo40 PM) | ||
64 | 9005:0285:9005:02d9 Adaptec 5445G (Voodoo44 PM) | ||
65 | 9005:0285:9005:02da Adaptec 5805G (Voodoo80 PM) | ||
66 | 9005:0285:9005:02db Adaptec 5085G (Voodoo08 PM) | ||
67 | 9005:0285:9005:02dc Adaptec 51245G (Voodoo124 PM) | ||
68 | 9005:0285:9005:02dd Adaptec 51645G (Voodoo164 PM) | ||
69 | 9005:0285:9005:02de Adaptec 52445G (Voodoo244 PM) | ||
70 | 9005:0285:9005:02df Adaptec ASR-2045G (Voodoo04 Lite PM) | ||
71 | 9005:0285:9005:02e0 Adaptec ASR-2405G (Voodoo40 Lite PM) | ||
72 | 9005:0285:9005:02e1 Adaptec ASR-2445G (Voodoo44 Lite PM) | ||
73 | 9005:0285:9005:02e2 Adaptec ASR-2805G (Voodoo80 Lite PM) | ||
63 | 1011:0046:9005:0364 Adaptec 5400S (Mustang) | 74 | 1011:0046:9005:0364 Adaptec 5400S (Mustang) |
75 | 1011:0046:9005:0365 Adaptec 5400S (Mustang) | ||
64 | 9005:0287:9005:0800 Adaptec Themisto (Jupiter) | 76 | 9005:0287:9005:0800 Adaptec Themisto (Jupiter) |
65 | 9005:0200:9005:0200 Adaptec Themisto (Jupiter) | 77 | 9005:0200:9005:0200 Adaptec Themisto (Jupiter) |
66 | 9005:0286:9005:0800 Adaptec Callisto (Jupiter) | 78 | 9005:0286:9005:0800 Adaptec Callisto (Jupiter) |
67 | 1011:0046:9005:1364 Dell PERC 2/QC (Quad Channel, Mustang) | 79 | 1011:0046:9005:1364 Dell PERC 2/QC (Quad Channel, Mustang) |
80 | 1011:0046:9005:1365 Dell PERC 2/QC (Quad Channel, Mustang) | ||
68 | 1028:0001:1028:0001 Dell PERC 2/Si (Iguana) | 81 | 1028:0001:1028:0001 Dell PERC 2/Si (Iguana) |
69 | 1028:0003:1028:0003 Dell PERC 3/Si (SlimFast) | 82 | 1028:0003:1028:0003 Dell PERC 3/Si (SlimFast) |
70 | 1028:0002:1028:0002 Dell PERC 3/Di (Opal) | 83 | 1028:0002:1028:0002 Dell PERC 3/Di (Opal) |
71 | 1028:0004:1028:0004 Dell PERC 3/DiF (Iguana) | 84 | 1028:0004:1028:0004 Dell PERC 3/SiF (Iguana) |
85 | 1028:0004:1028:00d0 Dell PERC 3/DiF (Iguana) | ||
72 | 1028:0002:1028:00d1 Dell PERC 3/DiV (Viper) | 86 | 1028:0002:1028:00d1 Dell PERC 3/DiV (Viper) |
73 | 1028:0002:1028:00d9 Dell PERC 3/DiL (Lexus) | 87 | 1028:0002:1028:00d9 Dell PERC 3/DiL (Lexus) |
74 | 1028:000a:1028:0106 Dell PERC 3/DiJ (Jaguar) | 88 | 1028:000a:1028:0106 Dell PERC 3/DiJ (Jaguar) |
diff --git a/block/bsg.c b/block/bsg.c index 0b3b282f0384..5fb9b0bdbe85 100644 --- a/block/bsg.c +++ b/block/bsg.c | |||
@@ -740,8 +740,13 @@ static int bsg_put_device(struct bsg_device *bd) | |||
740 | mutex_lock(&bsg_mutex); | 740 | mutex_lock(&bsg_mutex); |
741 | 741 | ||
742 | do_free = atomic_dec_and_test(&bd->ref_count); | 742 | do_free = atomic_dec_and_test(&bd->ref_count); |
743 | if (!do_free) | 743 | if (!do_free) { |
744 | mutex_unlock(&bsg_mutex); | ||
744 | goto out; | 745 | goto out; |
746 | } | ||
747 | |||
748 | hlist_del(&bd->dev_list); | ||
749 | mutex_unlock(&bsg_mutex); | ||
745 | 750 | ||
746 | dprintk("%s: tearing down\n", bd->name); | 751 | dprintk("%s: tearing down\n", bd->name); |
747 | 752 | ||
@@ -757,10 +762,8 @@ static int bsg_put_device(struct bsg_device *bd) | |||
757 | */ | 762 | */ |
758 | ret = bsg_complete_all_commands(bd); | 763 | ret = bsg_complete_all_commands(bd); |
759 | 764 | ||
760 | hlist_del(&bd->dev_list); | ||
761 | kfree(bd); | 765 | kfree(bd); |
762 | out: | 766 | out: |
763 | mutex_unlock(&bsg_mutex); | ||
764 | kref_put(&q->bsg_dev.ref, bsg_kref_release_function); | 767 | kref_put(&q->bsg_dev.ref, bsg_kref_release_function); |
765 | if (do_free) | 768 | if (do_free) |
766 | blk_put_queue(q); | 769 | blk_put_queue(q); |
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 356fac6d105a..5a1cf2580e16 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c | |||
@@ -71,6 +71,10 @@ | |||
71 | 71 | ||
72 | #include "iscsi_iser.h" | 72 | #include "iscsi_iser.h" |
73 | 73 | ||
74 | static struct scsi_host_template iscsi_iser_sht; | ||
75 | static struct iscsi_transport iscsi_iser_transport; | ||
76 | static struct scsi_transport_template *iscsi_iser_scsi_transport; | ||
77 | |||
74 | static unsigned int iscsi_max_lun = 512; | 78 | static unsigned int iscsi_max_lun = 512; |
75 | module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); | 79 | module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); |
76 | 80 | ||
@@ -91,7 +95,6 @@ iscsi_iser_recv(struct iscsi_conn *conn, | |||
91 | struct iscsi_hdr *hdr, char *rx_data, int rx_data_len) | 95 | struct iscsi_hdr *hdr, char *rx_data, int rx_data_len) |
92 | { | 96 | { |
93 | int rc = 0; | 97 | int rc = 0; |
94 | uint32_t ret_itt; | ||
95 | int datalen; | 98 | int datalen; |
96 | int ahslen; | 99 | int ahslen; |
97 | 100 | ||
@@ -107,12 +110,7 @@ iscsi_iser_recv(struct iscsi_conn *conn, | |||
107 | /* read AHS */ | 110 | /* read AHS */ |
108 | ahslen = hdr->hlength * 4; | 111 | ahslen = hdr->hlength * 4; |
109 | 112 | ||
110 | /* verify itt (itt encoding: age+cid+itt) */ | 113 | rc = iscsi_complete_pdu(conn, hdr, rx_data, rx_data_len); |
111 | rc = iscsi_verify_itt(conn, hdr, &ret_itt); | ||
112 | |||
113 | if (!rc) | ||
114 | rc = iscsi_complete_pdu(conn, hdr, rx_data, rx_data_len); | ||
115 | |||
116 | if (rc && rc != ISCSI_ERR_NO_SCSI_CMD) | 114 | if (rc && rc != ISCSI_ERR_NO_SCSI_CMD) |
117 | goto error; | 115 | goto error; |
118 | 116 | ||
@@ -123,25 +121,33 @@ error: | |||
123 | 121 | ||
124 | 122 | ||
125 | /** | 123 | /** |
126 | * iscsi_iser_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands | 124 | * iscsi_iser_task_init - Initialize task |
125 | * @task: iscsi task | ||
127 | * | 126 | * |
128 | **/ | 127 | * Initialize the task for the scsi command or mgmt command. |
128 | */ | ||
129 | static int | 129 | static int |
130 | iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask) | 130 | iscsi_iser_task_init(struct iscsi_task *task) |
131 | { | 131 | { |
132 | struct iscsi_iser_conn *iser_conn = ctask->conn->dd_data; | 132 | struct iscsi_iser_conn *iser_conn = task->conn->dd_data; |
133 | struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; | 133 | struct iscsi_iser_task *iser_task = task->dd_data; |
134 | |||
135 | /* mgmt task */ | ||
136 | if (!task->sc) { | ||
137 | iser_task->desc.data = task->data; | ||
138 | return 0; | ||
139 | } | ||
134 | 140 | ||
135 | iser_ctask->command_sent = 0; | 141 | iser_task->command_sent = 0; |
136 | iser_ctask->iser_conn = iser_conn; | 142 | iser_task->iser_conn = iser_conn; |
137 | iser_ctask_rdma_init(iser_ctask); | 143 | iser_task_rdma_init(iser_task); |
138 | return 0; | 144 | return 0; |
139 | } | 145 | } |
140 | 146 | ||
141 | /** | 147 | /** |
142 | * iscsi_mtask_xmit - xmit management(immediate) task | 148 | * iscsi_iser_mtask_xmit - xmit management(immediate) task |
143 | * @conn: iscsi connection | 149 | * @conn: iscsi connection |
144 | * @mtask: task management task | 150 | * @task: task management task |
145 | * | 151 | * |
146 | * Notes: | 152 | * Notes: |
147 | * The function can return -EAGAIN in which case caller must | 153 | * The function can return -EAGAIN in which case caller must |
@@ -150,20 +156,19 @@ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask) | |||
150 | * | 156 | * |
151 | **/ | 157 | **/ |
152 | static int | 158 | static int |
153 | iscsi_iser_mtask_xmit(struct iscsi_conn *conn, | 159 | iscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task) |
154 | struct iscsi_mgmt_task *mtask) | ||
155 | { | 160 | { |
156 | int error = 0; | 161 | int error = 0; |
157 | 162 | ||
158 | debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt); | 163 | debug_scsi("task deq [cid %d itt 0x%x]\n", conn->id, task->itt); |
159 | 164 | ||
160 | error = iser_send_control(conn, mtask); | 165 | error = iser_send_control(conn, task); |
161 | 166 | ||
162 | /* since iser xmits control with zero copy, mtasks can not be recycled | 167 | /* since iser xmits control with zero copy, tasks can not be recycled |
163 | * right after sending them. | 168 | * right after sending them. |
164 | * The recycling scheme is based on whether a response is expected | 169 | * The recycling scheme is based on whether a response is expected |
165 | * - if yes, the mtask is recycled at iscsi_complete_pdu | 170 | * - if yes, the task is recycled at iscsi_complete_pdu |
166 | * - if no, the mtask is recycled at iser_snd_completion | 171 | * - if no, the task is recycled at iser_snd_completion |
167 | */ | 172 | */ |
168 | if (error && error != -ENOBUFS) | 173 | if (error && error != -ENOBUFS) |
169 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 174 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
@@ -172,97 +177,86 @@ iscsi_iser_mtask_xmit(struct iscsi_conn *conn, | |||
172 | } | 177 | } |
173 | 178 | ||
174 | static int | 179 | static int |
175 | iscsi_iser_ctask_xmit_unsol_data(struct iscsi_conn *conn, | 180 | iscsi_iser_task_xmit_unsol_data(struct iscsi_conn *conn, |
176 | struct iscsi_cmd_task *ctask) | 181 | struct iscsi_task *task) |
177 | { | 182 | { |
178 | struct iscsi_data hdr; | 183 | struct iscsi_data hdr; |
179 | int error = 0; | 184 | int error = 0; |
180 | 185 | ||
181 | /* Send data-out PDUs while there's still unsolicited data to send */ | 186 | /* Send data-out PDUs while there's still unsolicited data to send */ |
182 | while (ctask->unsol_count > 0) { | 187 | while (task->unsol_count > 0) { |
183 | iscsi_prep_unsolicit_data_pdu(ctask, &hdr); | 188 | iscsi_prep_unsolicit_data_pdu(task, &hdr); |
184 | debug_scsi("Sending data-out: itt 0x%x, data count %d\n", | 189 | debug_scsi("Sending data-out: itt 0x%x, data count %d\n", |
185 | hdr.itt, ctask->data_count); | 190 | hdr.itt, task->data_count); |
186 | 191 | ||
187 | /* the buffer description has been passed with the command */ | 192 | /* the buffer description has been passed with the command */ |
188 | /* Send the command */ | 193 | /* Send the command */ |
189 | error = iser_send_data_out(conn, ctask, &hdr); | 194 | error = iser_send_data_out(conn, task, &hdr); |
190 | if (error) { | 195 | if (error) { |
191 | ctask->unsol_datasn--; | 196 | task->unsol_datasn--; |
192 | goto iscsi_iser_ctask_xmit_unsol_data_exit; | 197 | goto iscsi_iser_task_xmit_unsol_data_exit; |
193 | } | 198 | } |
194 | ctask->unsol_count -= ctask->data_count; | 199 | task->unsol_count -= task->data_count; |
195 | debug_scsi("Need to send %d more as data-out PDUs\n", | 200 | debug_scsi("Need to send %d more as data-out PDUs\n", |
196 | ctask->unsol_count); | 201 | task->unsol_count); |
197 | } | 202 | } |
198 | 203 | ||
199 | iscsi_iser_ctask_xmit_unsol_data_exit: | 204 | iscsi_iser_task_xmit_unsol_data_exit: |
200 | return error; | 205 | return error; |
201 | } | 206 | } |
202 | 207 | ||
203 | static int | 208 | static int |
204 | iscsi_iser_ctask_xmit(struct iscsi_conn *conn, | 209 | iscsi_iser_task_xmit(struct iscsi_task *task) |
205 | struct iscsi_cmd_task *ctask) | ||
206 | { | 210 | { |
207 | struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; | 211 | struct iscsi_conn *conn = task->conn; |
212 | struct iscsi_iser_task *iser_task = task->dd_data; | ||
208 | int error = 0; | 213 | int error = 0; |
209 | 214 | ||
210 | if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) { | 215 | if (!task->sc) |
211 | BUG_ON(scsi_bufflen(ctask->sc) == 0); | 216 | return iscsi_iser_mtask_xmit(conn, task); |
217 | |||
218 | if (task->sc->sc_data_direction == DMA_TO_DEVICE) { | ||
219 | BUG_ON(scsi_bufflen(task->sc) == 0); | ||
212 | 220 | ||
213 | debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n", | 221 | debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n", |
214 | ctask->itt, scsi_bufflen(ctask->sc), | 222 | task->itt, scsi_bufflen(task->sc), |
215 | ctask->imm_count, ctask->unsol_count); | 223 | task->imm_count, task->unsol_count); |
216 | } | 224 | } |
217 | 225 | ||
218 | debug_scsi("ctask deq [cid %d itt 0x%x]\n", | 226 | debug_scsi("task deq [cid %d itt 0x%x]\n", |
219 | conn->id, ctask->itt); | 227 | conn->id, task->itt); |
220 | 228 | ||
221 | /* Send the cmd PDU */ | 229 | /* Send the cmd PDU */ |
222 | if (!iser_ctask->command_sent) { | 230 | if (!iser_task->command_sent) { |
223 | error = iser_send_command(conn, ctask); | 231 | error = iser_send_command(conn, task); |
224 | if (error) | 232 | if (error) |
225 | goto iscsi_iser_ctask_xmit_exit; | 233 | goto iscsi_iser_task_xmit_exit; |
226 | iser_ctask->command_sent = 1; | 234 | iser_task->command_sent = 1; |
227 | } | 235 | } |
228 | 236 | ||
229 | /* Send unsolicited data-out PDU(s) if necessary */ | 237 | /* Send unsolicited data-out PDU(s) if necessary */ |
230 | if (ctask->unsol_count) | 238 | if (task->unsol_count) |
231 | error = iscsi_iser_ctask_xmit_unsol_data(conn, ctask); | 239 | error = iscsi_iser_task_xmit_unsol_data(conn, task); |
232 | 240 | ||
233 | iscsi_iser_ctask_xmit_exit: | 241 | iscsi_iser_task_xmit_exit: |
234 | if (error && error != -ENOBUFS) | 242 | if (error && error != -ENOBUFS) |
235 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 243 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
236 | return error; | 244 | return error; |
237 | } | 245 | } |
238 | 246 | ||
239 | static void | 247 | static void |
240 | iscsi_iser_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | 248 | iscsi_iser_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task) |
241 | { | 249 | { |
242 | struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; | 250 | struct iscsi_iser_task *iser_task = task->dd_data; |
243 | 251 | ||
244 | if (iser_ctask->status == ISER_TASK_STATUS_STARTED) { | 252 | /* mgmt tasks do not need special cleanup */ |
245 | iser_ctask->status = ISER_TASK_STATUS_COMPLETED; | 253 | if (!task->sc) |
246 | iser_ctask_rdma_finalize(iser_ctask); | 254 | return; |
247 | } | ||
248 | } | ||
249 | |||
250 | static struct iser_conn * | ||
251 | iscsi_iser_ib_conn_lookup(__u64 ep_handle) | ||
252 | { | ||
253 | struct iser_conn *ib_conn; | ||
254 | struct iser_conn *uib_conn = (struct iser_conn *)(unsigned long)ep_handle; | ||
255 | 255 | ||
256 | mutex_lock(&ig.connlist_mutex); | 256 | if (iser_task->status == ISER_TASK_STATUS_STARTED) { |
257 | list_for_each_entry(ib_conn, &ig.connlist, conn_list) { | 257 | iser_task->status = ISER_TASK_STATUS_COMPLETED; |
258 | if (ib_conn == uib_conn) { | 258 | iser_task_rdma_finalize(iser_task); |
259 | mutex_unlock(&ig.connlist_mutex); | ||
260 | return ib_conn; | ||
261 | } | ||
262 | } | 259 | } |
263 | mutex_unlock(&ig.connlist_mutex); | ||
264 | iser_err("no conn exists for eph %llx\n",(unsigned long long)ep_handle); | ||
265 | return NULL; | ||
266 | } | 260 | } |
267 | 261 | ||
268 | static struct iscsi_cls_conn * | 262 | static struct iscsi_cls_conn * |
@@ -272,7 +266,7 @@ iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
272 | struct iscsi_cls_conn *cls_conn; | 266 | struct iscsi_cls_conn *cls_conn; |
273 | struct iscsi_iser_conn *iser_conn; | 267 | struct iscsi_iser_conn *iser_conn; |
274 | 268 | ||
275 | cls_conn = iscsi_conn_setup(cls_session, conn_idx); | 269 | cls_conn = iscsi_conn_setup(cls_session, sizeof(*iser_conn), conn_idx); |
276 | if (!cls_conn) | 270 | if (!cls_conn) |
277 | return NULL; | 271 | return NULL; |
278 | conn = cls_conn->dd_data; | 272 | conn = cls_conn->dd_data; |
@@ -283,21 +277,11 @@ iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
283 | */ | 277 | */ |
284 | conn->max_recv_dlength = 128; | 278 | conn->max_recv_dlength = 128; |
285 | 279 | ||
286 | iser_conn = kzalloc(sizeof(*iser_conn), GFP_KERNEL); | 280 | iser_conn = conn->dd_data; |
287 | if (!iser_conn) | ||
288 | goto conn_alloc_fail; | ||
289 | |||
290 | /* currently this is the only field which need to be initiated */ | ||
291 | rwlock_init(&iser_conn->lock); | ||
292 | |||
293 | conn->dd_data = iser_conn; | 281 | conn->dd_data = iser_conn; |
294 | iser_conn->iscsi_conn = conn; | 282 | iser_conn->iscsi_conn = conn; |
295 | 283 | ||
296 | return cls_conn; | 284 | return cls_conn; |
297 | |||
298 | conn_alloc_fail: | ||
299 | iscsi_conn_teardown(cls_conn); | ||
300 | return NULL; | ||
301 | } | 285 | } |
302 | 286 | ||
303 | static void | 287 | static void |
@@ -305,11 +289,18 @@ iscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn) | |||
305 | { | 289 | { |
306 | struct iscsi_conn *conn = cls_conn->dd_data; | 290 | struct iscsi_conn *conn = cls_conn->dd_data; |
307 | struct iscsi_iser_conn *iser_conn = conn->dd_data; | 291 | struct iscsi_iser_conn *iser_conn = conn->dd_data; |
292 | struct iser_conn *ib_conn = iser_conn->ib_conn; | ||
308 | 293 | ||
309 | iscsi_conn_teardown(cls_conn); | 294 | iscsi_conn_teardown(cls_conn); |
310 | if (iser_conn->ib_conn) | 295 | /* |
311 | iser_conn->ib_conn->iser_conn = NULL; | 296 | * Userspace will normally call the stop callback and |
312 | kfree(iser_conn); | 297 | * already have freed the ib_conn, but if it goofed up then |
298 | * we free it here. | ||
299 | */ | ||
300 | if (ib_conn) { | ||
301 | ib_conn->iser_conn = NULL; | ||
302 | iser_conn_put(ib_conn); | ||
303 | } | ||
313 | } | 304 | } |
314 | 305 | ||
315 | static int | 306 | static int |
@@ -320,6 +311,7 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, | |||
320 | struct iscsi_conn *conn = cls_conn->dd_data; | 311 | struct iscsi_conn *conn = cls_conn->dd_data; |
321 | struct iscsi_iser_conn *iser_conn; | 312 | struct iscsi_iser_conn *iser_conn; |
322 | struct iser_conn *ib_conn; | 313 | struct iser_conn *ib_conn; |
314 | struct iscsi_endpoint *ep; | ||
323 | int error; | 315 | int error; |
324 | 316 | ||
325 | error = iscsi_conn_bind(cls_session, cls_conn, is_leading); | 317 | error = iscsi_conn_bind(cls_session, cls_conn, is_leading); |
@@ -328,12 +320,14 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, | |||
328 | 320 | ||
329 | /* the transport ep handle comes from user space so it must be | 321 | /* the transport ep handle comes from user space so it must be |
330 | * verified against the global ib connections list */ | 322 | * verified against the global ib connections list */ |
331 | ib_conn = iscsi_iser_ib_conn_lookup(transport_eph); | 323 | ep = iscsi_lookup_endpoint(transport_eph); |
332 | if (!ib_conn) { | 324 | if (!ep) { |
333 | iser_err("can't bind eph %llx\n", | 325 | iser_err("can't bind eph %llx\n", |
334 | (unsigned long long)transport_eph); | 326 | (unsigned long long)transport_eph); |
335 | return -EINVAL; | 327 | return -EINVAL; |
336 | } | 328 | } |
329 | ib_conn = ep->dd_data; | ||
330 | |||
337 | /* binds the iSER connection retrieved from the previously | 331 | /* binds the iSER connection retrieved from the previously |
338 | * connected ep_handle to the iSCSI layer connection. exchanges | 332 | * connected ep_handle to the iSCSI layer connection. exchanges |
339 | * connection pointers */ | 333 | * connection pointers */ |
@@ -341,10 +335,30 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, | |||
341 | iser_conn = conn->dd_data; | 335 | iser_conn = conn->dd_data; |
342 | ib_conn->iser_conn = iser_conn; | 336 | ib_conn->iser_conn = iser_conn; |
343 | iser_conn->ib_conn = ib_conn; | 337 | iser_conn->ib_conn = ib_conn; |
338 | iser_conn_get(ib_conn); | ||
339 | return 0; | ||
340 | } | ||
344 | 341 | ||
345 | conn->recv_lock = &iser_conn->lock; | 342 | static void |
343 | iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | ||
344 | { | ||
345 | struct iscsi_conn *conn = cls_conn->dd_data; | ||
346 | struct iscsi_iser_conn *iser_conn = conn->dd_data; | ||
347 | struct iser_conn *ib_conn = iser_conn->ib_conn; | ||
346 | 348 | ||
347 | return 0; | 349 | /* |
350 | * Userspace may have goofed up and not bound the connection or | ||
351 | * might have only partially setup the connection. | ||
352 | */ | ||
353 | if (ib_conn) { | ||
354 | iscsi_conn_stop(cls_conn, flag); | ||
355 | /* | ||
356 | * There is no unbind event so the stop callback | ||
357 | * must release the ref from the bind. | ||
358 | */ | ||
359 | iser_conn_put(ib_conn); | ||
360 | } | ||
361 | iser_conn->ib_conn = NULL; | ||
348 | } | 362 | } |
349 | 363 | ||
350 | static int | 364 | static int |
@@ -360,55 +374,75 @@ iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) | |||
360 | return iscsi_conn_start(cls_conn); | 374 | return iscsi_conn_start(cls_conn); |
361 | } | 375 | } |
362 | 376 | ||
363 | static struct iscsi_transport iscsi_iser_transport; | 377 | static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session) |
378 | { | ||
379 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); | ||
380 | |||
381 | iscsi_host_remove(shost); | ||
382 | iscsi_host_free(shost); | ||
383 | } | ||
364 | 384 | ||
365 | static struct iscsi_cls_session * | 385 | static struct iscsi_cls_session * |
366 | iscsi_iser_session_create(struct iscsi_transport *iscsit, | 386 | iscsi_iser_session_create(struct iscsi_endpoint *ep, |
367 | struct scsi_transport_template *scsit, | 387 | uint16_t cmds_max, uint16_t qdepth, |
368 | uint16_t cmds_max, uint16_t qdepth, | 388 | uint32_t initial_cmdsn, uint32_t *hostno) |
369 | uint32_t initial_cmdsn, uint32_t *hostno) | ||
370 | { | 389 | { |
371 | struct iscsi_cls_session *cls_session; | 390 | struct iscsi_cls_session *cls_session; |
372 | struct iscsi_session *session; | 391 | struct iscsi_session *session; |
392 | struct Scsi_Host *shost; | ||
373 | int i; | 393 | int i; |
374 | uint32_t hn; | 394 | struct iscsi_task *task; |
375 | struct iscsi_cmd_task *ctask; | 395 | struct iscsi_iser_task *iser_task; |
376 | struct iscsi_mgmt_task *mtask; | 396 | struct iser_conn *ib_conn; |
377 | struct iscsi_iser_cmd_task *iser_ctask; | 397 | |
378 | struct iser_desc *desc; | 398 | shost = iscsi_host_alloc(&iscsi_iser_sht, 0, ISCSI_MAX_CMD_PER_LUN); |
399 | if (!shost) | ||
400 | return NULL; | ||
401 | shost->transportt = iscsi_iser_scsi_transport; | ||
402 | shost->max_lun = iscsi_max_lun; | ||
403 | shost->max_id = 0; | ||
404 | shost->max_channel = 0; | ||
405 | shost->max_cmd_len = 16; | ||
406 | |||
407 | /* | ||
408 | * older userspace tools (before 2.0-870) did not pass us | ||
409 | * the leading conn's ep so this will be NULL; | ||
410 | */ | ||
411 | if (ep) | ||
412 | ib_conn = ep->dd_data; | ||
413 | |||
414 | if (iscsi_host_add(shost, | ||
415 | ep ? ib_conn->device->ib_device->dma_device : NULL)) | ||
416 | goto free_host; | ||
417 | *hostno = shost->host_no; | ||
379 | 418 | ||
380 | /* | 419 | /* |
381 | * we do not support setting can_queue cmd_per_lun from userspace yet | 420 | * we do not support setting can_queue cmd_per_lun from userspace yet |
382 | * because we preallocate so many resources | 421 | * because we preallocate so many resources |
383 | */ | 422 | */ |
384 | cls_session = iscsi_session_setup(iscsit, scsit, | 423 | cls_session = iscsi_session_setup(&iscsi_iser_transport, shost, |
385 | ISCSI_DEF_XMIT_CMDS_MAX, | 424 | ISCSI_DEF_XMIT_CMDS_MAX, |
386 | ISCSI_MAX_CMD_PER_LUN, | 425 | sizeof(struct iscsi_iser_task), |
387 | sizeof(struct iscsi_iser_cmd_task), | 426 | initial_cmdsn, 0); |
388 | sizeof(struct iser_desc), | ||
389 | initial_cmdsn, &hn); | ||
390 | if (!cls_session) | 427 | if (!cls_session) |
391 | return NULL; | 428 | goto remove_host; |
392 | 429 | session = cls_session->dd_data; | |
393 | *hostno = hn; | ||
394 | session = class_to_transport_session(cls_session); | ||
395 | 430 | ||
431 | shost->can_queue = session->scsi_cmds_max; | ||
396 | /* libiscsi setup itts, data and pool so just set desc fields */ | 432 | /* libiscsi setup itts, data and pool so just set desc fields */ |
397 | for (i = 0; i < session->cmds_max; i++) { | 433 | for (i = 0; i < session->cmds_max; i++) { |
398 | ctask = session->cmds[i]; | 434 | task = session->cmds[i]; |
399 | iser_ctask = ctask->dd_data; | 435 | iser_task = task->dd_data; |
400 | ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header; | 436 | task->hdr = (struct iscsi_cmd *)&iser_task->desc.iscsi_header; |
401 | ctask->hdr_max = sizeof(iser_ctask->desc.iscsi_header); | 437 | task->hdr_max = sizeof(iser_task->desc.iscsi_header); |
402 | } | ||
403 | |||
404 | for (i = 0; i < session->mgmtpool_max; i++) { | ||
405 | mtask = session->mgmt_cmds[i]; | ||
406 | desc = mtask->dd_data; | ||
407 | mtask->hdr = &desc->iscsi_header; | ||
408 | desc->data = mtask->data; | ||
409 | } | 438 | } |
410 | |||
411 | return cls_session; | 439 | return cls_session; |
440 | |||
441 | remove_host: | ||
442 | iscsi_host_remove(shost); | ||
443 | free_host: | ||
444 | iscsi_host_free(shost); | ||
445 | return NULL; | ||
412 | } | 446 | } |
413 | 447 | ||
414 | static int | 448 | static int |
@@ -481,34 +515,37 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *s | |||
481 | stats->custom[3].value = conn->fmr_unalign_cnt; | 515 | stats->custom[3].value = conn->fmr_unalign_cnt; |
482 | } | 516 | } |
483 | 517 | ||
484 | static int | 518 | static struct iscsi_endpoint * |
485 | iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking, | 519 | iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking) |
486 | __u64 *ep_handle) | ||
487 | { | 520 | { |
488 | int err; | 521 | int err; |
489 | struct iser_conn *ib_conn; | 522 | struct iser_conn *ib_conn; |
523 | struct iscsi_endpoint *ep; | ||
490 | 524 | ||
491 | err = iser_conn_init(&ib_conn); | 525 | ep = iscsi_create_endpoint(sizeof(*ib_conn)); |
492 | if (err) | 526 | if (!ep) |
493 | goto out; | 527 | return ERR_PTR(-ENOMEM); |
494 | 528 | ||
495 | err = iser_connect(ib_conn, NULL, (struct sockaddr_in *)dst_addr, non_blocking); | 529 | ib_conn = ep->dd_data; |
496 | if (!err) | 530 | ib_conn->ep = ep; |
497 | *ep_handle = (__u64)(unsigned long)ib_conn; | 531 | iser_conn_init(ib_conn); |
498 | 532 | ||
499 | out: | 533 | err = iser_connect(ib_conn, NULL, (struct sockaddr_in *)dst_addr, |
500 | return err; | 534 | non_blocking); |
535 | if (err) { | ||
536 | iscsi_destroy_endpoint(ep); | ||
537 | return ERR_PTR(err); | ||
538 | } | ||
539 | return ep; | ||
501 | } | 540 | } |
502 | 541 | ||
503 | static int | 542 | static int |
504 | iscsi_iser_ep_poll(__u64 ep_handle, int timeout_ms) | 543 | iscsi_iser_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) |
505 | { | 544 | { |
506 | struct iser_conn *ib_conn = iscsi_iser_ib_conn_lookup(ep_handle); | 545 | struct iser_conn *ib_conn; |
507 | int rc; | 546 | int rc; |
508 | 547 | ||
509 | if (!ib_conn) | 548 | ib_conn = ep->dd_data; |
510 | return -EINVAL; | ||
511 | |||
512 | rc = wait_event_interruptible_timeout(ib_conn->wait, | 549 | rc = wait_event_interruptible_timeout(ib_conn->wait, |
513 | ib_conn->state == ISER_CONN_UP, | 550 | ib_conn->state == ISER_CONN_UP, |
514 | msecs_to_jiffies(timeout_ms)); | 551 | msecs_to_jiffies(timeout_ms)); |
@@ -530,13 +567,21 @@ iscsi_iser_ep_poll(__u64 ep_handle, int timeout_ms) | |||
530 | } | 567 | } |
531 | 568 | ||
532 | static void | 569 | static void |
533 | iscsi_iser_ep_disconnect(__u64 ep_handle) | 570 | iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep) |
534 | { | 571 | { |
535 | struct iser_conn *ib_conn; | 572 | struct iser_conn *ib_conn; |
536 | 573 | ||
537 | ib_conn = iscsi_iser_ib_conn_lookup(ep_handle); | 574 | ib_conn = ep->dd_data; |
538 | if (!ib_conn) | 575 | if (ib_conn->iser_conn) |
539 | return; | 576 | /* |
577 | * Must suspend xmit path if the ep is bound to the | ||
578 | * iscsi_conn, so we know we are not accessing the ib_conn | ||
579 | * when we free it. | ||
580 | * | ||
581 | * This may not be bound if the ep poll failed. | ||
582 | */ | ||
583 | iscsi_suspend_tx(ib_conn->iser_conn->iscsi_conn); | ||
584 | |||
540 | 585 | ||
541 | iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state); | 586 | iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state); |
542 | iser_conn_terminate(ib_conn); | 587 | iser_conn_terminate(ib_conn); |
@@ -547,7 +592,6 @@ static struct scsi_host_template iscsi_iser_sht = { | |||
547 | .name = "iSCSI Initiator over iSER, v." DRV_VER, | 592 | .name = "iSCSI Initiator over iSER, v." DRV_VER, |
548 | .queuecommand = iscsi_queuecommand, | 593 | .queuecommand = iscsi_queuecommand, |
549 | .change_queue_depth = iscsi_change_queue_depth, | 594 | .change_queue_depth = iscsi_change_queue_depth, |
550 | .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, | ||
551 | .sg_tablesize = ISCSI_ISER_SG_TABLESIZE, | 595 | .sg_tablesize = ISCSI_ISER_SG_TABLESIZE, |
552 | .max_sectors = 1024, | 596 | .max_sectors = 1024, |
553 | .cmd_per_lun = ISCSI_MAX_CMD_PER_LUN, | 597 | .cmd_per_lun = ISCSI_MAX_CMD_PER_LUN, |
@@ -581,17 +625,14 @@ static struct iscsi_transport iscsi_iser_transport = { | |||
581 | ISCSI_USERNAME | ISCSI_PASSWORD | | 625 | ISCSI_USERNAME | ISCSI_PASSWORD | |
582 | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | | 626 | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | |
583 | ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | | 627 | ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | |
584 | ISCSI_PING_TMO | ISCSI_RECV_TMO, | 628 | ISCSI_PING_TMO | ISCSI_RECV_TMO | |
629 | ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, | ||
585 | .host_param_mask = ISCSI_HOST_HWADDRESS | | 630 | .host_param_mask = ISCSI_HOST_HWADDRESS | |
586 | ISCSI_HOST_NETDEV_NAME | | 631 | ISCSI_HOST_NETDEV_NAME | |
587 | ISCSI_HOST_INITIATOR_NAME, | 632 | ISCSI_HOST_INITIATOR_NAME, |
588 | .host_template = &iscsi_iser_sht, | ||
589 | .conndata_size = sizeof(struct iscsi_conn), | ||
590 | .max_lun = ISCSI_ISER_MAX_LUN, | ||
591 | .max_cmd_len = ISCSI_ISER_MAX_CMD_LEN, | ||
592 | /* session management */ | 633 | /* session management */ |
593 | .create_session = iscsi_iser_session_create, | 634 | .create_session = iscsi_iser_session_create, |
594 | .destroy_session = iscsi_session_teardown, | 635 | .destroy_session = iscsi_iser_session_destroy, |
595 | /* connection management */ | 636 | /* connection management */ |
596 | .create_conn = iscsi_iser_conn_create, | 637 | .create_conn = iscsi_iser_conn_create, |
597 | .bind_conn = iscsi_iser_conn_bind, | 638 | .bind_conn = iscsi_iser_conn_bind, |
@@ -600,17 +641,16 @@ static struct iscsi_transport iscsi_iser_transport = { | |||
600 | .get_conn_param = iscsi_conn_get_param, | 641 | .get_conn_param = iscsi_conn_get_param, |
601 | .get_session_param = iscsi_session_get_param, | 642 | .get_session_param = iscsi_session_get_param, |
602 | .start_conn = iscsi_iser_conn_start, | 643 | .start_conn = iscsi_iser_conn_start, |
603 | .stop_conn = iscsi_conn_stop, | 644 | .stop_conn = iscsi_iser_conn_stop, |
604 | /* iscsi host params */ | 645 | /* iscsi host params */ |
605 | .get_host_param = iscsi_host_get_param, | 646 | .get_host_param = iscsi_host_get_param, |
606 | .set_host_param = iscsi_host_set_param, | 647 | .set_host_param = iscsi_host_set_param, |
607 | /* IO */ | 648 | /* IO */ |
608 | .send_pdu = iscsi_conn_send_pdu, | 649 | .send_pdu = iscsi_conn_send_pdu, |
609 | .get_stats = iscsi_iser_conn_get_stats, | 650 | .get_stats = iscsi_iser_conn_get_stats, |
610 | .init_cmd_task = iscsi_iser_cmd_init, | 651 | .init_task = iscsi_iser_task_init, |
611 | .xmit_cmd_task = iscsi_iser_ctask_xmit, | 652 | .xmit_task = iscsi_iser_task_xmit, |
612 | .xmit_mgmt_task = iscsi_iser_mtask_xmit, | 653 | .cleanup_task = iscsi_iser_cleanup_task, |
613 | .cleanup_cmd_task = iscsi_iser_cleanup_ctask, | ||
614 | /* recovery */ | 654 | /* recovery */ |
615 | .session_recovery_timedout = iscsi_session_recovery_timedout, | 655 | .session_recovery_timedout = iscsi_session_recovery_timedout, |
616 | 656 | ||
@@ -630,8 +670,6 @@ static int __init iser_init(void) | |||
630 | return -EINVAL; | 670 | return -EINVAL; |
631 | } | 671 | } |
632 | 672 | ||
633 | iscsi_iser_transport.max_lun = iscsi_max_lun; | ||
634 | |||
635 | memset(&ig, 0, sizeof(struct iser_global)); | 673 | memset(&ig, 0, sizeof(struct iser_global)); |
636 | 674 | ||
637 | ig.desc_cache = kmem_cache_create("iser_descriptors", | 675 | ig.desc_cache = kmem_cache_create("iser_descriptors", |
@@ -647,7 +685,9 @@ static int __init iser_init(void) | |||
647 | mutex_init(&ig.connlist_mutex); | 685 | mutex_init(&ig.connlist_mutex); |
648 | INIT_LIST_HEAD(&ig.connlist); | 686 | INIT_LIST_HEAD(&ig.connlist); |
649 | 687 | ||
650 | if (!iscsi_register_transport(&iscsi_iser_transport)) { | 688 | iscsi_iser_scsi_transport = iscsi_register_transport( |
689 | &iscsi_iser_transport); | ||
690 | if (!iscsi_iser_scsi_transport) { | ||
651 | iser_err("iscsi_register_transport failed\n"); | 691 | iser_err("iscsi_register_transport failed\n"); |
652 | err = -EINVAL; | 692 | err = -EINVAL; |
653 | goto register_transport_failure; | 693 | goto register_transport_failure; |
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 0e10703cf59e..81a82628a5f1 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h | |||
@@ -94,7 +94,6 @@ | |||
94 | /* support upto 512KB in one RDMA */ | 94 | /* support upto 512KB in one RDMA */ |
95 | #define ISCSI_ISER_SG_TABLESIZE (0x80000 >> SHIFT_4K) | 95 | #define ISCSI_ISER_SG_TABLESIZE (0x80000 >> SHIFT_4K) |
96 | #define ISCSI_ISER_MAX_LUN 256 | 96 | #define ISCSI_ISER_MAX_LUN 256 |
97 | #define ISCSI_ISER_MAX_CMD_LEN 16 | ||
98 | 97 | ||
99 | /* QP settings */ | 98 | /* QP settings */ |
100 | /* Maximal bounds on received asynchronous PDUs */ | 99 | /* Maximal bounds on received asynchronous PDUs */ |
@@ -172,7 +171,8 @@ struct iser_data_buf { | |||
172 | /* fwd declarations */ | 171 | /* fwd declarations */ |
173 | struct iser_device; | 172 | struct iser_device; |
174 | struct iscsi_iser_conn; | 173 | struct iscsi_iser_conn; |
175 | struct iscsi_iser_cmd_task; | 174 | struct iscsi_iser_task; |
175 | struct iscsi_endpoint; | ||
176 | 176 | ||
177 | struct iser_mem_reg { | 177 | struct iser_mem_reg { |
178 | u32 lkey; | 178 | u32 lkey; |
@@ -196,7 +196,7 @@ struct iser_regd_buf { | |||
196 | #define MAX_REGD_BUF_VECTOR_LEN 2 | 196 | #define MAX_REGD_BUF_VECTOR_LEN 2 |
197 | 197 | ||
198 | struct iser_dto { | 198 | struct iser_dto { |
199 | struct iscsi_iser_cmd_task *ctask; | 199 | struct iscsi_iser_task *task; |
200 | struct iser_conn *ib_conn; | 200 | struct iser_conn *ib_conn; |
201 | int notify_enable; | 201 | int notify_enable; |
202 | 202 | ||
@@ -240,7 +240,9 @@ struct iser_device { | |||
240 | 240 | ||
241 | struct iser_conn { | 241 | struct iser_conn { |
242 | struct iscsi_iser_conn *iser_conn; /* iser conn for upcalls */ | 242 | struct iscsi_iser_conn *iser_conn; /* iser conn for upcalls */ |
243 | struct iscsi_endpoint *ep; | ||
243 | enum iser_ib_conn_state state; /* rdma connection state */ | 244 | enum iser_ib_conn_state state; /* rdma connection state */ |
245 | atomic_t refcount; | ||
244 | spinlock_t lock; /* used for state changes */ | 246 | spinlock_t lock; /* used for state changes */ |
245 | struct iser_device *device; /* device context */ | 247 | struct iser_device *device; /* device context */ |
246 | struct rdma_cm_id *cma_id; /* CMA ID */ | 248 | struct rdma_cm_id *cma_id; /* CMA ID */ |
@@ -259,11 +261,9 @@ struct iser_conn { | |||
259 | struct iscsi_iser_conn { | 261 | struct iscsi_iser_conn { |
260 | struct iscsi_conn *iscsi_conn;/* ptr to iscsi conn */ | 262 | struct iscsi_conn *iscsi_conn;/* ptr to iscsi conn */ |
261 | struct iser_conn *ib_conn; /* iSER IB conn */ | 263 | struct iser_conn *ib_conn; /* iSER IB conn */ |
262 | |||
263 | rwlock_t lock; | ||
264 | }; | 264 | }; |
265 | 265 | ||
266 | struct iscsi_iser_cmd_task { | 266 | struct iscsi_iser_task { |
267 | struct iser_desc desc; | 267 | struct iser_desc desc; |
268 | struct iscsi_iser_conn *iser_conn; | 268 | struct iscsi_iser_conn *iser_conn; |
269 | enum iser_task_status status; | 269 | enum iser_task_status status; |
@@ -296,22 +296,26 @@ extern int iser_debug_level; | |||
296 | /* allocate connection resources needed for rdma functionality */ | 296 | /* allocate connection resources needed for rdma functionality */ |
297 | int iser_conn_set_full_featured_mode(struct iscsi_conn *conn); | 297 | int iser_conn_set_full_featured_mode(struct iscsi_conn *conn); |
298 | 298 | ||
299 | int iser_send_control(struct iscsi_conn *conn, | 299 | int iser_send_control(struct iscsi_conn *conn, |
300 | struct iscsi_mgmt_task *mtask); | 300 | struct iscsi_task *task); |
301 | 301 | ||
302 | int iser_send_command(struct iscsi_conn *conn, | 302 | int iser_send_command(struct iscsi_conn *conn, |
303 | struct iscsi_cmd_task *ctask); | 303 | struct iscsi_task *task); |
304 | 304 | ||
305 | int iser_send_data_out(struct iscsi_conn *conn, | 305 | int iser_send_data_out(struct iscsi_conn *conn, |
306 | struct iscsi_cmd_task *ctask, | 306 | struct iscsi_task *task, |
307 | struct iscsi_data *hdr); | 307 | struct iscsi_data *hdr); |
308 | 308 | ||
309 | void iscsi_iser_recv(struct iscsi_conn *conn, | 309 | void iscsi_iser_recv(struct iscsi_conn *conn, |
310 | struct iscsi_hdr *hdr, | 310 | struct iscsi_hdr *hdr, |
311 | char *rx_data, | 311 | char *rx_data, |
312 | int rx_data_len); | 312 | int rx_data_len); |
313 | 313 | ||
314 | int iser_conn_init(struct iser_conn **ib_conn); | 314 | void iser_conn_init(struct iser_conn *ib_conn); |
315 | |||
316 | void iser_conn_get(struct iser_conn *ib_conn); | ||
317 | |||
318 | void iser_conn_put(struct iser_conn *ib_conn); | ||
315 | 319 | ||
316 | void iser_conn_terminate(struct iser_conn *ib_conn); | 320 | void iser_conn_terminate(struct iser_conn *ib_conn); |
317 | 321 | ||
@@ -320,9 +324,9 @@ void iser_rcv_completion(struct iser_desc *desc, | |||
320 | 324 | ||
321 | void iser_snd_completion(struct iser_desc *desc); | 325 | void iser_snd_completion(struct iser_desc *desc); |
322 | 326 | ||
323 | void iser_ctask_rdma_init(struct iscsi_iser_cmd_task *ctask); | 327 | void iser_task_rdma_init(struct iscsi_iser_task *task); |
324 | 328 | ||
325 | void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *ctask); | 329 | void iser_task_rdma_finalize(struct iscsi_iser_task *task); |
326 | 330 | ||
327 | void iser_dto_buffs_release(struct iser_dto *dto); | 331 | void iser_dto_buffs_release(struct iser_dto *dto); |
328 | 332 | ||
@@ -332,10 +336,10 @@ void iser_reg_single(struct iser_device *device, | |||
332 | struct iser_regd_buf *regd_buf, | 336 | struct iser_regd_buf *regd_buf, |
333 | enum dma_data_direction direction); | 337 | enum dma_data_direction direction); |
334 | 338 | ||
335 | void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask, | 339 | void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *task, |
336 | enum iser_data_dir cmd_dir); | 340 | enum iser_data_dir cmd_dir); |
337 | 341 | ||
338 | int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *ctask, | 342 | int iser_reg_rdma_mem(struct iscsi_iser_task *task, |
339 | enum iser_data_dir cmd_dir); | 343 | enum iser_data_dir cmd_dir); |
340 | 344 | ||
341 | int iser_connect(struct iser_conn *ib_conn, | 345 | int iser_connect(struct iser_conn *ib_conn, |
@@ -355,10 +359,10 @@ int iser_post_send(struct iser_desc *tx_desc); | |||
355 | int iser_conn_state_comp(struct iser_conn *ib_conn, | 359 | int iser_conn_state_comp(struct iser_conn *ib_conn, |
356 | enum iser_ib_conn_state comp); | 360 | enum iser_ib_conn_state comp); |
357 | 361 | ||
358 | int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask, | 362 | int iser_dma_map_task_data(struct iscsi_iser_task *iser_task, |
359 | struct iser_data_buf *data, | 363 | struct iser_data_buf *data, |
360 | enum iser_data_dir iser_dir, | 364 | enum iser_data_dir iser_dir, |
361 | enum dma_data_direction dma_dir); | 365 | enum dma_data_direction dma_dir); |
362 | 366 | ||
363 | void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask); | 367 | void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task); |
364 | #endif | 368 | #endif |
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 31ad498bdc51..cdd283189047 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c | |||
@@ -64,46 +64,46 @@ static void iser_dto_add_regd_buff(struct iser_dto *dto, | |||
64 | 64 | ||
65 | /* Register user buffer memory and initialize passive rdma | 65 | /* Register user buffer memory and initialize passive rdma |
66 | * dto descriptor. Total data size is stored in | 66 | * dto descriptor. Total data size is stored in |
67 | * iser_ctask->data[ISER_DIR_IN].data_len | 67 | * iser_task->data[ISER_DIR_IN].data_len |
68 | */ | 68 | */ |
69 | static int iser_prepare_read_cmd(struct iscsi_cmd_task *ctask, | 69 | static int iser_prepare_read_cmd(struct iscsi_task *task, |
70 | unsigned int edtl) | 70 | unsigned int edtl) |
71 | 71 | ||
72 | { | 72 | { |
73 | struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; | 73 | struct iscsi_iser_task *iser_task = task->dd_data; |
74 | struct iser_regd_buf *regd_buf; | 74 | struct iser_regd_buf *regd_buf; |
75 | int err; | 75 | int err; |
76 | struct iser_hdr *hdr = &iser_ctask->desc.iser_header; | 76 | struct iser_hdr *hdr = &iser_task->desc.iser_header; |
77 | struct iser_data_buf *buf_in = &iser_ctask->data[ISER_DIR_IN]; | 77 | struct iser_data_buf *buf_in = &iser_task->data[ISER_DIR_IN]; |
78 | 78 | ||
79 | err = iser_dma_map_task_data(iser_ctask, | 79 | err = iser_dma_map_task_data(iser_task, |
80 | buf_in, | 80 | buf_in, |
81 | ISER_DIR_IN, | 81 | ISER_DIR_IN, |
82 | DMA_FROM_DEVICE); | 82 | DMA_FROM_DEVICE); |
83 | if (err) | 83 | if (err) |
84 | return err; | 84 | return err; |
85 | 85 | ||
86 | if (edtl > iser_ctask->data[ISER_DIR_IN].data_len) { | 86 | if (edtl > iser_task->data[ISER_DIR_IN].data_len) { |
87 | iser_err("Total data length: %ld, less than EDTL: " | 87 | iser_err("Total data length: %ld, less than EDTL: " |
88 | "%d, in READ cmd BHS itt: %d, conn: 0x%p\n", | 88 | "%d, in READ cmd BHS itt: %d, conn: 0x%p\n", |
89 | iser_ctask->data[ISER_DIR_IN].data_len, edtl, | 89 | iser_task->data[ISER_DIR_IN].data_len, edtl, |
90 | ctask->itt, iser_ctask->iser_conn); | 90 | task->itt, iser_task->iser_conn); |
91 | return -EINVAL; | 91 | return -EINVAL; |
92 | } | 92 | } |
93 | 93 | ||
94 | err = iser_reg_rdma_mem(iser_ctask,ISER_DIR_IN); | 94 | err = iser_reg_rdma_mem(iser_task,ISER_DIR_IN); |
95 | if (err) { | 95 | if (err) { |
96 | iser_err("Failed to set up Data-IN RDMA\n"); | 96 | iser_err("Failed to set up Data-IN RDMA\n"); |
97 | return err; | 97 | return err; |
98 | } | 98 | } |
99 | regd_buf = &iser_ctask->rdma_regd[ISER_DIR_IN]; | 99 | regd_buf = &iser_task->rdma_regd[ISER_DIR_IN]; |
100 | 100 | ||
101 | hdr->flags |= ISER_RSV; | 101 | hdr->flags |= ISER_RSV; |
102 | hdr->read_stag = cpu_to_be32(regd_buf->reg.rkey); | 102 | hdr->read_stag = cpu_to_be32(regd_buf->reg.rkey); |
103 | hdr->read_va = cpu_to_be64(regd_buf->reg.va); | 103 | hdr->read_va = cpu_to_be64(regd_buf->reg.va); |
104 | 104 | ||
105 | iser_dbg("Cmd itt:%d READ tags RKEY:%#.4X VA:%#llX\n", | 105 | iser_dbg("Cmd itt:%d READ tags RKEY:%#.4X VA:%#llX\n", |
106 | ctask->itt, regd_buf->reg.rkey, | 106 | task->itt, regd_buf->reg.rkey, |
107 | (unsigned long long)regd_buf->reg.va); | 107 | (unsigned long long)regd_buf->reg.va); |
108 | 108 | ||
109 | return 0; | 109 | return 0; |
@@ -111,43 +111,43 @@ static int iser_prepare_read_cmd(struct iscsi_cmd_task *ctask, | |||
111 | 111 | ||
112 | /* Register user buffer memory and initialize passive rdma | 112 | /* Register user buffer memory and initialize passive rdma |
113 | * dto descriptor. Total data size is stored in | 113 | * dto descriptor. Total data size is stored in |
114 | * ctask->data[ISER_DIR_OUT].data_len | 114 | * task->data[ISER_DIR_OUT].data_len |
115 | */ | 115 | */ |
116 | static int | 116 | static int |
117 | iser_prepare_write_cmd(struct iscsi_cmd_task *ctask, | 117 | iser_prepare_write_cmd(struct iscsi_task *task, |
118 | unsigned int imm_sz, | 118 | unsigned int imm_sz, |
119 | unsigned int unsol_sz, | 119 | unsigned int unsol_sz, |
120 | unsigned int edtl) | 120 | unsigned int edtl) |
121 | { | 121 | { |
122 | struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; | 122 | struct iscsi_iser_task *iser_task = task->dd_data; |
123 | struct iser_regd_buf *regd_buf; | 123 | struct iser_regd_buf *regd_buf; |
124 | int err; | 124 | int err; |
125 | struct iser_dto *send_dto = &iser_ctask->desc.dto; | 125 | struct iser_dto *send_dto = &iser_task->desc.dto; |
126 | struct iser_hdr *hdr = &iser_ctask->desc.iser_header; | 126 | struct iser_hdr *hdr = &iser_task->desc.iser_header; |
127 | struct iser_data_buf *buf_out = &iser_ctask->data[ISER_DIR_OUT]; | 127 | struct iser_data_buf *buf_out = &iser_task->data[ISER_DIR_OUT]; |
128 | 128 | ||
129 | err = iser_dma_map_task_data(iser_ctask, | 129 | err = iser_dma_map_task_data(iser_task, |
130 | buf_out, | 130 | buf_out, |
131 | ISER_DIR_OUT, | 131 | ISER_DIR_OUT, |
132 | DMA_TO_DEVICE); | 132 | DMA_TO_DEVICE); |
133 | if (err) | 133 | if (err) |
134 | return err; | 134 | return err; |
135 | 135 | ||
136 | if (edtl > iser_ctask->data[ISER_DIR_OUT].data_len) { | 136 | if (edtl > iser_task->data[ISER_DIR_OUT].data_len) { |
137 | iser_err("Total data length: %ld, less than EDTL: %d, " | 137 | iser_err("Total data length: %ld, less than EDTL: %d, " |
138 | "in WRITE cmd BHS itt: %d, conn: 0x%p\n", | 138 | "in WRITE cmd BHS itt: %d, conn: 0x%p\n", |
139 | iser_ctask->data[ISER_DIR_OUT].data_len, | 139 | iser_task->data[ISER_DIR_OUT].data_len, |
140 | edtl, ctask->itt, ctask->conn); | 140 | edtl, task->itt, task->conn); |
141 | return -EINVAL; | 141 | return -EINVAL; |
142 | } | 142 | } |
143 | 143 | ||
144 | err = iser_reg_rdma_mem(iser_ctask,ISER_DIR_OUT); | 144 | err = iser_reg_rdma_mem(iser_task,ISER_DIR_OUT); |
145 | if (err != 0) { | 145 | if (err != 0) { |
146 | iser_err("Failed to register write cmd RDMA mem\n"); | 146 | iser_err("Failed to register write cmd RDMA mem\n"); |
147 | return err; | 147 | return err; |
148 | } | 148 | } |
149 | 149 | ||
150 | regd_buf = &iser_ctask->rdma_regd[ISER_DIR_OUT]; | 150 | regd_buf = &iser_task->rdma_regd[ISER_DIR_OUT]; |
151 | 151 | ||
152 | if (unsol_sz < edtl) { | 152 | if (unsol_sz < edtl) { |
153 | hdr->flags |= ISER_WSV; | 153 | hdr->flags |= ISER_WSV; |
@@ -156,13 +156,13 @@ iser_prepare_write_cmd(struct iscsi_cmd_task *ctask, | |||
156 | 156 | ||
157 | iser_dbg("Cmd itt:%d, WRITE tags, RKEY:%#.4X " | 157 | iser_dbg("Cmd itt:%d, WRITE tags, RKEY:%#.4X " |
158 | "VA:%#llX + unsol:%d\n", | 158 | "VA:%#llX + unsol:%d\n", |
159 | ctask->itt, regd_buf->reg.rkey, | 159 | task->itt, regd_buf->reg.rkey, |
160 | (unsigned long long)regd_buf->reg.va, unsol_sz); | 160 | (unsigned long long)regd_buf->reg.va, unsol_sz); |
161 | } | 161 | } |
162 | 162 | ||
163 | if (imm_sz > 0) { | 163 | if (imm_sz > 0) { |
164 | iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n", | 164 | iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n", |
165 | ctask->itt, imm_sz); | 165 | task->itt, imm_sz); |
166 | iser_dto_add_regd_buff(send_dto, | 166 | iser_dto_add_regd_buff(send_dto, |
167 | regd_buf, | 167 | regd_buf, |
168 | 0, | 168 | 0, |
@@ -314,38 +314,38 @@ iser_check_xmit(struct iscsi_conn *conn, void *task) | |||
314 | /** | 314 | /** |
315 | * iser_send_command - send command PDU | 315 | * iser_send_command - send command PDU |
316 | */ | 316 | */ |
317 | int iser_send_command(struct iscsi_conn *conn, | 317 | int iser_send_command(struct iscsi_conn *conn, |
318 | struct iscsi_cmd_task *ctask) | 318 | struct iscsi_task *task) |
319 | { | 319 | { |
320 | struct iscsi_iser_conn *iser_conn = conn->dd_data; | 320 | struct iscsi_iser_conn *iser_conn = conn->dd_data; |
321 | struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; | 321 | struct iscsi_iser_task *iser_task = task->dd_data; |
322 | struct iser_dto *send_dto = NULL; | 322 | struct iser_dto *send_dto = NULL; |
323 | unsigned long edtl; | 323 | unsigned long edtl; |
324 | int err = 0; | 324 | int err = 0; |
325 | struct iser_data_buf *data_buf; | 325 | struct iser_data_buf *data_buf; |
326 | 326 | ||
327 | struct iscsi_cmd *hdr = ctask->hdr; | 327 | struct iscsi_cmd *hdr = task->hdr; |
328 | struct scsi_cmnd *sc = ctask->sc; | 328 | struct scsi_cmnd *sc = task->sc; |
329 | 329 | ||
330 | if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) { | 330 | if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) { |
331 | iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn); | 331 | iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn); |
332 | return -EPERM; | 332 | return -EPERM; |
333 | } | 333 | } |
334 | if (iser_check_xmit(conn, ctask)) | 334 | if (iser_check_xmit(conn, task)) |
335 | return -ENOBUFS; | 335 | return -ENOBUFS; |
336 | 336 | ||
337 | edtl = ntohl(hdr->data_length); | 337 | edtl = ntohl(hdr->data_length); |
338 | 338 | ||
339 | /* build the tx desc regd header and add it to the tx desc dto */ | 339 | /* build the tx desc regd header and add it to the tx desc dto */ |
340 | iser_ctask->desc.type = ISCSI_TX_SCSI_COMMAND; | 340 | iser_task->desc.type = ISCSI_TX_SCSI_COMMAND; |
341 | send_dto = &iser_ctask->desc.dto; | 341 | send_dto = &iser_task->desc.dto; |
342 | send_dto->ctask = iser_ctask; | 342 | send_dto->task = iser_task; |
343 | iser_create_send_desc(iser_conn, &iser_ctask->desc); | 343 | iser_create_send_desc(iser_conn, &iser_task->desc); |
344 | 344 | ||
345 | if (hdr->flags & ISCSI_FLAG_CMD_READ) | 345 | if (hdr->flags & ISCSI_FLAG_CMD_READ) |
346 | data_buf = &iser_ctask->data[ISER_DIR_IN]; | 346 | data_buf = &iser_task->data[ISER_DIR_IN]; |
347 | else | 347 | else |
348 | data_buf = &iser_ctask->data[ISER_DIR_OUT]; | 348 | data_buf = &iser_task->data[ISER_DIR_OUT]; |
349 | 349 | ||
350 | if (scsi_sg_count(sc)) { /* using a scatter list */ | 350 | if (scsi_sg_count(sc)) { /* using a scatter list */ |
351 | data_buf->buf = scsi_sglist(sc); | 351 | data_buf->buf = scsi_sglist(sc); |
@@ -355,15 +355,15 @@ int iser_send_command(struct iscsi_conn *conn, | |||
355 | data_buf->data_len = scsi_bufflen(sc); | 355 | data_buf->data_len = scsi_bufflen(sc); |
356 | 356 | ||
357 | if (hdr->flags & ISCSI_FLAG_CMD_READ) { | 357 | if (hdr->flags & ISCSI_FLAG_CMD_READ) { |
358 | err = iser_prepare_read_cmd(ctask, edtl); | 358 | err = iser_prepare_read_cmd(task, edtl); |
359 | if (err) | 359 | if (err) |
360 | goto send_command_error; | 360 | goto send_command_error; |
361 | } | 361 | } |
362 | if (hdr->flags & ISCSI_FLAG_CMD_WRITE) { | 362 | if (hdr->flags & ISCSI_FLAG_CMD_WRITE) { |
363 | err = iser_prepare_write_cmd(ctask, | 363 | err = iser_prepare_write_cmd(task, |
364 | ctask->imm_count, | 364 | task->imm_count, |
365 | ctask->imm_count + | 365 | task->imm_count + |
366 | ctask->unsol_count, | 366 | task->unsol_count, |
367 | edtl); | 367 | edtl); |
368 | if (err) | 368 | if (err) |
369 | goto send_command_error; | 369 | goto send_command_error; |
@@ -378,27 +378,27 @@ int iser_send_command(struct iscsi_conn *conn, | |||
378 | goto send_command_error; | 378 | goto send_command_error; |
379 | } | 379 | } |
380 | 380 | ||
381 | iser_ctask->status = ISER_TASK_STATUS_STARTED; | 381 | iser_task->status = ISER_TASK_STATUS_STARTED; |
382 | 382 | ||
383 | err = iser_post_send(&iser_ctask->desc); | 383 | err = iser_post_send(&iser_task->desc); |
384 | if (!err) | 384 | if (!err) |
385 | return 0; | 385 | return 0; |
386 | 386 | ||
387 | send_command_error: | 387 | send_command_error: |
388 | iser_dto_buffs_release(send_dto); | 388 | iser_dto_buffs_release(send_dto); |
389 | iser_err("conn %p failed ctask->itt %d err %d\n",conn, ctask->itt, err); | 389 | iser_err("conn %p failed task->itt %d err %d\n",conn, task->itt, err); |
390 | return err; | 390 | return err; |
391 | } | 391 | } |
392 | 392 | ||
393 | /** | 393 | /** |
394 | * iser_send_data_out - send data out PDU | 394 | * iser_send_data_out - send data out PDU |
395 | */ | 395 | */ |
396 | int iser_send_data_out(struct iscsi_conn *conn, | 396 | int iser_send_data_out(struct iscsi_conn *conn, |
397 | struct iscsi_cmd_task *ctask, | 397 | struct iscsi_task *task, |
398 | struct iscsi_data *hdr) | 398 | struct iscsi_data *hdr) |
399 | { | 399 | { |
400 | struct iscsi_iser_conn *iser_conn = conn->dd_data; | 400 | struct iscsi_iser_conn *iser_conn = conn->dd_data; |
401 | struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data; | 401 | struct iscsi_iser_task *iser_task = task->dd_data; |
402 | struct iser_desc *tx_desc = NULL; | 402 | struct iser_desc *tx_desc = NULL; |
403 | struct iser_dto *send_dto = NULL; | 403 | struct iser_dto *send_dto = NULL; |
404 | unsigned long buf_offset; | 404 | unsigned long buf_offset; |
@@ -411,7 +411,7 @@ int iser_send_data_out(struct iscsi_conn *conn, | |||
411 | return -EPERM; | 411 | return -EPERM; |
412 | } | 412 | } |
413 | 413 | ||
414 | if (iser_check_xmit(conn, ctask)) | 414 | if (iser_check_xmit(conn, task)) |
415 | return -ENOBUFS; | 415 | return -ENOBUFS; |
416 | 416 | ||
417 | itt = (__force uint32_t)hdr->itt; | 417 | itt = (__force uint32_t)hdr->itt; |
@@ -432,7 +432,7 @@ int iser_send_data_out(struct iscsi_conn *conn, | |||
432 | 432 | ||
433 | /* build the tx desc regd header and add it to the tx desc dto */ | 433 | /* build the tx desc regd header and add it to the tx desc dto */ |
434 | send_dto = &tx_desc->dto; | 434 | send_dto = &tx_desc->dto; |
435 | send_dto->ctask = iser_ctask; | 435 | send_dto->task = iser_task; |
436 | iser_create_send_desc(iser_conn, tx_desc); | 436 | iser_create_send_desc(iser_conn, tx_desc); |
437 | 437 | ||
438 | iser_reg_single(iser_conn->ib_conn->device, | 438 | iser_reg_single(iser_conn->ib_conn->device, |
@@ -440,15 +440,15 @@ int iser_send_data_out(struct iscsi_conn *conn, | |||
440 | 440 | ||
441 | /* all data was registered for RDMA, we can use the lkey */ | 441 | /* all data was registered for RDMA, we can use the lkey */ |
442 | iser_dto_add_regd_buff(send_dto, | 442 | iser_dto_add_regd_buff(send_dto, |
443 | &iser_ctask->rdma_regd[ISER_DIR_OUT], | 443 | &iser_task->rdma_regd[ISER_DIR_OUT], |
444 | buf_offset, | 444 | buf_offset, |
445 | data_seg_len); | 445 | data_seg_len); |
446 | 446 | ||
447 | if (buf_offset + data_seg_len > iser_ctask->data[ISER_DIR_OUT].data_len) { | 447 | if (buf_offset + data_seg_len > iser_task->data[ISER_DIR_OUT].data_len) { |
448 | iser_err("Offset:%ld & DSL:%ld in Data-Out " | 448 | iser_err("Offset:%ld & DSL:%ld in Data-Out " |
449 | "inconsistent with total len:%ld, itt:%d\n", | 449 | "inconsistent with total len:%ld, itt:%d\n", |
450 | buf_offset, data_seg_len, | 450 | buf_offset, data_seg_len, |
451 | iser_ctask->data[ISER_DIR_OUT].data_len, itt); | 451 | iser_task->data[ISER_DIR_OUT].data_len, itt); |
452 | err = -EINVAL; | 452 | err = -EINVAL; |
453 | goto send_data_out_error; | 453 | goto send_data_out_error; |
454 | } | 454 | } |
@@ -468,10 +468,11 @@ send_data_out_error: | |||
468 | } | 468 | } |
469 | 469 | ||
470 | int iser_send_control(struct iscsi_conn *conn, | 470 | int iser_send_control(struct iscsi_conn *conn, |
471 | struct iscsi_mgmt_task *mtask) | 471 | struct iscsi_task *task) |
472 | { | 472 | { |
473 | struct iscsi_iser_conn *iser_conn = conn->dd_data; | 473 | struct iscsi_iser_conn *iser_conn = conn->dd_data; |
474 | struct iser_desc *mdesc = mtask->dd_data; | 474 | struct iscsi_iser_task *iser_task = task->dd_data; |
475 | struct iser_desc *mdesc = &iser_task->desc; | ||
475 | struct iser_dto *send_dto = NULL; | 476 | struct iser_dto *send_dto = NULL; |
476 | unsigned long data_seg_len; | 477 | unsigned long data_seg_len; |
477 | int err = 0; | 478 | int err = 0; |
@@ -483,27 +484,27 @@ int iser_send_control(struct iscsi_conn *conn, | |||
483 | return -EPERM; | 484 | return -EPERM; |
484 | } | 485 | } |
485 | 486 | ||
486 | if (iser_check_xmit(conn,mtask)) | 487 | if (iser_check_xmit(conn, task)) |
487 | return -ENOBUFS; | 488 | return -ENOBUFS; |
488 | 489 | ||
489 | /* build the tx desc regd header and add it to the tx desc dto */ | 490 | /* build the tx desc regd header and add it to the tx desc dto */ |
490 | mdesc->type = ISCSI_TX_CONTROL; | 491 | mdesc->type = ISCSI_TX_CONTROL; |
491 | send_dto = &mdesc->dto; | 492 | send_dto = &mdesc->dto; |
492 | send_dto->ctask = NULL; | 493 | send_dto->task = NULL; |
493 | iser_create_send_desc(iser_conn, mdesc); | 494 | iser_create_send_desc(iser_conn, mdesc); |
494 | 495 | ||
495 | device = iser_conn->ib_conn->device; | 496 | device = iser_conn->ib_conn->device; |
496 | 497 | ||
497 | iser_reg_single(device, send_dto->regd[0], DMA_TO_DEVICE); | 498 | iser_reg_single(device, send_dto->regd[0], DMA_TO_DEVICE); |
498 | 499 | ||
499 | data_seg_len = ntoh24(mtask->hdr->dlength); | 500 | data_seg_len = ntoh24(task->hdr->dlength); |
500 | 501 | ||
501 | if (data_seg_len > 0) { | 502 | if (data_seg_len > 0) { |
502 | regd_buf = &mdesc->data_regd_buf; | 503 | regd_buf = &mdesc->data_regd_buf; |
503 | memset(regd_buf, 0, sizeof(struct iser_regd_buf)); | 504 | memset(regd_buf, 0, sizeof(struct iser_regd_buf)); |
504 | regd_buf->device = device; | 505 | regd_buf->device = device; |
505 | regd_buf->virt_addr = mtask->data; | 506 | regd_buf->virt_addr = task->data; |
506 | regd_buf->data_size = mtask->data_count; | 507 | regd_buf->data_size = task->data_count; |
507 | iser_reg_single(device, regd_buf, | 508 | iser_reg_single(device, regd_buf, |
508 | DMA_TO_DEVICE); | 509 | DMA_TO_DEVICE); |
509 | iser_dto_add_regd_buff(send_dto, regd_buf, | 510 | iser_dto_add_regd_buff(send_dto, regd_buf, |
@@ -533,15 +534,13 @@ send_control_error: | |||
533 | void iser_rcv_completion(struct iser_desc *rx_desc, | 534 | void iser_rcv_completion(struct iser_desc *rx_desc, |
534 | unsigned long dto_xfer_len) | 535 | unsigned long dto_xfer_len) |
535 | { | 536 | { |
536 | struct iser_dto *dto = &rx_desc->dto; | 537 | struct iser_dto *dto = &rx_desc->dto; |
537 | struct iscsi_iser_conn *conn = dto->ib_conn->iser_conn; | 538 | struct iscsi_iser_conn *conn = dto->ib_conn->iser_conn; |
538 | struct iscsi_session *session = conn->iscsi_conn->session; | 539 | struct iscsi_task *task; |
539 | struct iscsi_cmd_task *ctask; | 540 | struct iscsi_iser_task *iser_task; |
540 | struct iscsi_iser_cmd_task *iser_ctask; | ||
541 | struct iscsi_hdr *hdr; | 541 | struct iscsi_hdr *hdr; |
542 | char *rx_data = NULL; | 542 | char *rx_data = NULL; |
543 | int rx_data_len = 0; | 543 | int rx_data_len = 0; |
544 | unsigned int itt; | ||
545 | unsigned char opcode; | 544 | unsigned char opcode; |
546 | 545 | ||
547 | hdr = &rx_desc->iscsi_header; | 546 | hdr = &rx_desc->iscsi_header; |
@@ -557,19 +556,24 @@ void iser_rcv_completion(struct iser_desc *rx_desc, | |||
557 | opcode = hdr->opcode & ISCSI_OPCODE_MASK; | 556 | opcode = hdr->opcode & ISCSI_OPCODE_MASK; |
558 | 557 | ||
559 | if (opcode == ISCSI_OP_SCSI_CMD_RSP) { | 558 | if (opcode == ISCSI_OP_SCSI_CMD_RSP) { |
560 | itt = get_itt(hdr->itt); /* mask out cid and age bits */ | 559 | spin_lock(&conn->iscsi_conn->session->lock); |
561 | if (!(itt < session->cmds_max)) | 560 | task = iscsi_itt_to_ctask(conn->iscsi_conn, hdr->itt); |
561 | if (task) | ||
562 | __iscsi_get_task(task); | ||
563 | spin_unlock(&conn->iscsi_conn->session->lock); | ||
564 | |||
565 | if (!task) | ||
562 | iser_err("itt can't be matched to task!!! " | 566 | iser_err("itt can't be matched to task!!! " |
563 | "conn %p opcode %d cmds_max %d itt %d\n", | 567 | "conn %p opcode %d itt %d\n", |
564 | conn->iscsi_conn,opcode,session->cmds_max,itt); | 568 | conn->iscsi_conn, opcode, hdr->itt); |
565 | /* use the mapping given with the cmds array indexed by itt */ | 569 | else { |
566 | ctask = (struct iscsi_cmd_task *)session->cmds[itt]; | 570 | iser_task = task->dd_data; |
567 | iser_ctask = ctask->dd_data; | 571 | iser_dbg("itt %d task %p\n",hdr->itt, task); |
568 | iser_dbg("itt %d ctask %p\n",itt,ctask); | 572 | iser_task->status = ISER_TASK_STATUS_COMPLETED; |
569 | iser_ctask->status = ISER_TASK_STATUS_COMPLETED; | 573 | iser_task_rdma_finalize(iser_task); |
570 | iser_ctask_rdma_finalize(iser_ctask); | 574 | iscsi_put_task(task); |
575 | } | ||
571 | } | 576 | } |
572 | |||
573 | iser_dto_buffs_release(dto); | 577 | iser_dto_buffs_release(dto); |
574 | 578 | ||
575 | iscsi_iser_recv(conn->iscsi_conn, hdr, rx_data, rx_data_len); | 579 | iscsi_iser_recv(conn->iscsi_conn, hdr, rx_data, rx_data_len); |
@@ -590,7 +594,7 @@ void iser_snd_completion(struct iser_desc *tx_desc) | |||
590 | struct iser_conn *ib_conn = dto->ib_conn; | 594 | struct iser_conn *ib_conn = dto->ib_conn; |
591 | struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn; | 595 | struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn; |
592 | struct iscsi_conn *conn = iser_conn->iscsi_conn; | 596 | struct iscsi_conn *conn = iser_conn->iscsi_conn; |
593 | struct iscsi_mgmt_task *mtask; | 597 | struct iscsi_task *task; |
594 | int resume_tx = 0; | 598 | int resume_tx = 0; |
595 | 599 | ||
596 | iser_dbg("Initiator, Data sent dto=0x%p\n", dto); | 600 | iser_dbg("Initiator, Data sent dto=0x%p\n", dto); |
@@ -613,36 +617,31 @@ void iser_snd_completion(struct iser_desc *tx_desc) | |||
613 | 617 | ||
614 | if (tx_desc->type == ISCSI_TX_CONTROL) { | 618 | if (tx_desc->type == ISCSI_TX_CONTROL) { |
615 | /* this arithmetic is legal by libiscsi dd_data allocation */ | 619 | /* this arithmetic is legal by libiscsi dd_data allocation */ |
616 | mtask = (void *) ((long)(void *)tx_desc - | 620 | task = (void *) ((long)(void *)tx_desc - |
617 | sizeof(struct iscsi_mgmt_task)); | 621 | sizeof(struct iscsi_task)); |
618 | if (mtask->hdr->itt == RESERVED_ITT) { | 622 | if (task->hdr->itt == RESERVED_ITT) |
619 | struct iscsi_session *session = conn->session; | 623 | iscsi_put_task(task); |
620 | |||
621 | spin_lock(&conn->session->lock); | ||
622 | iscsi_free_mgmt_task(conn, mtask); | ||
623 | spin_unlock(&session->lock); | ||
624 | } | ||
625 | } | 624 | } |
626 | } | 625 | } |
627 | 626 | ||
628 | void iser_ctask_rdma_init(struct iscsi_iser_cmd_task *iser_ctask) | 627 | void iser_task_rdma_init(struct iscsi_iser_task *iser_task) |
629 | 628 | ||
630 | { | 629 | { |
631 | iser_ctask->status = ISER_TASK_STATUS_INIT; | 630 | iser_task->status = ISER_TASK_STATUS_INIT; |
632 | 631 | ||
633 | iser_ctask->dir[ISER_DIR_IN] = 0; | 632 | iser_task->dir[ISER_DIR_IN] = 0; |
634 | iser_ctask->dir[ISER_DIR_OUT] = 0; | 633 | iser_task->dir[ISER_DIR_OUT] = 0; |
635 | 634 | ||
636 | iser_ctask->data[ISER_DIR_IN].data_len = 0; | 635 | iser_task->data[ISER_DIR_IN].data_len = 0; |
637 | iser_ctask->data[ISER_DIR_OUT].data_len = 0; | 636 | iser_task->data[ISER_DIR_OUT].data_len = 0; |
638 | 637 | ||
639 | memset(&iser_ctask->rdma_regd[ISER_DIR_IN], 0, | 638 | memset(&iser_task->rdma_regd[ISER_DIR_IN], 0, |
640 | sizeof(struct iser_regd_buf)); | 639 | sizeof(struct iser_regd_buf)); |
641 | memset(&iser_ctask->rdma_regd[ISER_DIR_OUT], 0, | 640 | memset(&iser_task->rdma_regd[ISER_DIR_OUT], 0, |
642 | sizeof(struct iser_regd_buf)); | 641 | sizeof(struct iser_regd_buf)); |
643 | } | 642 | } |
644 | 643 | ||
645 | void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *iser_ctask) | 644 | void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) |
646 | { | 645 | { |
647 | int deferred; | 646 | int deferred; |
648 | int is_rdma_aligned = 1; | 647 | int is_rdma_aligned = 1; |
@@ -651,17 +650,17 @@ void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *iser_ctask) | |||
651 | /* if we were reading, copy back to unaligned sglist, | 650 | /* if we were reading, copy back to unaligned sglist, |
652 | * anyway dma_unmap and free the copy | 651 | * anyway dma_unmap and free the copy |
653 | */ | 652 | */ |
654 | if (iser_ctask->data_copy[ISER_DIR_IN].copy_buf != NULL) { | 653 | if (iser_task->data_copy[ISER_DIR_IN].copy_buf != NULL) { |
655 | is_rdma_aligned = 0; | 654 | is_rdma_aligned = 0; |
656 | iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_IN); | 655 | iser_finalize_rdma_unaligned_sg(iser_task, ISER_DIR_IN); |
657 | } | 656 | } |
658 | if (iser_ctask->data_copy[ISER_DIR_OUT].copy_buf != NULL) { | 657 | if (iser_task->data_copy[ISER_DIR_OUT].copy_buf != NULL) { |
659 | is_rdma_aligned = 0; | 658 | is_rdma_aligned = 0; |
660 | iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_OUT); | 659 | iser_finalize_rdma_unaligned_sg(iser_task, ISER_DIR_OUT); |
661 | } | 660 | } |
662 | 661 | ||
663 | if (iser_ctask->dir[ISER_DIR_IN]) { | 662 | if (iser_task->dir[ISER_DIR_IN]) { |
664 | regd = &iser_ctask->rdma_regd[ISER_DIR_IN]; | 663 | regd = &iser_task->rdma_regd[ISER_DIR_IN]; |
665 | deferred = iser_regd_buff_release(regd); | 664 | deferred = iser_regd_buff_release(regd); |
666 | if (deferred) { | 665 | if (deferred) { |
667 | iser_err("%d references remain for BUF-IN rdma reg\n", | 666 | iser_err("%d references remain for BUF-IN rdma reg\n", |
@@ -669,8 +668,8 @@ void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *iser_ctask) | |||
669 | } | 668 | } |
670 | } | 669 | } |
671 | 670 | ||
672 | if (iser_ctask->dir[ISER_DIR_OUT]) { | 671 | if (iser_task->dir[ISER_DIR_OUT]) { |
673 | regd = &iser_ctask->rdma_regd[ISER_DIR_OUT]; | 672 | regd = &iser_task->rdma_regd[ISER_DIR_OUT]; |
674 | deferred = iser_regd_buff_release(regd); | 673 | deferred = iser_regd_buff_release(regd); |
675 | if (deferred) { | 674 | if (deferred) { |
676 | iser_err("%d references remain for BUF-OUT rdma reg\n", | 675 | iser_err("%d references remain for BUF-OUT rdma reg\n", |
@@ -680,7 +679,7 @@ void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *iser_ctask) | |||
680 | 679 | ||
681 | /* if the data was unaligned, it was already unmapped and then copied */ | 680 | /* if the data was unaligned, it was already unmapped and then copied */ |
682 | if (is_rdma_aligned) | 681 | if (is_rdma_aligned) |
683 | iser_dma_unmap_task_data(iser_ctask); | 682 | iser_dma_unmap_task_data(iser_task); |
684 | } | 683 | } |
685 | 684 | ||
686 | void iser_dto_buffs_release(struct iser_dto *dto) | 685 | void iser_dto_buffs_release(struct iser_dto *dto) |
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 81e49cb10ed3..b9453d068e9d 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c | |||
@@ -99,13 +99,13 @@ void iser_reg_single(struct iser_device *device, | |||
99 | /** | 99 | /** |
100 | * iser_start_rdma_unaligned_sg | 100 | * iser_start_rdma_unaligned_sg |
101 | */ | 101 | */ |
102 | static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask, | 102 | static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, |
103 | enum iser_data_dir cmd_dir) | 103 | enum iser_data_dir cmd_dir) |
104 | { | 104 | { |
105 | int dma_nents; | 105 | int dma_nents; |
106 | struct ib_device *dev; | 106 | struct ib_device *dev; |
107 | char *mem = NULL; | 107 | char *mem = NULL; |
108 | struct iser_data_buf *data = &iser_ctask->data[cmd_dir]; | 108 | struct iser_data_buf *data = &iser_task->data[cmd_dir]; |
109 | unsigned long cmd_data_len = data->data_len; | 109 | unsigned long cmd_data_len = data->data_len; |
110 | 110 | ||
111 | if (cmd_data_len > ISER_KMALLOC_THRESHOLD) | 111 | if (cmd_data_len > ISER_KMALLOC_THRESHOLD) |
@@ -138,37 +138,37 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask, | |||
138 | } | 138 | } |
139 | } | 139 | } |
140 | 140 | ||
141 | sg_init_one(&iser_ctask->data_copy[cmd_dir].sg_single, mem, cmd_data_len); | 141 | sg_init_one(&iser_task->data_copy[cmd_dir].sg_single, mem, cmd_data_len); |
142 | iser_ctask->data_copy[cmd_dir].buf = | 142 | iser_task->data_copy[cmd_dir].buf = |
143 | &iser_ctask->data_copy[cmd_dir].sg_single; | 143 | &iser_task->data_copy[cmd_dir].sg_single; |
144 | iser_ctask->data_copy[cmd_dir].size = 1; | 144 | iser_task->data_copy[cmd_dir].size = 1; |
145 | 145 | ||
146 | iser_ctask->data_copy[cmd_dir].copy_buf = mem; | 146 | iser_task->data_copy[cmd_dir].copy_buf = mem; |
147 | 147 | ||
148 | dev = iser_ctask->iser_conn->ib_conn->device->ib_device; | 148 | dev = iser_task->iser_conn->ib_conn->device->ib_device; |
149 | dma_nents = ib_dma_map_sg(dev, | 149 | dma_nents = ib_dma_map_sg(dev, |
150 | &iser_ctask->data_copy[cmd_dir].sg_single, | 150 | &iser_task->data_copy[cmd_dir].sg_single, |
151 | 1, | 151 | 1, |
152 | (cmd_dir == ISER_DIR_OUT) ? | 152 | (cmd_dir == ISER_DIR_OUT) ? |
153 | DMA_TO_DEVICE : DMA_FROM_DEVICE); | 153 | DMA_TO_DEVICE : DMA_FROM_DEVICE); |
154 | BUG_ON(dma_nents == 0); | 154 | BUG_ON(dma_nents == 0); |
155 | 155 | ||
156 | iser_ctask->data_copy[cmd_dir].dma_nents = dma_nents; | 156 | iser_task->data_copy[cmd_dir].dma_nents = dma_nents; |
157 | return 0; | 157 | return 0; |
158 | } | 158 | } |
159 | 159 | ||
160 | /** | 160 | /** |
161 | * iser_finalize_rdma_unaligned_sg | 161 | * iser_finalize_rdma_unaligned_sg |
162 | */ | 162 | */ |
163 | void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask, | 163 | void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, |
164 | enum iser_data_dir cmd_dir) | 164 | enum iser_data_dir cmd_dir) |
165 | { | 165 | { |
166 | struct ib_device *dev; | 166 | struct ib_device *dev; |
167 | struct iser_data_buf *mem_copy; | 167 | struct iser_data_buf *mem_copy; |
168 | unsigned long cmd_data_len; | 168 | unsigned long cmd_data_len; |
169 | 169 | ||
170 | dev = iser_ctask->iser_conn->ib_conn->device->ib_device; | 170 | dev = iser_task->iser_conn->ib_conn->device->ib_device; |
171 | mem_copy = &iser_ctask->data_copy[cmd_dir]; | 171 | mem_copy = &iser_task->data_copy[cmd_dir]; |
172 | 172 | ||
173 | ib_dma_unmap_sg(dev, &mem_copy->sg_single, 1, | 173 | ib_dma_unmap_sg(dev, &mem_copy->sg_single, 1, |
174 | (cmd_dir == ISER_DIR_OUT) ? | 174 | (cmd_dir == ISER_DIR_OUT) ? |
@@ -184,8 +184,8 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask, | |||
184 | /* copy back read RDMA to unaligned sg */ | 184 | /* copy back read RDMA to unaligned sg */ |
185 | mem = mem_copy->copy_buf; | 185 | mem = mem_copy->copy_buf; |
186 | 186 | ||
187 | sgl = (struct scatterlist *)iser_ctask->data[ISER_DIR_IN].buf; | 187 | sgl = (struct scatterlist *)iser_task->data[ISER_DIR_IN].buf; |
188 | sg_size = iser_ctask->data[ISER_DIR_IN].size; | 188 | sg_size = iser_task->data[ISER_DIR_IN].size; |
189 | 189 | ||
190 | p = mem; | 190 | p = mem; |
191 | for_each_sg(sgl, sg, sg_size, i) { | 191 | for_each_sg(sgl, sg, sg_size, i) { |
@@ -198,7 +198,7 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask, | |||
198 | } | 198 | } |
199 | } | 199 | } |
200 | 200 | ||
201 | cmd_data_len = iser_ctask->data[cmd_dir].data_len; | 201 | cmd_data_len = iser_task->data[cmd_dir].data_len; |
202 | 202 | ||
203 | if (cmd_data_len > ISER_KMALLOC_THRESHOLD) | 203 | if (cmd_data_len > ISER_KMALLOC_THRESHOLD) |
204 | free_pages((unsigned long)mem_copy->copy_buf, | 204 | free_pages((unsigned long)mem_copy->copy_buf, |
@@ -376,15 +376,15 @@ static void iser_page_vec_build(struct iser_data_buf *data, | |||
376 | } | 376 | } |
377 | } | 377 | } |
378 | 378 | ||
379 | int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask, | 379 | int iser_dma_map_task_data(struct iscsi_iser_task *iser_task, |
380 | struct iser_data_buf *data, | 380 | struct iser_data_buf *data, |
381 | enum iser_data_dir iser_dir, | 381 | enum iser_data_dir iser_dir, |
382 | enum dma_data_direction dma_dir) | 382 | enum dma_data_direction dma_dir) |
383 | { | 383 | { |
384 | struct ib_device *dev; | 384 | struct ib_device *dev; |
385 | 385 | ||
386 | iser_ctask->dir[iser_dir] = 1; | 386 | iser_task->dir[iser_dir] = 1; |
387 | dev = iser_ctask->iser_conn->ib_conn->device->ib_device; | 387 | dev = iser_task->iser_conn->ib_conn->device->ib_device; |
388 | 388 | ||
389 | data->dma_nents = ib_dma_map_sg(dev, data->buf, data->size, dma_dir); | 389 | data->dma_nents = ib_dma_map_sg(dev, data->buf, data->size, dma_dir); |
390 | if (data->dma_nents == 0) { | 390 | if (data->dma_nents == 0) { |
@@ -394,20 +394,20 @@ int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask, | |||
394 | return 0; | 394 | return 0; |
395 | } | 395 | } |
396 | 396 | ||
397 | void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask) | 397 | void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task) |
398 | { | 398 | { |
399 | struct ib_device *dev; | 399 | struct ib_device *dev; |
400 | struct iser_data_buf *data; | 400 | struct iser_data_buf *data; |
401 | 401 | ||
402 | dev = iser_ctask->iser_conn->ib_conn->device->ib_device; | 402 | dev = iser_task->iser_conn->ib_conn->device->ib_device; |
403 | 403 | ||
404 | if (iser_ctask->dir[ISER_DIR_IN]) { | 404 | if (iser_task->dir[ISER_DIR_IN]) { |
405 | data = &iser_ctask->data[ISER_DIR_IN]; | 405 | data = &iser_task->data[ISER_DIR_IN]; |
406 | ib_dma_unmap_sg(dev, data->buf, data->size, DMA_FROM_DEVICE); | 406 | ib_dma_unmap_sg(dev, data->buf, data->size, DMA_FROM_DEVICE); |
407 | } | 407 | } |
408 | 408 | ||
409 | if (iser_ctask->dir[ISER_DIR_OUT]) { | 409 | if (iser_task->dir[ISER_DIR_OUT]) { |
410 | data = &iser_ctask->data[ISER_DIR_OUT]; | 410 | data = &iser_task->data[ISER_DIR_OUT]; |
411 | ib_dma_unmap_sg(dev, data->buf, data->size, DMA_TO_DEVICE); | 411 | ib_dma_unmap_sg(dev, data->buf, data->size, DMA_TO_DEVICE); |
412 | } | 412 | } |
413 | } | 413 | } |
@@ -418,21 +418,21 @@ void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask) | |||
418 | * | 418 | * |
419 | * returns 0 on success, errno code on failure | 419 | * returns 0 on success, errno code on failure |
420 | */ | 420 | */ |
421 | int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask, | 421 | int iser_reg_rdma_mem(struct iscsi_iser_task *iser_task, |
422 | enum iser_data_dir cmd_dir) | 422 | enum iser_data_dir cmd_dir) |
423 | { | 423 | { |
424 | struct iscsi_conn *iscsi_conn = iser_ctask->iser_conn->iscsi_conn; | 424 | struct iscsi_conn *iscsi_conn = iser_task->iser_conn->iscsi_conn; |
425 | struct iser_conn *ib_conn = iser_ctask->iser_conn->ib_conn; | 425 | struct iser_conn *ib_conn = iser_task->iser_conn->ib_conn; |
426 | struct iser_device *device = ib_conn->device; | 426 | struct iser_device *device = ib_conn->device; |
427 | struct ib_device *ibdev = device->ib_device; | 427 | struct ib_device *ibdev = device->ib_device; |
428 | struct iser_data_buf *mem = &iser_ctask->data[cmd_dir]; | 428 | struct iser_data_buf *mem = &iser_task->data[cmd_dir]; |
429 | struct iser_regd_buf *regd_buf; | 429 | struct iser_regd_buf *regd_buf; |
430 | int aligned_len; | 430 | int aligned_len; |
431 | int err; | 431 | int err; |
432 | int i; | 432 | int i; |
433 | struct scatterlist *sg; | 433 | struct scatterlist *sg; |
434 | 434 | ||
435 | regd_buf = &iser_ctask->rdma_regd[cmd_dir]; | 435 | regd_buf = &iser_task->rdma_regd[cmd_dir]; |
436 | 436 | ||
437 | aligned_len = iser_data_buf_aligned_len(mem, ibdev); | 437 | aligned_len = iser_data_buf_aligned_len(mem, ibdev); |
438 | if (aligned_len != mem->dma_nents) { | 438 | if (aligned_len != mem->dma_nents) { |
@@ -442,13 +442,13 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask, | |||
442 | iser_data_buf_dump(mem, ibdev); | 442 | iser_data_buf_dump(mem, ibdev); |
443 | 443 | ||
444 | /* unmap the command data before accessing it */ | 444 | /* unmap the command data before accessing it */ |
445 | iser_dma_unmap_task_data(iser_ctask); | 445 | iser_dma_unmap_task_data(iser_task); |
446 | 446 | ||
447 | /* allocate copy buf, if we are writing, copy the */ | 447 | /* allocate copy buf, if we are writing, copy the */ |
448 | /* unaligned scatterlist, dma map the copy */ | 448 | /* unaligned scatterlist, dma map the copy */ |
449 | if (iser_start_rdma_unaligned_sg(iser_ctask, cmd_dir) != 0) | 449 | if (iser_start_rdma_unaligned_sg(iser_task, cmd_dir) != 0) |
450 | return -ENOMEM; | 450 | return -ENOMEM; |
451 | mem = &iser_ctask->data_copy[cmd_dir]; | 451 | mem = &iser_task->data_copy[cmd_dir]; |
452 | } | 452 | } |
453 | 453 | ||
454 | /* if there a single dma entry, FMR is not needed */ | 454 | /* if there a single dma entry, FMR is not needed */ |
@@ -472,8 +472,9 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask, | |||
472 | err = iser_reg_page_vec(ib_conn, ib_conn->page_vec, ®d_buf->reg); | 472 | err = iser_reg_page_vec(ib_conn, ib_conn->page_vec, ®d_buf->reg); |
473 | if (err) { | 473 | if (err) { |
474 | iser_data_buf_dump(mem, ibdev); | 474 | iser_data_buf_dump(mem, ibdev); |
475 | iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", mem->dma_nents, | 475 | iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", |
476 | ntoh24(iser_ctask->desc.iscsi_header.dlength)); | 476 | mem->dma_nents, |
477 | ntoh24(iser_task->desc.iscsi_header.dlength)); | ||
477 | iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n", | 478 | iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n", |
478 | ib_conn->page_vec->data_size, ib_conn->page_vec->length, | 479 | ib_conn->page_vec->data_size, ib_conn->page_vec->length, |
479 | ib_conn->page_vec->offset); | 480 | ib_conn->page_vec->offset); |
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 77cabee7cc08..3a917c1f796f 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c | |||
@@ -323,7 +323,18 @@ static void iser_conn_release(struct iser_conn *ib_conn) | |||
323 | iser_device_try_release(device); | 323 | iser_device_try_release(device); |
324 | if (ib_conn->iser_conn) | 324 | if (ib_conn->iser_conn) |
325 | ib_conn->iser_conn->ib_conn = NULL; | 325 | ib_conn->iser_conn->ib_conn = NULL; |
326 | kfree(ib_conn); | 326 | iscsi_destroy_endpoint(ib_conn->ep); |
327 | } | ||
328 | |||
329 | void iser_conn_get(struct iser_conn *ib_conn) | ||
330 | { | ||
331 | atomic_inc(&ib_conn->refcount); | ||
332 | } | ||
333 | |||
334 | void iser_conn_put(struct iser_conn *ib_conn) | ||
335 | { | ||
336 | if (atomic_dec_and_test(&ib_conn->refcount)) | ||
337 | iser_conn_release(ib_conn); | ||
327 | } | 338 | } |
328 | 339 | ||
329 | /** | 340 | /** |
@@ -347,7 +358,7 @@ void iser_conn_terminate(struct iser_conn *ib_conn) | |||
347 | wait_event_interruptible(ib_conn->wait, | 358 | wait_event_interruptible(ib_conn->wait, |
348 | ib_conn->state == ISER_CONN_DOWN); | 359 | ib_conn->state == ISER_CONN_DOWN); |
349 | 360 | ||
350 | iser_conn_release(ib_conn); | 361 | iser_conn_put(ib_conn); |
351 | } | 362 | } |
352 | 363 | ||
353 | static void iser_connect_error(struct rdma_cm_id *cma_id) | 364 | static void iser_connect_error(struct rdma_cm_id *cma_id) |
@@ -481,24 +492,15 @@ static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *eve | |||
481 | return ret; | 492 | return ret; |
482 | } | 493 | } |
483 | 494 | ||
484 | int iser_conn_init(struct iser_conn **ibconn) | 495 | void iser_conn_init(struct iser_conn *ib_conn) |
485 | { | 496 | { |
486 | struct iser_conn *ib_conn; | ||
487 | |||
488 | ib_conn = kzalloc(sizeof *ib_conn, GFP_KERNEL); | ||
489 | if (!ib_conn) { | ||
490 | iser_err("can't alloc memory for struct iser_conn\n"); | ||
491 | return -ENOMEM; | ||
492 | } | ||
493 | ib_conn->state = ISER_CONN_INIT; | 497 | ib_conn->state = ISER_CONN_INIT; |
494 | init_waitqueue_head(&ib_conn->wait); | 498 | init_waitqueue_head(&ib_conn->wait); |
495 | atomic_set(&ib_conn->post_recv_buf_count, 0); | 499 | atomic_set(&ib_conn->post_recv_buf_count, 0); |
496 | atomic_set(&ib_conn->post_send_buf_count, 0); | 500 | atomic_set(&ib_conn->post_send_buf_count, 0); |
501 | atomic_set(&ib_conn->refcount, 1); | ||
497 | INIT_LIST_HEAD(&ib_conn->conn_list); | 502 | INIT_LIST_HEAD(&ib_conn->conn_list); |
498 | spin_lock_init(&ib_conn->lock); | 503 | spin_lock_init(&ib_conn->lock); |
499 | |||
500 | *ibconn = ib_conn; | ||
501 | return 0; | ||
502 | } | 504 | } |
503 | 505 | ||
504 | /** | 506 | /** |
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 610af916891e..07d92c11b5d8 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig | |||
@@ -252,27 +252,14 @@ config DM_ZERO | |||
252 | config DM_MULTIPATH | 252 | config DM_MULTIPATH |
253 | tristate "Multipath target" | 253 | tristate "Multipath target" |
254 | depends on BLK_DEV_DM | 254 | depends on BLK_DEV_DM |
255 | # nasty syntax but means make DM_MULTIPATH independent | ||
256 | # of SCSI_DH if the latter isn't defined but if | ||
257 | # it is, DM_MULTIPATH must depend on it. We get a build | ||
258 | # error if SCSI_DH=m and DM_MULTIPATH=y | ||
259 | depends on SCSI_DH || !SCSI_DH | ||
255 | ---help--- | 260 | ---help--- |
256 | Allow volume managers to support multipath hardware. | 261 | Allow volume managers to support multipath hardware. |
257 | 262 | ||
258 | config DM_MULTIPATH_EMC | ||
259 | tristate "EMC CX/AX multipath support" | ||
260 | depends on DM_MULTIPATH && BLK_DEV_DM | ||
261 | ---help--- | ||
262 | Multipath support for EMC CX/AX series hardware. | ||
263 | |||
264 | config DM_MULTIPATH_RDAC | ||
265 | tristate "LSI/Engenio RDAC multipath support (EXPERIMENTAL)" | ||
266 | depends on DM_MULTIPATH && BLK_DEV_DM && SCSI && EXPERIMENTAL | ||
267 | ---help--- | ||
268 | Multipath support for LSI/Engenio RDAC. | ||
269 | |||
270 | config DM_MULTIPATH_HP | ||
271 | tristate "HP MSA multipath support (EXPERIMENTAL)" | ||
272 | depends on DM_MULTIPATH && BLK_DEV_DM && SCSI && EXPERIMENTAL | ||
273 | ---help--- | ||
274 | Multipath support for HP MSA (Active/Passive) series hardware. | ||
275 | |||
276 | config DM_DELAY | 263 | config DM_DELAY |
277 | tristate "I/O delaying target (EXPERIMENTAL)" | 264 | tristate "I/O delaying target (EXPERIMENTAL)" |
278 | depends on BLK_DEV_DM && EXPERIMENTAL | 265 | depends on BLK_DEV_DM && EXPERIMENTAL |
diff --git a/drivers/md/Makefile b/drivers/md/Makefile index 7be09eeea293..f1ef33dfd8cf 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile | |||
@@ -4,11 +4,9 @@ | |||
4 | 4 | ||
5 | dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \ | 5 | dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \ |
6 | dm-ioctl.o dm-io.o dm-kcopyd.o | 6 | dm-ioctl.o dm-io.o dm-kcopyd.o |
7 | dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o | 7 | dm-multipath-objs := dm-path-selector.o dm-mpath.o |
8 | dm-snapshot-objs := dm-snap.o dm-exception-store.o | 8 | dm-snapshot-objs := dm-snap.o dm-exception-store.o |
9 | dm-mirror-objs := dm-raid1.o | 9 | dm-mirror-objs := dm-raid1.o |
10 | dm-rdac-objs := dm-mpath-rdac.o | ||
11 | dm-hp-sw-objs := dm-mpath-hp-sw.o | ||
12 | md-mod-objs := md.o bitmap.o | 10 | md-mod-objs := md.o bitmap.o |
13 | raid456-objs := raid5.o raid6algos.o raid6recov.o raid6tables.o \ | 11 | raid456-objs := raid5.o raid6algos.o raid6recov.o raid6tables.o \ |
14 | raid6int1.o raid6int2.o raid6int4.o \ | 12 | raid6int1.o raid6int2.o raid6int4.o \ |
@@ -35,9 +33,6 @@ obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o | |||
35 | obj-$(CONFIG_DM_CRYPT) += dm-crypt.o | 33 | obj-$(CONFIG_DM_CRYPT) += dm-crypt.o |
36 | obj-$(CONFIG_DM_DELAY) += dm-delay.o | 34 | obj-$(CONFIG_DM_DELAY) += dm-delay.o |
37 | obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o | 35 | obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o |
38 | obj-$(CONFIG_DM_MULTIPATH_EMC) += dm-emc.o | ||
39 | obj-$(CONFIG_DM_MULTIPATH_HP) += dm-hp-sw.o | ||
40 | obj-$(CONFIG_DM_MULTIPATH_RDAC) += dm-rdac.o | ||
41 | obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o | 36 | obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o |
42 | obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o | 37 | obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o |
43 | obj-$(CONFIG_DM_ZERO) += dm-zero.o | 38 | obj-$(CONFIG_DM_ZERO) += dm-zero.o |
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c deleted file mode 100644 index 3ea5ad4b7805..000000000000 --- a/drivers/md/dm-emc.c +++ /dev/null | |||
@@ -1,345 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 SUSE LINUX Products GmbH. All rights reserved. | ||
3 | * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * This file is released under the GPL. | ||
6 | * | ||
7 | * Multipath support for EMC CLARiiON AX/CX-series hardware. | ||
8 | */ | ||
9 | |||
10 | #include "dm.h" | ||
11 | #include "dm-hw-handler.h" | ||
12 | #include <scsi/scsi.h> | ||
13 | #include <scsi/scsi_cmnd.h> | ||
14 | |||
15 | #define DM_MSG_PREFIX "multipath emc" | ||
16 | |||
17 | struct emc_handler { | ||
18 | spinlock_t lock; | ||
19 | |||
20 | /* Whether we should send the short trespass command (FC-series) | ||
21 | * or the long version (default for AX/CX CLARiiON arrays). */ | ||
22 | unsigned short_trespass; | ||
23 | /* Whether or not to honor SCSI reservations when initiating a | ||
24 | * switch-over. Default: Don't. */ | ||
25 | unsigned hr; | ||
26 | |||
27 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
28 | }; | ||
29 | |||
30 | #define TRESPASS_PAGE 0x22 | ||
31 | #define EMC_FAILOVER_TIMEOUT (60 * HZ) | ||
32 | |||
33 | /* Code borrowed from dm-lsi-rdac by Mike Christie */ | ||
34 | |||
35 | static inline void free_bio(struct bio *bio) | ||
36 | { | ||
37 | __free_page(bio->bi_io_vec[0].bv_page); | ||
38 | bio_put(bio); | ||
39 | } | ||
40 | |||
41 | static void emc_endio(struct bio *bio, int error) | ||
42 | { | ||
43 | struct dm_path *path = bio->bi_private; | ||
44 | |||
45 | /* We also need to look at the sense keys here whether or not to | ||
46 | * switch to the next PG etc. | ||
47 | * | ||
48 | * For now simple logic: either it works or it doesn't. | ||
49 | */ | ||
50 | if (error) | ||
51 | dm_pg_init_complete(path, MP_FAIL_PATH); | ||
52 | else | ||
53 | dm_pg_init_complete(path, 0); | ||
54 | |||
55 | /* request is freed in block layer */ | ||
56 | free_bio(bio); | ||
57 | } | ||
58 | |||
59 | static struct bio *get_failover_bio(struct dm_path *path, unsigned data_size) | ||
60 | { | ||
61 | struct bio *bio; | ||
62 | struct page *page; | ||
63 | |||
64 | bio = bio_alloc(GFP_ATOMIC, 1); | ||
65 | if (!bio) { | ||
66 | DMERR("get_failover_bio: bio_alloc() failed."); | ||
67 | return NULL; | ||
68 | } | ||
69 | |||
70 | bio->bi_rw |= (1 << BIO_RW); | ||
71 | bio->bi_bdev = path->dev->bdev; | ||
72 | bio->bi_sector = 0; | ||
73 | bio->bi_private = path; | ||
74 | bio->bi_end_io = emc_endio; | ||
75 | |||
76 | page = alloc_page(GFP_ATOMIC); | ||
77 | if (!page) { | ||
78 | DMERR("get_failover_bio: alloc_page() failed."); | ||
79 | bio_put(bio); | ||
80 | return NULL; | ||
81 | } | ||
82 | |||
83 | if (bio_add_page(bio, page, data_size, 0) != data_size) { | ||
84 | DMERR("get_failover_bio: bio_add_page() failed."); | ||
85 | __free_page(page); | ||
86 | bio_put(bio); | ||
87 | return NULL; | ||
88 | } | ||
89 | |||
90 | return bio; | ||
91 | } | ||
92 | |||
93 | static struct request *get_failover_req(struct emc_handler *h, | ||
94 | struct bio *bio, struct dm_path *path) | ||
95 | { | ||
96 | struct request *rq; | ||
97 | struct block_device *bdev = bio->bi_bdev; | ||
98 | struct request_queue *q = bdev_get_queue(bdev); | ||
99 | |||
100 | /* FIXME: Figure out why it fails with GFP_ATOMIC. */ | ||
101 | rq = blk_get_request(q, WRITE, __GFP_WAIT); | ||
102 | if (!rq) { | ||
103 | DMERR("get_failover_req: blk_get_request failed"); | ||
104 | return NULL; | ||
105 | } | ||
106 | |||
107 | blk_rq_append_bio(q, rq, bio); | ||
108 | |||
109 | rq->sense = h->sense; | ||
110 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
111 | rq->sense_len = 0; | ||
112 | |||
113 | rq->timeout = EMC_FAILOVER_TIMEOUT; | ||
114 | rq->cmd_type = REQ_TYPE_BLOCK_PC; | ||
115 | rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; | ||
116 | |||
117 | return rq; | ||
118 | } | ||
119 | |||
120 | static struct request *emc_trespass_get(struct emc_handler *h, | ||
121 | struct dm_path *path) | ||
122 | { | ||
123 | struct bio *bio; | ||
124 | struct request *rq; | ||
125 | unsigned char *page22; | ||
126 | unsigned char long_trespass_pg[] = { | ||
127 | 0, 0, 0, 0, | ||
128 | TRESPASS_PAGE, /* Page code */ | ||
129 | 0x09, /* Page length - 2 */ | ||
130 | h->hr ? 0x01 : 0x81, /* Trespass code + Honor reservation bit */ | ||
131 | 0xff, 0xff, /* Trespass target */ | ||
132 | 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ | ||
133 | }; | ||
134 | unsigned char short_trespass_pg[] = { | ||
135 | 0, 0, 0, 0, | ||
136 | TRESPASS_PAGE, /* Page code */ | ||
137 | 0x02, /* Page length - 2 */ | ||
138 | h->hr ? 0x01 : 0x81, /* Trespass code + Honor reservation bit */ | ||
139 | 0xff, /* Trespass target */ | ||
140 | }; | ||
141 | unsigned data_size = h->short_trespass ? sizeof(short_trespass_pg) : | ||
142 | sizeof(long_trespass_pg); | ||
143 | |||
144 | /* get bio backing */ | ||
145 | if (data_size > PAGE_SIZE) | ||
146 | /* this should never happen */ | ||
147 | return NULL; | ||
148 | |||
149 | bio = get_failover_bio(path, data_size); | ||
150 | if (!bio) { | ||
151 | DMERR("emc_trespass_get: no bio"); | ||
152 | return NULL; | ||
153 | } | ||
154 | |||
155 | page22 = (unsigned char *)bio_data(bio); | ||
156 | memset(page22, 0, data_size); | ||
157 | |||
158 | memcpy(page22, h->short_trespass ? | ||
159 | short_trespass_pg : long_trespass_pg, data_size); | ||
160 | |||
161 | /* get request for block layer packet command */ | ||
162 | rq = get_failover_req(h, bio, path); | ||
163 | if (!rq) { | ||
164 | DMERR("emc_trespass_get: no rq"); | ||
165 | free_bio(bio); | ||
166 | return NULL; | ||
167 | } | ||
168 | |||
169 | /* Prepare the command. */ | ||
170 | rq->cmd[0] = MODE_SELECT; | ||
171 | rq->cmd[1] = 0x10; | ||
172 | rq->cmd[4] = data_size; | ||
173 | rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); | ||
174 | |||
175 | return rq; | ||
176 | } | ||
177 | |||
178 | static void emc_pg_init(struct hw_handler *hwh, unsigned bypassed, | ||
179 | struct dm_path *path) | ||
180 | { | ||
181 | struct request *rq; | ||
182 | struct request_queue *q = bdev_get_queue(path->dev->bdev); | ||
183 | |||
184 | /* | ||
185 | * We can either blindly init the pg (then look at the sense), | ||
186 | * or we can send some commands to get the state here (then | ||
187 | * possibly send the fo cmnd), or we can also have the | ||
188 | * initial state passed into us and then get an update here. | ||
189 | */ | ||
190 | if (!q) { | ||
191 | DMINFO("emc_pg_init: no queue"); | ||
192 | goto fail_path; | ||
193 | } | ||
194 | |||
195 | /* FIXME: The request should be pre-allocated. */ | ||
196 | rq = emc_trespass_get(hwh->context, path); | ||
197 | if (!rq) { | ||
198 | DMERR("emc_pg_init: no rq"); | ||
199 | goto fail_path; | ||
200 | } | ||
201 | |||
202 | DMINFO("emc_pg_init: sending switch-over command"); | ||
203 | elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1); | ||
204 | return; | ||
205 | |||
206 | fail_path: | ||
207 | dm_pg_init_complete(path, MP_FAIL_PATH); | ||
208 | } | ||
209 | |||
210 | static struct emc_handler *alloc_emc_handler(void) | ||
211 | { | ||
212 | struct emc_handler *h = kzalloc(sizeof(*h), GFP_KERNEL); | ||
213 | |||
214 | if (h) | ||
215 | spin_lock_init(&h->lock); | ||
216 | |||
217 | return h; | ||
218 | } | ||
219 | |||
220 | static int emc_create(struct hw_handler *hwh, unsigned argc, char **argv) | ||
221 | { | ||
222 | struct emc_handler *h; | ||
223 | unsigned hr, short_trespass; | ||
224 | |||
225 | if (argc == 0) { | ||
226 | /* No arguments: use defaults */ | ||
227 | hr = 0; | ||
228 | short_trespass = 0; | ||
229 | } else if (argc != 2) { | ||
230 | DMWARN("incorrect number of arguments"); | ||
231 | return -EINVAL; | ||
232 | } else { | ||
233 | if ((sscanf(argv[0], "%u", &short_trespass) != 1) | ||
234 | || (short_trespass > 1)) { | ||
235 | DMWARN("invalid trespass mode selected"); | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | if ((sscanf(argv[1], "%u", &hr) != 1) | ||
240 | || (hr > 1)) { | ||
241 | DMWARN("invalid honor reservation flag selected"); | ||
242 | return -EINVAL; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | h = alloc_emc_handler(); | ||
247 | if (!h) | ||
248 | return -ENOMEM; | ||
249 | |||
250 | hwh->context = h; | ||
251 | |||
252 | if ((h->short_trespass = short_trespass)) | ||
253 | DMWARN("short trespass command will be send"); | ||
254 | else | ||
255 | DMWARN("long trespass command will be send"); | ||
256 | |||
257 | if ((h->hr = hr)) | ||
258 | DMWARN("honor reservation bit will be set"); | ||
259 | else | ||
260 | DMWARN("honor reservation bit will not be set (default)"); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static void emc_destroy(struct hw_handler *hwh) | ||
266 | { | ||
267 | struct emc_handler *h = (struct emc_handler *) hwh->context; | ||
268 | |||
269 | kfree(h); | ||
270 | hwh->context = NULL; | ||
271 | } | ||
272 | |||
273 | static unsigned emc_error(struct hw_handler *hwh, struct bio *bio) | ||
274 | { | ||
275 | /* FIXME: Patch from axboe still missing */ | ||
276 | #if 0 | ||
277 | int sense; | ||
278 | |||
279 | if (bio->bi_error & BIO_SENSE) { | ||
280 | sense = bio->bi_error & 0xffffff; /* sense key / asc / ascq */ | ||
281 | |||
282 | if (sense == 0x020403) { | ||
283 | /* LUN Not Ready - Manual Intervention Required | ||
284 | * indicates this is a passive path. | ||
285 | * | ||
286 | * FIXME: However, if this is seen and EVPD C0 | ||
287 | * indicates that this is due to a NDU in | ||
288 | * progress, we should set FAIL_PATH too. | ||
289 | * This indicates we might have to do a SCSI | ||
290 | * inquiry in the end_io path. Ugh. */ | ||
291 | return MP_BYPASS_PG | MP_RETRY_IO; | ||
292 | } else if (sense == 0x052501) { | ||
293 | /* An array based copy is in progress. Do not | ||
294 | * fail the path, do not bypass to another PG, | ||
295 | * do not retry. Fail the IO immediately. | ||
296 | * (Actually this is the same conclusion as in | ||
297 | * the default handler, but lets make sure.) */ | ||
298 | return 0; | ||
299 | } else if (sense == 0x062900) { | ||
300 | /* Unit Attention Code. This is the first IO | ||
301 | * to the new path, so just retry. */ | ||
302 | return MP_RETRY_IO; | ||
303 | } | ||
304 | } | ||
305 | #endif | ||
306 | |||
307 | /* Try default handler */ | ||
308 | return dm_scsi_err_handler(hwh, bio); | ||
309 | } | ||
310 | |||
311 | static struct hw_handler_type emc_hwh = { | ||
312 | .name = "emc", | ||
313 | .module = THIS_MODULE, | ||
314 | .create = emc_create, | ||
315 | .destroy = emc_destroy, | ||
316 | .pg_init = emc_pg_init, | ||
317 | .error = emc_error, | ||
318 | }; | ||
319 | |||
320 | static int __init dm_emc_init(void) | ||
321 | { | ||
322 | int r = dm_register_hw_handler(&emc_hwh); | ||
323 | |||
324 | if (r < 0) | ||
325 | DMERR("register failed %d", r); | ||
326 | |||
327 | DMINFO("version 0.0.3 loaded"); | ||
328 | |||
329 | return r; | ||
330 | } | ||
331 | |||
332 | static void __exit dm_emc_exit(void) | ||
333 | { | ||
334 | int r = dm_unregister_hw_handler(&emc_hwh); | ||
335 | |||
336 | if (r < 0) | ||
337 | DMERR("unregister failed %d", r); | ||
338 | } | ||
339 | |||
340 | module_init(dm_emc_init); | ||
341 | module_exit(dm_emc_exit); | ||
342 | |||
343 | MODULE_DESCRIPTION(DM_NAME " EMC CX/AX/FC-family multipath"); | ||
344 | MODULE_AUTHOR("Lars Marowsky-Bree <lmb@suse.de>"); | ||
345 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/md/dm-hw-handler.c b/drivers/md/dm-hw-handler.c deleted file mode 100644 index 2ee84d8aa0bf..000000000000 --- a/drivers/md/dm-hw-handler.c +++ /dev/null | |||
@@ -1,213 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||
3 | * | ||
4 | * This file is released under the GPL. | ||
5 | * | ||
6 | * Multipath hardware handler registration. | ||
7 | */ | ||
8 | |||
9 | #include "dm.h" | ||
10 | #include "dm-hw-handler.h" | ||
11 | |||
12 | #include <linux/slab.h> | ||
13 | |||
14 | struct hwh_internal { | ||
15 | struct hw_handler_type hwht; | ||
16 | |||
17 | struct list_head list; | ||
18 | long use; | ||
19 | }; | ||
20 | |||
21 | #define hwht_to_hwhi(__hwht) container_of((__hwht), struct hwh_internal, hwht) | ||
22 | |||
23 | static LIST_HEAD(_hw_handlers); | ||
24 | static DECLARE_RWSEM(_hwh_lock); | ||
25 | |||
26 | static struct hwh_internal *__find_hw_handler_type(const char *name) | ||
27 | { | ||
28 | struct hwh_internal *hwhi; | ||
29 | |||
30 | list_for_each_entry(hwhi, &_hw_handlers, list) { | ||
31 | if (!strcmp(name, hwhi->hwht.name)) | ||
32 | return hwhi; | ||
33 | } | ||
34 | |||
35 | return NULL; | ||
36 | } | ||
37 | |||
38 | static struct hwh_internal *get_hw_handler(const char *name) | ||
39 | { | ||
40 | struct hwh_internal *hwhi; | ||
41 | |||
42 | down_read(&_hwh_lock); | ||
43 | hwhi = __find_hw_handler_type(name); | ||
44 | if (hwhi) { | ||
45 | if ((hwhi->use == 0) && !try_module_get(hwhi->hwht.module)) | ||
46 | hwhi = NULL; | ||
47 | else | ||
48 | hwhi->use++; | ||
49 | } | ||
50 | up_read(&_hwh_lock); | ||
51 | |||
52 | return hwhi; | ||
53 | } | ||
54 | |||
55 | struct hw_handler_type *dm_get_hw_handler(const char *name) | ||
56 | { | ||
57 | struct hwh_internal *hwhi; | ||
58 | |||
59 | if (!name) | ||
60 | return NULL; | ||
61 | |||
62 | hwhi = get_hw_handler(name); | ||
63 | if (!hwhi) { | ||
64 | request_module("dm-%s", name); | ||
65 | hwhi = get_hw_handler(name); | ||
66 | } | ||
67 | |||
68 | return hwhi ? &hwhi->hwht : NULL; | ||
69 | } | ||
70 | |||
71 | void dm_put_hw_handler(struct hw_handler_type *hwht) | ||
72 | { | ||
73 | struct hwh_internal *hwhi; | ||
74 | |||
75 | if (!hwht) | ||
76 | return; | ||
77 | |||
78 | down_read(&_hwh_lock); | ||
79 | hwhi = __find_hw_handler_type(hwht->name); | ||
80 | if (!hwhi) | ||
81 | goto out; | ||
82 | |||
83 | if (--hwhi->use == 0) | ||
84 | module_put(hwhi->hwht.module); | ||
85 | |||
86 | BUG_ON(hwhi->use < 0); | ||
87 | |||
88 | out: | ||
89 | up_read(&_hwh_lock); | ||
90 | } | ||
91 | |||
92 | static struct hwh_internal *_alloc_hw_handler(struct hw_handler_type *hwht) | ||
93 | { | ||
94 | struct hwh_internal *hwhi = kzalloc(sizeof(*hwhi), GFP_KERNEL); | ||
95 | |||
96 | if (hwhi) | ||
97 | hwhi->hwht = *hwht; | ||
98 | |||
99 | return hwhi; | ||
100 | } | ||
101 | |||
102 | int dm_register_hw_handler(struct hw_handler_type *hwht) | ||
103 | { | ||
104 | int r = 0; | ||
105 | struct hwh_internal *hwhi = _alloc_hw_handler(hwht); | ||
106 | |||
107 | if (!hwhi) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | down_write(&_hwh_lock); | ||
111 | |||
112 | if (__find_hw_handler_type(hwht->name)) { | ||
113 | kfree(hwhi); | ||
114 | r = -EEXIST; | ||
115 | } else | ||
116 | list_add(&hwhi->list, &_hw_handlers); | ||
117 | |||
118 | up_write(&_hwh_lock); | ||
119 | |||
120 | return r; | ||
121 | } | ||
122 | |||
123 | int dm_unregister_hw_handler(struct hw_handler_type *hwht) | ||
124 | { | ||
125 | struct hwh_internal *hwhi; | ||
126 | |||
127 | down_write(&_hwh_lock); | ||
128 | |||
129 | hwhi = __find_hw_handler_type(hwht->name); | ||
130 | if (!hwhi) { | ||
131 | up_write(&_hwh_lock); | ||
132 | return -EINVAL; | ||
133 | } | ||
134 | |||
135 | if (hwhi->use) { | ||
136 | up_write(&_hwh_lock); | ||
137 | return -ETXTBSY; | ||
138 | } | ||
139 | |||
140 | list_del(&hwhi->list); | ||
141 | |||
142 | up_write(&_hwh_lock); | ||
143 | |||
144 | kfree(hwhi); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | unsigned dm_scsi_err_handler(struct hw_handler *hwh, struct bio *bio) | ||
150 | { | ||
151 | #if 0 | ||
152 | int sense_key, asc, ascq; | ||
153 | |||
154 | if (bio->bi_error & BIO_SENSE) { | ||
155 | /* FIXME: This is just an initial guess. */ | ||
156 | /* key / asc / ascq */ | ||
157 | sense_key = (bio->bi_error >> 16) & 0xff; | ||
158 | asc = (bio->bi_error >> 8) & 0xff; | ||
159 | ascq = bio->bi_error & 0xff; | ||
160 | |||
161 | switch (sense_key) { | ||
162 | /* This block as a whole comes from the device. | ||
163 | * So no point retrying on another path. */ | ||
164 | case 0x03: /* Medium error */ | ||
165 | case 0x05: /* Illegal request */ | ||
166 | case 0x07: /* Data protect */ | ||
167 | case 0x08: /* Blank check */ | ||
168 | case 0x0a: /* copy aborted */ | ||
169 | case 0x0c: /* obsolete - no clue ;-) */ | ||
170 | case 0x0d: /* volume overflow */ | ||
171 | case 0x0e: /* data miscompare */ | ||
172 | case 0x0f: /* reserved - no idea either. */ | ||
173 | return MP_ERROR_IO; | ||
174 | |||
175 | /* For these errors it's unclear whether they | ||
176 | * come from the device or the controller. | ||
177 | * So just lets try a different path, and if | ||
178 | * it eventually succeeds, user-space will clear | ||
179 | * the paths again... */ | ||
180 | case 0x02: /* Not ready */ | ||
181 | case 0x04: /* Hardware error */ | ||
182 | case 0x09: /* vendor specific */ | ||
183 | case 0x0b: /* Aborted command */ | ||
184 | return MP_FAIL_PATH; | ||
185 | |||
186 | case 0x06: /* Unit attention - might want to decode */ | ||
187 | if (asc == 0x04 && ascq == 0x01) | ||
188 | /* "Unit in the process of | ||
189 | * becoming ready" */ | ||
190 | return 0; | ||
191 | return MP_FAIL_PATH; | ||
192 | |||
193 | /* FIXME: For Unit Not Ready we may want | ||
194 | * to have a generic pg activation | ||
195 | * feature (START_UNIT). */ | ||
196 | |||
197 | /* Should these two ever end up in the | ||
198 | * error path? I don't think so. */ | ||
199 | case 0x00: /* No sense */ | ||
200 | case 0x01: /* Recovered error */ | ||
201 | return 0; | ||
202 | } | ||
203 | } | ||
204 | #endif | ||
205 | |||
206 | /* We got no idea how to decode the other kinds of errors -> | ||
207 | * assume generic error condition. */ | ||
208 | return MP_FAIL_PATH; | ||
209 | } | ||
210 | |||
211 | EXPORT_SYMBOL_GPL(dm_register_hw_handler); | ||
212 | EXPORT_SYMBOL_GPL(dm_unregister_hw_handler); | ||
213 | EXPORT_SYMBOL_GPL(dm_scsi_err_handler); | ||
diff --git a/drivers/md/dm-hw-handler.h b/drivers/md/dm-hw-handler.h deleted file mode 100644 index 46809dcb121a..000000000000 --- a/drivers/md/dm-hw-handler.h +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | ||
3 | * | ||
4 | * This file is released under the GPL. | ||
5 | * | ||
6 | * Multipath hardware handler registration. | ||
7 | */ | ||
8 | |||
9 | #ifndef DM_HW_HANDLER_H | ||
10 | #define DM_HW_HANDLER_H | ||
11 | |||
12 | #include <linux/device-mapper.h> | ||
13 | |||
14 | #include "dm-mpath.h" | ||
15 | |||
16 | struct hw_handler_type; | ||
17 | struct hw_handler { | ||
18 | struct hw_handler_type *type; | ||
19 | struct mapped_device *md; | ||
20 | void *context; | ||
21 | }; | ||
22 | |||
23 | /* | ||
24 | * Constructs a hardware handler object, takes custom arguments | ||
25 | */ | ||
26 | /* Information about a hardware handler type */ | ||
27 | struct hw_handler_type { | ||
28 | char *name; | ||
29 | struct module *module; | ||
30 | |||
31 | int (*create) (struct hw_handler *handler, unsigned int argc, | ||
32 | char **argv); | ||
33 | void (*destroy) (struct hw_handler *hwh); | ||
34 | |||
35 | void (*pg_init) (struct hw_handler *hwh, unsigned bypassed, | ||
36 | struct dm_path *path); | ||
37 | unsigned (*error) (struct hw_handler *hwh, struct bio *bio); | ||
38 | int (*status) (struct hw_handler *hwh, status_type_t type, | ||
39 | char *result, unsigned int maxlen); | ||
40 | }; | ||
41 | |||
42 | /* Register a hardware handler */ | ||
43 | int dm_register_hw_handler(struct hw_handler_type *type); | ||
44 | |||
45 | /* Unregister a hardware handler */ | ||
46 | int dm_unregister_hw_handler(struct hw_handler_type *type); | ||
47 | |||
48 | /* Returns a registered hardware handler type */ | ||
49 | struct hw_handler_type *dm_get_hw_handler(const char *name); | ||
50 | |||
51 | /* Releases a hardware handler */ | ||
52 | void dm_put_hw_handler(struct hw_handler_type *hwht); | ||
53 | |||
54 | /* Default err function */ | ||
55 | unsigned dm_scsi_err_handler(struct hw_handler *hwh, struct bio *bio); | ||
56 | |||
57 | /* Error flags for err and dm_pg_init_complete */ | ||
58 | #define MP_FAIL_PATH 1 | ||
59 | #define MP_BYPASS_PG 2 | ||
60 | #define MP_ERROR_IO 4 /* Don't retry this I/O */ | ||
61 | #define MP_RETRY 8 | ||
62 | |||
63 | #endif | ||
diff --git a/drivers/md/dm-mpath-hp-sw.c b/drivers/md/dm-mpath-hp-sw.c deleted file mode 100644 index b63a0ab37c53..000000000000 --- a/drivers/md/dm-mpath-hp-sw.c +++ /dev/null | |||
@@ -1,247 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Mike Christie, All rights reserved. | ||
3 | * Copyright (C) 2007 Red Hat, Inc. All rights reserved. | ||
4 | * Authors: Mike Christie | ||
5 | * Dave Wysochanski | ||
6 | * | ||
7 | * This file is released under the GPL. | ||
8 | * | ||
9 | * This module implements the specific path activation code for | ||
10 | * HP StorageWorks and FSC FibreCat Asymmetric (Active/Passive) | ||
11 | * storage arrays. | ||
12 | * These storage arrays have controller-based failover, not | ||
13 | * LUN-based failover. However, LUN-based failover is the design | ||
14 | * of dm-multipath. Thus, this module is written for LUN-based failover. | ||
15 | */ | ||
16 | #include <linux/blkdev.h> | ||
17 | #include <linux/list.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <scsi/scsi.h> | ||
20 | #include <scsi/scsi_cmnd.h> | ||
21 | #include <scsi/scsi_dbg.h> | ||
22 | |||
23 | #include "dm.h" | ||
24 | #include "dm-hw-handler.h" | ||
25 | |||
26 | #define DM_MSG_PREFIX "multipath hp-sw" | ||
27 | #define DM_HP_HWH_NAME "hp-sw" | ||
28 | #define DM_HP_HWH_VER "1.0.0" | ||
29 | |||
30 | struct hp_sw_context { | ||
31 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
32 | }; | ||
33 | |||
34 | /* | ||
35 | * hp_sw_error_is_retryable - Is an HP-specific check condition retryable? | ||
36 | * @req: path activation request | ||
37 | * | ||
38 | * Examine error codes of request and determine whether the error is retryable. | ||
39 | * Some error codes are already retried by scsi-ml (see | ||
40 | * scsi_decide_disposition), but some HP specific codes are not. | ||
41 | * The intent of this routine is to supply the logic for the HP specific | ||
42 | * check conditions. | ||
43 | * | ||
44 | * Returns: | ||
45 | * 1 - command completed with retryable error | ||
46 | * 0 - command completed with non-retryable error | ||
47 | * | ||
48 | * Possible optimizations | ||
49 | * 1. More hardware-specific error codes | ||
50 | */ | ||
51 | static int hp_sw_error_is_retryable(struct request *req) | ||
52 | { | ||
53 | /* | ||
54 | * NOT_READY is known to be retryable | ||
55 | * For now we just dump out the sense data and call it retryable | ||
56 | */ | ||
57 | if (status_byte(req->errors) == CHECK_CONDITION) | ||
58 | __scsi_print_sense(DM_HP_HWH_NAME, req->sense, req->sense_len); | ||
59 | |||
60 | /* | ||
61 | * At this point we don't have complete information about all the error | ||
62 | * codes from this hardware, so we are just conservative and retry | ||
63 | * when in doubt. | ||
64 | */ | ||
65 | return 1; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * hp_sw_end_io - Completion handler for HP path activation. | ||
70 | * @req: path activation request | ||
71 | * @error: scsi-ml error | ||
72 | * | ||
73 | * Check sense data, free request structure, and notify dm that | ||
74 | * pg initialization has completed. | ||
75 | * | ||
76 | * Context: scsi-ml softirq | ||
77 | * | ||
78 | */ | ||
79 | static void hp_sw_end_io(struct request *req, int error) | ||
80 | { | ||
81 | struct dm_path *path = req->end_io_data; | ||
82 | unsigned err_flags = 0; | ||
83 | |||
84 | if (!error) { | ||
85 | DMDEBUG("%s path activation command - success", | ||
86 | path->dev->name); | ||
87 | goto out; | ||
88 | } | ||
89 | |||
90 | if (hp_sw_error_is_retryable(req)) { | ||
91 | DMDEBUG("%s path activation command - retry", | ||
92 | path->dev->name); | ||
93 | err_flags = MP_RETRY; | ||
94 | goto out; | ||
95 | } | ||
96 | |||
97 | DMWARN("%s path activation fail - error=0x%x", | ||
98 | path->dev->name, error); | ||
99 | err_flags = MP_FAIL_PATH; | ||
100 | |||
101 | out: | ||
102 | req->end_io_data = NULL; | ||
103 | __blk_put_request(req->q, req); | ||
104 | dm_pg_init_complete(path, err_flags); | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * hp_sw_get_request - Allocate an HP specific path activation request | ||
109 | * @path: path on which request will be sent (needed for request queue) | ||
110 | * | ||
111 | * The START command is used for path activation request. | ||
112 | * These arrays are controller-based failover, not LUN based. | ||
113 | * One START command issued to a single path will fail over all | ||
114 | * LUNs for the same controller. | ||
115 | * | ||
116 | * Possible optimizations | ||
117 | * 1. Make timeout configurable | ||
118 | * 2. Preallocate request | ||
119 | */ | ||
120 | static struct request *hp_sw_get_request(struct dm_path *path) | ||
121 | { | ||
122 | struct request *req; | ||
123 | struct block_device *bdev = path->dev->bdev; | ||
124 | struct request_queue *q = bdev_get_queue(bdev); | ||
125 | struct hp_sw_context *h = path->hwhcontext; | ||
126 | |||
127 | req = blk_get_request(q, WRITE, GFP_NOIO); | ||
128 | if (!req) | ||
129 | goto out; | ||
130 | |||
131 | req->timeout = 60 * HZ; | ||
132 | |||
133 | req->errors = 0; | ||
134 | req->cmd_type = REQ_TYPE_BLOCK_PC; | ||
135 | req->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; | ||
136 | req->end_io_data = path; | ||
137 | req->sense = h->sense; | ||
138 | memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
139 | |||
140 | req->cmd[0] = START_STOP; | ||
141 | req->cmd[4] = 1; | ||
142 | req->cmd_len = COMMAND_SIZE(req->cmd[0]); | ||
143 | |||
144 | out: | ||
145 | return req; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * hp_sw_pg_init - HP path activation implementation. | ||
150 | * @hwh: hardware handler specific data | ||
151 | * @bypassed: unused; is the path group bypassed? (see dm-mpath.c) | ||
152 | * @path: path to send initialization command | ||
153 | * | ||
154 | * Send an HP-specific path activation command on 'path'. | ||
155 | * Do not try to optimize in any way, just send the activation command. | ||
156 | * More than one path activation command may be sent to the same controller. | ||
157 | * This seems to work fine for basic failover support. | ||
158 | * | ||
159 | * Possible optimizations | ||
160 | * 1. Detect an in-progress activation request and avoid submitting another one | ||
161 | * 2. Model the controller and only send a single activation request at a time | ||
162 | * 3. Determine the state of a path before sending an activation request | ||
163 | * | ||
164 | * Context: kmpathd (see process_queued_ios() in dm-mpath.c) | ||
165 | */ | ||
166 | static void hp_sw_pg_init(struct hw_handler *hwh, unsigned bypassed, | ||
167 | struct dm_path *path) | ||
168 | { | ||
169 | struct request *req; | ||
170 | struct hp_sw_context *h; | ||
171 | |||
172 | path->hwhcontext = hwh->context; | ||
173 | h = hwh->context; | ||
174 | |||
175 | req = hp_sw_get_request(path); | ||
176 | if (!req) { | ||
177 | DMERR("%s path activation command - allocation fail", | ||
178 | path->dev->name); | ||
179 | goto retry; | ||
180 | } | ||
181 | |||
182 | DMDEBUG("%s path activation command - sent", path->dev->name); | ||
183 | |||
184 | blk_execute_rq_nowait(req->q, NULL, req, 1, hp_sw_end_io); | ||
185 | return; | ||
186 | |||
187 | retry: | ||
188 | dm_pg_init_complete(path, MP_RETRY); | ||
189 | } | ||
190 | |||
191 | static int hp_sw_create(struct hw_handler *hwh, unsigned argc, char **argv) | ||
192 | { | ||
193 | struct hp_sw_context *h; | ||
194 | |||
195 | h = kmalloc(sizeof(*h), GFP_KERNEL); | ||
196 | if (!h) | ||
197 | return -ENOMEM; | ||
198 | |||
199 | hwh->context = h; | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static void hp_sw_destroy(struct hw_handler *hwh) | ||
205 | { | ||
206 | struct hp_sw_context *h = hwh->context; | ||
207 | |||
208 | kfree(h); | ||
209 | } | ||
210 | |||
211 | static struct hw_handler_type hp_sw_hwh = { | ||
212 | .name = DM_HP_HWH_NAME, | ||
213 | .module = THIS_MODULE, | ||
214 | .create = hp_sw_create, | ||
215 | .destroy = hp_sw_destroy, | ||
216 | .pg_init = hp_sw_pg_init, | ||
217 | }; | ||
218 | |||
219 | static int __init hp_sw_init(void) | ||
220 | { | ||
221 | int r; | ||
222 | |||
223 | r = dm_register_hw_handler(&hp_sw_hwh); | ||
224 | if (r < 0) | ||
225 | DMERR("register failed %d", r); | ||
226 | else | ||
227 | DMINFO("version " DM_HP_HWH_VER " loaded"); | ||
228 | |||
229 | return r; | ||
230 | } | ||
231 | |||
232 | static void __exit hp_sw_exit(void) | ||
233 | { | ||
234 | int r; | ||
235 | |||
236 | r = dm_unregister_hw_handler(&hp_sw_hwh); | ||
237 | if (r < 0) | ||
238 | DMERR("unregister failed %d", r); | ||
239 | } | ||
240 | |||
241 | module_init(hp_sw_init); | ||
242 | module_exit(hp_sw_exit); | ||
243 | |||
244 | MODULE_DESCRIPTION("DM Multipath HP StorageWorks / FSC FibreCat (A/P) support"); | ||
245 | MODULE_AUTHOR("Mike Christie, Dave Wysochanski <dm-devel@redhat.com>"); | ||
246 | MODULE_LICENSE("GPL"); | ||
247 | MODULE_VERSION(DM_HP_HWH_VER); | ||
diff --git a/drivers/md/dm-mpath-rdac.c b/drivers/md/dm-mpath-rdac.c deleted file mode 100644 index 95e77734880a..000000000000 --- a/drivers/md/dm-mpath-rdac.c +++ /dev/null | |||
@@ -1,700 +0,0 @@ | |||
1 | /* | ||
2 | * Engenio/LSI RDAC DM HW handler | ||
3 | * | ||
4 | * Copyright (C) 2005 Mike Christie. All rights reserved. | ||
5 | * Copyright (C) Chandra Seetharaman, IBM Corp. 2007 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | * | ||
21 | */ | ||
22 | #include <scsi/scsi.h> | ||
23 | #include <scsi/scsi_cmnd.h> | ||
24 | #include <scsi/scsi_eh.h> | ||
25 | |||
26 | #define DM_MSG_PREFIX "multipath rdac" | ||
27 | |||
28 | #include "dm.h" | ||
29 | #include "dm-hw-handler.h" | ||
30 | |||
31 | #define RDAC_DM_HWH_NAME "rdac" | ||
32 | #define RDAC_DM_HWH_VER "0.4" | ||
33 | |||
34 | /* | ||
35 | * LSI mode page stuff | ||
36 | * | ||
37 | * These struct definitions and the forming of the | ||
38 | * mode page were taken from the LSI RDAC 2.4 GPL'd | ||
39 | * driver, and then converted to Linux conventions. | ||
40 | */ | ||
41 | #define RDAC_QUIESCENCE_TIME 20; | ||
42 | /* | ||
43 | * Page Codes | ||
44 | */ | ||
45 | #define RDAC_PAGE_CODE_REDUNDANT_CONTROLLER 0x2c | ||
46 | |||
47 | /* | ||
48 | * Controller modes definitions | ||
49 | */ | ||
50 | #define RDAC_MODE_TRANSFER_ALL_LUNS 0x01 | ||
51 | #define RDAC_MODE_TRANSFER_SPECIFIED_LUNS 0x02 | ||
52 | |||
53 | /* | ||
54 | * RDAC Options field | ||
55 | */ | ||
56 | #define RDAC_FORCED_QUIESENCE 0x02 | ||
57 | |||
58 | #define RDAC_FAILOVER_TIMEOUT (60 * HZ) | ||
59 | |||
60 | struct rdac_mode_6_hdr { | ||
61 | u8 data_len; | ||
62 | u8 medium_type; | ||
63 | u8 device_params; | ||
64 | u8 block_desc_len; | ||
65 | }; | ||
66 | |||
67 | struct rdac_mode_10_hdr { | ||
68 | u16 data_len; | ||
69 | u8 medium_type; | ||
70 | u8 device_params; | ||
71 | u16 reserved; | ||
72 | u16 block_desc_len; | ||
73 | }; | ||
74 | |||
75 | struct rdac_mode_common { | ||
76 | u8 controller_serial[16]; | ||
77 | u8 alt_controller_serial[16]; | ||
78 | u8 rdac_mode[2]; | ||
79 | u8 alt_rdac_mode[2]; | ||
80 | u8 quiescence_timeout; | ||
81 | u8 rdac_options; | ||
82 | }; | ||
83 | |||
84 | struct rdac_pg_legacy { | ||
85 | struct rdac_mode_6_hdr hdr; | ||
86 | u8 page_code; | ||
87 | u8 page_len; | ||
88 | struct rdac_mode_common common; | ||
89 | #define MODE6_MAX_LUN 32 | ||
90 | u8 lun_table[MODE6_MAX_LUN]; | ||
91 | u8 reserved2[32]; | ||
92 | u8 reserved3; | ||
93 | u8 reserved4; | ||
94 | }; | ||
95 | |||
96 | struct rdac_pg_expanded { | ||
97 | struct rdac_mode_10_hdr hdr; | ||
98 | u8 page_code; | ||
99 | u8 subpage_code; | ||
100 | u8 page_len[2]; | ||
101 | struct rdac_mode_common common; | ||
102 | u8 lun_table[256]; | ||
103 | u8 reserved3; | ||
104 | u8 reserved4; | ||
105 | }; | ||
106 | |||
107 | struct c9_inquiry { | ||
108 | u8 peripheral_info; | ||
109 | u8 page_code; /* 0xC9 */ | ||
110 | u8 reserved1; | ||
111 | u8 page_len; | ||
112 | u8 page_id[4]; /* "vace" */ | ||
113 | u8 avte_cvp; | ||
114 | u8 path_prio; | ||
115 | u8 reserved2[38]; | ||
116 | }; | ||
117 | |||
118 | #define SUBSYS_ID_LEN 16 | ||
119 | #define SLOT_ID_LEN 2 | ||
120 | |||
121 | struct c4_inquiry { | ||
122 | u8 peripheral_info; | ||
123 | u8 page_code; /* 0xC4 */ | ||
124 | u8 reserved1; | ||
125 | u8 page_len; | ||
126 | u8 page_id[4]; /* "subs" */ | ||
127 | u8 subsys_id[SUBSYS_ID_LEN]; | ||
128 | u8 revision[4]; | ||
129 | u8 slot_id[SLOT_ID_LEN]; | ||
130 | u8 reserved[2]; | ||
131 | }; | ||
132 | |||
133 | struct rdac_controller { | ||
134 | u8 subsys_id[SUBSYS_ID_LEN]; | ||
135 | u8 slot_id[SLOT_ID_LEN]; | ||
136 | int use_10_ms; | ||
137 | struct kref kref; | ||
138 | struct list_head node; /* list of all controllers */ | ||
139 | spinlock_t lock; | ||
140 | int submitted; | ||
141 | struct list_head cmd_list; /* list of commands to be submitted */ | ||
142 | union { | ||
143 | struct rdac_pg_legacy legacy; | ||
144 | struct rdac_pg_expanded expanded; | ||
145 | } mode_select; | ||
146 | }; | ||
147 | struct c8_inquiry { | ||
148 | u8 peripheral_info; | ||
149 | u8 page_code; /* 0xC8 */ | ||
150 | u8 reserved1; | ||
151 | u8 page_len; | ||
152 | u8 page_id[4]; /* "edid" */ | ||
153 | u8 reserved2[3]; | ||
154 | u8 vol_uniq_id_len; | ||
155 | u8 vol_uniq_id[16]; | ||
156 | u8 vol_user_label_len; | ||
157 | u8 vol_user_label[60]; | ||
158 | u8 array_uniq_id_len; | ||
159 | u8 array_unique_id[16]; | ||
160 | u8 array_user_label_len; | ||
161 | u8 array_user_label[60]; | ||
162 | u8 lun[8]; | ||
163 | }; | ||
164 | |||
165 | struct c2_inquiry { | ||
166 | u8 peripheral_info; | ||
167 | u8 page_code; /* 0xC2 */ | ||
168 | u8 reserved1; | ||
169 | u8 page_len; | ||
170 | u8 page_id[4]; /* "swr4" */ | ||
171 | u8 sw_version[3]; | ||
172 | u8 sw_date[3]; | ||
173 | u8 features_enabled; | ||
174 | u8 max_lun_supported; | ||
175 | u8 partitions[239]; /* Total allocation length should be 0xFF */ | ||
176 | }; | ||
177 | |||
178 | struct rdac_handler { | ||
179 | struct list_head entry; /* list waiting to submit MODE SELECT */ | ||
180 | unsigned timeout; | ||
181 | struct rdac_controller *ctlr; | ||
182 | #define UNINITIALIZED_LUN (1 << 8) | ||
183 | unsigned lun; | ||
184 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
185 | struct dm_path *path; | ||
186 | struct work_struct work; | ||
187 | #define SEND_C2_INQUIRY 1 | ||
188 | #define SEND_C4_INQUIRY 2 | ||
189 | #define SEND_C8_INQUIRY 3 | ||
190 | #define SEND_C9_INQUIRY 4 | ||
191 | #define SEND_MODE_SELECT 5 | ||
192 | int cmd_to_send; | ||
193 | union { | ||
194 | struct c2_inquiry c2; | ||
195 | struct c4_inquiry c4; | ||
196 | struct c8_inquiry c8; | ||
197 | struct c9_inquiry c9; | ||
198 | } inq; | ||
199 | }; | ||
200 | |||
201 | static LIST_HEAD(ctlr_list); | ||
202 | static DEFINE_SPINLOCK(list_lock); | ||
203 | static struct workqueue_struct *rdac_wkqd; | ||
204 | |||
205 | static inline int had_failures(struct request *req, int error) | ||
206 | { | ||
207 | return (error || host_byte(req->errors) != DID_OK || | ||
208 | msg_byte(req->errors) != COMMAND_COMPLETE); | ||
209 | } | ||
210 | |||
211 | static void rdac_resubmit_all(struct rdac_handler *h) | ||
212 | { | ||
213 | struct rdac_controller *ctlr = h->ctlr; | ||
214 | struct rdac_handler *tmp, *h1; | ||
215 | |||
216 | spin_lock(&ctlr->lock); | ||
217 | list_for_each_entry_safe(h1, tmp, &ctlr->cmd_list, entry) { | ||
218 | h1->cmd_to_send = SEND_C9_INQUIRY; | ||
219 | queue_work(rdac_wkqd, &h1->work); | ||
220 | list_del(&h1->entry); | ||
221 | } | ||
222 | ctlr->submitted = 0; | ||
223 | spin_unlock(&ctlr->lock); | ||
224 | } | ||
225 | |||
226 | static void mode_select_endio(struct request *req, int error) | ||
227 | { | ||
228 | struct rdac_handler *h = req->end_io_data; | ||
229 | struct scsi_sense_hdr sense_hdr; | ||
230 | int sense = 0, fail = 0; | ||
231 | |||
232 | if (had_failures(req, error)) { | ||
233 | fail = 1; | ||
234 | goto failed; | ||
235 | } | ||
236 | |||
237 | if (status_byte(req->errors) == CHECK_CONDITION) { | ||
238 | scsi_normalize_sense(req->sense, SCSI_SENSE_BUFFERSIZE, | ||
239 | &sense_hdr); | ||
240 | sense = (sense_hdr.sense_key << 16) | (sense_hdr.asc << 8) | | ||
241 | sense_hdr.ascq; | ||
242 | /* If it is retryable failure, submit the c9 inquiry again */ | ||
243 | if (sense == 0x59136 || sense == 0x68b02 || sense == 0xb8b02 || | ||
244 | sense == 0x62900) { | ||
245 | /* 0x59136 - Command lock contention | ||
246 | * 0x[6b]8b02 - Quiesense in progress or achieved | ||
247 | * 0x62900 - Power On, Reset, or Bus Device Reset | ||
248 | */ | ||
249 | h->cmd_to_send = SEND_C9_INQUIRY; | ||
250 | queue_work(rdac_wkqd, &h->work); | ||
251 | goto done; | ||
252 | } | ||
253 | if (sense) | ||
254 | DMINFO("MODE_SELECT failed on %s with sense 0x%x", | ||
255 | h->path->dev->name, sense); | ||
256 | } | ||
257 | failed: | ||
258 | if (fail || sense) | ||
259 | dm_pg_init_complete(h->path, MP_FAIL_PATH); | ||
260 | else | ||
261 | dm_pg_init_complete(h->path, 0); | ||
262 | |||
263 | done: | ||
264 | rdac_resubmit_all(h); | ||
265 | __blk_put_request(req->q, req); | ||
266 | } | ||
267 | |||
268 | static struct request *get_rdac_req(struct rdac_handler *h, | ||
269 | void *buffer, unsigned buflen, int rw) | ||
270 | { | ||
271 | struct request *rq; | ||
272 | struct request_queue *q = bdev_get_queue(h->path->dev->bdev); | ||
273 | |||
274 | rq = blk_get_request(q, rw, GFP_KERNEL); | ||
275 | |||
276 | if (!rq) { | ||
277 | DMINFO("get_rdac_req: blk_get_request failed"); | ||
278 | return NULL; | ||
279 | } | ||
280 | |||
281 | if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_KERNEL)) { | ||
282 | blk_put_request(rq); | ||
283 | DMINFO("get_rdac_req: blk_rq_map_kern failed"); | ||
284 | return NULL; | ||
285 | } | ||
286 | |||
287 | rq->sense = h->sense; | ||
288 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
289 | rq->sense_len = 0; | ||
290 | |||
291 | rq->end_io_data = h; | ||
292 | rq->timeout = h->timeout; | ||
293 | rq->cmd_type = REQ_TYPE_BLOCK_PC; | ||
294 | rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; | ||
295 | return rq; | ||
296 | } | ||
297 | |||
298 | static struct request *rdac_failover_get(struct rdac_handler *h) | ||
299 | { | ||
300 | struct request *rq; | ||
301 | struct rdac_mode_common *common; | ||
302 | unsigned data_size; | ||
303 | |||
304 | if (h->ctlr->use_10_ms) { | ||
305 | struct rdac_pg_expanded *rdac_pg; | ||
306 | |||
307 | data_size = sizeof(struct rdac_pg_expanded); | ||
308 | rdac_pg = &h->ctlr->mode_select.expanded; | ||
309 | memset(rdac_pg, 0, data_size); | ||
310 | common = &rdac_pg->common; | ||
311 | rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER + 0x40; | ||
312 | rdac_pg->subpage_code = 0x1; | ||
313 | rdac_pg->page_len[0] = 0x01; | ||
314 | rdac_pg->page_len[1] = 0x28; | ||
315 | rdac_pg->lun_table[h->lun] = 0x81; | ||
316 | } else { | ||
317 | struct rdac_pg_legacy *rdac_pg; | ||
318 | |||
319 | data_size = sizeof(struct rdac_pg_legacy); | ||
320 | rdac_pg = &h->ctlr->mode_select.legacy; | ||
321 | memset(rdac_pg, 0, data_size); | ||
322 | common = &rdac_pg->common; | ||
323 | rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER; | ||
324 | rdac_pg->page_len = 0x68; | ||
325 | rdac_pg->lun_table[h->lun] = 0x81; | ||
326 | } | ||
327 | common->rdac_mode[1] = RDAC_MODE_TRANSFER_SPECIFIED_LUNS; | ||
328 | common->quiescence_timeout = RDAC_QUIESCENCE_TIME; | ||
329 | common->rdac_options = RDAC_FORCED_QUIESENCE; | ||
330 | |||
331 | /* get request for block layer packet command */ | ||
332 | rq = get_rdac_req(h, &h->ctlr->mode_select, data_size, WRITE); | ||
333 | if (!rq) { | ||
334 | DMERR("rdac_failover_get: no rq"); | ||
335 | return NULL; | ||
336 | } | ||
337 | |||
338 | /* Prepare the command. */ | ||
339 | if (h->ctlr->use_10_ms) { | ||
340 | rq->cmd[0] = MODE_SELECT_10; | ||
341 | rq->cmd[7] = data_size >> 8; | ||
342 | rq->cmd[8] = data_size & 0xff; | ||
343 | } else { | ||
344 | rq->cmd[0] = MODE_SELECT; | ||
345 | rq->cmd[4] = data_size; | ||
346 | } | ||
347 | rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); | ||
348 | |||
349 | return rq; | ||
350 | } | ||
351 | |||
352 | /* Acquires h->ctlr->lock */ | ||
353 | static void submit_mode_select(struct rdac_handler *h) | ||
354 | { | ||
355 | struct request *rq; | ||
356 | struct request_queue *q = bdev_get_queue(h->path->dev->bdev); | ||
357 | |||
358 | spin_lock(&h->ctlr->lock); | ||
359 | if (h->ctlr->submitted) { | ||
360 | list_add(&h->entry, &h->ctlr->cmd_list); | ||
361 | goto drop_lock; | ||
362 | } | ||
363 | |||
364 | if (!q) { | ||
365 | DMINFO("submit_mode_select: no queue"); | ||
366 | goto fail_path; | ||
367 | } | ||
368 | |||
369 | rq = rdac_failover_get(h); | ||
370 | if (!rq) { | ||
371 | DMERR("submit_mode_select: no rq"); | ||
372 | goto fail_path; | ||
373 | } | ||
374 | |||
375 | DMINFO("queueing MODE_SELECT command on %s", h->path->dev->name); | ||
376 | |||
377 | blk_execute_rq_nowait(q, NULL, rq, 1, mode_select_endio); | ||
378 | h->ctlr->submitted = 1; | ||
379 | goto drop_lock; | ||
380 | fail_path: | ||
381 | dm_pg_init_complete(h->path, MP_FAIL_PATH); | ||
382 | drop_lock: | ||
383 | spin_unlock(&h->ctlr->lock); | ||
384 | } | ||
385 | |||
386 | static void release_ctlr(struct kref *kref) | ||
387 | { | ||
388 | struct rdac_controller *ctlr; | ||
389 | ctlr = container_of(kref, struct rdac_controller, kref); | ||
390 | |||
391 | spin_lock(&list_lock); | ||
392 | list_del(&ctlr->node); | ||
393 | spin_unlock(&list_lock); | ||
394 | kfree(ctlr); | ||
395 | } | ||
396 | |||
397 | static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id) | ||
398 | { | ||
399 | struct rdac_controller *ctlr, *tmp; | ||
400 | |||
401 | spin_lock(&list_lock); | ||
402 | |||
403 | list_for_each_entry(tmp, &ctlr_list, node) { | ||
404 | if ((memcmp(tmp->subsys_id, subsys_id, SUBSYS_ID_LEN) == 0) && | ||
405 | (memcmp(tmp->slot_id, slot_id, SLOT_ID_LEN) == 0)) { | ||
406 | kref_get(&tmp->kref); | ||
407 | spin_unlock(&list_lock); | ||
408 | return tmp; | ||
409 | } | ||
410 | } | ||
411 | ctlr = kmalloc(sizeof(*ctlr), GFP_ATOMIC); | ||
412 | if (!ctlr) | ||
413 | goto done; | ||
414 | |||
415 | /* initialize fields of controller */ | ||
416 | memcpy(ctlr->subsys_id, subsys_id, SUBSYS_ID_LEN); | ||
417 | memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN); | ||
418 | kref_init(&ctlr->kref); | ||
419 | spin_lock_init(&ctlr->lock); | ||
420 | ctlr->submitted = 0; | ||
421 | ctlr->use_10_ms = -1; | ||
422 | INIT_LIST_HEAD(&ctlr->cmd_list); | ||
423 | list_add(&ctlr->node, &ctlr_list); | ||
424 | done: | ||
425 | spin_unlock(&list_lock); | ||
426 | return ctlr; | ||
427 | } | ||
428 | |||
429 | static void c4_endio(struct request *req, int error) | ||
430 | { | ||
431 | struct rdac_handler *h = req->end_io_data; | ||
432 | struct c4_inquiry *sp; | ||
433 | |||
434 | if (had_failures(req, error)) { | ||
435 | dm_pg_init_complete(h->path, MP_FAIL_PATH); | ||
436 | goto done; | ||
437 | } | ||
438 | |||
439 | sp = &h->inq.c4; | ||
440 | |||
441 | h->ctlr = get_controller(sp->subsys_id, sp->slot_id); | ||
442 | |||
443 | if (h->ctlr) { | ||
444 | h->cmd_to_send = SEND_C9_INQUIRY; | ||
445 | queue_work(rdac_wkqd, &h->work); | ||
446 | } else | ||
447 | dm_pg_init_complete(h->path, MP_FAIL_PATH); | ||
448 | done: | ||
449 | __blk_put_request(req->q, req); | ||
450 | } | ||
451 | |||
452 | static void c2_endio(struct request *req, int error) | ||
453 | { | ||
454 | struct rdac_handler *h = req->end_io_data; | ||
455 | struct c2_inquiry *sp; | ||
456 | |||
457 | if (had_failures(req, error)) { | ||
458 | dm_pg_init_complete(h->path, MP_FAIL_PATH); | ||
459 | goto done; | ||
460 | } | ||
461 | |||
462 | sp = &h->inq.c2; | ||
463 | |||
464 | /* If more than MODE6_MAX_LUN luns are supported, use mode select 10 */ | ||
465 | if (sp->max_lun_supported >= MODE6_MAX_LUN) | ||
466 | h->ctlr->use_10_ms = 1; | ||
467 | else | ||
468 | h->ctlr->use_10_ms = 0; | ||
469 | |||
470 | h->cmd_to_send = SEND_MODE_SELECT; | ||
471 | queue_work(rdac_wkqd, &h->work); | ||
472 | done: | ||
473 | __blk_put_request(req->q, req); | ||
474 | } | ||
475 | |||
476 | static void c9_endio(struct request *req, int error) | ||
477 | { | ||
478 | struct rdac_handler *h = req->end_io_data; | ||
479 | struct c9_inquiry *sp; | ||
480 | |||
481 | if (had_failures(req, error)) { | ||
482 | dm_pg_init_complete(h->path, MP_FAIL_PATH); | ||
483 | goto done; | ||
484 | } | ||
485 | |||
486 | /* We need to look at the sense keys here to take clear action. | ||
487 | * For now simple logic: If the host is in AVT mode or if controller | ||
488 | * owns the lun, return dm_pg_init_complete(), otherwise submit | ||
489 | * MODE SELECT. | ||
490 | */ | ||
491 | sp = &h->inq.c9; | ||
492 | |||
493 | /* If in AVT mode, return success */ | ||
494 | if ((sp->avte_cvp >> 7) == 0x1) { | ||
495 | dm_pg_init_complete(h->path, 0); | ||
496 | goto done; | ||
497 | } | ||
498 | |||
499 | /* If the controller on this path owns the LUN, return success */ | ||
500 | if (sp->avte_cvp & 0x1) { | ||
501 | dm_pg_init_complete(h->path, 0); | ||
502 | goto done; | ||
503 | } | ||
504 | |||
505 | if (h->ctlr) { | ||
506 | if (h->ctlr->use_10_ms == -1) | ||
507 | h->cmd_to_send = SEND_C2_INQUIRY; | ||
508 | else | ||
509 | h->cmd_to_send = SEND_MODE_SELECT; | ||
510 | } else | ||
511 | h->cmd_to_send = SEND_C4_INQUIRY; | ||
512 | queue_work(rdac_wkqd, &h->work); | ||
513 | done: | ||
514 | __blk_put_request(req->q, req); | ||
515 | } | ||
516 | |||
517 | static void c8_endio(struct request *req, int error) | ||
518 | { | ||
519 | struct rdac_handler *h = req->end_io_data; | ||
520 | struct c8_inquiry *sp; | ||
521 | |||
522 | if (had_failures(req, error)) { | ||
523 | dm_pg_init_complete(h->path, MP_FAIL_PATH); | ||
524 | goto done; | ||
525 | } | ||
526 | |||
527 | /* We need to look at the sense keys here to take clear action. | ||
528 | * For now simple logic: Get the lun from the inquiry page. | ||
529 | */ | ||
530 | sp = &h->inq.c8; | ||
531 | h->lun = sp->lun[7]; /* currently it uses only one byte */ | ||
532 | h->cmd_to_send = SEND_C9_INQUIRY; | ||
533 | queue_work(rdac_wkqd, &h->work); | ||
534 | done: | ||
535 | __blk_put_request(req->q, req); | ||
536 | } | ||
537 | |||
538 | static void submit_inquiry(struct rdac_handler *h, int page_code, | ||
539 | unsigned int len, rq_end_io_fn endio) | ||
540 | { | ||
541 | struct request *rq; | ||
542 | struct request_queue *q = bdev_get_queue(h->path->dev->bdev); | ||
543 | |||
544 | if (!q) | ||
545 | goto fail_path; | ||
546 | |||
547 | rq = get_rdac_req(h, &h->inq, len, READ); | ||
548 | if (!rq) | ||
549 | goto fail_path; | ||
550 | |||
551 | /* Prepare the command. */ | ||
552 | rq->cmd[0] = INQUIRY; | ||
553 | rq->cmd[1] = 1; | ||
554 | rq->cmd[2] = page_code; | ||
555 | rq->cmd[4] = len; | ||
556 | rq->cmd_len = COMMAND_SIZE(INQUIRY); | ||
557 | blk_execute_rq_nowait(q, NULL, rq, 1, endio); | ||
558 | return; | ||
559 | |||
560 | fail_path: | ||
561 | dm_pg_init_complete(h->path, MP_FAIL_PATH); | ||
562 | } | ||
563 | |||
564 | static void service_wkq(struct work_struct *work) | ||
565 | { | ||
566 | struct rdac_handler *h = container_of(work, struct rdac_handler, work); | ||
567 | |||
568 | switch (h->cmd_to_send) { | ||
569 | case SEND_C2_INQUIRY: | ||
570 | submit_inquiry(h, 0xC2, sizeof(struct c2_inquiry), c2_endio); | ||
571 | break; | ||
572 | case SEND_C4_INQUIRY: | ||
573 | submit_inquiry(h, 0xC4, sizeof(struct c4_inquiry), c4_endio); | ||
574 | break; | ||
575 | case SEND_C8_INQUIRY: | ||
576 | submit_inquiry(h, 0xC8, sizeof(struct c8_inquiry), c8_endio); | ||
577 | break; | ||
578 | case SEND_C9_INQUIRY: | ||
579 | submit_inquiry(h, 0xC9, sizeof(struct c9_inquiry), c9_endio); | ||
580 | break; | ||
581 | case SEND_MODE_SELECT: | ||
582 | submit_mode_select(h); | ||
583 | break; | ||
584 | default: | ||
585 | BUG(); | ||
586 | } | ||
587 | } | ||
588 | /* | ||
589 | * only support subpage2c until we confirm that this is just a matter of | ||
590 | * of updating firmware or not, and RDAC (basic AVT works already) for now | ||
591 | * but we can add these in in when we get time and testers | ||
592 | */ | ||
593 | static int rdac_create(struct hw_handler *hwh, unsigned argc, char **argv) | ||
594 | { | ||
595 | struct rdac_handler *h; | ||
596 | unsigned timeout; | ||
597 | |||
598 | if (argc == 0) { | ||
599 | /* No arguments: use defaults */ | ||
600 | timeout = RDAC_FAILOVER_TIMEOUT; | ||
601 | } else if (argc != 1) { | ||
602 | DMWARN("incorrect number of arguments"); | ||
603 | return -EINVAL; | ||
604 | } else { | ||
605 | if (sscanf(argv[1], "%u", &timeout) != 1) { | ||
606 | DMWARN("invalid timeout value"); | ||
607 | return -EINVAL; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | h = kzalloc(sizeof(*h), GFP_KERNEL); | ||
612 | if (!h) | ||
613 | return -ENOMEM; | ||
614 | |||
615 | hwh->context = h; | ||
616 | h->timeout = timeout; | ||
617 | h->lun = UNINITIALIZED_LUN; | ||
618 | INIT_WORK(&h->work, service_wkq); | ||
619 | DMWARN("using RDAC command with timeout %u", h->timeout); | ||
620 | |||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | static void rdac_destroy(struct hw_handler *hwh) | ||
625 | { | ||
626 | struct rdac_handler *h = hwh->context; | ||
627 | |||
628 | if (h->ctlr) | ||
629 | kref_put(&h->ctlr->kref, release_ctlr); | ||
630 | kfree(h); | ||
631 | hwh->context = NULL; | ||
632 | } | ||
633 | |||
634 | static unsigned rdac_error(struct hw_handler *hwh, struct bio *bio) | ||
635 | { | ||
636 | /* Try default handler */ | ||
637 | return dm_scsi_err_handler(hwh, bio); | ||
638 | } | ||
639 | |||
640 | static void rdac_pg_init(struct hw_handler *hwh, unsigned bypassed, | ||
641 | struct dm_path *path) | ||
642 | { | ||
643 | struct rdac_handler *h = hwh->context; | ||
644 | |||
645 | h->path = path; | ||
646 | switch (h->lun) { | ||
647 | case UNINITIALIZED_LUN: | ||
648 | submit_inquiry(h, 0xC8, sizeof(struct c8_inquiry), c8_endio); | ||
649 | break; | ||
650 | default: | ||
651 | submit_inquiry(h, 0xC9, sizeof(struct c9_inquiry), c9_endio); | ||
652 | } | ||
653 | } | ||
654 | |||
655 | static struct hw_handler_type rdac_handler = { | ||
656 | .name = RDAC_DM_HWH_NAME, | ||
657 | .module = THIS_MODULE, | ||
658 | .create = rdac_create, | ||
659 | .destroy = rdac_destroy, | ||
660 | .pg_init = rdac_pg_init, | ||
661 | .error = rdac_error, | ||
662 | }; | ||
663 | |||
664 | static int __init rdac_init(void) | ||
665 | { | ||
666 | int r; | ||
667 | |||
668 | rdac_wkqd = create_singlethread_workqueue("rdac_wkqd"); | ||
669 | if (!rdac_wkqd) { | ||
670 | DMERR("Failed to create workqueue rdac_wkqd."); | ||
671 | return -ENOMEM; | ||
672 | } | ||
673 | |||
674 | r = dm_register_hw_handler(&rdac_handler); | ||
675 | if (r < 0) { | ||
676 | DMERR("%s: register failed %d", RDAC_DM_HWH_NAME, r); | ||
677 | destroy_workqueue(rdac_wkqd); | ||
678 | return r; | ||
679 | } | ||
680 | |||
681 | DMINFO("%s: version %s loaded", RDAC_DM_HWH_NAME, RDAC_DM_HWH_VER); | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | static void __exit rdac_exit(void) | ||
686 | { | ||
687 | int r = dm_unregister_hw_handler(&rdac_handler); | ||
688 | |||
689 | destroy_workqueue(rdac_wkqd); | ||
690 | if (r < 0) | ||
691 | DMERR("%s: unregister failed %d", RDAC_DM_HWH_NAME, r); | ||
692 | } | ||
693 | |||
694 | module_init(rdac_init); | ||
695 | module_exit(rdac_exit); | ||
696 | |||
697 | MODULE_DESCRIPTION("DM Multipath LSI/Engenio RDAC support"); | ||
698 | MODULE_AUTHOR("Mike Christie, Chandra Seetharaman"); | ||
699 | MODULE_LICENSE("GPL"); | ||
700 | MODULE_VERSION(RDAC_DM_HWH_VER); | ||
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index e7ee59e655d5..9f7302d4878d 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -7,7 +7,6 @@ | |||
7 | 7 | ||
8 | #include "dm.h" | 8 | #include "dm.h" |
9 | #include "dm-path-selector.h" | 9 | #include "dm-path-selector.h" |
10 | #include "dm-hw-handler.h" | ||
11 | #include "dm-bio-list.h" | 10 | #include "dm-bio-list.h" |
12 | #include "dm-bio-record.h" | 11 | #include "dm-bio-record.h" |
13 | #include "dm-uevent.h" | 12 | #include "dm-uevent.h" |
@@ -20,6 +19,7 @@ | |||
20 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
21 | #include <linux/time.h> | 20 | #include <linux/time.h> |
22 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | #include <scsi/scsi_dh.h> | ||
23 | #include <asm/atomic.h> | 23 | #include <asm/atomic.h> |
24 | 24 | ||
25 | #define DM_MSG_PREFIX "multipath" | 25 | #define DM_MSG_PREFIX "multipath" |
@@ -61,7 +61,8 @@ struct multipath { | |||
61 | 61 | ||
62 | spinlock_t lock; | 62 | spinlock_t lock; |
63 | 63 | ||
64 | struct hw_handler hw_handler; | 64 | const char *hw_handler_name; |
65 | struct work_struct activate_path; | ||
65 | unsigned nr_priority_groups; | 66 | unsigned nr_priority_groups; |
66 | struct list_head priority_groups; | 67 | struct list_head priority_groups; |
67 | unsigned pg_init_required; /* pg_init needs calling? */ | 68 | unsigned pg_init_required; /* pg_init needs calling? */ |
@@ -106,9 +107,10 @@ typedef int (*action_fn) (struct pgpath *pgpath); | |||
106 | 107 | ||
107 | static struct kmem_cache *_mpio_cache; | 108 | static struct kmem_cache *_mpio_cache; |
108 | 109 | ||
109 | static struct workqueue_struct *kmultipathd; | 110 | static struct workqueue_struct *kmultipathd, *kmpath_handlerd; |
110 | static void process_queued_ios(struct work_struct *work); | 111 | static void process_queued_ios(struct work_struct *work); |
111 | static void trigger_event(struct work_struct *work); | 112 | static void trigger_event(struct work_struct *work); |
113 | static void activate_path(struct work_struct *work); | ||
112 | 114 | ||
113 | 115 | ||
114 | /*----------------------------------------------- | 116 | /*----------------------------------------------- |
@@ -178,6 +180,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti) | |||
178 | m->queue_io = 1; | 180 | m->queue_io = 1; |
179 | INIT_WORK(&m->process_queued_ios, process_queued_ios); | 181 | INIT_WORK(&m->process_queued_ios, process_queued_ios); |
180 | INIT_WORK(&m->trigger_event, trigger_event); | 182 | INIT_WORK(&m->trigger_event, trigger_event); |
183 | INIT_WORK(&m->activate_path, activate_path); | ||
181 | m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache); | 184 | m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache); |
182 | if (!m->mpio_pool) { | 185 | if (!m->mpio_pool) { |
183 | kfree(m); | 186 | kfree(m); |
@@ -193,18 +196,13 @@ static struct multipath *alloc_multipath(struct dm_target *ti) | |||
193 | static void free_multipath(struct multipath *m) | 196 | static void free_multipath(struct multipath *m) |
194 | { | 197 | { |
195 | struct priority_group *pg, *tmp; | 198 | struct priority_group *pg, *tmp; |
196 | struct hw_handler *hwh = &m->hw_handler; | ||
197 | 199 | ||
198 | list_for_each_entry_safe(pg, tmp, &m->priority_groups, list) { | 200 | list_for_each_entry_safe(pg, tmp, &m->priority_groups, list) { |
199 | list_del(&pg->list); | 201 | list_del(&pg->list); |
200 | free_priority_group(pg, m->ti); | 202 | free_priority_group(pg, m->ti); |
201 | } | 203 | } |
202 | 204 | ||
203 | if (hwh->type) { | 205 | kfree(m->hw_handler_name); |
204 | hwh->type->destroy(hwh); | ||
205 | dm_put_hw_handler(hwh->type); | ||
206 | } | ||
207 | |||
208 | mempool_destroy(m->mpio_pool); | 206 | mempool_destroy(m->mpio_pool); |
209 | kfree(m); | 207 | kfree(m); |
210 | } | 208 | } |
@@ -216,12 +214,10 @@ static void free_multipath(struct multipath *m) | |||
216 | 214 | ||
217 | static void __switch_pg(struct multipath *m, struct pgpath *pgpath) | 215 | static void __switch_pg(struct multipath *m, struct pgpath *pgpath) |
218 | { | 216 | { |
219 | struct hw_handler *hwh = &m->hw_handler; | ||
220 | |||
221 | m->current_pg = pgpath->pg; | 217 | m->current_pg = pgpath->pg; |
222 | 218 | ||
223 | /* Must we initialise the PG first, and queue I/O till it's ready? */ | 219 | /* Must we initialise the PG first, and queue I/O till it's ready? */ |
224 | if (hwh->type && hwh->type->pg_init) { | 220 | if (m->hw_handler_name) { |
225 | m->pg_init_required = 1; | 221 | m->pg_init_required = 1; |
226 | m->queue_io = 1; | 222 | m->queue_io = 1; |
227 | } else { | 223 | } else { |
@@ -409,7 +405,6 @@ static void process_queued_ios(struct work_struct *work) | |||
409 | { | 405 | { |
410 | struct multipath *m = | 406 | struct multipath *m = |
411 | container_of(work, struct multipath, process_queued_ios); | 407 | container_of(work, struct multipath, process_queued_ios); |
412 | struct hw_handler *hwh = &m->hw_handler; | ||
413 | struct pgpath *pgpath = NULL; | 408 | struct pgpath *pgpath = NULL; |
414 | unsigned init_required = 0, must_queue = 1; | 409 | unsigned init_required = 0, must_queue = 1; |
415 | unsigned long flags; | 410 | unsigned long flags; |
@@ -439,7 +434,7 @@ out: | |||
439 | spin_unlock_irqrestore(&m->lock, flags); | 434 | spin_unlock_irqrestore(&m->lock, flags); |
440 | 435 | ||
441 | if (init_required) | 436 | if (init_required) |
442 | hwh->type->pg_init(hwh, pgpath->pg->bypassed, &pgpath->path); | 437 | queue_work(kmpath_handlerd, &m->activate_path); |
443 | 438 | ||
444 | if (!must_queue) | 439 | if (!must_queue) |
445 | dispatch_queued_ios(m); | 440 | dispatch_queued_ios(m); |
@@ -652,8 +647,6 @@ static struct priority_group *parse_priority_group(struct arg_set *as, | |||
652 | 647 | ||
653 | static int parse_hw_handler(struct arg_set *as, struct multipath *m) | 648 | static int parse_hw_handler(struct arg_set *as, struct multipath *m) |
654 | { | 649 | { |
655 | int r; | ||
656 | struct hw_handler_type *hwht; | ||
657 | unsigned hw_argc; | 650 | unsigned hw_argc; |
658 | struct dm_target *ti = m->ti; | 651 | struct dm_target *ti = m->ti; |
659 | 652 | ||
@@ -661,30 +654,20 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m) | |||
661 | {0, 1024, "invalid number of hardware handler args"}, | 654 | {0, 1024, "invalid number of hardware handler args"}, |
662 | }; | 655 | }; |
663 | 656 | ||
664 | r = read_param(_params, shift(as), &hw_argc, &ti->error); | 657 | if (read_param(_params, shift(as), &hw_argc, &ti->error)) |
665 | if (r) | ||
666 | return -EINVAL; | 658 | return -EINVAL; |
667 | 659 | ||
668 | if (!hw_argc) | 660 | if (!hw_argc) |
669 | return 0; | 661 | return 0; |
670 | 662 | ||
671 | hwht = dm_get_hw_handler(shift(as)); | 663 | m->hw_handler_name = kstrdup(shift(as), GFP_KERNEL); |
672 | if (!hwht) { | 664 | request_module("scsi_dh_%s", m->hw_handler_name); |
665 | if (scsi_dh_handler_exist(m->hw_handler_name) == 0) { | ||
673 | ti->error = "unknown hardware handler type"; | 666 | ti->error = "unknown hardware handler type"; |
667 | kfree(m->hw_handler_name); | ||
668 | m->hw_handler_name = NULL; | ||
674 | return -EINVAL; | 669 | return -EINVAL; |
675 | } | 670 | } |
676 | |||
677 | m->hw_handler.md = dm_table_get_md(ti->table); | ||
678 | dm_put(m->hw_handler.md); | ||
679 | |||
680 | r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv); | ||
681 | if (r) { | ||
682 | dm_put_hw_handler(hwht); | ||
683 | ti->error = "hardware handler constructor failed"; | ||
684 | return r; | ||
685 | } | ||
686 | |||
687 | m->hw_handler.type = hwht; | ||
688 | consume(as, hw_argc - 1); | 671 | consume(as, hw_argc - 1); |
689 | 672 | ||
690 | return 0; | 673 | return 0; |
@@ -808,6 +791,7 @@ static void multipath_dtr(struct dm_target *ti) | |||
808 | { | 791 | { |
809 | struct multipath *m = (struct multipath *) ti->private; | 792 | struct multipath *m = (struct multipath *) ti->private; |
810 | 793 | ||
794 | flush_workqueue(kmpath_handlerd); | ||
811 | flush_workqueue(kmultipathd); | 795 | flush_workqueue(kmultipathd); |
812 | free_multipath(m); | 796 | free_multipath(m); |
813 | } | 797 | } |
@@ -1025,52 +1009,85 @@ static int pg_init_limit_reached(struct multipath *m, struct pgpath *pgpath) | |||
1025 | return limit_reached; | 1009 | return limit_reached; |
1026 | } | 1010 | } |
1027 | 1011 | ||
1028 | /* | 1012 | static void pg_init_done(struct dm_path *path, int errors) |
1029 | * pg_init must call this when it has completed its initialisation | ||
1030 | */ | ||
1031 | void dm_pg_init_complete(struct dm_path *path, unsigned err_flags) | ||
1032 | { | 1013 | { |
1033 | struct pgpath *pgpath = path_to_pgpath(path); | 1014 | struct pgpath *pgpath = path_to_pgpath(path); |
1034 | struct priority_group *pg = pgpath->pg; | 1015 | struct priority_group *pg = pgpath->pg; |
1035 | struct multipath *m = pg->m; | 1016 | struct multipath *m = pg->m; |
1036 | unsigned long flags; | 1017 | unsigned long flags; |
1037 | 1018 | ||
1038 | /* | 1019 | /* device or driver problems */ |
1039 | * If requested, retry pg_init until maximum number of retries exceeded. | 1020 | switch (errors) { |
1040 | * If retry not requested and PG already bypassed, always fail the path. | 1021 | case SCSI_DH_OK: |
1041 | */ | 1022 | break; |
1042 | if (err_flags & MP_RETRY) { | 1023 | case SCSI_DH_NOSYS: |
1043 | if (pg_init_limit_reached(m, pgpath)) | 1024 | if (!m->hw_handler_name) { |
1044 | err_flags |= MP_FAIL_PATH; | 1025 | errors = 0; |
1045 | } else if (err_flags && pg->bypassed) | 1026 | break; |
1046 | err_flags |= MP_FAIL_PATH; | 1027 | } |
1047 | 1028 | DMERR("Cannot failover device because scsi_dh_%s was not " | |
1048 | if (err_flags & MP_FAIL_PATH) | 1029 | "loaded.", m->hw_handler_name); |
1030 | /* | ||
1031 | * Fail path for now, so we do not ping pong | ||
1032 | */ | ||
1049 | fail_path(pgpath); | 1033 | fail_path(pgpath); |
1050 | 1034 | break; | |
1051 | if (err_flags & MP_BYPASS_PG) | 1035 | case SCSI_DH_DEV_TEMP_BUSY: |
1036 | /* | ||
1037 | * Probably doing something like FW upgrade on the | ||
1038 | * controller so try the other pg. | ||
1039 | */ | ||
1052 | bypass_pg(m, pg, 1); | 1040 | bypass_pg(m, pg, 1); |
1041 | break; | ||
1042 | /* TODO: For SCSI_DH_RETRY we should wait a couple seconds */ | ||
1043 | case SCSI_DH_RETRY: | ||
1044 | case SCSI_DH_IMM_RETRY: | ||
1045 | case SCSI_DH_RES_TEMP_UNAVAIL: | ||
1046 | if (pg_init_limit_reached(m, pgpath)) | ||
1047 | fail_path(pgpath); | ||
1048 | errors = 0; | ||
1049 | break; | ||
1050 | default: | ||
1051 | /* | ||
1052 | * We probably do not want to fail the path for a device | ||
1053 | * error, but this is what the old dm did. In future | ||
1054 | * patches we can do more advanced handling. | ||
1055 | */ | ||
1056 | fail_path(pgpath); | ||
1057 | } | ||
1053 | 1058 | ||
1054 | spin_lock_irqsave(&m->lock, flags); | 1059 | spin_lock_irqsave(&m->lock, flags); |
1055 | if (err_flags & ~MP_RETRY) { | 1060 | if (errors) { |
1061 | DMERR("Could not failover device. Error %d.", errors); | ||
1056 | m->current_pgpath = NULL; | 1062 | m->current_pgpath = NULL; |
1057 | m->current_pg = NULL; | 1063 | m->current_pg = NULL; |
1058 | } else if (!m->pg_init_required) | 1064 | } else if (!m->pg_init_required) { |
1059 | m->queue_io = 0; | 1065 | m->queue_io = 0; |
1066 | pg->bypassed = 0; | ||
1067 | } | ||
1060 | 1068 | ||
1061 | m->pg_init_in_progress = 0; | 1069 | m->pg_init_in_progress = 0; |
1062 | queue_work(kmultipathd, &m->process_queued_ios); | 1070 | queue_work(kmultipathd, &m->process_queued_ios); |
1063 | spin_unlock_irqrestore(&m->lock, flags); | 1071 | spin_unlock_irqrestore(&m->lock, flags); |
1064 | } | 1072 | } |
1065 | 1073 | ||
1074 | static void activate_path(struct work_struct *work) | ||
1075 | { | ||
1076 | int ret; | ||
1077 | struct multipath *m = | ||
1078 | container_of(work, struct multipath, activate_path); | ||
1079 | struct dm_path *path = &m->current_pgpath->path; | ||
1080 | |||
1081 | ret = scsi_dh_activate(bdev_get_queue(path->dev->bdev)); | ||
1082 | pg_init_done(path, ret); | ||
1083 | } | ||
1084 | |||
1066 | /* | 1085 | /* |
1067 | * end_io handling | 1086 | * end_io handling |
1068 | */ | 1087 | */ |
1069 | static int do_end_io(struct multipath *m, struct bio *bio, | 1088 | static int do_end_io(struct multipath *m, struct bio *bio, |
1070 | int error, struct dm_mpath_io *mpio) | 1089 | int error, struct dm_mpath_io *mpio) |
1071 | { | 1090 | { |
1072 | struct hw_handler *hwh = &m->hw_handler; | ||
1073 | unsigned err_flags = MP_FAIL_PATH; /* Default behavior */ | ||
1074 | unsigned long flags; | 1091 | unsigned long flags; |
1075 | 1092 | ||
1076 | if (!error) | 1093 | if (!error) |
@@ -1097,19 +1114,8 @@ static int do_end_io(struct multipath *m, struct bio *bio, | |||
1097 | } | 1114 | } |
1098 | spin_unlock_irqrestore(&m->lock, flags); | 1115 | spin_unlock_irqrestore(&m->lock, flags); |
1099 | 1116 | ||
1100 | if (hwh->type && hwh->type->error) | 1117 | if (mpio->pgpath) |
1101 | err_flags = hwh->type->error(hwh, bio); | 1118 | fail_path(mpio->pgpath); |
1102 | |||
1103 | if (mpio->pgpath) { | ||
1104 | if (err_flags & MP_FAIL_PATH) | ||
1105 | fail_path(mpio->pgpath); | ||
1106 | |||
1107 | if (err_flags & MP_BYPASS_PG) | ||
1108 | bypass_pg(m, mpio->pgpath->pg, 1); | ||
1109 | } | ||
1110 | |||
1111 | if (err_flags & MP_ERROR_IO) | ||
1112 | return -EIO; | ||
1113 | 1119 | ||
1114 | requeue: | 1120 | requeue: |
1115 | dm_bio_restore(&mpio->details, bio); | 1121 | dm_bio_restore(&mpio->details, bio); |
@@ -1194,7 +1200,6 @@ static int multipath_status(struct dm_target *ti, status_type_t type, | |||
1194 | int sz = 0; | 1200 | int sz = 0; |
1195 | unsigned long flags; | 1201 | unsigned long flags; |
1196 | struct multipath *m = (struct multipath *) ti->private; | 1202 | struct multipath *m = (struct multipath *) ti->private; |
1197 | struct hw_handler *hwh = &m->hw_handler; | ||
1198 | struct priority_group *pg; | 1203 | struct priority_group *pg; |
1199 | struct pgpath *p; | 1204 | struct pgpath *p; |
1200 | unsigned pg_num; | 1205 | unsigned pg_num; |
@@ -1214,12 +1219,10 @@ static int multipath_status(struct dm_target *ti, status_type_t type, | |||
1214 | DMEMIT("pg_init_retries %u ", m->pg_init_retries); | 1219 | DMEMIT("pg_init_retries %u ", m->pg_init_retries); |
1215 | } | 1220 | } |
1216 | 1221 | ||
1217 | if (hwh->type && hwh->type->status) | 1222 | if (!m->hw_handler_name || type == STATUSTYPE_INFO) |
1218 | sz += hwh->type->status(hwh, type, result + sz, maxlen - sz); | ||
1219 | else if (!hwh->type || type == STATUSTYPE_INFO) | ||
1220 | DMEMIT("0 "); | 1223 | DMEMIT("0 "); |
1221 | else | 1224 | else |
1222 | DMEMIT("1 %s ", hwh->type->name); | 1225 | DMEMIT("1 %s ", m->hw_handler_name); |
1223 | 1226 | ||
1224 | DMEMIT("%u ", m->nr_priority_groups); | 1227 | DMEMIT("%u ", m->nr_priority_groups); |
1225 | 1228 | ||
@@ -1422,6 +1425,21 @@ static int __init dm_multipath_init(void) | |||
1422 | return -ENOMEM; | 1425 | return -ENOMEM; |
1423 | } | 1426 | } |
1424 | 1427 | ||
1428 | /* | ||
1429 | * A separate workqueue is used to handle the device handlers | ||
1430 | * to avoid overloading existing workqueue. Overloading the | ||
1431 | * old workqueue would also create a bottleneck in the | ||
1432 | * path of the storage hardware device activation. | ||
1433 | */ | ||
1434 | kmpath_handlerd = create_singlethread_workqueue("kmpath_handlerd"); | ||
1435 | if (!kmpath_handlerd) { | ||
1436 | DMERR("failed to create workqueue kmpath_handlerd"); | ||
1437 | destroy_workqueue(kmultipathd); | ||
1438 | dm_unregister_target(&multipath_target); | ||
1439 | kmem_cache_destroy(_mpio_cache); | ||
1440 | return -ENOMEM; | ||
1441 | } | ||
1442 | |||
1425 | DMINFO("version %u.%u.%u loaded", | 1443 | DMINFO("version %u.%u.%u loaded", |
1426 | multipath_target.version[0], multipath_target.version[1], | 1444 | multipath_target.version[0], multipath_target.version[1], |
1427 | multipath_target.version[2]); | 1445 | multipath_target.version[2]); |
@@ -1433,6 +1451,7 @@ static void __exit dm_multipath_exit(void) | |||
1433 | { | 1451 | { |
1434 | int r; | 1452 | int r; |
1435 | 1453 | ||
1454 | destroy_workqueue(kmpath_handlerd); | ||
1436 | destroy_workqueue(kmultipathd); | 1455 | destroy_workqueue(kmultipathd); |
1437 | 1456 | ||
1438 | r = dm_unregister_target(&multipath_target); | 1457 | r = dm_unregister_target(&multipath_target); |
@@ -1441,8 +1460,6 @@ static void __exit dm_multipath_exit(void) | |||
1441 | kmem_cache_destroy(_mpio_cache); | 1460 | kmem_cache_destroy(_mpio_cache); |
1442 | } | 1461 | } |
1443 | 1462 | ||
1444 | EXPORT_SYMBOL_GPL(dm_pg_init_complete); | ||
1445 | |||
1446 | module_init(dm_multipath_init); | 1463 | module_init(dm_multipath_init); |
1447 | module_exit(dm_multipath_exit); | 1464 | module_exit(dm_multipath_exit); |
1448 | 1465 | ||
diff --git a/drivers/md/dm-mpath.h b/drivers/md/dm-mpath.h index b9cdcbb3ed59..c198b856a452 100644 --- a/drivers/md/dm-mpath.h +++ b/drivers/md/dm-mpath.h | |||
@@ -16,7 +16,6 @@ struct dm_path { | |||
16 | unsigned is_active; /* Read-only */ | 16 | unsigned is_active; /* Read-only */ |
17 | 17 | ||
18 | void *pscontext; /* For path-selector use */ | 18 | void *pscontext; /* For path-selector use */ |
19 | void *hwhcontext; /* For hw-handler use */ | ||
20 | }; | 19 | }; |
21 | 20 | ||
22 | /* Callback for hwh_pg_init_fn to use when complete */ | 21 | /* Callback for hwh_pg_init_fn to use when complete */ |
diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h index 1acbdd61b670..10b6ef758725 100644 --- a/drivers/message/fusion/lsi/mpi.h +++ b/drivers/message/fusion/lsi/mpi.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2007 LSI Corporation. | 2 | * Copyright (c) 2000-2008 LSI Corporation. |
3 | * | 3 | * |
4 | * | 4 | * |
5 | * Name: mpi.h | 5 | * Name: mpi.h |
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h index 2bd8adae0f00..b2db3330c591 100644 --- a/drivers/message/fusion/lsi/mpi_cnfg.h +++ b/drivers/message/fusion/lsi/mpi_cnfg.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2007 LSI Corporation. | 2 | * Copyright (c) 2000-2008 LSI Corporation. |
3 | * | 3 | * |
4 | * | 4 | * |
5 | * Name: mpi_cnfg.h | 5 | * Name: mpi_cnfg.h |
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index d40d6d15ae20..75e599b85b64 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * For use with LSI PCI chip/adapter(s) | 5 | * For use with LSI PCI chip/adapter(s) |
6 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 6 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
7 | * | 7 | * |
8 | * Copyright (c) 1999-2007 LSI Corporation | 8 | * Copyright (c) 1999-2008 LSI Corporation |
9 | * (mailto:DL-MPTFusionLinux@lsi.com) | 9 | * (mailto:DL-MPTFusionLinux@lsi.com) |
10 | * | 10 | * |
11 | */ | 11 | */ |
@@ -103,7 +103,7 @@ static int mfcounter = 0; | |||
103 | * Public data... | 103 | * Public data... |
104 | */ | 104 | */ |
105 | 105 | ||
106 | struct proc_dir_entry *mpt_proc_root_dir; | 106 | static struct proc_dir_entry *mpt_proc_root_dir; |
107 | 107 | ||
108 | #define WHOINIT_UNKNOWN 0xAA | 108 | #define WHOINIT_UNKNOWN 0xAA |
109 | 109 | ||
@@ -253,6 +253,55 @@ mpt_get_cb_idx(MPT_DRIVER_CLASS dclass) | |||
253 | return 0; | 253 | return 0; |
254 | } | 254 | } |
255 | 255 | ||
256 | /** | ||
257 | * mpt_fault_reset_work - work performed on workq after ioc fault | ||
258 | * @work: input argument, used to derive ioc | ||
259 | * | ||
260 | **/ | ||
261 | static void | ||
262 | mpt_fault_reset_work(struct work_struct *work) | ||
263 | { | ||
264 | MPT_ADAPTER *ioc = | ||
265 | container_of(work, MPT_ADAPTER, fault_reset_work.work); | ||
266 | u32 ioc_raw_state; | ||
267 | int rc; | ||
268 | unsigned long flags; | ||
269 | |||
270 | if (ioc->diagPending || !ioc->active) | ||
271 | goto out; | ||
272 | |||
273 | ioc_raw_state = mpt_GetIocState(ioc, 0); | ||
274 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { | ||
275 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", | ||
276 | ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); | ||
277 | printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", | ||
278 | ioc->name, __FUNCTION__); | ||
279 | rc = mpt_HardResetHandler(ioc, CAN_SLEEP); | ||
280 | printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name, | ||
281 | __FUNCTION__, (rc == 0) ? "success" : "failed"); | ||
282 | ioc_raw_state = mpt_GetIocState(ioc, 0); | ||
283 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) | ||
284 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after " | ||
285 | "reset (%04xh)\n", ioc->name, ioc_raw_state & | ||
286 | MPI_DOORBELL_DATA_MASK); | ||
287 | } | ||
288 | |||
289 | out: | ||
290 | /* | ||
291 | * Take turns polling alternate controller | ||
292 | */ | ||
293 | if (ioc->alt_ioc) | ||
294 | ioc = ioc->alt_ioc; | ||
295 | |||
296 | /* rearm the timer */ | ||
297 | spin_lock_irqsave(&ioc->fault_reset_work_lock, flags); | ||
298 | if (ioc->reset_work_q) | ||
299 | queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, | ||
300 | msecs_to_jiffies(MPT_POLLING_INTERVAL)); | ||
301 | spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags); | ||
302 | } | ||
303 | |||
304 | |||
256 | /* | 305 | /* |
257 | * Process turbo (context) reply... | 306 | * Process turbo (context) reply... |
258 | */ | 307 | */ |
@@ -1616,6 +1665,22 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1616 | /* Find lookup slot. */ | 1665 | /* Find lookup slot. */ |
1617 | INIT_LIST_HEAD(&ioc->list); | 1666 | INIT_LIST_HEAD(&ioc->list); |
1618 | 1667 | ||
1668 | |||
1669 | /* Initialize workqueue */ | ||
1670 | INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work); | ||
1671 | spin_lock_init(&ioc->fault_reset_work_lock); | ||
1672 | |||
1673 | snprintf(ioc->reset_work_q_name, KOBJ_NAME_LEN, "mpt_poll_%d", ioc->id); | ||
1674 | ioc->reset_work_q = | ||
1675 | create_singlethread_workqueue(ioc->reset_work_q_name); | ||
1676 | if (!ioc->reset_work_q) { | ||
1677 | printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n", | ||
1678 | ioc->name); | ||
1679 | pci_release_selected_regions(pdev, ioc->bars); | ||
1680 | kfree(ioc); | ||
1681 | return -ENOMEM; | ||
1682 | } | ||
1683 | |||
1619 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n", | 1684 | dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n", |
1620 | ioc->name, &ioc->facts, &ioc->pfacts[0])); | 1685 | ioc->name, &ioc->facts, &ioc->pfacts[0])); |
1621 | 1686 | ||
@@ -1727,6 +1792,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1727 | iounmap(ioc->memmap); | 1792 | iounmap(ioc->memmap); |
1728 | if (r != -5) | 1793 | if (r != -5) |
1729 | pci_release_selected_regions(pdev, ioc->bars); | 1794 | pci_release_selected_regions(pdev, ioc->bars); |
1795 | |||
1796 | destroy_workqueue(ioc->reset_work_q); | ||
1797 | ioc->reset_work_q = NULL; | ||
1798 | |||
1730 | kfree(ioc); | 1799 | kfree(ioc); |
1731 | pci_set_drvdata(pdev, NULL); | 1800 | pci_set_drvdata(pdev, NULL); |
1732 | return r; | 1801 | return r; |
@@ -1759,6 +1828,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1759 | } | 1828 | } |
1760 | #endif | 1829 | #endif |
1761 | 1830 | ||
1831 | if (!ioc->alt_ioc) | ||
1832 | queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, | ||
1833 | msecs_to_jiffies(MPT_POLLING_INTERVAL)); | ||
1834 | |||
1762 | return 0; | 1835 | return 0; |
1763 | } | 1836 | } |
1764 | 1837 | ||
@@ -1774,6 +1847,19 @@ mpt_detach(struct pci_dev *pdev) | |||
1774 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | 1847 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
1775 | char pname[32]; | 1848 | char pname[32]; |
1776 | u8 cb_idx; | 1849 | u8 cb_idx; |
1850 | unsigned long flags; | ||
1851 | struct workqueue_struct *wq; | ||
1852 | |||
1853 | /* | ||
1854 | * Stop polling ioc for fault condition | ||
1855 | */ | ||
1856 | spin_lock_irqsave(&ioc->fault_reset_work_lock, flags); | ||
1857 | wq = ioc->reset_work_q; | ||
1858 | ioc->reset_work_q = NULL; | ||
1859 | spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags); | ||
1860 | cancel_delayed_work(&ioc->fault_reset_work); | ||
1861 | destroy_workqueue(wq); | ||
1862 | |||
1777 | 1863 | ||
1778 | sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); | 1864 | sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); |
1779 | remove_proc_entry(pname, NULL); | 1865 | remove_proc_entry(pname, NULL); |
@@ -7456,7 +7542,6 @@ EXPORT_SYMBOL(mpt_resume); | |||
7456 | EXPORT_SYMBOL(mpt_suspend); | 7542 | EXPORT_SYMBOL(mpt_suspend); |
7457 | #endif | 7543 | #endif |
7458 | EXPORT_SYMBOL(ioc_list); | 7544 | EXPORT_SYMBOL(ioc_list); |
7459 | EXPORT_SYMBOL(mpt_proc_root_dir); | ||
7460 | EXPORT_SYMBOL(mpt_register); | 7545 | EXPORT_SYMBOL(mpt_register); |
7461 | EXPORT_SYMBOL(mpt_deregister); | 7546 | EXPORT_SYMBOL(mpt_deregister); |
7462 | EXPORT_SYMBOL(mpt_event_register); | 7547 | EXPORT_SYMBOL(mpt_event_register); |
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index a8f617447d22..6adab648dbb9 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * LSIFC9xx/LSI409xx Fibre Channel | 5 | * LSIFC9xx/LSI409xx Fibre Channel |
6 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 6 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
7 | * | 7 | * |
8 | * Copyright (c) 1999-2007 LSI Corporation | 8 | * Copyright (c) 1999-2008 LSI Corporation |
9 | * (mailto:DL-MPTFusionLinux@lsi.com) | 9 | * (mailto:DL-MPTFusionLinux@lsi.com) |
10 | * | 10 | * |
11 | */ | 11 | */ |
@@ -73,11 +73,11 @@ | |||
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | #ifndef COPYRIGHT | 75 | #ifndef COPYRIGHT |
76 | #define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR | 76 | #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR |
77 | #endif | 77 | #endif |
78 | 78 | ||
79 | #define MPT_LINUX_VERSION_COMMON "3.04.06" | 79 | #define MPT_LINUX_VERSION_COMMON "3.04.07" |
80 | #define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.06" | 80 | #define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.07" |
81 | #define WHAT_MAGIC_STRING "@" "(" "#" ")" | 81 | #define WHAT_MAGIC_STRING "@" "(" "#" ")" |
82 | 82 | ||
83 | #define show_mptmod_ver(s,ver) \ | 83 | #define show_mptmod_ver(s,ver) \ |
@@ -176,6 +176,8 @@ | |||
176 | /* debug print string length used for events and iocstatus */ | 176 | /* debug print string length used for events and iocstatus */ |
177 | # define EVENT_DESCR_STR_SZ 100 | 177 | # define EVENT_DESCR_STR_SZ 100 |
178 | 178 | ||
179 | #define MPT_POLLING_INTERVAL 1000 /* in milliseconds */ | ||
180 | |||
179 | #ifdef __KERNEL__ /* { */ | 181 | #ifdef __KERNEL__ /* { */ |
180 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 182 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
181 | 183 | ||
@@ -709,6 +711,12 @@ typedef struct _MPT_ADAPTER | |||
709 | struct workqueue_struct *fc_rescan_work_q; | 711 | struct workqueue_struct *fc_rescan_work_q; |
710 | struct scsi_cmnd **ScsiLookup; | 712 | struct scsi_cmnd **ScsiLookup; |
711 | spinlock_t scsi_lookup_lock; | 713 | spinlock_t scsi_lookup_lock; |
714 | |||
715 | char reset_work_q_name[KOBJ_NAME_LEN]; | ||
716 | struct workqueue_struct *reset_work_q; | ||
717 | struct delayed_work fault_reset_work; | ||
718 | spinlock_t fault_reset_work_lock; | ||
719 | |||
712 | } MPT_ADAPTER; | 720 | } MPT_ADAPTER; |
713 | 721 | ||
714 | /* | 722 | /* |
@@ -919,7 +927,6 @@ extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhys | |||
919 | * Public data decl's... | 927 | * Public data decl's... |
920 | */ | 928 | */ |
921 | extern struct list_head ioc_list; | 929 | extern struct list_head ioc_list; |
922 | extern struct proc_dir_entry *mpt_proc_root_dir; | ||
923 | 930 | ||
924 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 931 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
925 | #endif /* } __KERNEL__ */ | 932 | #endif /* } __KERNEL__ */ |
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index c5946560c4e2..a5920423e2b2 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * For use with LSI PCI chip/adapters | 4 | * For use with LSI PCI chip/adapters |
5 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 5 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
6 | * | 6 | * |
7 | * Copyright (c) 1999-2007 LSI Corporation | 7 | * Copyright (c) 1999-2008 LSI Corporation |
8 | * (mailto:DL-MPTFusionLinux@lsi.com) | 8 | * (mailto:DL-MPTFusionLinux@lsi.com) |
9 | * | 9 | * |
10 | */ | 10 | */ |
@@ -66,7 +66,7 @@ | |||
66 | #include <scsi/scsi_host.h> | 66 | #include <scsi/scsi_host.h> |
67 | #include <scsi/scsi_tcq.h> | 67 | #include <scsi/scsi_tcq.h> |
68 | 68 | ||
69 | #define COPYRIGHT "Copyright (c) 1999-2007 LSI Corporation" | 69 | #define COPYRIGHT "Copyright (c) 1999-2008 LSI Corporation" |
70 | #define MODULEAUTHOR "LSI Corporation" | 70 | #define MODULEAUTHOR "LSI Corporation" |
71 | #include "mptbase.h" | 71 | #include "mptbase.h" |
72 | #include "mptctl.h" | 72 | #include "mptctl.h" |
diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h index 2c1890127e15..d564cc9ada6a 100644 --- a/drivers/message/fusion/mptctl.h +++ b/drivers/message/fusion/mptctl.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * LSIFC9xx/LSI409xx Fibre Channel | 5 | * LSIFC9xx/LSI409xx Fibre Channel |
6 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 6 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
7 | * | 7 | * |
8 | * Copyright (c) 1999-2007 LSI Corporation | 8 | * Copyright (c) 1999-2008 LSI Corporation |
9 | * (mailto:DL-MPTFusionLinux@lsi.com) | 9 | * (mailto:DL-MPTFusionLinux@lsi.com) |
10 | * | 10 | * |
11 | */ | 11 | */ |
diff --git a/drivers/message/fusion/mptdebug.h b/drivers/message/fusion/mptdebug.h index ffdb0a6191b4..510b9f492093 100644 --- a/drivers/message/fusion/mptdebug.h +++ b/drivers/message/fusion/mptdebug.h | |||
@@ -3,7 +3,7 @@ | |||
3 | * For use with LSI PCI chip/adapter(s) | 3 | * For use with LSI PCI chip/adapter(s) |
4 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 4 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
5 | * | 5 | * |
6 | * Copyright (c) 1999-2007 LSI Corporation | 6 | * Copyright (c) 1999-2008 LSI Corporation |
7 | * (mailto:DL-MPTFusionLinux@lsi.com) | 7 | * (mailto:DL-MPTFusionLinux@lsi.com) |
8 | * | 8 | * |
9 | */ | 9 | */ |
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 1e24ab4ac38c..fc31ca6829d8 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * For use with LSI PCI chip/adapter(s) | 3 | * For use with LSI PCI chip/adapter(s) |
4 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 4 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
5 | * | 5 | * |
6 | * Copyright (c) 1999-2007 LSI Corporation | 6 | * Copyright (c) 1999-2008 LSI Corporation |
7 | * (mailto:DL-MPTFusionLinux@lsi.com) | 7 | * (mailto:DL-MPTFusionLinux@lsi.com) |
8 | * | 8 | * |
9 | */ | 9 | */ |
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 7950fc678ed1..d709d92b7b30 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * For use with LSI Fibre Channel PCI chip/adapters | 4 | * For use with LSI Fibre Channel PCI chip/adapters |
5 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 5 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
6 | * | 6 | * |
7 | * Copyright (c) 2000-2007 LSI Corporation | 7 | * Copyright (c) 2000-2008 LSI Corporation |
8 | * (mailto:DL-MPTFusionLinux@lsi.com) | 8 | * (mailto:DL-MPTFusionLinux@lsi.com) |
9 | * | 9 | * |
10 | */ | 10 | */ |
diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h index bafb67fc8181..33927ee7dc3b 100644 --- a/drivers/message/fusion/mptlan.h +++ b/drivers/message/fusion/mptlan.h | |||
@@ -4,7 +4,7 @@ | |||
4 | * For use with LSI Fibre Channel PCI chip/adapters | 4 | * For use with LSI Fibre Channel PCI chip/adapters |
5 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 5 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
6 | * | 6 | * |
7 | * Copyright (c) 2000-2007 LSI Corporation | 7 | * Copyright (c) 2000-2008 LSI Corporation |
8 | * (mailto:DL-MPTFusionLinux@lsi.com) | 8 | * (mailto:DL-MPTFusionLinux@lsi.com) |
9 | * | 9 | * |
10 | */ | 10 | */ |
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 4d492ba232b0..b1147aa7afde 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * For use with LSI PCI chip/adapter(s) | 3 | * For use with LSI PCI chip/adapter(s) |
4 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 4 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
5 | * | 5 | * |
6 | * Copyright (c) 1999-2007 LSI Corporation | 6 | * Copyright (c) 1999-2008 LSI Corporation |
7 | * (mailto:DL-MPTFusionLinux@lsi.com) | 7 | * (mailto:DL-MPTFusionLinux@lsi.com) |
8 | */ | 8 | */ |
9 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 9 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h index 7c150f50629a..2b544e0877e6 100644 --- a/drivers/message/fusion/mptsas.h +++ b/drivers/message/fusion/mptsas.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * LSIFC9xx/LSI409xx Fibre Channel | 5 | * LSIFC9xx/LSI409xx Fibre Channel |
6 | * running LSI MPT (Message Passing Technology) firmware. | 6 | * running LSI MPT (Message Passing Technology) firmware. |
7 | * | 7 | * |
8 | * Copyright (c) 1999-2007 LSI Corporation | 8 | * Copyright (c) 1999-2008 LSI Corporation |
9 | * (mailto:DL-MPTFusionLinux@lsi.com) | 9 | * (mailto:DL-MPTFusionLinux@lsi.com) |
10 | * | 10 | * |
11 | */ | 11 | */ |
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index c68ef00c2f92..d142b6b4b976 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * For use with LSI PCI chip/adapter(s) | 3 | * For use with LSI PCI chip/adapter(s) |
4 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 4 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
5 | * | 5 | * |
6 | * Copyright (c) 1999-2007 LSI Corporation | 6 | * Copyright (c) 1999-2008 LSI Corporation |
7 | * (mailto:DL-MPTFusionLinux@lsi.com) | 7 | * (mailto:DL-MPTFusionLinux@lsi.com) |
8 | * | 8 | * |
9 | */ | 9 | */ |
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 7ea7da0e090c..319aa3033371 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * LSIFC9xx/LSI409xx Fibre Channel | 5 | * LSIFC9xx/LSI409xx Fibre Channel |
6 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 6 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
7 | * | 7 | * |
8 | * Copyright (c) 1999-2007 LSI Corporation | 8 | * Copyright (c) 1999-2008 LSI Corporation |
9 | * (mailto:DL-MPTFusionLinux@lsi.com) | 9 | * (mailto:DL-MPTFusionLinux@lsi.com) |
10 | * | 10 | * |
11 | */ | 11 | */ |
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 1effca4e40e1..61620144e49c 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * For use with LSI PCI chip/adapter(s) | 3 | * For use with LSI PCI chip/adapter(s) |
4 | * running LSI Fusion MPT (Message Passing Technology) firmware. | 4 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
5 | * | 5 | * |
6 | * Copyright (c) 1999-2007 LSI Corporation | 6 | * Copyright (c) 1999-2008 LSI Corporation |
7 | * (mailto:DL-MPTFusionLinux@lsi.com) | 7 | * (mailto:DL-MPTFusionLinux@lsi.com) |
8 | * | 8 | * |
9 | */ | 9 | */ |
@@ -447,6 +447,7 @@ static int mptspi_target_alloc(struct scsi_target *starget) | |||
447 | spi_max_offset(starget) = ioc->spi_data.maxSyncOffset; | 447 | spi_max_offset(starget) = ioc->spi_data.maxSyncOffset; |
448 | 448 | ||
449 | spi_offset(starget) = 0; | 449 | spi_offset(starget) = 0; |
450 | spi_period(starget) = 0xFF; | ||
450 | mptspi_write_width(starget, 0); | 451 | mptspi_write_width(starget, 0); |
451 | 452 | ||
452 | return 0; | 453 | return 0; |
diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index d6a78f1a2f16..cb301cc6178c 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile | |||
@@ -3,7 +3,6 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ | 5 | zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ |
6 | zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ | 6 | zfcp_fsf.o zfcp_dbf.o zfcp_sysfs.o zfcp_fc.o zfcp_cfdc.o |
7 | zfcp_sysfs_unit.o zfcp_sysfs_driver.o | ||
8 | 7 | ||
9 | obj-$(CONFIG_ZFCP) += zfcp.o | 8 | obj-$(CONFIG_ZFCP) += zfcp.o |
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 8c7e2b778ef1..90abfd06ed55 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -1,22 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Module interface and handling of zfcp data structures. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | /* | 9 | /* |
@@ -31,93 +18,25 @@ | |||
31 | * Maxim Shchetynin | 18 | * Maxim Shchetynin |
32 | * Volker Sameske | 19 | * Volker Sameske |
33 | * Ralph Wuerthner | 20 | * Ralph Wuerthner |
21 | * Michael Loehr | ||
22 | * Swen Schillig | ||
23 | * Christof Schmitt | ||
24 | * Martin Petermann | ||
25 | * Sven Schuetz | ||
34 | */ | 26 | */ |
35 | 27 | ||
28 | #include <linux/miscdevice.h> | ||
36 | #include "zfcp_ext.h" | 29 | #include "zfcp_ext.h" |
37 | 30 | ||
38 | /* accumulated log level (module parameter) */ | ||
39 | static u32 loglevel = ZFCP_LOG_LEVEL_DEFAULTS; | ||
40 | static char *device; | 31 | static char *device; |
41 | /*********************** FUNCTION PROTOTYPES *********************************/ | ||
42 | |||
43 | /* written against the module interface */ | ||
44 | static int __init zfcp_module_init(void); | ||
45 | |||
46 | /* FCP related */ | ||
47 | static void zfcp_ns_gid_pn_handler(unsigned long); | ||
48 | |||
49 | /* miscellaneous */ | ||
50 | static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); | ||
51 | static void zfcp_sg_list_free(struct zfcp_sg_list *); | ||
52 | static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, | ||
53 | void __user *, size_t); | ||
54 | static int zfcp_sg_list_copy_to_user(void __user *, | ||
55 | struct zfcp_sg_list *, size_t); | ||
56 | static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long); | ||
57 | |||
58 | #define ZFCP_CFDC_IOC_MAGIC 0xDD | ||
59 | #define ZFCP_CFDC_IOC \ | ||
60 | _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_sense_data) | ||
61 | |||
62 | |||
63 | static const struct file_operations zfcp_cfdc_fops = { | ||
64 | .unlocked_ioctl = zfcp_cfdc_dev_ioctl, | ||
65 | #ifdef CONFIG_COMPAT | ||
66 | .compat_ioctl = zfcp_cfdc_dev_ioctl | ||
67 | #endif | ||
68 | }; | ||
69 | |||
70 | static struct miscdevice zfcp_cfdc_misc = { | ||
71 | .minor = ZFCP_CFDC_DEV_MINOR, | ||
72 | .name = ZFCP_CFDC_DEV_NAME, | ||
73 | .fops = &zfcp_cfdc_fops | ||
74 | }; | ||
75 | |||
76 | /*********************** KERNEL/MODULE PARAMETERS ***************************/ | ||
77 | |||
78 | /* declare driver module init/cleanup functions */ | ||
79 | module_init(zfcp_module_init); | ||
80 | 32 | ||
81 | MODULE_AUTHOR("IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com"); | 33 | MODULE_AUTHOR("IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com"); |
82 | MODULE_DESCRIPTION | 34 | MODULE_DESCRIPTION("FCP HBA driver"); |
83 | ("FCP (SCSI over Fibre Channel) HBA driver for IBM System z9 and zSeries"); | ||
84 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
85 | 36 | ||
86 | module_param(device, charp, 0400); | 37 | module_param(device, charp, 0400); |
87 | MODULE_PARM_DESC(device, "specify initial device"); | 38 | MODULE_PARM_DESC(device, "specify initial device"); |
88 | 39 | ||
89 | module_param(loglevel, uint, 0400); | ||
90 | MODULE_PARM_DESC(loglevel, | ||
91 | "log levels, 8 nibbles: " | ||
92 | "FC ERP QDIO CIO Config FSF SCSI Other, " | ||
93 | "levels: 0=none 1=normal 2=devel 3=trace"); | ||
94 | |||
95 | /****************************************************************/ | ||
96 | /************** Functions without logging ***********************/ | ||
97 | /****************************************************************/ | ||
98 | |||
99 | void | ||
100 | _zfcp_hex_dump(char *addr, int count) | ||
101 | { | ||
102 | int i; | ||
103 | for (i = 0; i < count; i++) { | ||
104 | printk("%02x", addr[i]); | ||
105 | if ((i % 4) == 3) | ||
106 | printk(" "); | ||
107 | if ((i % 32) == 31) | ||
108 | printk("\n"); | ||
109 | } | ||
110 | if (((i-1) % 32) != 31) | ||
111 | printk("\n"); | ||
112 | } | ||
113 | |||
114 | |||
115 | /****************************************************************/ | ||
116 | /****** Functions to handle the request ID hash table ********/ | ||
117 | /****************************************************************/ | ||
118 | |||
119 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF | ||
120 | |||
121 | static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) | 40 | static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) |
122 | { | 41 | { |
123 | int idx; | 42 | int idx; |
@@ -132,11 +51,12 @@ static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) | |||
132 | return 0; | 51 | return 0; |
133 | } | 52 | } |
134 | 53 | ||
135 | static void zfcp_reqlist_free(struct zfcp_adapter *adapter) | 54 | /** |
136 | { | 55 | * zfcp_reqlist_isempty - is the request list empty |
137 | kfree(adapter->req_list); | 56 | * @adapter: pointer to struct zfcp_adapter |
138 | } | 57 | * |
139 | 58 | * Returns: true if list is empty, false otherwise | |
59 | */ | ||
140 | int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) | 60 | int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) |
141 | { | 61 | { |
142 | unsigned int idx; | 62 | unsigned int idx; |
@@ -147,62 +67,58 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) | |||
147 | return 1; | 67 | return 1; |
148 | } | 68 | } |
149 | 69 | ||
150 | #undef ZFCP_LOG_AREA | 70 | static int __init zfcp_device_setup(char *devstr) |
151 | |||
152 | /****************************************************************/ | ||
153 | /************** Uncategorised Functions *************************/ | ||
154 | /****************************************************************/ | ||
155 | |||
156 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER | ||
157 | |||
158 | /** | ||
159 | * zfcp_device_setup - setup function | ||
160 | * @str: pointer to parameter string | ||
161 | * | ||
162 | * Parse "device=..." parameter string. | ||
163 | */ | ||
164 | static int __init | ||
165 | zfcp_device_setup(char *devstr) | ||
166 | { | 71 | { |
167 | char *tmp, *str; | 72 | char *token; |
168 | size_t len; | 73 | char *str; |
169 | 74 | ||
170 | if (!devstr) | 75 | if (!devstr) |
171 | return 0; | 76 | return 0; |
172 | 77 | ||
173 | len = strlen(devstr) + 1; | 78 | /* duplicate devstr and keep the original for sysfs presentation*/ |
174 | str = kmalloc(len, GFP_KERNEL); | 79 | str = kmalloc(strlen(devstr) + 1, GFP_KERNEL); |
175 | if (!str) | 80 | if (!str) |
176 | goto err_out; | 81 | return 0; |
177 | memcpy(str, devstr, len); | ||
178 | 82 | ||
179 | tmp = strchr(str, ','); | 83 | strcpy(str, devstr); |
180 | if (!tmp) | ||
181 | goto err_out; | ||
182 | *tmp++ = '\0'; | ||
183 | strncpy(zfcp_data.init_busid, str, BUS_ID_SIZE); | ||
184 | zfcp_data.init_busid[BUS_ID_SIZE-1] = '\0'; | ||
185 | 84 | ||
186 | zfcp_data.init_wwpn = simple_strtoull(tmp, &tmp, 0); | 85 | token = strsep(&str, ","); |
187 | if (*tmp++ != ',') | 86 | if (!token || strlen(token) >= BUS_ID_SIZE) |
188 | goto err_out; | 87 | goto err_out; |
189 | if (*tmp == '\0') | 88 | strncpy(zfcp_data.init_busid, token, BUS_ID_SIZE); |
89 | |||
90 | token = strsep(&str, ","); | ||
91 | if (!token || strict_strtoull(token, 0, &zfcp_data.init_wwpn)) | ||
190 | goto err_out; | 92 | goto err_out; |
191 | 93 | ||
192 | zfcp_data.init_fcp_lun = simple_strtoull(tmp, &tmp, 0); | 94 | token = strsep(&str, ","); |
193 | if (*tmp != '\0') | 95 | if (!token || strict_strtoull(token, 0, &zfcp_data.init_fcp_lun)) |
194 | goto err_out; | 96 | goto err_out; |
97 | |||
195 | kfree(str); | 98 | kfree(str); |
196 | return 1; | 99 | return 1; |
197 | 100 | ||
198 | err_out: | 101 | err_out: |
199 | ZFCP_LOG_NORMAL("Parse error for device parameter string %s\n", str); | ||
200 | kfree(str); | 102 | kfree(str); |
103 | pr_err("zfcp: Parse error for device parameter string %s, " | ||
104 | "device not attached.\n", devstr); | ||
201 | return 0; | 105 | return 0; |
202 | } | 106 | } |
203 | 107 | ||
204 | static void __init | 108 | static struct zfcp_adapter *zfcp_get_adapter_by_busid(char *bus_id) |
205 | zfcp_init_device_configure(void) | 109 | { |
110 | struct zfcp_adapter *adapter; | ||
111 | |||
112 | list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) | ||
113 | if ((strncmp(bus_id, adapter->ccw_device->dev.bus_id, | ||
114 | BUS_ID_SIZE) == 0) && | ||
115 | !(atomic_read(&adapter->status) & | ||
116 | ZFCP_STATUS_COMMON_REMOVE)) | ||
117 | return adapter; | ||
118 | return NULL; | ||
119 | } | ||
120 | |||
121 | static void __init zfcp_init_device_configure(void) | ||
206 | { | 122 | { |
207 | struct zfcp_adapter *adapter; | 123 | struct zfcp_adapter *adapter; |
208 | struct zfcp_port *port; | 124 | struct zfcp_port *port; |
@@ -215,101 +131,75 @@ zfcp_init_device_configure(void) | |||
215 | zfcp_adapter_get(adapter); | 131 | zfcp_adapter_get(adapter); |
216 | read_unlock_irq(&zfcp_data.config_lock); | 132 | read_unlock_irq(&zfcp_data.config_lock); |
217 | 133 | ||
218 | if (adapter == NULL) | 134 | if (!adapter) |
219 | goto out_adapter; | 135 | goto out_adapter; |
220 | port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0); | 136 | port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0); |
221 | if (!port) | 137 | if (IS_ERR(port)) |
222 | goto out_port; | 138 | goto out_port; |
223 | unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); | 139 | unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); |
224 | if (!unit) | 140 | if (IS_ERR(unit)) |
225 | goto out_unit; | 141 | goto out_unit; |
226 | up(&zfcp_data.config_sema); | 142 | up(&zfcp_data.config_sema); |
227 | ccw_device_set_online(adapter->ccw_device); | 143 | ccw_device_set_online(adapter->ccw_device); |
228 | zfcp_erp_wait(adapter); | 144 | zfcp_erp_wait(adapter); |
229 | down(&zfcp_data.config_sema); | 145 | down(&zfcp_data.config_sema); |
230 | zfcp_unit_put(unit); | 146 | zfcp_unit_put(unit); |
231 | out_unit: | 147 | out_unit: |
232 | zfcp_port_put(port); | 148 | zfcp_port_put(port); |
233 | out_port: | 149 | out_port: |
234 | zfcp_adapter_put(adapter); | 150 | zfcp_adapter_put(adapter); |
235 | out_adapter: | 151 | out_adapter: |
236 | up(&zfcp_data.config_sema); | 152 | up(&zfcp_data.config_sema); |
237 | return; | 153 | return; |
238 | } | 154 | } |
239 | 155 | ||
240 | static int calc_alignment(int size) | 156 | static struct kmem_cache *zfcp_cache_create(int size, char *name) |
241 | { | 157 | { |
242 | int align = 1; | 158 | int align = 1; |
243 | |||
244 | if (!size) | ||
245 | return 0; | ||
246 | |||
247 | while ((size - align) > 0) | 159 | while ((size - align) > 0) |
248 | align <<= 1; | 160 | align <<= 1; |
249 | 161 | return kmem_cache_create(name , size, align, 0, NULL); | |
250 | return align; | ||
251 | } | 162 | } |
252 | 163 | ||
253 | static int __init | 164 | static int __init zfcp_module_init(void) |
254 | zfcp_module_init(void) | ||
255 | { | 165 | { |
256 | int retval = -ENOMEM; | 166 | int retval = -ENOMEM; |
257 | int size, align; | ||
258 | 167 | ||
259 | size = sizeof(struct zfcp_fsf_req_qtcb); | 168 | zfcp_data.fsf_req_qtcb_cache = zfcp_cache_create( |
260 | align = calc_alignment(size); | 169 | sizeof(struct zfcp_fsf_req_qtcb), "zfcp_fsf"); |
261 | zfcp_data.fsf_req_qtcb_cache = | ||
262 | kmem_cache_create("zfcp_fsf", size, align, 0, NULL); | ||
263 | if (!zfcp_data.fsf_req_qtcb_cache) | 170 | if (!zfcp_data.fsf_req_qtcb_cache) |
264 | goto out; | 171 | goto out; |
265 | 172 | ||
266 | size = sizeof(struct fsf_status_read_buffer); | 173 | zfcp_data.sr_buffer_cache = zfcp_cache_create( |
267 | align = calc_alignment(size); | 174 | sizeof(struct fsf_status_read_buffer), "zfcp_sr"); |
268 | zfcp_data.sr_buffer_cache = | ||
269 | kmem_cache_create("zfcp_sr", size, align, 0, NULL); | ||
270 | if (!zfcp_data.sr_buffer_cache) | 175 | if (!zfcp_data.sr_buffer_cache) |
271 | goto out_sr_cache; | 176 | goto out_sr_cache; |
272 | 177 | ||
273 | size = sizeof(struct zfcp_gid_pn_data); | 178 | zfcp_data.gid_pn_cache = zfcp_cache_create( |
274 | align = calc_alignment(size); | 179 | sizeof(struct zfcp_gid_pn_data), "zfcp_gid"); |
275 | zfcp_data.gid_pn_cache = | ||
276 | kmem_cache_create("zfcp_gid", size, align, 0, NULL); | ||
277 | if (!zfcp_data.gid_pn_cache) | 180 | if (!zfcp_data.gid_pn_cache) |
278 | goto out_gid_cache; | 181 | goto out_gid_cache; |
279 | 182 | ||
280 | atomic_set(&zfcp_data.loglevel, loglevel); | ||
281 | |||
282 | /* initialize adapter list */ | ||
283 | INIT_LIST_HEAD(&zfcp_data.adapter_list_head); | 183 | INIT_LIST_HEAD(&zfcp_data.adapter_list_head); |
284 | |||
285 | /* initialize adapters to be removed list head */ | ||
286 | INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh); | 184 | INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh); |
287 | 185 | ||
186 | sema_init(&zfcp_data.config_sema, 1); | ||
187 | rwlock_init(&zfcp_data.config_lock); | ||
188 | |||
288 | zfcp_data.scsi_transport_template = | 189 | zfcp_data.scsi_transport_template = |
289 | fc_attach_transport(&zfcp_transport_functions); | 190 | fc_attach_transport(&zfcp_transport_functions); |
290 | if (!zfcp_data.scsi_transport_template) | 191 | if (!zfcp_data.scsi_transport_template) |
291 | goto out_transport; | 192 | goto out_transport; |
292 | 193 | ||
293 | retval = misc_register(&zfcp_cfdc_misc); | 194 | retval = misc_register(&zfcp_cfdc_misc); |
294 | if (retval != 0) { | 195 | if (retval) { |
295 | ZFCP_LOG_INFO("registration of misc device " | 196 | pr_err("zfcp: registration of misc device zfcp_cfdc failed\n"); |
296 | "zfcp_cfdc failed\n"); | ||
297 | goto out_misc; | 197 | goto out_misc; |
298 | } | 198 | } |
299 | 199 | ||
300 | ZFCP_LOG_TRACE("major/minor for zfcp_cfdc: %d/%d\n", | ||
301 | ZFCP_CFDC_DEV_MAJOR, zfcp_cfdc_misc.minor); | ||
302 | |||
303 | /* Initialise proc semaphores */ | ||
304 | sema_init(&zfcp_data.config_sema, 1); | ||
305 | |||
306 | /* initialise configuration rw lock */ | ||
307 | rwlock_init(&zfcp_data.config_lock); | ||
308 | |||
309 | /* setup dynamic I/O */ | ||
310 | retval = zfcp_ccw_register(); | 200 | retval = zfcp_ccw_register(); |
311 | if (retval) { | 201 | if (retval) { |
312 | ZFCP_LOG_NORMAL("registration with common I/O layer failed\n"); | 202 | pr_err("zfcp: Registration with common I/O layer failed.\n"); |
313 | goto out_ccw_register; | 203 | goto out_ccw_register; |
314 | } | 204 | } |
315 | 205 | ||
@@ -318,527 +208,88 @@ zfcp_module_init(void) | |||
318 | 208 | ||
319 | goto out; | 209 | goto out; |
320 | 210 | ||
321 | out_ccw_register: | 211 | out_ccw_register: |
322 | misc_deregister(&zfcp_cfdc_misc); | 212 | misc_deregister(&zfcp_cfdc_misc); |
323 | out_misc: | 213 | out_misc: |
324 | fc_release_transport(zfcp_data.scsi_transport_template); | 214 | fc_release_transport(zfcp_data.scsi_transport_template); |
325 | out_transport: | 215 | out_transport: |
326 | kmem_cache_destroy(zfcp_data.gid_pn_cache); | 216 | kmem_cache_destroy(zfcp_data.gid_pn_cache); |
327 | out_gid_cache: | 217 | out_gid_cache: |
328 | kmem_cache_destroy(zfcp_data.sr_buffer_cache); | 218 | kmem_cache_destroy(zfcp_data.sr_buffer_cache); |
329 | out_sr_cache: | 219 | out_sr_cache: |
330 | kmem_cache_destroy(zfcp_data.fsf_req_qtcb_cache); | 220 | kmem_cache_destroy(zfcp_data.fsf_req_qtcb_cache); |
331 | out: | 221 | out: |
332 | return retval; | 222 | return retval; |
333 | } | 223 | } |
334 | 224 | ||
335 | /* | 225 | module_init(zfcp_module_init); |
336 | * function: zfcp_cfdc_dev_ioctl | ||
337 | * | ||
338 | * purpose: Handle control file upload/download transaction via IOCTL | ||
339 | * interface | ||
340 | * | ||
341 | * returns: 0 - Operation completed successfuly | ||
342 | * -ENOTTY - Unknown IOCTL command | ||
343 | * -EINVAL - Invalid sense data record | ||
344 | * -ENXIO - The FCP adapter is not available | ||
345 | * -EOPNOTSUPP - The FCP adapter does not have CFDC support | ||
346 | * -ENOMEM - Insufficient memory | ||
347 | * -EFAULT - User space memory I/O operation fault | ||
348 | * -EPERM - Cannot create or queue FSF request or create SBALs | ||
349 | * -ERESTARTSYS- Received signal (is mapped to EAGAIN by VFS) | ||
350 | */ | ||
351 | static long | ||
352 | zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, | ||
353 | unsigned long buffer) | ||
354 | { | ||
355 | struct zfcp_cfdc_sense_data *sense_data, __user *sense_data_user; | ||
356 | struct zfcp_adapter *adapter = NULL; | ||
357 | struct zfcp_fsf_req *fsf_req = NULL; | ||
358 | struct zfcp_sg_list *sg_list = NULL; | ||
359 | u32 fsf_command, option; | ||
360 | char *bus_id = NULL; | ||
361 | int retval = 0; | ||
362 | |||
363 | sense_data = kmalloc(sizeof(struct zfcp_cfdc_sense_data), GFP_KERNEL); | ||
364 | if (sense_data == NULL) { | ||
365 | retval = -ENOMEM; | ||
366 | goto out; | ||
367 | } | ||
368 | |||
369 | sg_list = kzalloc(sizeof(struct zfcp_sg_list), GFP_KERNEL); | ||
370 | if (sg_list == NULL) { | ||
371 | retval = -ENOMEM; | ||
372 | goto out; | ||
373 | } | ||
374 | |||
375 | if (command != ZFCP_CFDC_IOC) { | ||
376 | ZFCP_LOG_INFO("IOC request code 0x%x invalid\n", command); | ||
377 | retval = -ENOTTY; | ||
378 | goto out; | ||
379 | } | ||
380 | |||
381 | if ((sense_data_user = (void __user *) buffer) == NULL) { | ||
382 | ZFCP_LOG_INFO("sense data record is required\n"); | ||
383 | retval = -EINVAL; | ||
384 | goto out; | ||
385 | } | ||
386 | |||
387 | retval = copy_from_user(sense_data, sense_data_user, | ||
388 | sizeof(struct zfcp_cfdc_sense_data)); | ||
389 | if (retval) { | ||
390 | retval = -EFAULT; | ||
391 | goto out; | ||
392 | } | ||
393 | |||
394 | if (sense_data->signature != ZFCP_CFDC_SIGNATURE) { | ||
395 | ZFCP_LOG_INFO("invalid sense data request signature 0x%08x\n", | ||
396 | ZFCP_CFDC_SIGNATURE); | ||
397 | retval = -EINVAL; | ||
398 | goto out; | ||
399 | } | ||
400 | |||
401 | switch (sense_data->command) { | ||
402 | |||
403 | case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL: | ||
404 | fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
405 | option = FSF_CFDC_OPTION_NORMAL_MODE; | ||
406 | break; | ||
407 | |||
408 | case ZFCP_CFDC_CMND_DOWNLOAD_FORCE: | ||
409 | fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
410 | option = FSF_CFDC_OPTION_FORCE; | ||
411 | break; | ||
412 | |||
413 | case ZFCP_CFDC_CMND_FULL_ACCESS: | ||
414 | fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
415 | option = FSF_CFDC_OPTION_FULL_ACCESS; | ||
416 | break; | ||
417 | |||
418 | case ZFCP_CFDC_CMND_RESTRICTED_ACCESS: | ||
419 | fsf_command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
420 | option = FSF_CFDC_OPTION_RESTRICTED_ACCESS; | ||
421 | break; | ||
422 | |||
423 | case ZFCP_CFDC_CMND_UPLOAD: | ||
424 | fsf_command = FSF_QTCB_UPLOAD_CONTROL_FILE; | ||
425 | option = 0; | ||
426 | break; | ||
427 | |||
428 | default: | ||
429 | ZFCP_LOG_INFO("invalid command code 0x%08x\n", | ||
430 | sense_data->command); | ||
431 | retval = -EINVAL; | ||
432 | goto out; | ||
433 | } | ||
434 | |||
435 | bus_id = kmalloc(BUS_ID_SIZE, GFP_KERNEL); | ||
436 | if (bus_id == NULL) { | ||
437 | retval = -ENOMEM; | ||
438 | goto out; | ||
439 | } | ||
440 | snprintf(bus_id, BUS_ID_SIZE, "%d.%d.%04x", | ||
441 | (sense_data->devno >> 24), | ||
442 | (sense_data->devno >> 16) & 0xFF, | ||
443 | (sense_data->devno & 0xFFFF)); | ||
444 | |||
445 | read_lock_irq(&zfcp_data.config_lock); | ||
446 | adapter = zfcp_get_adapter_by_busid(bus_id); | ||
447 | if (adapter) | ||
448 | zfcp_adapter_get(adapter); | ||
449 | read_unlock_irq(&zfcp_data.config_lock); | ||
450 | |||
451 | kfree(bus_id); | ||
452 | |||
453 | if (adapter == NULL) { | ||
454 | ZFCP_LOG_INFO("invalid adapter\n"); | ||
455 | retval = -ENXIO; | ||
456 | goto out; | ||
457 | } | ||
458 | |||
459 | if (sense_data->command & ZFCP_CFDC_WITH_CONTROL_FILE) { | ||
460 | retval = zfcp_sg_list_alloc(sg_list, | ||
461 | ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); | ||
462 | if (retval) { | ||
463 | retval = -ENOMEM; | ||
464 | goto out; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | if ((sense_data->command & ZFCP_CFDC_DOWNLOAD) && | ||
469 | (sense_data->command & ZFCP_CFDC_WITH_CONTROL_FILE)) { | ||
470 | retval = zfcp_sg_list_copy_from_user( | ||
471 | sg_list, &sense_data_user->control_file, | ||
472 | ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); | ||
473 | if (retval) { | ||
474 | retval = -EFAULT; | ||
475 | goto out; | ||
476 | } | ||
477 | } | ||
478 | |||
479 | retval = zfcp_fsf_control_file(adapter, &fsf_req, fsf_command, | ||
480 | option, sg_list); | ||
481 | if (retval) | ||
482 | goto out; | ||
483 | |||
484 | if ((fsf_req->qtcb->prefix.prot_status != FSF_PROT_GOOD) && | ||
485 | (fsf_req->qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { | ||
486 | retval = -ENXIO; | ||
487 | goto out; | ||
488 | } | ||
489 | |||
490 | sense_data->fsf_status = fsf_req->qtcb->header.fsf_status; | ||
491 | memcpy(&sense_data->fsf_status_qual, | ||
492 | &fsf_req->qtcb->header.fsf_status_qual, | ||
493 | sizeof(union fsf_status_qual)); | ||
494 | memcpy(&sense_data->payloads, &fsf_req->qtcb->bottom.support.els, 256); | ||
495 | |||
496 | retval = copy_to_user(sense_data_user, sense_data, | ||
497 | sizeof(struct zfcp_cfdc_sense_data)); | ||
498 | if (retval) { | ||
499 | retval = -EFAULT; | ||
500 | goto out; | ||
501 | } | ||
502 | |||
503 | if (sense_data->command & ZFCP_CFDC_UPLOAD) { | ||
504 | retval = zfcp_sg_list_copy_to_user( | ||
505 | &sense_data_user->control_file, sg_list, | ||
506 | ZFCP_CFDC_MAX_CONTROL_FILE_SIZE); | ||
507 | if (retval) { | ||
508 | retval = -EFAULT; | ||
509 | goto out; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | out: | ||
514 | if (fsf_req != NULL) | ||
515 | zfcp_fsf_req_free(fsf_req); | ||
516 | |||
517 | if ((adapter != NULL) && (retval != -ENXIO)) | ||
518 | zfcp_adapter_put(adapter); | ||
519 | |||
520 | if (sg_list != NULL) { | ||
521 | zfcp_sg_list_free(sg_list); | ||
522 | kfree(sg_list); | ||
523 | } | ||
524 | |||
525 | kfree(sense_data); | ||
526 | |||
527 | return retval; | ||
528 | } | ||
529 | |||
530 | |||
531 | /** | ||
532 | * zfcp_sg_list_alloc - create a scatter-gather list of the specified size | ||
533 | * @sg_list: structure describing a scatter gather list | ||
534 | * @size: size of scatter-gather list | ||
535 | * Return: 0 on success, else -ENOMEM | ||
536 | * | ||
537 | * In sg_list->sg a pointer to the created scatter-gather list is returned, | ||
538 | * or NULL if we run out of memory. sg_list->count specifies the number of | ||
539 | * elements of the scatter-gather list. The maximum size of a single element | ||
540 | * in the scatter-gather list is PAGE_SIZE. | ||
541 | */ | ||
542 | static int | ||
543 | zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) | ||
544 | { | ||
545 | struct scatterlist *sg; | ||
546 | unsigned int i; | ||
547 | int retval = 0; | ||
548 | void *address; | ||
549 | |||
550 | BUG_ON(sg_list == NULL); | ||
551 | |||
552 | sg_list->count = size >> PAGE_SHIFT; | ||
553 | if (size & ~PAGE_MASK) | ||
554 | sg_list->count++; | ||
555 | sg_list->sg = kcalloc(sg_list->count, sizeof(struct scatterlist), | ||
556 | GFP_KERNEL); | ||
557 | if (sg_list->sg == NULL) { | ||
558 | sg_list->count = 0; | ||
559 | retval = -ENOMEM; | ||
560 | goto out; | ||
561 | } | ||
562 | sg_init_table(sg_list->sg, sg_list->count); | ||
563 | |||
564 | for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) { | ||
565 | address = (void *) get_zeroed_page(GFP_KERNEL); | ||
566 | if (address == NULL) { | ||
567 | sg_list->count = i; | ||
568 | zfcp_sg_list_free(sg_list); | ||
569 | retval = -ENOMEM; | ||
570 | goto out; | ||
571 | } | ||
572 | zfcp_address_to_sg(address, sg, min(size, PAGE_SIZE)); | ||
573 | size -= sg->length; | ||
574 | } | ||
575 | |||
576 | out: | ||
577 | return retval; | ||
578 | } | ||
579 | |||
580 | |||
581 | /** | ||
582 | * zfcp_sg_list_free - free memory of a scatter-gather list | ||
583 | * @sg_list: structure describing a scatter-gather list | ||
584 | * | ||
585 | * Memory for each element in the scatter-gather list is freed. | ||
586 | * Finally sg_list->sg is freed itself and sg_list->count is reset. | ||
587 | */ | ||
588 | static void | ||
589 | zfcp_sg_list_free(struct zfcp_sg_list *sg_list) | ||
590 | { | ||
591 | struct scatterlist *sg; | ||
592 | unsigned int i; | ||
593 | |||
594 | BUG_ON(sg_list == NULL); | ||
595 | |||
596 | for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) | ||
597 | free_page((unsigned long) zfcp_sg_to_address(sg)); | ||
598 | |||
599 | sg_list->count = 0; | ||
600 | kfree(sg_list->sg); | ||
601 | } | ||
602 | |||
603 | /** | ||
604 | * zfcp_sg_size - determine size of a scatter-gather list | ||
605 | * @sg: array of (struct scatterlist) | ||
606 | * @sg_count: elements in array | ||
607 | * Return: size of entire scatter-gather list | ||
608 | */ | ||
609 | static size_t zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count) | ||
610 | { | ||
611 | unsigned int i; | ||
612 | struct scatterlist *p; | ||
613 | size_t size; | ||
614 | |||
615 | size = 0; | ||
616 | for (i = 0, p = sg; i < sg_count; i++, p++) { | ||
617 | BUG_ON(p == NULL); | ||
618 | size += p->length; | ||
619 | } | ||
620 | |||
621 | return size; | ||
622 | } | ||
623 | |||
624 | |||
625 | /** | ||
626 | * zfcp_sg_list_copy_from_user -copy data from user space to scatter-gather list | ||
627 | * @sg_list: structure describing a scatter-gather list | ||
628 | * @user_buffer: pointer to buffer in user space | ||
629 | * @size: number of bytes to be copied | ||
630 | * Return: 0 on success, -EFAULT if copy_from_user fails. | ||
631 | */ | ||
632 | static int | ||
633 | zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, | ||
634 | void __user *user_buffer, | ||
635 | size_t size) | ||
636 | { | ||
637 | struct scatterlist *sg; | ||
638 | unsigned int length; | ||
639 | void *zfcp_buffer; | ||
640 | int retval = 0; | ||
641 | |||
642 | BUG_ON(sg_list == NULL); | ||
643 | |||
644 | if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) | ||
645 | return -EFAULT; | ||
646 | |||
647 | for (sg = sg_list->sg; size > 0; sg++) { | ||
648 | length = min((unsigned int)size, sg->length); | ||
649 | zfcp_buffer = zfcp_sg_to_address(sg); | ||
650 | if (copy_from_user(zfcp_buffer, user_buffer, length)) { | ||
651 | retval = -EFAULT; | ||
652 | goto out; | ||
653 | } | ||
654 | user_buffer += length; | ||
655 | size -= length; | ||
656 | } | ||
657 | |||
658 | out: | ||
659 | return retval; | ||
660 | } | ||
661 | |||
662 | |||
663 | /** | ||
664 | * zfcp_sg_list_copy_to_user - copy data from scatter-gather list to user space | ||
665 | * @user_buffer: pointer to buffer in user space | ||
666 | * @sg_list: structure describing a scatter-gather list | ||
667 | * @size: number of bytes to be copied | ||
668 | * Return: 0 on success, -EFAULT if copy_to_user fails | ||
669 | */ | ||
670 | static int | ||
671 | zfcp_sg_list_copy_to_user(void __user *user_buffer, | ||
672 | struct zfcp_sg_list *sg_list, | ||
673 | size_t size) | ||
674 | { | ||
675 | struct scatterlist *sg; | ||
676 | unsigned int length; | ||
677 | void *zfcp_buffer; | ||
678 | int retval = 0; | ||
679 | |||
680 | BUG_ON(sg_list == NULL); | ||
681 | |||
682 | if (zfcp_sg_size(sg_list->sg, sg_list->count) < size) | ||
683 | return -EFAULT; | ||
684 | |||
685 | for (sg = sg_list->sg; size > 0; sg++) { | ||
686 | length = min((unsigned int) size, sg->length); | ||
687 | zfcp_buffer = zfcp_sg_to_address(sg); | ||
688 | if (copy_to_user(user_buffer, zfcp_buffer, length)) { | ||
689 | retval = -EFAULT; | ||
690 | goto out; | ||
691 | } | ||
692 | user_buffer += length; | ||
693 | size -= length; | ||
694 | } | ||
695 | |||
696 | out: | ||
697 | return retval; | ||
698 | } | ||
699 | |||
700 | |||
701 | #undef ZFCP_LOG_AREA | ||
702 | |||
703 | /****************************************************************/ | ||
704 | /****** Functions for configuration/set-up of structures ********/ | ||
705 | /****************************************************************/ | ||
706 | |||
707 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | ||
708 | 226 | ||
709 | /** | 227 | /** |
710 | * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN | 228 | * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN |
711 | * @port: pointer to port to search for unit | 229 | * @port: pointer to port to search for unit |
712 | * @fcp_lun: FCP LUN to search for | 230 | * @fcp_lun: FCP LUN to search for |
713 | * Traverse list of all units of a port and return pointer to a unit | 231 | * |
714 | * with the given FCP LUN. | 232 | * Returns: pointer to zfcp_unit or NULL |
715 | */ | 233 | */ |
716 | struct zfcp_unit * | 234 | struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, |
717 | zfcp_get_unit_by_lun(struct zfcp_port *port, fcp_lun_t fcp_lun) | 235 | fcp_lun_t fcp_lun) |
718 | { | 236 | { |
719 | struct zfcp_unit *unit; | 237 | struct zfcp_unit *unit; |
720 | int found = 0; | ||
721 | 238 | ||
722 | list_for_each_entry(unit, &port->unit_list_head, list) { | 239 | list_for_each_entry(unit, &port->unit_list_head, list) |
723 | if ((unit->fcp_lun == fcp_lun) && | 240 | if ((unit->fcp_lun == fcp_lun) && |
724 | !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status)) | 241 | !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) |
725 | { | 242 | return unit; |
726 | found = 1; | 243 | return NULL; |
727 | break; | ||
728 | } | ||
729 | } | ||
730 | return found ? unit : NULL; | ||
731 | } | 244 | } |
732 | 245 | ||
733 | /** | 246 | /** |
734 | * zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn | 247 | * zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn |
735 | * @adapter: pointer to adapter to search for port | 248 | * @adapter: pointer to adapter to search for port |
736 | * @wwpn: wwpn to search for | 249 | * @wwpn: wwpn to search for |
737 | * Traverse list of all ports of an adapter and return pointer to a port | 250 | * |
738 | * with the given wwpn. | 251 | * Returns: pointer to zfcp_port or NULL |
739 | */ | ||
740 | struct zfcp_port * | ||
741 | zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, wwn_t wwpn) | ||
742 | { | ||
743 | struct zfcp_port *port; | ||
744 | int found = 0; | ||
745 | |||
746 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
747 | if ((port->wwpn == wwpn) && | ||
748 | !(atomic_read(&port->status) & | ||
749 | (ZFCP_STATUS_PORT_NO_WWPN | ZFCP_STATUS_COMMON_REMOVE))) { | ||
750 | found = 1; | ||
751 | break; | ||
752 | } | ||
753 | } | ||
754 | return found ? port : NULL; | ||
755 | } | ||
756 | |||
757 | /** | ||
758 | * zfcp_get_port_by_did - find port in port list of adapter by d_id | ||
759 | * @adapter: pointer to adapter to search for port | ||
760 | * @d_id: d_id to search for | ||
761 | * Traverse list of all ports of an adapter and return pointer to a port | ||
762 | * with the given d_id. | ||
763 | */ | 252 | */ |
764 | struct zfcp_port * | 253 | struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, |
765 | zfcp_get_port_by_did(struct zfcp_adapter *adapter, u32 d_id) | 254 | wwn_t wwpn) |
766 | { | 255 | { |
767 | struct zfcp_port *port; | 256 | struct zfcp_port *port; |
768 | int found = 0; | ||
769 | 257 | ||
770 | list_for_each_entry(port, &adapter->port_list_head, list) { | 258 | list_for_each_entry(port, &adapter->port_list_head, list) |
771 | if ((port->d_id == d_id) && | 259 | if ((port->wwpn == wwpn) && !(atomic_read(&port->status) & |
772 | !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) | 260 | (ZFCP_STATUS_PORT_NO_WWPN | ZFCP_STATUS_COMMON_REMOVE))) |
773 | { | 261 | return port; |
774 | found = 1; | 262 | return NULL; |
775 | break; | ||
776 | } | ||
777 | } | ||
778 | return found ? port : NULL; | ||
779 | } | 263 | } |
780 | 264 | ||
781 | /** | 265 | static void zfcp_sysfs_unit_release(struct device *dev) |
782 | * zfcp_get_adapter_by_busid - find adpater in adapter list by bus_id | ||
783 | * @bus_id: bus_id to search for | ||
784 | * Traverse list of all adapters and return pointer to an adapter | ||
785 | * with the given bus_id. | ||
786 | */ | ||
787 | struct zfcp_adapter * | ||
788 | zfcp_get_adapter_by_busid(char *bus_id) | ||
789 | { | 266 | { |
790 | struct zfcp_adapter *adapter; | 267 | kfree(container_of(dev, struct zfcp_unit, sysfs_device)); |
791 | int found = 0; | ||
792 | |||
793 | list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) { | ||
794 | if ((strncmp(bus_id, zfcp_get_busid_by_adapter(adapter), | ||
795 | BUS_ID_SIZE) == 0) && | ||
796 | !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, | ||
797 | &adapter->status)){ | ||
798 | found = 1; | ||
799 | break; | ||
800 | } | ||
801 | } | ||
802 | return found ? adapter : NULL; | ||
803 | } | 268 | } |
804 | 269 | ||
805 | /** | 270 | /** |
806 | * zfcp_unit_enqueue - enqueue unit to unit list of a port. | 271 | * zfcp_unit_enqueue - enqueue unit to unit list of a port. |
807 | * @port: pointer to port where unit is added | 272 | * @port: pointer to port where unit is added |
808 | * @fcp_lun: FCP LUN of unit to be enqueued | 273 | * @fcp_lun: FCP LUN of unit to be enqueued |
809 | * Return: pointer to enqueued unit on success, NULL on error | 274 | * Returns: pointer to enqueued unit on success, ERR_PTR on error |
810 | * Locks: config_sema must be held to serialize changes to the unit list | 275 | * Locks: config_sema must be held to serialize changes to the unit list |
811 | * | 276 | * |
812 | * Sets up some unit internal structures and creates sysfs entry. | 277 | * Sets up some unit internal structures and creates sysfs entry. |
813 | */ | 278 | */ |
814 | struct zfcp_unit * | 279 | struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) |
815 | zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) | ||
816 | { | 280 | { |
817 | struct zfcp_unit *unit; | 281 | struct zfcp_unit *unit; |
818 | 282 | ||
819 | /* | 283 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); |
820 | * check that there is no unit with this FCP_LUN already in list | ||
821 | * and enqueue it. | ||
822 | * Note: Unlike for the adapter and the port, this is an error | ||
823 | */ | ||
824 | read_lock_irq(&zfcp_data.config_lock); | ||
825 | unit = zfcp_get_unit_by_lun(port, fcp_lun); | ||
826 | read_unlock_irq(&zfcp_data.config_lock); | ||
827 | if (unit) | ||
828 | return NULL; | ||
829 | |||
830 | unit = kzalloc(sizeof (struct zfcp_unit), GFP_KERNEL); | ||
831 | if (!unit) | 284 | if (!unit) |
832 | return NULL; | 285 | return ERR_PTR(-ENOMEM); |
833 | 286 | ||
834 | /* initialise reference count stuff */ | ||
835 | atomic_set(&unit->refcount, 0); | 287 | atomic_set(&unit->refcount, 0); |
836 | init_waitqueue_head(&unit->remove_wq); | 288 | init_waitqueue_head(&unit->remove_wq); |
837 | 289 | ||
838 | unit->port = port; | 290 | unit->port = port; |
839 | unit->fcp_lun = fcp_lun; | 291 | unit->fcp_lun = fcp_lun; |
840 | 292 | ||
841 | /* setup for sysfs registration */ | ||
842 | snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", fcp_lun); | 293 | snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", fcp_lun); |
843 | unit->sysfs_device.parent = &port->sysfs_device; | 294 | unit->sysfs_device.parent = &port->sysfs_device; |
844 | unit->sysfs_device.release = zfcp_sysfs_unit_release; | 295 | unit->sysfs_device.release = zfcp_sysfs_unit_release; |
@@ -847,14 +298,28 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) | |||
847 | /* mark unit unusable as long as sysfs registration is not complete */ | 298 | /* mark unit unusable as long as sysfs registration is not complete */ |
848 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | 299 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); |
849 | 300 | ||
850 | if (device_register(&unit->sysfs_device)) { | 301 | spin_lock_init(&unit->latencies.lock); |
851 | kfree(unit); | 302 | unit->latencies.write.channel.min = 0xFFFFFFFF; |
852 | return NULL; | 303 | unit->latencies.write.fabric.min = 0xFFFFFFFF; |
304 | unit->latencies.read.channel.min = 0xFFFFFFFF; | ||
305 | unit->latencies.read.fabric.min = 0xFFFFFFFF; | ||
306 | unit->latencies.cmd.channel.min = 0xFFFFFFFF; | ||
307 | unit->latencies.cmd.fabric.min = 0xFFFFFFFF; | ||
308 | |||
309 | read_lock_irq(&zfcp_data.config_lock); | ||
310 | if (zfcp_get_unit_by_lun(port, fcp_lun)) { | ||
311 | read_unlock_irq(&zfcp_data.config_lock); | ||
312 | goto err_out_free; | ||
853 | } | 313 | } |
314 | read_unlock_irq(&zfcp_data.config_lock); | ||
854 | 315 | ||
855 | if (zfcp_sysfs_unit_create_files(&unit->sysfs_device)) { | 316 | if (device_register(&unit->sysfs_device)) |
317 | goto err_out_free; | ||
318 | |||
319 | if (sysfs_create_group(&unit->sysfs_device.kobj, | ||
320 | &zfcp_sysfs_unit_attrs)) { | ||
856 | device_unregister(&unit->sysfs_device); | 321 | device_unregister(&unit->sysfs_device); |
857 | return NULL; | 322 | return ERR_PTR(-EIO); |
858 | } | 323 | } |
859 | 324 | ||
860 | zfcp_unit_get(unit); | 325 | zfcp_unit_get(unit); |
@@ -864,16 +329,27 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) | |||
864 | list_add_tail(&unit->list, &port->unit_list_head); | 329 | list_add_tail(&unit->list, &port->unit_list_head); |
865 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | 330 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); |
866 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); | 331 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); |
332 | |||
867 | write_unlock_irq(&zfcp_data.config_lock); | 333 | write_unlock_irq(&zfcp_data.config_lock); |
868 | 334 | ||
869 | port->units++; | 335 | port->units++; |
870 | zfcp_port_get(port); | 336 | zfcp_port_get(port); |
871 | 337 | ||
872 | return unit; | 338 | return unit; |
339 | |||
340 | err_out_free: | ||
341 | kfree(unit); | ||
342 | return ERR_PTR(-EINVAL); | ||
873 | } | 343 | } |
874 | 344 | ||
875 | void | 345 | /** |
876 | zfcp_unit_dequeue(struct zfcp_unit *unit) | 346 | * zfcp_unit_dequeue - dequeue unit |
347 | * @unit: pointer to zfcp_unit | ||
348 | * | ||
349 | * waits until all work is done on unit and removes it then from the unit->list | ||
350 | * of the associated port. | ||
351 | */ | ||
352 | void zfcp_unit_dequeue(struct zfcp_unit *unit) | ||
877 | { | 353 | { |
878 | zfcp_unit_wait(unit); | 354 | zfcp_unit_wait(unit); |
879 | write_lock_irq(&zfcp_data.config_lock); | 355 | write_lock_irq(&zfcp_data.config_lock); |
@@ -881,68 +357,51 @@ zfcp_unit_dequeue(struct zfcp_unit *unit) | |||
881 | write_unlock_irq(&zfcp_data.config_lock); | 357 | write_unlock_irq(&zfcp_data.config_lock); |
882 | unit->port->units--; | 358 | unit->port->units--; |
883 | zfcp_port_put(unit->port); | 359 | zfcp_port_put(unit->port); |
884 | zfcp_sysfs_unit_remove_files(&unit->sysfs_device); | 360 | sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs); |
885 | device_unregister(&unit->sysfs_device); | 361 | device_unregister(&unit->sysfs_device); |
886 | } | 362 | } |
887 | 363 | ||
888 | /* | 364 | static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) |
889 | * Allocates a combined QTCB/fsf_req buffer for erp actions and fcp/SCSI | ||
890 | * commands. | ||
891 | * It also genrates fcp-nameserver request/response buffer and unsolicited | ||
892 | * status read fsf_req buffers. | ||
893 | * | ||
894 | * locks: must only be called with zfcp_data.config_sema taken | ||
895 | */ | ||
896 | static int | ||
897 | zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) | ||
898 | { | 365 | { |
366 | /* must only be called with zfcp_data.config_sema taken */ | ||
899 | adapter->pool.fsf_req_erp = | 367 | adapter->pool.fsf_req_erp = |
900 | mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_ERP_NR, | 368 | mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); |
901 | zfcp_data.fsf_req_qtcb_cache); | ||
902 | if (!adapter->pool.fsf_req_erp) | 369 | if (!adapter->pool.fsf_req_erp) |
903 | return -ENOMEM; | 370 | return -ENOMEM; |
904 | 371 | ||
905 | adapter->pool.fsf_req_scsi = | 372 | adapter->pool.fsf_req_scsi = |
906 | mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_SCSI_NR, | 373 | mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); |
907 | zfcp_data.fsf_req_qtcb_cache); | ||
908 | if (!adapter->pool.fsf_req_scsi) | 374 | if (!adapter->pool.fsf_req_scsi) |
909 | return -ENOMEM; | 375 | return -ENOMEM; |
910 | 376 | ||
911 | adapter->pool.fsf_req_abort = | 377 | adapter->pool.fsf_req_abort = |
912 | mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_ABORT_NR, | 378 | mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); |
913 | zfcp_data.fsf_req_qtcb_cache); | ||
914 | if (!adapter->pool.fsf_req_abort) | 379 | if (!adapter->pool.fsf_req_abort) |
915 | return -ENOMEM; | 380 | return -ENOMEM; |
916 | 381 | ||
917 | adapter->pool.fsf_req_status_read = | 382 | adapter->pool.fsf_req_status_read = |
918 | mempool_create_kmalloc_pool(ZFCP_POOL_STATUS_READ_NR, | 383 | mempool_create_kmalloc_pool(FSF_STATUS_READS_RECOM, |
919 | sizeof(struct zfcp_fsf_req)); | 384 | sizeof(struct zfcp_fsf_req)); |
920 | if (!adapter->pool.fsf_req_status_read) | 385 | if (!adapter->pool.fsf_req_status_read) |
921 | return -ENOMEM; | 386 | return -ENOMEM; |
922 | 387 | ||
923 | adapter->pool.data_status_read = | 388 | adapter->pool.data_status_read = |
924 | mempool_create_slab_pool(ZFCP_POOL_STATUS_READ_NR, | 389 | mempool_create_slab_pool(FSF_STATUS_READS_RECOM, |
925 | zfcp_data.sr_buffer_cache); | 390 | zfcp_data.sr_buffer_cache); |
926 | if (!adapter->pool.data_status_read) | 391 | if (!adapter->pool.data_status_read) |
927 | return -ENOMEM; | 392 | return -ENOMEM; |
928 | 393 | ||
929 | adapter->pool.data_gid_pn = | 394 | adapter->pool.data_gid_pn = |
930 | mempool_create_slab_pool(ZFCP_POOL_DATA_GID_PN_NR, | 395 | mempool_create_slab_pool(1, zfcp_data.gid_pn_cache); |
931 | zfcp_data.gid_pn_cache); | ||
932 | if (!adapter->pool.data_gid_pn) | 396 | if (!adapter->pool.data_gid_pn) |
933 | return -ENOMEM; | 397 | return -ENOMEM; |
934 | 398 | ||
935 | return 0; | 399 | return 0; |
936 | } | 400 | } |
937 | 401 | ||
938 | /** | 402 | static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) |
939 | * zfcp_free_low_mem_buffers - free memory pools of an adapter | ||
940 | * @adapter: pointer to zfcp_adapter for which memory pools should be freed | ||
941 | * locking: zfcp_data.config_sema must be held | ||
942 | */ | ||
943 | static void | ||
944 | zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) | ||
945 | { | 403 | { |
404 | /* zfcp_data.config_sema must be held */ | ||
946 | if (adapter->pool.fsf_req_erp) | 405 | if (adapter->pool.fsf_req_erp) |
947 | mempool_destroy(adapter->pool.fsf_req_erp); | 406 | mempool_destroy(adapter->pool.fsf_req_erp); |
948 | if (adapter->pool.fsf_req_scsi) | 407 | if (adapter->pool.fsf_req_scsi) |
@@ -962,20 +421,61 @@ static void zfcp_dummy_release(struct device *dev) | |||
962 | return; | 421 | return; |
963 | } | 422 | } |
964 | 423 | ||
965 | /* | 424 | /** |
425 | * zfcp_status_read_refill - refill the long running status_read_requests | ||
426 | * @adapter: ptr to struct zfcp_adapter for which the buffers should be refilled | ||
427 | * | ||
428 | * Returns: 0 on success, 1 otherwise | ||
429 | * | ||
430 | * if there are 16 or more status_read requests missing an adapter_reopen | ||
431 | * is triggered | ||
432 | */ | ||
433 | int zfcp_status_read_refill(struct zfcp_adapter *adapter) | ||
434 | { | ||
435 | while (atomic_read(&adapter->stat_miss) > 0) | ||
436 | if (zfcp_fsf_status_read(adapter)) { | ||
437 | if (atomic_read(&adapter->stat_miss) >= 16) { | ||
438 | zfcp_erp_adapter_reopen(adapter, 0, 103, NULL); | ||
439 | return 1; | ||
440 | } | ||
441 | break; | ||
442 | } else | ||
443 | atomic_dec(&adapter->stat_miss); | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static void _zfcp_status_read_scheduler(struct work_struct *work) | ||
448 | { | ||
449 | zfcp_status_read_refill(container_of(work, struct zfcp_adapter, | ||
450 | stat_work)); | ||
451 | } | ||
452 | |||
453 | static int zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) | ||
454 | { | ||
455 | struct zfcp_port *port; | ||
456 | |||
457 | port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, | ||
458 | ZFCP_DID_DIRECTORY_SERVICE); | ||
459 | if (IS_ERR(port)) | ||
460 | return PTR_ERR(port); | ||
461 | zfcp_port_put(port); | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | /** | ||
467 | * zfcp_adapter_enqueue - enqueue a new adapter to the list | ||
468 | * @ccw_device: pointer to the struct cc_device | ||
469 | * | ||
470 | * Returns: 0 if a new adapter was successfully enqueued | ||
471 | * -ENOMEM if alloc failed | ||
966 | * Enqueues an adapter at the end of the adapter list in the driver data. | 472 | * Enqueues an adapter at the end of the adapter list in the driver data. |
967 | * All adapter internal structures are set up. | 473 | * All adapter internal structures are set up. |
968 | * Proc-fs entries are also created. | 474 | * Proc-fs entries are also created. |
969 | * | ||
970 | * returns: 0 if a new adapter was successfully enqueued | ||
971 | * ZFCP_KNOWN if an adapter with this devno was already present | ||
972 | * -ENOMEM if alloc failed | ||
973 | * locks: config_sema must be held to serialise changes to the adapter list | 475 | * locks: config_sema must be held to serialise changes to the adapter list |
974 | */ | 476 | */ |
975 | struct zfcp_adapter * | 477 | int zfcp_adapter_enqueue(struct ccw_device *ccw_device) |
976 | zfcp_adapter_enqueue(struct ccw_device *ccw_device) | ||
977 | { | 478 | { |
978 | int retval = 0; | ||
979 | struct zfcp_adapter *adapter; | 479 | struct zfcp_adapter *adapter; |
980 | 480 | ||
981 | /* | 481 | /* |
@@ -983,85 +483,58 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
983 | * are protected by the config_sema, which must be held to get here | 483 | * are protected by the config_sema, which must be held to get here |
984 | */ | 484 | */ |
985 | 485 | ||
986 | /* try to allocate new adapter data structure (zeroed) */ | 486 | adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); |
987 | adapter = kzalloc(sizeof (struct zfcp_adapter), GFP_KERNEL); | 487 | if (!adapter) |
988 | if (!adapter) { | 488 | return -ENOMEM; |
989 | ZFCP_LOG_INFO("error: allocation of base adapter " | ||
990 | "structure failed\n"); | ||
991 | goto out; | ||
992 | } | ||
993 | 489 | ||
994 | ccw_device->handler = NULL; | 490 | ccw_device->handler = NULL; |
995 | |||
996 | /* save ccw_device pointer */ | ||
997 | adapter->ccw_device = ccw_device; | 491 | adapter->ccw_device = ccw_device; |
492 | atomic_set(&adapter->refcount, 0); | ||
998 | 493 | ||
999 | retval = zfcp_qdio_allocate_queues(adapter); | 494 | if (zfcp_qdio_allocate(adapter)) |
1000 | if (retval) | ||
1001 | goto queues_alloc_failed; | ||
1002 | |||
1003 | retval = zfcp_qdio_allocate(adapter); | ||
1004 | if (retval) | ||
1005 | goto qdio_allocate_failed; | 495 | goto qdio_allocate_failed; |
1006 | 496 | ||
1007 | retval = zfcp_allocate_low_mem_buffers(adapter); | 497 | if (zfcp_allocate_low_mem_buffers(adapter)) |
1008 | if (retval) { | ||
1009 | ZFCP_LOG_INFO("error: pool allocation failed\n"); | ||
1010 | goto failed_low_mem_buffers; | 498 | goto failed_low_mem_buffers; |
1011 | } | ||
1012 | 499 | ||
1013 | /* initialise reference count stuff */ | 500 | if (zfcp_reqlist_alloc(adapter)) |
1014 | atomic_set(&adapter->refcount, 0); | 501 | goto failed_low_mem_buffers; |
502 | |||
503 | if (zfcp_adapter_debug_register(adapter)) | ||
504 | goto debug_register_failed; | ||
505 | |||
1015 | init_waitqueue_head(&adapter->remove_wq); | 506 | init_waitqueue_head(&adapter->remove_wq); |
507 | init_waitqueue_head(&adapter->erp_thread_wqh); | ||
508 | init_waitqueue_head(&adapter->erp_done_wqh); | ||
1016 | 509 | ||
1017 | /* initialise list of ports */ | ||
1018 | INIT_LIST_HEAD(&adapter->port_list_head); | 510 | INIT_LIST_HEAD(&adapter->port_list_head); |
1019 | |||
1020 | /* initialise list of ports to be removed */ | ||
1021 | INIT_LIST_HEAD(&adapter->port_remove_lh); | 511 | INIT_LIST_HEAD(&adapter->port_remove_lh); |
512 | INIT_LIST_HEAD(&adapter->erp_ready_head); | ||
513 | INIT_LIST_HEAD(&adapter->erp_running_head); | ||
1022 | 514 | ||
1023 | /* initialize list of fsf requests */ | ||
1024 | spin_lock_init(&adapter->req_list_lock); | 515 | spin_lock_init(&adapter->req_list_lock); |
1025 | retval = zfcp_reqlist_alloc(adapter); | ||
1026 | if (retval) { | ||
1027 | ZFCP_LOG_INFO("request list initialization failed\n"); | ||
1028 | goto failed_low_mem_buffers; | ||
1029 | } | ||
1030 | |||
1031 | /* initialize debug locks */ | ||
1032 | 516 | ||
1033 | spin_lock_init(&adapter->hba_dbf_lock); | 517 | spin_lock_init(&adapter->hba_dbf_lock); |
1034 | spin_lock_init(&adapter->san_dbf_lock); | 518 | spin_lock_init(&adapter->san_dbf_lock); |
1035 | spin_lock_init(&adapter->scsi_dbf_lock); | 519 | spin_lock_init(&adapter->scsi_dbf_lock); |
1036 | spin_lock_init(&adapter->rec_dbf_lock); | 520 | spin_lock_init(&adapter->rec_dbf_lock); |
1037 | 521 | spin_lock_init(&adapter->req_q.lock); | |
1038 | retval = zfcp_adapter_debug_register(adapter); | ||
1039 | if (retval) | ||
1040 | goto debug_register_failed; | ||
1041 | |||
1042 | /* initialize error recovery stuff */ | ||
1043 | 522 | ||
1044 | rwlock_init(&adapter->erp_lock); | 523 | rwlock_init(&adapter->erp_lock); |
1045 | sema_init(&adapter->erp_ready_sem, 0); | ||
1046 | INIT_LIST_HEAD(&adapter->erp_ready_head); | ||
1047 | INIT_LIST_HEAD(&adapter->erp_running_head); | ||
1048 | |||
1049 | /* initialize abort lock */ | ||
1050 | rwlock_init(&adapter->abort_lock); | 524 | rwlock_init(&adapter->abort_lock); |
1051 | 525 | ||
1052 | /* initialise some erp stuff */ | 526 | sema_init(&adapter->erp_ready_sem, 0); |
1053 | init_waitqueue_head(&adapter->erp_thread_wqh); | ||
1054 | init_waitqueue_head(&adapter->erp_done_wqh); | ||
1055 | 527 | ||
1056 | /* initialize lock of associated request queue */ | 528 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); |
1057 | rwlock_init(&adapter->request_queue.queue_lock); | 529 | INIT_WORK(&adapter->scan_work, _zfcp_scan_ports_later); |
1058 | 530 | ||
1059 | /* mark adapter unusable as long as sysfs registration is not complete */ | 531 | /* mark adapter unusable as long as sysfs registration is not complete */ |
1060 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | 532 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); |
1061 | 533 | ||
1062 | dev_set_drvdata(&ccw_device->dev, adapter); | 534 | dev_set_drvdata(&ccw_device->dev, adapter); |
1063 | 535 | ||
1064 | if (zfcp_sysfs_adapter_create_files(&ccw_device->dev)) | 536 | if (sysfs_create_group(&ccw_device->dev.kobj, |
537 | &zfcp_sysfs_adapter_attrs)) | ||
1065 | goto sysfs_failed; | 538 | goto sysfs_failed; |
1066 | 539 | ||
1067 | adapter->generic_services.parent = &adapter->ccw_device->dev; | 540 | adapter->generic_services.parent = &adapter->ccw_device->dev; |
@@ -1072,7 +545,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
1072 | if (device_register(&adapter->generic_services)) | 545 | if (device_register(&adapter->generic_services)) |
1073 | goto generic_services_failed; | 546 | goto generic_services_failed; |
1074 | 547 | ||
1075 | /* put allocated adapter at list tail */ | ||
1076 | write_lock_irq(&zfcp_data.config_lock); | 548 | write_lock_irq(&zfcp_data.config_lock); |
1077 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | 549 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); |
1078 | list_add_tail(&adapter->list, &zfcp_data.adapter_list_head); | 550 | list_add_tail(&adapter->list, &zfcp_data.adapter_list_head); |
@@ -1080,57 +552,49 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
1080 | 552 | ||
1081 | zfcp_data.adapters++; | 553 | zfcp_data.adapters++; |
1082 | 554 | ||
1083 | goto out; | 555 | zfcp_nameserver_enqueue(adapter); |
556 | |||
557 | return 0; | ||
1084 | 558 | ||
1085 | generic_services_failed: | 559 | generic_services_failed: |
1086 | zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); | 560 | sysfs_remove_group(&ccw_device->dev.kobj, |
1087 | sysfs_failed: | 561 | &zfcp_sysfs_adapter_attrs); |
562 | sysfs_failed: | ||
1088 | zfcp_adapter_debug_unregister(adapter); | 563 | zfcp_adapter_debug_unregister(adapter); |
1089 | debug_register_failed: | 564 | debug_register_failed: |
1090 | dev_set_drvdata(&ccw_device->dev, NULL); | 565 | dev_set_drvdata(&ccw_device->dev, NULL); |
1091 | zfcp_reqlist_free(adapter); | 566 | kfree(adapter->req_list); |
1092 | failed_low_mem_buffers: | 567 | failed_low_mem_buffers: |
1093 | zfcp_free_low_mem_buffers(adapter); | 568 | zfcp_free_low_mem_buffers(adapter); |
1094 | if (qdio_free(ccw_device) != 0) | 569 | qdio_allocate_failed: |
1095 | ZFCP_LOG_NORMAL("bug: qdio_free for adapter %s failed\n", | 570 | zfcp_qdio_free(adapter); |
1096 | zfcp_get_busid_by_adapter(adapter)); | ||
1097 | qdio_allocate_failed: | ||
1098 | zfcp_qdio_free_queues(adapter); | ||
1099 | queues_alloc_failed: | ||
1100 | kfree(adapter); | 571 | kfree(adapter); |
1101 | adapter = NULL; | 572 | return -ENOMEM; |
1102 | out: | ||
1103 | return adapter; | ||
1104 | } | 573 | } |
1105 | 574 | ||
1106 | /* | 575 | /** |
1107 | * returns: 0 - struct zfcp_adapter data structure successfully removed | 576 | * zfcp_adapter_dequeue - remove the adapter from the resource list |
1108 | * !0 - struct zfcp_adapter data structure could not be removed | 577 | * @adapter: pointer to struct zfcp_adapter which should be removed |
1109 | * (e.g. still used) | ||
1110 | * locks: adapter list write lock is assumed to be held by caller | 578 | * locks: adapter list write lock is assumed to be held by caller |
1111 | */ | 579 | */ |
1112 | void | 580 | void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) |
1113 | zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | ||
1114 | { | 581 | { |
1115 | int retval = 0; | 582 | int retval = 0; |
1116 | unsigned long flags; | 583 | unsigned long flags; |
1117 | 584 | ||
585 | cancel_work_sync(&adapter->scan_work); | ||
586 | cancel_work_sync(&adapter->stat_work); | ||
1118 | zfcp_adapter_scsi_unregister(adapter); | 587 | zfcp_adapter_scsi_unregister(adapter); |
1119 | device_unregister(&adapter->generic_services); | 588 | device_unregister(&adapter->generic_services); |
1120 | zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); | 589 | sysfs_remove_group(&adapter->ccw_device->dev.kobj, |
590 | &zfcp_sysfs_adapter_attrs); | ||
1121 | dev_set_drvdata(&adapter->ccw_device->dev, NULL); | 591 | dev_set_drvdata(&adapter->ccw_device->dev, NULL); |
1122 | /* sanity check: no pending FSF requests */ | 592 | /* sanity check: no pending FSF requests */ |
1123 | spin_lock_irqsave(&adapter->req_list_lock, flags); | 593 | spin_lock_irqsave(&adapter->req_list_lock, flags); |
1124 | retval = zfcp_reqlist_isempty(adapter); | 594 | retval = zfcp_reqlist_isempty(adapter); |
1125 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); | 595 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); |
1126 | if (!retval) { | 596 | if (!retval) |
1127 | ZFCP_LOG_NORMAL("bug: adapter %s (%p) still in use, " | 597 | return; |
1128 | "%i requests outstanding\n", | ||
1129 | zfcp_get_busid_by_adapter(adapter), adapter, | ||
1130 | atomic_read(&adapter->reqs_active)); | ||
1131 | retval = -EBUSY; | ||
1132 | goto out; | ||
1133 | } | ||
1134 | 598 | ||
1135 | zfcp_adapter_debug_unregister(adapter); | 599 | zfcp_adapter_debug_unregister(adapter); |
1136 | 600 | ||
@@ -1142,26 +606,18 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | |||
1142 | /* decrease number of adapters in list */ | 606 | /* decrease number of adapters in list */ |
1143 | zfcp_data.adapters--; | 607 | zfcp_data.adapters--; |
1144 | 608 | ||
1145 | ZFCP_LOG_TRACE("adapter %s (%p) removed from list, " | 609 | zfcp_qdio_free(adapter); |
1146 | "%i adapters still in list\n", | ||
1147 | zfcp_get_busid_by_adapter(adapter), | ||
1148 | adapter, zfcp_data.adapters); | ||
1149 | |||
1150 | retval = qdio_free(adapter->ccw_device); | ||
1151 | if (retval) | ||
1152 | ZFCP_LOG_NORMAL("bug: qdio_free for adapter %s failed\n", | ||
1153 | zfcp_get_busid_by_adapter(adapter)); | ||
1154 | 610 | ||
1155 | zfcp_free_low_mem_buffers(adapter); | 611 | zfcp_free_low_mem_buffers(adapter); |
1156 | /* free memory of adapter data structure and queues */ | 612 | kfree(adapter->req_list); |
1157 | zfcp_qdio_free_queues(adapter); | ||
1158 | zfcp_reqlist_free(adapter); | ||
1159 | kfree(adapter->fc_stats); | 613 | kfree(adapter->fc_stats); |
1160 | kfree(adapter->stats_reset_data); | 614 | kfree(adapter->stats_reset_data); |
1161 | ZFCP_LOG_TRACE("freeing adapter structure\n"); | ||
1162 | kfree(adapter); | 615 | kfree(adapter); |
1163 | out: | 616 | } |
1164 | return; | 617 | |
618 | static void zfcp_sysfs_port_release(struct device *dev) | ||
619 | { | ||
620 | kfree(container_of(dev, struct zfcp_port, sysfs_device)); | ||
1165 | } | 621 | } |
1166 | 622 | ||
1167 | /** | 623 | /** |
@@ -1170,98 +626,90 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | |||
1170 | * @wwpn: WWPN of the remote port to be enqueued | 626 | * @wwpn: WWPN of the remote port to be enqueued |
1171 | * @status: initial status for the port | 627 | * @status: initial status for the port |
1172 | * @d_id: destination id of the remote port to be enqueued | 628 | * @d_id: destination id of the remote port to be enqueued |
1173 | * Return: pointer to enqueued port on success, NULL on error | 629 | * Returns: pointer to enqueued port on success, ERR_PTR on error |
1174 | * Locks: config_sema must be held to serialize changes to the port list | 630 | * Locks: config_sema must be held to serialize changes to the port list |
1175 | * | 631 | * |
1176 | * All port internal structures are set up and the sysfs entry is generated. | 632 | * All port internal structures are set up and the sysfs entry is generated. |
1177 | * d_id is used to enqueue ports with a well known address like the Directory | 633 | * d_id is used to enqueue ports with a well known address like the Directory |
1178 | * Service for nameserver lookup. | 634 | * Service for nameserver lookup. |
1179 | */ | 635 | */ |
1180 | struct zfcp_port * | 636 | struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, |
1181 | zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, | 637 | u32 status, u32 d_id) |
1182 | u32 d_id) | ||
1183 | { | 638 | { |
1184 | struct zfcp_port *port; | 639 | struct zfcp_port *port; |
1185 | int check_wwpn; | 640 | int retval; |
1186 | 641 | char *bus_id; | |
1187 | check_wwpn = !(status & ZFCP_STATUS_PORT_NO_WWPN); | ||
1188 | /* | ||
1189 | * check that there is no port with this WWPN already in list | ||
1190 | */ | ||
1191 | if (check_wwpn) { | ||
1192 | read_lock_irq(&zfcp_data.config_lock); | ||
1193 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | ||
1194 | read_unlock_irq(&zfcp_data.config_lock); | ||
1195 | if (port) | ||
1196 | return NULL; | ||
1197 | } | ||
1198 | 642 | ||
1199 | port = kzalloc(sizeof (struct zfcp_port), GFP_KERNEL); | 643 | port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); |
1200 | if (!port) | 644 | if (!port) |
1201 | return NULL; | 645 | return ERR_PTR(-ENOMEM); |
1202 | 646 | ||
1203 | /* initialise reference count stuff */ | ||
1204 | atomic_set(&port->refcount, 0); | ||
1205 | init_waitqueue_head(&port->remove_wq); | 647 | init_waitqueue_head(&port->remove_wq); |
1206 | 648 | ||
1207 | INIT_LIST_HEAD(&port->unit_list_head); | 649 | INIT_LIST_HEAD(&port->unit_list_head); |
1208 | INIT_LIST_HEAD(&port->unit_remove_lh); | 650 | INIT_LIST_HEAD(&port->unit_remove_lh); |
1209 | 651 | ||
1210 | port->adapter = adapter; | 652 | port->adapter = adapter; |
653 | port->d_id = d_id; | ||
654 | port->wwpn = wwpn; | ||
1211 | 655 | ||
1212 | if (check_wwpn) | 656 | /* mark port unusable as long as sysfs registration is not complete */ |
1213 | port->wwpn = wwpn; | 657 | atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); |
1214 | 658 | atomic_set(&port->refcount, 0); | |
1215 | atomic_set_mask(status, &port->status); | ||
1216 | 659 | ||
1217 | /* setup for sysfs registration */ | ||
1218 | if (status & ZFCP_STATUS_PORT_WKA) { | 660 | if (status & ZFCP_STATUS_PORT_WKA) { |
1219 | switch (d_id) { | 661 | switch (d_id) { |
1220 | case ZFCP_DID_DIRECTORY_SERVICE: | 662 | case ZFCP_DID_DIRECTORY_SERVICE: |
1221 | snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, | 663 | bus_id = "directory"; |
1222 | "directory"); | ||
1223 | break; | 664 | break; |
1224 | case ZFCP_DID_MANAGEMENT_SERVICE: | 665 | case ZFCP_DID_MANAGEMENT_SERVICE: |
1225 | snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, | 666 | bus_id = "management"; |
1226 | "management"); | ||
1227 | break; | 667 | break; |
1228 | case ZFCP_DID_KEY_DISTRIBUTION_SERVICE: | 668 | case ZFCP_DID_KEY_DISTRIBUTION_SERVICE: |
1229 | snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, | 669 | bus_id = "key_distribution"; |
1230 | "key_distribution"); | ||
1231 | break; | 670 | break; |
1232 | case ZFCP_DID_ALIAS_SERVICE: | 671 | case ZFCP_DID_ALIAS_SERVICE: |
1233 | snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, | 672 | bus_id = "alias"; |
1234 | "alias"); | ||
1235 | break; | 673 | break; |
1236 | case ZFCP_DID_TIME_SERVICE: | 674 | case ZFCP_DID_TIME_SERVICE: |
1237 | snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, | 675 | bus_id = "time"; |
1238 | "time"); | ||
1239 | break; | 676 | break; |
1240 | default: | 677 | default: |
1241 | kfree(port); | 678 | kfree(port); |
1242 | return NULL; | 679 | return ERR_PTR(-EINVAL); |
1243 | } | 680 | } |
1244 | port->d_id = d_id; | 681 | snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "%s", bus_id); |
1245 | port->sysfs_device.parent = &adapter->generic_services; | 682 | port->sysfs_device.parent = &adapter->generic_services; |
1246 | } else { | 683 | } else { |
1247 | snprintf(port->sysfs_device.bus_id, | 684 | snprintf(port->sysfs_device.bus_id, |
1248 | BUS_ID_SIZE, "0x%016llx", wwpn); | 685 | BUS_ID_SIZE, "0x%016llx", wwpn); |
1249 | port->sysfs_device.parent = &adapter->ccw_device->dev; | 686 | port->sysfs_device.parent = &adapter->ccw_device->dev; |
1250 | } | 687 | } |
688 | |||
1251 | port->sysfs_device.release = zfcp_sysfs_port_release; | 689 | port->sysfs_device.release = zfcp_sysfs_port_release; |
1252 | dev_set_drvdata(&port->sysfs_device, port); | 690 | dev_set_drvdata(&port->sysfs_device, port); |
1253 | 691 | ||
1254 | /* mark port unusable as long as sysfs registration is not complete */ | 692 | read_lock_irq(&zfcp_data.config_lock); |
1255 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | 693 | if (!(status & ZFCP_STATUS_PORT_NO_WWPN)) |
694 | if (zfcp_get_port_by_wwpn(adapter, wwpn)) { | ||
695 | read_unlock_irq(&zfcp_data.config_lock); | ||
696 | goto err_out_free; | ||
697 | } | ||
698 | read_unlock_irq(&zfcp_data.config_lock); | ||
1256 | 699 | ||
1257 | if (device_register(&port->sysfs_device)) { | 700 | if (device_register(&port->sysfs_device)) |
1258 | kfree(port); | 701 | goto err_out_free; |
1259 | return NULL; | 702 | |
1260 | } | 703 | if (status & ZFCP_STATUS_PORT_WKA) |
704 | retval = sysfs_create_group(&port->sysfs_device.kobj, | ||
705 | &zfcp_sysfs_ns_port_attrs); | ||
706 | else | ||
707 | retval = sysfs_create_group(&port->sysfs_device.kobj, | ||
708 | &zfcp_sysfs_port_attrs); | ||
1261 | 709 | ||
1262 | if (zfcp_sysfs_port_create_files(&port->sysfs_device, status)) { | 710 | if (retval) { |
1263 | device_unregister(&port->sysfs_device); | 711 | device_unregister(&port->sysfs_device); |
1264 | return NULL; | 712 | goto err_out; |
1265 | } | 713 | } |
1266 | 714 | ||
1267 | zfcp_port_get(port); | 715 | zfcp_port_get(port); |
@@ -1274,15 +722,23 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, | |||
1274 | if (!adapter->nameserver_port) | 722 | if (!adapter->nameserver_port) |
1275 | adapter->nameserver_port = port; | 723 | adapter->nameserver_port = port; |
1276 | adapter->ports++; | 724 | adapter->ports++; |
725 | |||
1277 | write_unlock_irq(&zfcp_data.config_lock); | 726 | write_unlock_irq(&zfcp_data.config_lock); |
1278 | 727 | ||
1279 | zfcp_adapter_get(adapter); | 728 | zfcp_adapter_get(adapter); |
1280 | |||
1281 | return port; | 729 | return port; |
730 | |||
731 | err_out_free: | ||
732 | kfree(port); | ||
733 | err_out: | ||
734 | return ERR_PTR(-EINVAL); | ||
1282 | } | 735 | } |
1283 | 736 | ||
1284 | void | 737 | /** |
1285 | zfcp_port_dequeue(struct zfcp_port *port) | 738 | * zfcp_port_dequeue - dequeues a port from the port list of the adapter |
739 | * @port: pointer to struct zfcp_port which should be removed | ||
740 | */ | ||
741 | void zfcp_port_dequeue(struct zfcp_port *port) | ||
1286 | { | 742 | { |
1287 | zfcp_port_wait(port); | 743 | zfcp_port_wait(port); |
1288 | write_lock_irq(&zfcp_data.config_lock); | 744 | write_lock_irq(&zfcp_data.config_lock); |
@@ -1293,546 +749,53 @@ zfcp_port_dequeue(struct zfcp_port *port) | |||
1293 | fc_remote_port_delete(port->rport); | 749 | fc_remote_port_delete(port->rport); |
1294 | port->rport = NULL; | 750 | port->rport = NULL; |
1295 | zfcp_adapter_put(port->adapter); | 751 | zfcp_adapter_put(port->adapter); |
1296 | zfcp_sysfs_port_remove_files(&port->sysfs_device, | 752 | if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA) |
1297 | atomic_read(&port->status)); | 753 | sysfs_remove_group(&port->sysfs_device.kobj, |
1298 | device_unregister(&port->sysfs_device); | 754 | &zfcp_sysfs_ns_port_attrs); |
1299 | } | ||
1300 | |||
1301 | /* Enqueues a nameserver port */ | ||
1302 | int | ||
1303 | zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) | ||
1304 | { | ||
1305 | struct zfcp_port *port; | ||
1306 | |||
1307 | port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, | ||
1308 | ZFCP_DID_DIRECTORY_SERVICE); | ||
1309 | if (!port) { | ||
1310 | ZFCP_LOG_INFO("error: enqueue of nameserver port for " | ||
1311 | "adapter %s failed\n", | ||
1312 | zfcp_get_busid_by_adapter(adapter)); | ||
1313 | return -ENXIO; | ||
1314 | } | ||
1315 | zfcp_port_put(port); | ||
1316 | |||
1317 | return 0; | ||
1318 | } | ||
1319 | |||
1320 | #undef ZFCP_LOG_AREA | ||
1321 | |||
1322 | /****************************************************************/ | ||
1323 | /******* Fibre Channel Standard related Functions **************/ | ||
1324 | /****************************************************************/ | ||
1325 | |||
1326 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_FC | ||
1327 | |||
1328 | static void zfcp_fsf_incoming_els_rscn(struct zfcp_fsf_req *fsf_req) | ||
1329 | { | ||
1330 | struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; | ||
1331 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
1332 | struct fcp_rscn_head *fcp_rscn_head; | ||
1333 | struct fcp_rscn_element *fcp_rscn_element; | ||
1334 | struct zfcp_port *port; | ||
1335 | u16 i; | ||
1336 | u16 no_entries; | ||
1337 | u32 range_mask; | ||
1338 | unsigned long flags; | ||
1339 | |||
1340 | fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload; | ||
1341 | fcp_rscn_element = (struct fcp_rscn_element *) status_buffer->payload; | ||
1342 | |||
1343 | /* see FC-FS */ | ||
1344 | no_entries = (fcp_rscn_head->payload_len / 4); | ||
1345 | |||
1346 | for (i = 1; i < no_entries; i++) { | ||
1347 | /* skip head and start with 1st element */ | ||
1348 | fcp_rscn_element++; | ||
1349 | switch (fcp_rscn_element->addr_format) { | ||
1350 | case ZFCP_PORT_ADDRESS: | ||
1351 | range_mask = ZFCP_PORTS_RANGE_PORT; | ||
1352 | break; | ||
1353 | case ZFCP_AREA_ADDRESS: | ||
1354 | range_mask = ZFCP_PORTS_RANGE_AREA; | ||
1355 | break; | ||
1356 | case ZFCP_DOMAIN_ADDRESS: | ||
1357 | range_mask = ZFCP_PORTS_RANGE_DOMAIN; | ||
1358 | break; | ||
1359 | case ZFCP_FABRIC_ADDRESS: | ||
1360 | range_mask = ZFCP_PORTS_RANGE_FABRIC; | ||
1361 | break; | ||
1362 | default: | ||
1363 | ZFCP_LOG_INFO("incoming RSCN with unknown " | ||
1364 | "address format\n"); | ||
1365 | continue; | ||
1366 | } | ||
1367 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1368 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
1369 | if (atomic_test_mask | ||
1370 | (ZFCP_STATUS_PORT_WKA, &port->status)) | ||
1371 | continue; | ||
1372 | /* Do we know this port? If not skip it. */ | ||
1373 | if (!atomic_test_mask | ||
1374 | (ZFCP_STATUS_PORT_DID_DID, &port->status)) { | ||
1375 | ZFCP_LOG_INFO("incoming RSCN, trying to open " | ||
1376 | "port 0x%016Lx\n", port->wwpn); | ||
1377 | zfcp_erp_port_reopen(port, | ||
1378 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
1379 | 82, fsf_req); | ||
1380 | continue; | ||
1381 | } | ||
1382 | |||
1383 | /* | ||
1384 | * FIXME: race: d_id might being invalidated | ||
1385 | * (...DID_DID reset) | ||
1386 | */ | ||
1387 | if ((port->d_id & range_mask) | ||
1388 | == (fcp_rscn_element->nport_did & range_mask)) { | ||
1389 | ZFCP_LOG_TRACE("reopen did 0x%08x\n", | ||
1390 | fcp_rscn_element->nport_did); | ||
1391 | /* | ||
1392 | * Unfortunately, an RSCN does not specify the | ||
1393 | * type of change a target underwent. We assume | ||
1394 | * that it makes sense to reopen the link. | ||
1395 | * FIXME: Shall we try to find out more about | ||
1396 | * the target and link state before closing it? | ||
1397 | * How to accomplish this? (nameserver?) | ||
1398 | * Where would such code be put in? | ||
1399 | * (inside or outside erp) | ||
1400 | */ | ||
1401 | ZFCP_LOG_INFO("incoming RSCN, trying to open " | ||
1402 | "port 0x%016Lx\n", port->wwpn); | ||
1403 | zfcp_test_link(port); | ||
1404 | } | ||
1405 | } | ||
1406 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1407 | } | ||
1408 | } | ||
1409 | |||
1410 | static void zfcp_fsf_incoming_els_plogi(struct zfcp_fsf_req *fsf_req) | ||
1411 | { | ||
1412 | struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; | ||
1413 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
1414 | struct fsf_plogi *els_plogi; | ||
1415 | struct zfcp_port *port; | ||
1416 | unsigned long flags; | ||
1417 | |||
1418 | els_plogi = (struct fsf_plogi *) status_buffer->payload; | ||
1419 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1420 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
1421 | if (port->wwpn == (*(wwn_t *) &els_plogi->serv_param.wwpn)) | ||
1422 | break; | ||
1423 | } | ||
1424 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1425 | |||
1426 | if (!port || (port->wwpn != (*(wwn_t *) &els_plogi->serv_param.wwpn))) { | ||
1427 | ZFCP_LOG_DEBUG("ignored incoming PLOGI for nonexisting port " | ||
1428 | "with d_id 0x%06x on adapter %s\n", | ||
1429 | status_buffer->d_id, | ||
1430 | zfcp_get_busid_by_adapter(adapter)); | ||
1431 | } else { | ||
1432 | zfcp_erp_port_forced_reopen(port, 0, 83, fsf_req); | ||
1433 | } | ||
1434 | } | ||
1435 | |||
1436 | static void zfcp_fsf_incoming_els_logo(struct zfcp_fsf_req *fsf_req) | ||
1437 | { | ||
1438 | struct fsf_status_read_buffer *status_buffer = (void*)fsf_req->data; | ||
1439 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
1440 | struct fcp_logo *els_logo = (struct fcp_logo *) status_buffer->payload; | ||
1441 | struct zfcp_port *port; | ||
1442 | unsigned long flags; | ||
1443 | |||
1444 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1445 | list_for_each_entry(port, &adapter->port_list_head, list) { | ||
1446 | if (port->wwpn == els_logo->nport_wwpn) | ||
1447 | break; | ||
1448 | } | ||
1449 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1450 | |||
1451 | if (!port || (port->wwpn != els_logo->nport_wwpn)) { | ||
1452 | ZFCP_LOG_DEBUG("ignored incoming LOGO for nonexisting port " | ||
1453 | "with d_id 0x%06x on adapter %s\n", | ||
1454 | status_buffer->d_id, | ||
1455 | zfcp_get_busid_by_adapter(adapter)); | ||
1456 | } else { | ||
1457 | zfcp_erp_port_forced_reopen(port, 0, 84, fsf_req); | ||
1458 | } | ||
1459 | } | ||
1460 | |||
1461 | static void | ||
1462 | zfcp_fsf_incoming_els_unknown(struct zfcp_adapter *adapter, | ||
1463 | struct fsf_status_read_buffer *status_buffer) | ||
1464 | { | ||
1465 | ZFCP_LOG_NORMAL("warning: unknown incoming ELS 0x%08x " | ||
1466 | "for adapter %s\n", *(u32 *) (status_buffer->payload), | ||
1467 | zfcp_get_busid_by_adapter(adapter)); | ||
1468 | |||
1469 | } | ||
1470 | |||
1471 | void | ||
1472 | zfcp_fsf_incoming_els(struct zfcp_fsf_req *fsf_req) | ||
1473 | { | ||
1474 | struct fsf_status_read_buffer *status_buffer; | ||
1475 | u32 els_type; | ||
1476 | struct zfcp_adapter *adapter; | ||
1477 | |||
1478 | status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; | ||
1479 | els_type = *(u32 *) (status_buffer->payload); | ||
1480 | adapter = fsf_req->adapter; | ||
1481 | |||
1482 | zfcp_san_dbf_event_incoming_els(fsf_req); | ||
1483 | if (els_type == LS_PLOGI) | ||
1484 | zfcp_fsf_incoming_els_plogi(fsf_req); | ||
1485 | else if (els_type == LS_LOGO) | ||
1486 | zfcp_fsf_incoming_els_logo(fsf_req); | ||
1487 | else if ((els_type & 0xffff0000) == LS_RSCN) | ||
1488 | /* we are only concerned with the command, not the length */ | ||
1489 | zfcp_fsf_incoming_els_rscn(fsf_req); | ||
1490 | else | ||
1491 | zfcp_fsf_incoming_els_unknown(adapter, status_buffer); | ||
1492 | } | ||
1493 | |||
1494 | |||
1495 | /** | ||
1496 | * zfcp_gid_pn_buffers_alloc - allocate buffers for GID_PN nameserver request | ||
1497 | * @gid_pn: pointer to return pointer to struct zfcp_gid_pn_data | ||
1498 | * @pool: pointer to mempool_t if non-null memory pool is used for allocation | ||
1499 | */ | ||
1500 | static int | ||
1501 | zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool) | ||
1502 | { | ||
1503 | struct zfcp_gid_pn_data *data; | ||
1504 | |||
1505 | if (pool != NULL) { | ||
1506 | data = mempool_alloc(pool, GFP_ATOMIC); | ||
1507 | if (likely(data != NULL)) { | ||
1508 | data->ct.pool = pool; | ||
1509 | } | ||
1510 | } else { | ||
1511 | data = kmem_cache_alloc(zfcp_data.gid_pn_cache, GFP_ATOMIC); | ||
1512 | } | ||
1513 | |||
1514 | if (NULL == data) | ||
1515 | return -ENOMEM; | ||
1516 | |||
1517 | memset(data, 0, sizeof(*data)); | ||
1518 | sg_init_table(&data->req , 1); | ||
1519 | sg_init_table(&data->resp , 1); | ||
1520 | data->ct.req = &data->req; | ||
1521 | data->ct.resp = &data->resp; | ||
1522 | data->ct.req_count = data->ct.resp_count = 1; | ||
1523 | zfcp_address_to_sg(&data->ct_iu_req, &data->req, sizeof(struct ct_iu_gid_pn_req)); | ||
1524 | zfcp_address_to_sg(&data->ct_iu_resp, &data->resp, sizeof(struct ct_iu_gid_pn_resp)); | ||
1525 | |||
1526 | *gid_pn = data; | ||
1527 | return 0; | ||
1528 | } | ||
1529 | |||
1530 | /** | ||
1531 | * zfcp_gid_pn_buffers_free - free buffers for GID_PN nameserver request | ||
1532 | * @gid_pn: pointer to struct zfcp_gid_pn_data which has to be freed | ||
1533 | */ | ||
1534 | static void zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn) | ||
1535 | { | ||
1536 | if (gid_pn->ct.pool) | ||
1537 | mempool_free(gid_pn, gid_pn->ct.pool); | ||
1538 | else | 755 | else |
1539 | kmem_cache_free(zfcp_data.gid_pn_cache, gid_pn); | 756 | sysfs_remove_group(&port->sysfs_device.kobj, |
1540 | } | 757 | &zfcp_sysfs_port_attrs); |
1541 | 758 | device_unregister(&port->sysfs_device); | |
1542 | /** | ||
1543 | * zfcp_ns_gid_pn_request - initiate GID_PN nameserver request | ||
1544 | * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed | ||
1545 | */ | ||
1546 | int | ||
1547 | zfcp_ns_gid_pn_request(struct zfcp_erp_action *erp_action) | ||
1548 | { | ||
1549 | int ret; | ||
1550 | struct ct_iu_gid_pn_req *ct_iu_req; | ||
1551 | struct zfcp_gid_pn_data *gid_pn; | ||
1552 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1553 | |||
1554 | ret = zfcp_gid_pn_buffers_alloc(&gid_pn, adapter->pool.data_gid_pn); | ||
1555 | if (ret < 0) { | ||
1556 | ZFCP_LOG_INFO("error: buffer allocation for gid_pn nameserver " | ||
1557 | "request failed for adapter %s\n", | ||
1558 | zfcp_get_busid_by_adapter(adapter)); | ||
1559 | goto out; | ||
1560 | } | ||
1561 | |||
1562 | /* setup nameserver request */ | ||
1563 | ct_iu_req = zfcp_sg_to_address(gid_pn->ct.req); | ||
1564 | ct_iu_req->header.revision = ZFCP_CT_REVISION; | ||
1565 | ct_iu_req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; | ||
1566 | ct_iu_req->header.gs_subtype = ZFCP_CT_NAME_SERVER; | ||
1567 | ct_iu_req->header.options = ZFCP_CT_SYNCHRONOUS; | ||
1568 | ct_iu_req->header.cmd_rsp_code = ZFCP_CT_GID_PN; | ||
1569 | ct_iu_req->header.max_res_size = ZFCP_CT_MAX_SIZE; | ||
1570 | ct_iu_req->wwpn = erp_action->port->wwpn; | ||
1571 | |||
1572 | /* setup parameters for send generic command */ | ||
1573 | gid_pn->ct.port = adapter->nameserver_port; | ||
1574 | gid_pn->ct.handler = zfcp_ns_gid_pn_handler; | ||
1575 | gid_pn->ct.handler_data = (unsigned long) gid_pn; | ||
1576 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; | ||
1577 | gid_pn->port = erp_action->port; | ||
1578 | |||
1579 | ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, | ||
1580 | erp_action); | ||
1581 | if (ret) { | ||
1582 | ZFCP_LOG_INFO("error: initiation of gid_pn nameserver request " | ||
1583 | "failed for adapter %s\n", | ||
1584 | zfcp_get_busid_by_adapter(adapter)); | ||
1585 | |||
1586 | zfcp_gid_pn_buffers_free(gid_pn); | ||
1587 | } | ||
1588 | |||
1589 | out: | ||
1590 | return ret; | ||
1591 | } | ||
1592 | |||
1593 | /** | ||
1594 | * zfcp_ns_gid_pn_handler - handler for GID_PN nameserver request | ||
1595 | * @data: unsigned long, contains pointer to struct zfcp_gid_pn_data | ||
1596 | */ | ||
1597 | static void zfcp_ns_gid_pn_handler(unsigned long data) | ||
1598 | { | ||
1599 | struct zfcp_port *port; | ||
1600 | struct zfcp_send_ct *ct; | ||
1601 | struct ct_iu_gid_pn_req *ct_iu_req; | ||
1602 | struct ct_iu_gid_pn_resp *ct_iu_resp; | ||
1603 | struct zfcp_gid_pn_data *gid_pn; | ||
1604 | |||
1605 | |||
1606 | gid_pn = (struct zfcp_gid_pn_data *) data; | ||
1607 | port = gid_pn->port; | ||
1608 | ct = &gid_pn->ct; | ||
1609 | ct_iu_req = zfcp_sg_to_address(ct->req); | ||
1610 | ct_iu_resp = zfcp_sg_to_address(ct->resp); | ||
1611 | |||
1612 | if (ct->status != 0) | ||
1613 | goto failed; | ||
1614 | |||
1615 | if (zfcp_check_ct_response(&ct_iu_resp->header)) { | ||
1616 | /* FIXME: do we need some specific erp entry points */ | ||
1617 | atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); | ||
1618 | goto failed; | ||
1619 | } | ||
1620 | /* paranoia */ | ||
1621 | if (ct_iu_req->wwpn != port->wwpn) { | ||
1622 | ZFCP_LOG_NORMAL("bug: wwpn 0x%016Lx returned by nameserver " | ||
1623 | "lookup does not match expected wwpn 0x%016Lx " | ||
1624 | "for adapter %s\n", ct_iu_req->wwpn, port->wwpn, | ||
1625 | zfcp_get_busid_by_port(port)); | ||
1626 | goto mismatch; | ||
1627 | } | ||
1628 | |||
1629 | /* looks like a valid d_id */ | ||
1630 | port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; | ||
1631 | atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); | ||
1632 | ZFCP_LOG_DEBUG("adapter %s: wwpn=0x%016Lx ---> d_id=0x%06x\n", | ||
1633 | zfcp_get_busid_by_port(port), port->wwpn, port->d_id); | ||
1634 | goto out; | ||
1635 | |||
1636 | mismatch: | ||
1637 | ZFCP_LOG_DEBUG("CT IUs do not match:\n"); | ||
1638 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_req, | ||
1639 | sizeof(struct ct_iu_gid_pn_req)); | ||
1640 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) ct_iu_resp, | ||
1641 | sizeof(struct ct_iu_gid_pn_resp)); | ||
1642 | |||
1643 | failed: | ||
1644 | ZFCP_LOG_NORMAL("warning: failed gid_pn nameserver request for wwpn " | ||
1645 | "0x%016Lx for adapter %s\n", | ||
1646 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
1647 | out: | ||
1648 | zfcp_gid_pn_buffers_free(gid_pn); | ||
1649 | return; | ||
1650 | } | 759 | } |
1651 | 760 | ||
1652 | /* reject CT_IU reason codes acc. to FC-GS-4 */ | ||
1653 | static const struct zfcp_rc_entry zfcp_ct_rc[] = { | ||
1654 | {0x01, "invalid command code"}, | ||
1655 | {0x02, "invalid version level"}, | ||
1656 | {0x03, "logical error"}, | ||
1657 | {0x04, "invalid CT_IU size"}, | ||
1658 | {0x05, "logical busy"}, | ||
1659 | {0x07, "protocol error"}, | ||
1660 | {0x09, "unable to perform command request"}, | ||
1661 | {0x0b, "command not supported"}, | ||
1662 | {0x0d, "server not available"}, | ||
1663 | {0x0e, "session could not be established"}, | ||
1664 | {0xff, "vendor specific error"}, | ||
1665 | {0, NULL}, | ||
1666 | }; | ||
1667 | |||
1668 | /* LS_RJT reason codes acc. to FC-FS */ | ||
1669 | static const struct zfcp_rc_entry zfcp_ls_rjt_rc[] = { | ||
1670 | {0x01, "invalid LS_Command code"}, | ||
1671 | {0x03, "logical error"}, | ||
1672 | {0x05, "logical busy"}, | ||
1673 | {0x07, "protocol error"}, | ||
1674 | {0x09, "unable to perform command request"}, | ||
1675 | {0x0b, "command not supported"}, | ||
1676 | {0x0e, "command already in progress"}, | ||
1677 | {0xff, "vendor specific error"}, | ||
1678 | {0, NULL}, | ||
1679 | }; | ||
1680 | |||
1681 | /* reject reason codes according to FC-PH/FC-FS */ | ||
1682 | static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = { | ||
1683 | {0x01, "invalid D_ID"}, | ||
1684 | {0x02, "invalid S_ID"}, | ||
1685 | {0x03, "Nx_Port not available, temporary"}, | ||
1686 | {0x04, "Nx_Port not available, permament"}, | ||
1687 | {0x05, "class not supported"}, | ||
1688 | {0x06, "delimiter usage error"}, | ||
1689 | {0x07, "TYPE not supported"}, | ||
1690 | {0x08, "invalid Link_Control"}, | ||
1691 | {0x09, "invalid R_CTL field"}, | ||
1692 | {0x0a, "invalid F_CTL field"}, | ||
1693 | {0x0b, "invalid OX_ID"}, | ||
1694 | {0x0c, "invalid RX_ID"}, | ||
1695 | {0x0d, "invalid SEQ_ID"}, | ||
1696 | {0x0e, "invalid DF_CTL"}, | ||
1697 | {0x0f, "invalid SEQ_CNT"}, | ||
1698 | {0x10, "invalid parameter field"}, | ||
1699 | {0x11, "exchange error"}, | ||
1700 | {0x12, "protocol error"}, | ||
1701 | {0x13, "incorrect length"}, | ||
1702 | {0x14, "unsupported ACK"}, | ||
1703 | {0x15, "class of service not supported by entity at FFFFFE"}, | ||
1704 | {0x16, "login required"}, | ||
1705 | {0x17, "excessive sequences attempted"}, | ||
1706 | {0x18, "unable to establish exchange"}, | ||
1707 | {0x1a, "fabric path not available"}, | ||
1708 | {0x1b, "invalid VC_ID (class 4)"}, | ||
1709 | {0x1c, "invalid CS_CTL field"}, | ||
1710 | {0x1d, "insufficient resources for VC (class 4)"}, | ||
1711 | {0x1f, "invalid class of service"}, | ||
1712 | {0x20, "preemption request rejected"}, | ||
1713 | {0x21, "preemption not enabled"}, | ||
1714 | {0x22, "multicast error"}, | ||
1715 | {0x23, "multicast error terminate"}, | ||
1716 | {0x24, "process login required"}, | ||
1717 | {0xff, "vendor specific reject"}, | ||
1718 | {0, NULL}, | ||
1719 | }; | ||
1720 | |||
1721 | /** | 761 | /** |
1722 | * zfcp_rc_description - return description for given reaon code | 762 | * zfcp_sg_free_table - free memory used by scatterlists |
1723 | * @code: reason code | 763 | * @sg: pointer to scatterlist |
1724 | * @rc_table: table of reason codes and descriptions | 764 | * @count: number of scatterlist which are to be free'ed |
765 | * the scatterlist are expected to reference pages always | ||
1725 | */ | 766 | */ |
1726 | static const char * | 767 | void zfcp_sg_free_table(struct scatterlist *sg, int count) |
1727 | zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table) | ||
1728 | { | 768 | { |
1729 | const char *descr = "unknown reason code"; | 769 | int i; |
1730 | 770 | ||
1731 | do { | 771 | for (i = 0; i < count; i++, sg++) |
1732 | if (code == rc_table->code) { | 772 | if (sg) |
1733 | descr = rc_table->description; | 773 | free_page((unsigned long) sg_virt(sg)); |
774 | else | ||
1734 | break; | 775 | break; |
1735 | } | ||
1736 | rc_table++; | ||
1737 | } while (rc_table->code && rc_table->description); | ||
1738 | |||
1739 | return descr; | ||
1740 | } | 776 | } |
1741 | 777 | ||
1742 | /** | 778 | /** |
1743 | * zfcp_check_ct_response - evaluate reason code for CT_IU | 779 | * zfcp_sg_setup_table - init scatterlist and allocate, assign buffers |
1744 | * @rjt: response payload to an CT_IU request | 780 | * @sg: pointer to struct scatterlist |
1745 | * Return: 0 for accept CT_IU, 1 for reject CT_IU or invlid response code | 781 | * @count: number of scatterlists which should be assigned with buffers |
782 | * of size page | ||
783 | * | ||
784 | * Returns: 0 on success, -ENOMEM otherwise | ||
1746 | */ | 785 | */ |
1747 | int | 786 | int zfcp_sg_setup_table(struct scatterlist *sg, int count) |
1748 | zfcp_check_ct_response(struct ct_hdr *rjt) | ||
1749 | { | 787 | { |
1750 | if (rjt->cmd_rsp_code == ZFCP_CT_ACCEPT) | 788 | void *addr; |
1751 | return 0; | 789 | int i; |
1752 | 790 | ||
1753 | if (rjt->cmd_rsp_code != ZFCP_CT_REJECT) { | 791 | sg_init_table(sg, count); |
1754 | ZFCP_LOG_NORMAL("error: invalid Generic Service command/" | 792 | for (i = 0; i < count; i++, sg++) { |
1755 | "response code (0x%04hx)\n", | 793 | addr = (void *) get_zeroed_page(GFP_KERNEL); |
1756 | rjt->cmd_rsp_code); | 794 | if (!addr) { |
1757 | return 1; | 795 | zfcp_sg_free_table(sg, i); |
796 | return -ENOMEM; | ||
797 | } | ||
798 | sg_set_buf(sg, addr, PAGE_SIZE); | ||
1758 | } | 799 | } |
1759 | 800 | return 0; | |
1760 | ZFCP_LOG_INFO("Generic Service command rejected\n"); | ||
1761 | ZFCP_LOG_INFO("%s (0x%02x, 0x%02x, 0x%02x)\n", | ||
1762 | zfcp_rc_description(rjt->reason_code, zfcp_ct_rc), | ||
1763 | (u32) rjt->reason_code, (u32) rjt->reason_code_expl, | ||
1764 | (u32) rjt->vendor_unique); | ||
1765 | |||
1766 | return 1; | ||
1767 | } | ||
1768 | |||
1769 | /** | ||
1770 | * zfcp_print_els_rjt - print reject parameter and description for ELS reject | ||
1771 | * @rjt_par: reject parameter acc. to FC-PH/FC-FS | ||
1772 | * @rc_table: table of reason codes and descriptions | ||
1773 | */ | ||
1774 | static void | ||
1775 | zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par, | ||
1776 | const struct zfcp_rc_entry *rc_table) | ||
1777 | { | ||
1778 | ZFCP_LOG_INFO("%s (%02x %02x %02x %02x)\n", | ||
1779 | zfcp_rc_description(rjt_par->reason_code, rc_table), | ||
1780 | (u32) rjt_par->action, (u32) rjt_par->reason_code, | ||
1781 | (u32) rjt_par->reason_expl, (u32) rjt_par->vendor_unique); | ||
1782 | } | ||
1783 | |||
1784 | /** | ||
1785 | * zfcp_fsf_handle_els_rjt - evaluate status qualifier/reason code on ELS reject | ||
1786 | * @sq: status qualifier word | ||
1787 | * @rjt_par: reject parameter as described in FC-PH and FC-FS | ||
1788 | * Return: -EROMTEIO for LS_RJT, -EREMCHG for invalid D_ID, -EIO else | ||
1789 | */ | ||
1790 | int | ||
1791 | zfcp_handle_els_rjt(u32 sq, struct zfcp_ls_rjt_par *rjt_par) | ||
1792 | { | ||
1793 | int ret = -EIO; | ||
1794 | |||
1795 | if (sq == FSF_IOSTAT_NPORT_RJT) { | ||
1796 | ZFCP_LOG_INFO("ELS rejected (P_RJT)\n"); | ||
1797 | zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); | ||
1798 | /* invalid d_id */ | ||
1799 | if (rjt_par->reason_code == 0x01) | ||
1800 | ret = -EREMCHG; | ||
1801 | } else if (sq == FSF_IOSTAT_FABRIC_RJT) { | ||
1802 | ZFCP_LOG_INFO("ELS rejected (F_RJT)\n"); | ||
1803 | zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc); | ||
1804 | /* invalid d_id */ | ||
1805 | if (rjt_par->reason_code == 0x01) | ||
1806 | ret = -EREMCHG; | ||
1807 | } else if (sq == FSF_IOSTAT_LS_RJT) { | ||
1808 | ZFCP_LOG_INFO("ELS rejected (LS_RJT)\n"); | ||
1809 | zfcp_print_els_rjt(rjt_par, zfcp_ls_rjt_rc); | ||
1810 | ret = -EREMOTEIO; | ||
1811 | } else | ||
1812 | ZFCP_LOG_INFO("unexpected SQ: 0x%02x\n", sq); | ||
1813 | |||
1814 | return ret; | ||
1815 | } | ||
1816 | |||
1817 | /** | ||
1818 | * zfcp_plogi_evaluate - evaluate PLOGI playload and copy important fields | ||
1819 | * into zfcp_port structure | ||
1820 | * @port: zfcp_port structure | ||
1821 | * @plogi: plogi payload | ||
1822 | */ | ||
1823 | void | ||
1824 | zfcp_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi) | ||
1825 | { | ||
1826 | port->maxframe_size = plogi->serv_param.common_serv_param[7] | | ||
1827 | ((plogi->serv_param.common_serv_param[6] & 0x0F) << 8); | ||
1828 | if (plogi->serv_param.class1_serv_param[0] & 0x80) | ||
1829 | port->supported_classes |= FC_COS_CLASS1; | ||
1830 | if (plogi->serv_param.class2_serv_param[0] & 0x80) | ||
1831 | port->supported_classes |= FC_COS_CLASS2; | ||
1832 | if (plogi->serv_param.class3_serv_param[0] & 0x80) | ||
1833 | port->supported_classes |= FC_COS_CLASS3; | ||
1834 | if (plogi->serv_param.class4_serv_param[0] & 0x80) | ||
1835 | port->supported_classes |= FC_COS_CLASS4; | ||
1836 | } | 801 | } |
1837 | |||
1838 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 66d3b88844b0..391dd29749f8 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c | |||
@@ -1,64 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Registration and callback for the s390 common I/O layer. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #include "zfcp_ext.h" | 9 | #include "zfcp_ext.h" |
23 | 10 | ||
24 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | ||
25 | |||
26 | static int zfcp_ccw_probe(struct ccw_device *); | ||
27 | static void zfcp_ccw_remove(struct ccw_device *); | ||
28 | static int zfcp_ccw_set_online(struct ccw_device *); | ||
29 | static int zfcp_ccw_set_offline(struct ccw_device *); | ||
30 | static int zfcp_ccw_notify(struct ccw_device *, int); | ||
31 | static void zfcp_ccw_shutdown(struct ccw_device *); | ||
32 | |||
33 | static struct ccw_device_id zfcp_ccw_device_id[] = { | ||
34 | {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE, | ||
35 | ZFCP_CONTROL_UNIT_MODEL, | ||
36 | ZFCP_DEVICE_TYPE, | ||
37 | ZFCP_DEVICE_MODEL)}, | ||
38 | {CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE, | ||
39 | ZFCP_CONTROL_UNIT_MODEL, | ||
40 | ZFCP_DEVICE_TYPE, | ||
41 | ZFCP_DEVICE_MODEL_PRIV)}, | ||
42 | {}, | ||
43 | }; | ||
44 | |||
45 | static struct ccw_driver zfcp_ccw_driver = { | ||
46 | .owner = THIS_MODULE, | ||
47 | .name = ZFCP_NAME, | ||
48 | .ids = zfcp_ccw_device_id, | ||
49 | .probe = zfcp_ccw_probe, | ||
50 | .remove = zfcp_ccw_remove, | ||
51 | .set_online = zfcp_ccw_set_online, | ||
52 | .set_offline = zfcp_ccw_set_offline, | ||
53 | .notify = zfcp_ccw_notify, | ||
54 | .shutdown = zfcp_ccw_shutdown, | ||
55 | .driver = { | ||
56 | .groups = zfcp_driver_attr_groups, | ||
57 | }, | ||
58 | }; | ||
59 | |||
60 | MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); | ||
61 | |||
62 | /** | 11 | /** |
63 | * zfcp_ccw_probe - probe function of zfcp driver | 12 | * zfcp_ccw_probe - probe function of zfcp driver |
64 | * @ccw_device: pointer to belonging ccw device | 13 | * @ccw_device: pointer to belonging ccw device |
@@ -69,19 +18,16 @@ MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); | |||
69 | * In addition the nameserver port will be added to the ports of the adapter | 18 | * In addition the nameserver port will be added to the ports of the adapter |
70 | * and its sysfs representation will be created too. | 19 | * and its sysfs representation will be created too. |
71 | */ | 20 | */ |
72 | static int | 21 | static int zfcp_ccw_probe(struct ccw_device *ccw_device) |
73 | zfcp_ccw_probe(struct ccw_device *ccw_device) | ||
74 | { | 22 | { |
75 | struct zfcp_adapter *adapter; | ||
76 | int retval = 0; | 23 | int retval = 0; |
77 | 24 | ||
78 | down(&zfcp_data.config_sema); | 25 | down(&zfcp_data.config_sema); |
79 | adapter = zfcp_adapter_enqueue(ccw_device); | 26 | if (zfcp_adapter_enqueue(ccw_device)) { |
80 | if (!adapter) | 27 | dev_err(&ccw_device->dev, |
28 | "Setup of data structures failed.\n"); | ||
81 | retval = -EINVAL; | 29 | retval = -EINVAL; |
82 | else | 30 | } |
83 | ZFCP_LOG_DEBUG("Probed adapter %s\n", | ||
84 | zfcp_get_busid_by_adapter(adapter)); | ||
85 | up(&zfcp_data.config_sema); | 31 | up(&zfcp_data.config_sema); |
86 | return retval; | 32 | return retval; |
87 | } | 33 | } |
@@ -95,8 +41,7 @@ zfcp_ccw_probe(struct ccw_device *ccw_device) | |||
95 | * ports that belong to this adapter. And in addition all resources of this | 41 | * ports that belong to this adapter. And in addition all resources of this |
96 | * adapter will be freed too. | 42 | * adapter will be freed too. |
97 | */ | 43 | */ |
98 | static void | 44 | static void zfcp_ccw_remove(struct ccw_device *ccw_device) |
99 | zfcp_ccw_remove(struct ccw_device *ccw_device) | ||
100 | { | 45 | { |
101 | struct zfcp_adapter *adapter; | 46 | struct zfcp_adapter *adapter; |
102 | struct zfcp_port *port, *p; | 47 | struct zfcp_port *port, *p; |
@@ -106,8 +51,6 @@ zfcp_ccw_remove(struct ccw_device *ccw_device) | |||
106 | down(&zfcp_data.config_sema); | 51 | down(&zfcp_data.config_sema); |
107 | adapter = dev_get_drvdata(&ccw_device->dev); | 52 | adapter = dev_get_drvdata(&ccw_device->dev); |
108 | 53 | ||
109 | ZFCP_LOG_DEBUG("Removing adapter %s\n", | ||
110 | zfcp_get_busid_by_adapter(adapter)); | ||
111 | write_lock_irq(&zfcp_data.config_lock); | 54 | write_lock_irq(&zfcp_data.config_lock); |
112 | list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { | 55 | list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { |
113 | list_for_each_entry_safe(unit, u, &port->unit_list_head, list) { | 56 | list_for_each_entry_safe(unit, u, &port->unit_list_head, list) { |
@@ -145,8 +88,7 @@ zfcp_ccw_remove(struct ccw_device *ccw_device) | |||
145 | * registered with the SCSI stack, that the QDIO queues will be set up | 88 | * registered with the SCSI stack, that the QDIO queues will be set up |
146 | * and that the adapter will be opened (asynchronously). | 89 | * and that the adapter will be opened (asynchronously). |
147 | */ | 90 | */ |
148 | static int | 91 | static int zfcp_ccw_set_online(struct ccw_device *ccw_device) |
149 | zfcp_ccw_set_online(struct ccw_device *ccw_device) | ||
150 | { | 92 | { |
151 | struct zfcp_adapter *adapter; | 93 | struct zfcp_adapter *adapter; |
152 | int retval; | 94 | int retval; |
@@ -155,12 +97,8 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device) | |||
155 | adapter = dev_get_drvdata(&ccw_device->dev); | 97 | adapter = dev_get_drvdata(&ccw_device->dev); |
156 | 98 | ||
157 | retval = zfcp_erp_thread_setup(adapter); | 99 | retval = zfcp_erp_thread_setup(adapter); |
158 | if (retval) { | 100 | if (retval) |
159 | ZFCP_LOG_INFO("error: start of error recovery thread for " | ||
160 | "adapter %s failed\n", | ||
161 | zfcp_get_busid_by_adapter(adapter)); | ||
162 | goto out; | 101 | goto out; |
163 | } | ||
164 | 102 | ||
165 | retval = zfcp_adapter_scsi_register(adapter); | 103 | retval = zfcp_adapter_scsi_register(adapter); |
166 | if (retval) | 104 | if (retval) |
@@ -191,8 +129,7 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device) | |||
191 | * This function gets called by the common i/o layer and sets an adapter | 129 | * This function gets called by the common i/o layer and sets an adapter |
192 | * into state offline. | 130 | * into state offline. |
193 | */ | 131 | */ |
194 | static int | 132 | static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) |
195 | zfcp_ccw_set_offline(struct ccw_device *ccw_device) | ||
196 | { | 133 | { |
197 | struct zfcp_adapter *adapter; | 134 | struct zfcp_adapter *adapter; |
198 | 135 | ||
@@ -206,15 +143,14 @@ zfcp_ccw_set_offline(struct ccw_device *ccw_device) | |||
206 | } | 143 | } |
207 | 144 | ||
208 | /** | 145 | /** |
209 | * zfcp_ccw_notify | 146 | * zfcp_ccw_notify - ccw notify function |
210 | * @ccw_device: pointer to belonging ccw device | 147 | * @ccw_device: pointer to belonging ccw device |
211 | * @event: indicates if adapter was detached or attached | 148 | * @event: indicates if adapter was detached or attached |
212 | * | 149 | * |
213 | * This function gets called by the common i/o layer if an adapter has gone | 150 | * This function gets called by the common i/o layer if an adapter has gone |
214 | * or reappeared. | 151 | * or reappeared. |
215 | */ | 152 | */ |
216 | static int | 153 | static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) |
217 | zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | ||
218 | { | 154 | { |
219 | struct zfcp_adapter *adapter; | 155 | struct zfcp_adapter *adapter; |
220 | 156 | ||
@@ -222,18 +158,15 @@ zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | |||
222 | adapter = dev_get_drvdata(&ccw_device->dev); | 158 | adapter = dev_get_drvdata(&ccw_device->dev); |
223 | switch (event) { | 159 | switch (event) { |
224 | case CIO_GONE: | 160 | case CIO_GONE: |
225 | ZFCP_LOG_NORMAL("adapter %s: device gone\n", | 161 | dev_warn(&adapter->ccw_device->dev, "device gone\n"); |
226 | zfcp_get_busid_by_adapter(adapter)); | ||
227 | zfcp_erp_adapter_shutdown(adapter, 0, 87, NULL); | 162 | zfcp_erp_adapter_shutdown(adapter, 0, 87, NULL); |
228 | break; | 163 | break; |
229 | case CIO_NO_PATH: | 164 | case CIO_NO_PATH: |
230 | ZFCP_LOG_NORMAL("adapter %s: no path\n", | 165 | dev_warn(&adapter->ccw_device->dev, "no path\n"); |
231 | zfcp_get_busid_by_adapter(adapter)); | ||
232 | zfcp_erp_adapter_shutdown(adapter, 0, 88, NULL); | 166 | zfcp_erp_adapter_shutdown(adapter, 0, 88, NULL); |
233 | break; | 167 | break; |
234 | case CIO_OPER: | 168 | case CIO_OPER: |
235 | ZFCP_LOG_NORMAL("adapter %s: operational again\n", | 169 | dev_info(&adapter->ccw_device->dev, "operational again\n"); |
236 | zfcp_get_busid_by_adapter(adapter)); | ||
237 | zfcp_erp_modify_adapter_status(adapter, 11, NULL, | 170 | zfcp_erp_modify_adapter_status(adapter, 11, NULL, |
238 | ZFCP_STATUS_COMMON_RUNNING, | 171 | ZFCP_STATUS_COMMON_RUNNING, |
239 | ZFCP_SET); | 172 | ZFCP_SET); |
@@ -247,24 +180,10 @@ zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | |||
247 | } | 180 | } |
248 | 181 | ||
249 | /** | 182 | /** |
250 | * zfcp_ccw_register - ccw register function | 183 | * zfcp_ccw_shutdown - handle shutdown from cio |
251 | * | 184 | * @cdev: device for adapter to shutdown. |
252 | * Registers the driver at the common i/o layer. This function will be called | ||
253 | * at module load time/system start. | ||
254 | */ | ||
255 | int __init | ||
256 | zfcp_ccw_register(void) | ||
257 | { | ||
258 | return ccw_driver_register(&zfcp_ccw_driver); | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * zfcp_ccw_shutdown - gets called on reboot/shutdown | ||
263 | * | ||
264 | * Makes sure that QDIO queues are down when the system gets stopped. | ||
265 | */ | 185 | */ |
266 | static void | 186 | static void zfcp_ccw_shutdown(struct ccw_device *cdev) |
267 | zfcp_ccw_shutdown(struct ccw_device *cdev) | ||
268 | { | 187 | { |
269 | struct zfcp_adapter *adapter; | 188 | struct zfcp_adapter *adapter; |
270 | 189 | ||
@@ -275,4 +194,33 @@ zfcp_ccw_shutdown(struct ccw_device *cdev) | |||
275 | up(&zfcp_data.config_sema); | 194 | up(&zfcp_data.config_sema); |
276 | } | 195 | } |
277 | 196 | ||
278 | #undef ZFCP_LOG_AREA | 197 | static struct ccw_device_id zfcp_ccw_device_id[] = { |
198 | { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) }, | ||
199 | { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x4) }, /* priv. */ | ||
200 | {}, | ||
201 | }; | ||
202 | |||
203 | MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); | ||
204 | |||
205 | static struct ccw_driver zfcp_ccw_driver = { | ||
206 | .owner = THIS_MODULE, | ||
207 | .name = "zfcp", | ||
208 | .ids = zfcp_ccw_device_id, | ||
209 | .probe = zfcp_ccw_probe, | ||
210 | .remove = zfcp_ccw_remove, | ||
211 | .set_online = zfcp_ccw_set_online, | ||
212 | .set_offline = zfcp_ccw_set_offline, | ||
213 | .notify = zfcp_ccw_notify, | ||
214 | .shutdown = zfcp_ccw_shutdown, | ||
215 | }; | ||
216 | |||
217 | /** | ||
218 | * zfcp_ccw_register - ccw register function | ||
219 | * | ||
220 | * Registers the driver at the common i/o layer. This function will be called | ||
221 | * at module load time/system start. | ||
222 | */ | ||
223 | int __init zfcp_ccw_register(void) | ||
224 | { | ||
225 | return ccw_driver_register(&zfcp_ccw_driver); | ||
226 | } | ||
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c new file mode 100644 index 000000000000..ec2abceca6dc --- /dev/null +++ b/drivers/s390/scsi/zfcp_cfdc.c | |||
@@ -0,0 +1,259 @@ | |||
1 | /* | ||
2 | * zfcp device driver | ||
3 | * | ||
4 | * Userspace interface for accessing the | ||
5 | * Access Control Lists / Control File Data Channel | ||
6 | * | ||
7 | * Copyright IBM Corporation 2008 | ||
8 | */ | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | #include <linux/miscdevice.h> | ||
12 | #include <asm/ccwdev.h> | ||
13 | #include "zfcp_def.h" | ||
14 | #include "zfcp_ext.h" | ||
15 | #include "zfcp_fsf.h" | ||
16 | |||
17 | #define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL 0x00010001 | ||
18 | #define ZFCP_CFDC_CMND_DOWNLOAD_FORCE 0x00010101 | ||
19 | #define ZFCP_CFDC_CMND_FULL_ACCESS 0x00000201 | ||
20 | #define ZFCP_CFDC_CMND_RESTRICTED_ACCESS 0x00000401 | ||
21 | #define ZFCP_CFDC_CMND_UPLOAD 0x00010002 | ||
22 | |||
23 | #define ZFCP_CFDC_DOWNLOAD 0x00000001 | ||
24 | #define ZFCP_CFDC_UPLOAD 0x00000002 | ||
25 | #define ZFCP_CFDC_WITH_CONTROL_FILE 0x00010000 | ||
26 | |||
27 | #define ZFCP_CFDC_IOC_MAGIC 0xDD | ||
28 | #define ZFCP_CFDC_IOC \ | ||
29 | _IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_data) | ||
30 | |||
31 | /** | ||
32 | * struct zfcp_cfdc_data - data for ioctl cfdc interface | ||
33 | * @signature: request signature | ||
34 | * @devno: FCP adapter device number | ||
35 | * @command: command code | ||
36 | * @fsf_status: returns status of FSF command to userspace | ||
37 | * @fsf_status_qual: returned to userspace | ||
38 | * @payloads: access conflicts list | ||
39 | * @control_file: access control table | ||
40 | */ | ||
41 | struct zfcp_cfdc_data { | ||
42 | u32 signature; | ||
43 | u32 devno; | ||
44 | u32 command; | ||
45 | u32 fsf_status; | ||
46 | u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; | ||
47 | u8 payloads[256]; | ||
48 | u8 control_file[0]; | ||
49 | }; | ||
50 | |||
51 | static int zfcp_cfdc_copy_from_user(struct scatterlist *sg, | ||
52 | void __user *user_buffer) | ||
53 | { | ||
54 | unsigned int length; | ||
55 | unsigned int size = ZFCP_CFDC_MAX_SIZE; | ||
56 | |||
57 | while (size) { | ||
58 | length = min((unsigned int)size, sg->length); | ||
59 | if (copy_from_user(sg_virt(sg++), user_buffer, length)) | ||
60 | return -EFAULT; | ||
61 | user_buffer += length; | ||
62 | size -= length; | ||
63 | } | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int zfcp_cfdc_copy_to_user(void __user *user_buffer, | ||
68 | struct scatterlist *sg) | ||
69 | { | ||
70 | unsigned int length; | ||
71 | unsigned int size = ZFCP_CFDC_MAX_SIZE; | ||
72 | |||
73 | while (size) { | ||
74 | length = min((unsigned int) size, sg->length); | ||
75 | if (copy_to_user(user_buffer, sg_virt(sg++), length)) | ||
76 | return -EFAULT; | ||
77 | user_buffer += length; | ||
78 | size -= length; | ||
79 | } | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno) | ||
84 | { | ||
85 | struct zfcp_adapter *adapter = NULL, *cur_adapter; | ||
86 | struct ccw_dev_id dev_id; | ||
87 | |||
88 | read_lock_irq(&zfcp_data.config_lock); | ||
89 | list_for_each_entry(cur_adapter, &zfcp_data.adapter_list_head, list) { | ||
90 | ccw_device_get_id(cur_adapter->ccw_device, &dev_id); | ||
91 | if (dev_id.devno == devno) { | ||
92 | adapter = cur_adapter; | ||
93 | zfcp_adapter_get(adapter); | ||
94 | break; | ||
95 | } | ||
96 | } | ||
97 | read_unlock_irq(&zfcp_data.config_lock); | ||
98 | return adapter; | ||
99 | } | ||
100 | |||
101 | static int zfcp_cfdc_set_fsf(struct zfcp_fsf_cfdc *fsf_cfdc, int command) | ||
102 | { | ||
103 | switch (command) { | ||
104 | case ZFCP_CFDC_CMND_DOWNLOAD_NORMAL: | ||
105 | fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
106 | fsf_cfdc->option = FSF_CFDC_OPTION_NORMAL_MODE; | ||
107 | break; | ||
108 | case ZFCP_CFDC_CMND_DOWNLOAD_FORCE: | ||
109 | fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
110 | fsf_cfdc->option = FSF_CFDC_OPTION_FORCE; | ||
111 | break; | ||
112 | case ZFCP_CFDC_CMND_FULL_ACCESS: | ||
113 | fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
114 | fsf_cfdc->option = FSF_CFDC_OPTION_FULL_ACCESS; | ||
115 | break; | ||
116 | case ZFCP_CFDC_CMND_RESTRICTED_ACCESS: | ||
117 | fsf_cfdc->command = FSF_QTCB_DOWNLOAD_CONTROL_FILE; | ||
118 | fsf_cfdc->option = FSF_CFDC_OPTION_RESTRICTED_ACCESS; | ||
119 | break; | ||
120 | case ZFCP_CFDC_CMND_UPLOAD: | ||
121 | fsf_cfdc->command = FSF_QTCB_UPLOAD_CONTROL_FILE; | ||
122 | fsf_cfdc->option = 0; | ||
123 | break; | ||
124 | default: | ||
125 | return -EINVAL; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int zfcp_cfdc_sg_setup(int command, struct scatterlist *sg, | ||
132 | u8 __user *control_file) | ||
133 | { | ||
134 | int retval; | ||
135 | retval = zfcp_sg_setup_table(sg, ZFCP_CFDC_PAGES); | ||
136 | if (retval) | ||
137 | return retval; | ||
138 | |||
139 | sg[ZFCP_CFDC_PAGES - 1].length = ZFCP_CFDC_MAX_SIZE % PAGE_SIZE; | ||
140 | |||
141 | if (command & ZFCP_CFDC_WITH_CONTROL_FILE && | ||
142 | command & ZFCP_CFDC_DOWNLOAD) { | ||
143 | retval = zfcp_cfdc_copy_from_user(sg, control_file); | ||
144 | if (retval) { | ||
145 | zfcp_sg_free_table(sg, ZFCP_CFDC_PAGES); | ||
146 | return -EFAULT; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static void zfcp_cfdc_req_to_sense(struct zfcp_cfdc_data *data, | ||
154 | struct zfcp_fsf_req *req) | ||
155 | { | ||
156 | data->fsf_status = req->qtcb->header.fsf_status; | ||
157 | memcpy(&data->fsf_status_qual, &req->qtcb->header.fsf_status_qual, | ||
158 | sizeof(union fsf_status_qual)); | ||
159 | memcpy(&data->payloads, &req->qtcb->bottom.support.els, | ||
160 | sizeof(req->qtcb->bottom.support.els)); | ||
161 | } | ||
162 | |||
163 | static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, | ||
164 | unsigned long buffer) | ||
165 | { | ||
166 | struct zfcp_cfdc_data *data; | ||
167 | struct zfcp_cfdc_data __user *data_user; | ||
168 | struct zfcp_adapter *adapter; | ||
169 | struct zfcp_fsf_req *req; | ||
170 | struct zfcp_fsf_cfdc *fsf_cfdc; | ||
171 | int retval; | ||
172 | |||
173 | if (command != ZFCP_CFDC_IOC) | ||
174 | return -ENOTTY; | ||
175 | |||
176 | data_user = (void __user *) buffer; | ||
177 | if (!data_user) | ||
178 | return -EINVAL; | ||
179 | |||
180 | fsf_cfdc = kmalloc(sizeof(struct zfcp_fsf_cfdc), GFP_KERNEL); | ||
181 | if (!fsf_cfdc) | ||
182 | return -ENOMEM; | ||
183 | |||
184 | data = kmalloc(sizeof(struct zfcp_cfdc_data), GFP_KERNEL); | ||
185 | if (!data) { | ||
186 | retval = -ENOMEM; | ||
187 | goto no_mem_sense; | ||
188 | } | ||
189 | |||
190 | retval = copy_from_user(data, data_user, sizeof(*data)); | ||
191 | if (retval) { | ||
192 | retval = -EFAULT; | ||
193 | goto free_buffer; | ||
194 | } | ||
195 | |||
196 | if (data->signature != 0xCFDCACDF) { | ||
197 | retval = -EINVAL; | ||
198 | goto free_buffer; | ||
199 | } | ||
200 | |||
201 | retval = zfcp_cfdc_set_fsf(fsf_cfdc, data->command); | ||
202 | |||
203 | adapter = zfcp_cfdc_get_adapter(data->devno); | ||
204 | if (!adapter) { | ||
205 | retval = -ENXIO; | ||
206 | goto free_buffer; | ||
207 | } | ||
208 | |||
209 | retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg, | ||
210 | data_user->control_file); | ||
211 | if (retval) | ||
212 | goto adapter_put; | ||
213 | req = zfcp_fsf_control_file(adapter, fsf_cfdc); | ||
214 | if (IS_ERR(req)) { | ||
215 | retval = PTR_ERR(req); | ||
216 | goto free_sg; | ||
217 | } | ||
218 | |||
219 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
220 | retval = -ENXIO; | ||
221 | goto free_fsf; | ||
222 | } | ||
223 | |||
224 | zfcp_cfdc_req_to_sense(data, req); | ||
225 | retval = copy_to_user(data_user, data, sizeof(*data_user)); | ||
226 | if (retval) { | ||
227 | retval = -EFAULT; | ||
228 | goto free_fsf; | ||
229 | } | ||
230 | |||
231 | if (data->command & ZFCP_CFDC_UPLOAD) | ||
232 | retval = zfcp_cfdc_copy_to_user(&data_user->control_file, | ||
233 | fsf_cfdc->sg); | ||
234 | |||
235 | free_fsf: | ||
236 | zfcp_fsf_req_free(req); | ||
237 | free_sg: | ||
238 | zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES); | ||
239 | adapter_put: | ||
240 | zfcp_adapter_put(adapter); | ||
241 | free_buffer: | ||
242 | kfree(data); | ||
243 | no_mem_sense: | ||
244 | kfree(fsf_cfdc); | ||
245 | return retval; | ||
246 | } | ||
247 | |||
248 | static const struct file_operations zfcp_cfdc_fops = { | ||
249 | .unlocked_ioctl = zfcp_cfdc_dev_ioctl, | ||
250 | #ifdef CONFIG_COMPAT | ||
251 | .compat_ioctl = zfcp_cfdc_dev_ioctl | ||
252 | #endif | ||
253 | }; | ||
254 | |||
255 | struct miscdevice zfcp_cfdc_misc = { | ||
256 | .minor = MISC_DYNAMIC_MINOR, | ||
257 | .name = "zfcp_cfdc", | ||
258 | .fops = &zfcp_cfdc_fops, | ||
259 | }; | ||
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index c8bad675dbd1..36169c6944fd 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c | |||
@@ -1,22 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Debug traces for zfcp. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #include <linux/ctype.h> | 9 | #include <linux/ctype.h> |
@@ -29,8 +16,6 @@ module_param(dbfsize, uint, 0400); | |||
29 | MODULE_PARM_DESC(dbfsize, | 16 | MODULE_PARM_DESC(dbfsize, |
30 | "number of pages for each debug feature area (default 4)"); | 17 | "number of pages for each debug feature area (default 4)"); |
31 | 18 | ||
32 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER | ||
33 | |||
34 | static void zfcp_dbf_hexdump(debug_info_t *dbf, void *to, int to_len, | 19 | static void zfcp_dbf_hexdump(debug_info_t *dbf, void *to, int to_len, |
35 | int level, char *from, int from_len) | 20 | int level, char *from, int from_len) |
36 | { | 21 | { |
@@ -186,8 +171,8 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) | |||
186 | fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE); | 171 | fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE); |
187 | response->fsf_req_status = fsf_req->status; | 172 | response->fsf_req_status = fsf_req->status; |
188 | response->sbal_first = fsf_req->sbal_first; | 173 | response->sbal_first = fsf_req->sbal_first; |
189 | response->sbal_curr = fsf_req->sbal_curr; | ||
190 | response->sbal_last = fsf_req->sbal_last; | 174 | response->sbal_last = fsf_req->sbal_last; |
175 | response->sbal_response = fsf_req->sbal_response; | ||
191 | response->pool = fsf_req->pool != NULL; | 176 | response->pool = fsf_req->pool != NULL; |
192 | response->erp_action = (unsigned long)fsf_req->erp_action; | 177 | response->erp_action = (unsigned long)fsf_req->erp_action; |
193 | 178 | ||
@@ -268,7 +253,7 @@ void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, | |||
268 | strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); | 253 | strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); |
269 | strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); | 254 | strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); |
270 | 255 | ||
271 | rec->u.status.failed = adapter->status_read_failed; | 256 | rec->u.status.failed = atomic_read(&adapter->stat_miss); |
272 | if (status_buffer != NULL) { | 257 | if (status_buffer != NULL) { |
273 | rec->u.status.status_type = status_buffer->status_type; | 258 | rec->u.status.status_type = status_buffer->status_type; |
274 | rec->u.status.status_subtype = status_buffer->status_subtype; | 259 | rec->u.status.status_subtype = status_buffer->status_subtype; |
@@ -355,8 +340,8 @@ static void zfcp_hba_dbf_view_response(char **p, | |||
355 | FSF_STATUS_QUALIFIER_SIZE, 0, FSF_STATUS_QUALIFIER_SIZE); | 340 | FSF_STATUS_QUALIFIER_SIZE, 0, FSF_STATUS_QUALIFIER_SIZE); |
356 | zfcp_dbf_out(p, "fsf_req_status", "0x%08x", r->fsf_req_status); | 341 | zfcp_dbf_out(p, "fsf_req_status", "0x%08x", r->fsf_req_status); |
357 | zfcp_dbf_out(p, "sbal_first", "0x%02x", r->sbal_first); | 342 | zfcp_dbf_out(p, "sbal_first", "0x%02x", r->sbal_first); |
358 | zfcp_dbf_out(p, "sbal_curr", "0x%02x", r->sbal_curr); | ||
359 | zfcp_dbf_out(p, "sbal_last", "0x%02x", r->sbal_last); | 343 | zfcp_dbf_out(p, "sbal_last", "0x%02x", r->sbal_last); |
344 | zfcp_dbf_out(p, "sbal_response", "0x%02x", r->sbal_response); | ||
360 | zfcp_dbf_out(p, "pool", "0x%02x", r->pool); | 345 | zfcp_dbf_out(p, "pool", "0x%02x", r->pool); |
361 | 346 | ||
362 | switch (r->fsf_command) { | 347 | switch (r->fsf_command) { |
@@ -515,13 +500,13 @@ static const char *zfcp_rec_dbf_ids[] = { | |||
515 | [52] = "port boxed close unit", | 500 | [52] = "port boxed close unit", |
516 | [53] = "port boxed fcp", | 501 | [53] = "port boxed fcp", |
517 | [54] = "unit boxed fcp", | 502 | [54] = "unit boxed fcp", |
518 | [55] = "port access denied ct", | 503 | [55] = "port access denied", |
519 | [56] = "port access denied els", | 504 | [56] = "", |
520 | [57] = "port access denied open port", | 505 | [57] = "", |
521 | [58] = "port access denied close physical", | 506 | [58] = "", |
522 | [59] = "unit access denied open unit", | 507 | [59] = "unit access denied", |
523 | [60] = "shared unit access denied open unit", | 508 | [60] = "shared unit access denied open unit", |
524 | [61] = "unit access denied fcp", | 509 | [61] = "", |
525 | [62] = "request timeout", | 510 | [62] = "request timeout", |
526 | [63] = "adisc link test reject or timeout", | 511 | [63] = "adisc link test reject or timeout", |
527 | [64] = "adisc link test d_id changed", | 512 | [64] = "adisc link test d_id changed", |
@@ -546,8 +531,8 @@ static const char *zfcp_rec_dbf_ids[] = { | |||
546 | [80] = "exclusive read-only unit access unsupported", | 531 | [80] = "exclusive read-only unit access unsupported", |
547 | [81] = "shared read-write unit access unsupported", | 532 | [81] = "shared read-write unit access unsupported", |
548 | [82] = "incoming rscn", | 533 | [82] = "incoming rscn", |
549 | [83] = "incoming plogi", | 534 | [83] = "incoming wwpn", |
550 | [84] = "incoming logo", | 535 | [84] = "", |
551 | [85] = "online", | 536 | [85] = "online", |
552 | [86] = "offline", | 537 | [86] = "offline", |
553 | [87] = "ccw device gone", | 538 | [87] = "ccw device gone", |
@@ -586,8 +571,8 @@ static const char *zfcp_rec_dbf_ids[] = { | |||
586 | [120] = "unknown fsf command", | 571 | [120] = "unknown fsf command", |
587 | [121] = "no recommendation for status qualifier", | 572 | [121] = "no recommendation for status qualifier", |
588 | [122] = "status read physical port closed in error", | 573 | [122] = "status read physical port closed in error", |
589 | [123] = "fc service class not supported ct", | 574 | [123] = "fc service class not supported", |
590 | [124] = "fc service class not supported els", | 575 | [124] = "", |
591 | [125] = "need newer zfcp", | 576 | [125] = "need newer zfcp", |
592 | [126] = "need newer microcode", | 577 | [126] = "need newer microcode", |
593 | [127] = "arbitrated loop not supported", | 578 | [127] = "arbitrated loop not supported", |
@@ -595,7 +580,7 @@ static const char *zfcp_rec_dbf_ids[] = { | |||
595 | [129] = "qtcb size mismatch", | 580 | [129] = "qtcb size mismatch", |
596 | [130] = "unknown fsf status ecd", | 581 | [130] = "unknown fsf status ecd", |
597 | [131] = "fcp request too big", | 582 | [131] = "fcp request too big", |
598 | [132] = "fc service class not supported fcp", | 583 | [132] = "", |
599 | [133] = "data direction not valid fcp", | 584 | [133] = "data direction not valid fcp", |
600 | [134] = "command length not valid fcp", | 585 | [134] = "command length not valid fcp", |
601 | [135] = "status read act update", | 586 | [135] = "status read act update", |
@@ -603,13 +588,18 @@ static const char *zfcp_rec_dbf_ids[] = { | |||
603 | [137] = "hbaapi port open", | 588 | [137] = "hbaapi port open", |
604 | [138] = "hbaapi unit open", | 589 | [138] = "hbaapi unit open", |
605 | [139] = "hbaapi unit shutdown", | 590 | [139] = "hbaapi unit shutdown", |
606 | [140] = "qdio error", | 591 | [140] = "qdio error outbound", |
607 | [141] = "scsi host reset", | 592 | [141] = "scsi host reset", |
608 | [142] = "dismissing fsf request for recovery action", | 593 | [142] = "dismissing fsf request for recovery action", |
609 | [143] = "recovery action timed out", | 594 | [143] = "recovery action timed out", |
610 | [144] = "recovery action gone", | 595 | [144] = "recovery action gone", |
611 | [145] = "recovery action being processed", | 596 | [145] = "recovery action being processed", |
612 | [146] = "recovery action ready for next step", | 597 | [146] = "recovery action ready for next step", |
598 | [147] = "qdio error inbound", | ||
599 | [148] = "nameserver needed for port scan", | ||
600 | [149] = "port scan", | ||
601 | [150] = "ptp attach", | ||
602 | [151] = "port validation failed", | ||
613 | }; | 603 | }; |
614 | 604 | ||
615 | static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view, | 605 | static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view, |
@@ -670,24 +660,20 @@ static struct debug_view zfcp_rec_dbf_view = { | |||
670 | * zfcp_rec_dbf_event_thread - trace event related to recovery thread operation | 660 | * zfcp_rec_dbf_event_thread - trace event related to recovery thread operation |
671 | * @id2: identifier for event | 661 | * @id2: identifier for event |
672 | * @adapter: adapter | 662 | * @adapter: adapter |
673 | * @lock: non-zero value indicates that erp_lock has not yet been acquired | 663 | * This function assumes that the caller is holding erp_lock. |
674 | */ | 664 | */ |
675 | void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter, int lock) | 665 | void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter) |
676 | { | 666 | { |
677 | struct zfcp_rec_dbf_record *r = &adapter->rec_dbf_buf; | 667 | struct zfcp_rec_dbf_record *r = &adapter->rec_dbf_buf; |
678 | unsigned long flags = 0; | 668 | unsigned long flags = 0; |
679 | struct list_head *entry; | 669 | struct list_head *entry; |
680 | unsigned ready = 0, running = 0, total; | 670 | unsigned ready = 0, running = 0, total; |
681 | 671 | ||
682 | if (lock) | ||
683 | read_lock_irqsave(&adapter->erp_lock, flags); | ||
684 | list_for_each(entry, &adapter->erp_ready_head) | 672 | list_for_each(entry, &adapter->erp_ready_head) |
685 | ready++; | 673 | ready++; |
686 | list_for_each(entry, &adapter->erp_running_head) | 674 | list_for_each(entry, &adapter->erp_running_head) |
687 | running++; | 675 | running++; |
688 | total = adapter->erp_total_count; | 676 | total = adapter->erp_total_count; |
689 | if (lock) | ||
690 | read_unlock_irqrestore(&adapter->erp_lock, flags); | ||
691 | 677 | ||
692 | spin_lock_irqsave(&adapter->rec_dbf_lock, flags); | 678 | spin_lock_irqsave(&adapter->rec_dbf_lock, flags); |
693 | memset(r, 0, sizeof(*r)); | 679 | memset(r, 0, sizeof(*r)); |
@@ -696,10 +682,25 @@ void zfcp_rec_dbf_event_thread(u8 id2, struct zfcp_adapter *adapter, int lock) | |||
696 | r->u.thread.total = total; | 682 | r->u.thread.total = total; |
697 | r->u.thread.ready = ready; | 683 | r->u.thread.ready = ready; |
698 | r->u.thread.running = running; | 684 | r->u.thread.running = running; |
699 | debug_event(adapter->rec_dbf, 5, r, sizeof(*r)); | 685 | debug_event(adapter->rec_dbf, 6, r, sizeof(*r)); |
700 | spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); | 686 | spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); |
701 | } | 687 | } |
702 | 688 | ||
689 | /** | ||
690 | * zfcp_rec_dbf_event_thread - trace event related to recovery thread operation | ||
691 | * @id2: identifier for event | ||
692 | * @adapter: adapter | ||
693 | * This function assumes that the caller does not hold erp_lock. | ||
694 | */ | ||
695 | void zfcp_rec_dbf_event_thread_lock(u8 id2, struct zfcp_adapter *adapter) | ||
696 | { | ||
697 | unsigned long flags; | ||
698 | |||
699 | read_lock_irqsave(&adapter->erp_lock, flags); | ||
700 | zfcp_rec_dbf_event_thread(id2, adapter); | ||
701 | read_unlock_irqrestore(&adapter->erp_lock, flags); | ||
702 | } | ||
703 | |||
703 | static void zfcp_rec_dbf_event_target(u8 id2, void *ref, | 704 | static void zfcp_rec_dbf_event_target(u8 id2, void *ref, |
704 | struct zfcp_adapter *adapter, | 705 | struct zfcp_adapter *adapter, |
705 | atomic_t *status, atomic_t *erp_count, | 706 | atomic_t *status, atomic_t *erp_count, |
@@ -823,7 +824,7 @@ void zfcp_rec_dbf_event_action(u8 id2, struct zfcp_erp_action *erp_action) | |||
823 | r->u.action.status = erp_action->status; | 824 | r->u.action.status = erp_action->status; |
824 | r->u.action.step = erp_action->step; | 825 | r->u.action.step = erp_action->step; |
825 | r->u.action.fsf_req = (unsigned long)erp_action->fsf_req; | 826 | r->u.action.fsf_req = (unsigned long)erp_action->fsf_req; |
826 | debug_event(adapter->rec_dbf, 4, r, sizeof(*r)); | 827 | debug_event(adapter->rec_dbf, 5, r, sizeof(*r)); |
827 | spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); | 828 | spin_unlock_irqrestore(&adapter->rec_dbf_lock, flags); |
828 | } | 829 | } |
829 | 830 | ||
@@ -960,7 +961,7 @@ void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req) | |||
960 | 961 | ||
961 | zfcp_san_dbf_event_els("iels", 1, fsf_req, buf->d_id, | 962 | zfcp_san_dbf_event_els("iels", 1, fsf_req, buf->d_id, |
962 | fc_host_port_id(adapter->scsi_host), | 963 | fc_host_port_id(adapter->scsi_host), |
963 | *(u8 *)buf->payload, (void *)buf->payload, | 964 | buf->payload.data[0], (void *)buf->payload.data, |
964 | length); | 965 | length); |
965 | } | 966 | } |
966 | 967 | ||
@@ -1064,8 +1065,7 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, | |||
1064 | if (fsf_req != NULL) { | 1065 | if (fsf_req != NULL) { |
1065 | fcp_rsp = (struct fcp_rsp_iu *) | 1066 | fcp_rsp = (struct fcp_rsp_iu *) |
1066 | &(fsf_req->qtcb->bottom.io.fcp_rsp); | 1067 | &(fsf_req->qtcb->bottom.io.fcp_rsp); |
1067 | fcp_rsp_info = | 1068 | fcp_rsp_info = (unsigned char *) &fcp_rsp[1]; |
1068 | zfcp_get_fcp_rsp_info_ptr(fcp_rsp); | ||
1069 | fcp_sns_info = | 1069 | fcp_sns_info = |
1070 | zfcp_get_fcp_sns_info_ptr(fcp_rsp); | 1070 | zfcp_get_fcp_sns_info_ptr(fcp_rsp); |
1071 | 1071 | ||
@@ -1279,5 +1279,3 @@ void zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter) | |||
1279 | adapter->hba_dbf = NULL; | 1279 | adapter->hba_dbf = NULL; |
1280 | adapter->rec_dbf = NULL; | 1280 | adapter->rec_dbf = NULL; |
1281 | } | 1281 | } |
1282 | |||
1283 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 54c34e483457..d04aea604974 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h | |||
@@ -38,7 +38,7 @@ struct zfcp_rec_dbf_record_thread { | |||
38 | u32 total; | 38 | u32 total; |
39 | u32 ready; | 39 | u32 ready; |
40 | u32 running; | 40 | u32 running; |
41 | } __attribute__ ((packed)); | 41 | }; |
42 | 42 | ||
43 | struct zfcp_rec_dbf_record_target { | 43 | struct zfcp_rec_dbf_record_target { |
44 | u64 ref; | 44 | u64 ref; |
@@ -47,7 +47,7 @@ struct zfcp_rec_dbf_record_target { | |||
47 | u64 wwpn; | 47 | u64 wwpn; |
48 | u64 fcp_lun; | 48 | u64 fcp_lun; |
49 | u32 erp_count; | 49 | u32 erp_count; |
50 | } __attribute__ ((packed)); | 50 | }; |
51 | 51 | ||
52 | struct zfcp_rec_dbf_record_trigger { | 52 | struct zfcp_rec_dbf_record_trigger { |
53 | u8 want; | 53 | u8 want; |
@@ -59,14 +59,14 @@ struct zfcp_rec_dbf_record_trigger { | |||
59 | u64 action; | 59 | u64 action; |
60 | u64 wwpn; | 60 | u64 wwpn; |
61 | u64 fcp_lun; | 61 | u64 fcp_lun; |
62 | } __attribute__ ((packed)); | 62 | }; |
63 | 63 | ||
64 | struct zfcp_rec_dbf_record_action { | 64 | struct zfcp_rec_dbf_record_action { |
65 | u32 status; | 65 | u32 status; |
66 | u32 step; | 66 | u32 step; |
67 | u64 action; | 67 | u64 action; |
68 | u64 fsf_req; | 68 | u64 fsf_req; |
69 | } __attribute__ ((packed)); | 69 | }; |
70 | 70 | ||
71 | struct zfcp_rec_dbf_record { | 71 | struct zfcp_rec_dbf_record { |
72 | u8 id; | 72 | u8 id; |
@@ -77,7 +77,7 @@ struct zfcp_rec_dbf_record { | |||
77 | struct zfcp_rec_dbf_record_target target; | 77 | struct zfcp_rec_dbf_record_target target; |
78 | struct zfcp_rec_dbf_record_trigger trigger; | 78 | struct zfcp_rec_dbf_record_trigger trigger; |
79 | } u; | 79 | } u; |
80 | } __attribute__ ((packed)); | 80 | }; |
81 | 81 | ||
82 | enum { | 82 | enum { |
83 | ZFCP_REC_DBF_ID_ACTION, | 83 | ZFCP_REC_DBF_ID_ACTION, |
@@ -97,8 +97,8 @@ struct zfcp_hba_dbf_record_response { | |||
97 | u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; | 97 | u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; |
98 | u32 fsf_req_status; | 98 | u32 fsf_req_status; |
99 | u8 sbal_first; | 99 | u8 sbal_first; |
100 | u8 sbal_curr; | ||
101 | u8 sbal_last; | 100 | u8 sbal_last; |
101 | u8 sbal_response; | ||
102 | u8 pool; | 102 | u8 pool; |
103 | u64 erp_action; | 103 | u64 erp_action; |
104 | union { | 104 | union { |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index bda8c77b22da..67f45fc62f53 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -1,22 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Global definitions for the zfcp device driver. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #ifndef ZFCP_DEF_H | 9 | #ifndef ZFCP_DEF_H |
@@ -26,7 +13,6 @@ | |||
26 | 13 | ||
27 | #include <linux/init.h> | 14 | #include <linux/init.h> |
28 | #include <linux/moduleparam.h> | 15 | #include <linux/moduleparam.h> |
29 | #include <linux/miscdevice.h> | ||
30 | #include <linux/major.h> | 16 | #include <linux/major.h> |
31 | #include <linux/blkdev.h> | 17 | #include <linux/blkdev.h> |
32 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
@@ -53,9 +39,6 @@ | |||
53 | 39 | ||
54 | /********************* GENERAL DEFINES *********************************/ | 40 | /********************* GENERAL DEFINES *********************************/ |
55 | 41 | ||
56 | /* zfcp version number, it consists of major, minor, and patch-level number */ | ||
57 | #define ZFCP_VERSION "4.8.0" | ||
58 | |||
59 | /** | 42 | /** |
60 | * zfcp_sg_to_address - determine kernel address from struct scatterlist | 43 | * zfcp_sg_to_address - determine kernel address from struct scatterlist |
61 | * @list: struct scatterlist | 44 | * @list: struct scatterlist |
@@ -93,11 +76,6 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) | |||
93 | #define ZFCP_DEVICE_MODEL 0x03 | 76 | #define ZFCP_DEVICE_MODEL 0x03 |
94 | #define ZFCP_DEVICE_MODEL_PRIV 0x04 | 77 | #define ZFCP_DEVICE_MODEL_PRIV 0x04 |
95 | 78 | ||
96 | /* allow as many chained SBALs as are supported by hardware */ | ||
97 | #define ZFCP_MAX_SBALS_PER_REQ FSF_MAX_SBALS_PER_REQ | ||
98 | #define ZFCP_MAX_SBALS_PER_CT_REQ FSF_MAX_SBALS_PER_REQ | ||
99 | #define ZFCP_MAX_SBALS_PER_ELS_REQ FSF_MAX_SBALS_PER_ELS_REQ | ||
100 | |||
101 | /* DMQ bug workaround: don't use last SBALE */ | 79 | /* DMQ bug workaround: don't use last SBALE */ |
102 | #define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) | 80 | #define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) |
103 | 81 | ||
@@ -106,42 +84,17 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) | |||
106 | 84 | ||
107 | /* max. number of (data buffer) SBALEs in largest SBAL chain */ | 85 | /* max. number of (data buffer) SBALEs in largest SBAL chain */ |
108 | #define ZFCP_MAX_SBALES_PER_REQ \ | 86 | #define ZFCP_MAX_SBALES_PER_REQ \ |
109 | (ZFCP_MAX_SBALS_PER_REQ * ZFCP_MAX_SBALES_PER_SBAL - 2) | 87 | (FSF_MAX_SBALS_PER_REQ * ZFCP_MAX_SBALES_PER_SBAL - 2) |
110 | /* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */ | 88 | /* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */ |
111 | 89 | ||
112 | #define ZFCP_MAX_SECTORS (ZFCP_MAX_SBALES_PER_REQ * 8) | 90 | #define ZFCP_MAX_SECTORS (ZFCP_MAX_SBALES_PER_REQ * 8) |
113 | /* max. number of (data buffer) SBALEs in largest SBAL chain | 91 | /* max. number of (data buffer) SBALEs in largest SBAL chain |
114 | multiplied with number of sectors per 4k block */ | 92 | multiplied with number of sectors per 4k block */ |
115 | 93 | ||
116 | /* FIXME(tune): free space should be one max. SBAL chain plus what? */ | ||
117 | #define ZFCP_QDIO_PCI_INTERVAL (QDIO_MAX_BUFFERS_PER_Q \ | ||
118 | - (ZFCP_MAX_SBALS_PER_REQ + 4)) | ||
119 | |||
120 | #define ZFCP_SBAL_TIMEOUT (5*HZ) | ||
121 | |||
122 | #define ZFCP_TYPE2_RECOVERY_TIME 8 /* seconds */ | ||
123 | |||
124 | /* queue polling (values in microseconds) */ | ||
125 | #define ZFCP_MAX_INPUT_THRESHOLD 5000 /* FIXME: tune */ | ||
126 | #define ZFCP_MAX_OUTPUT_THRESHOLD 1000 /* FIXME: tune */ | ||
127 | #define ZFCP_MIN_INPUT_THRESHOLD 1 /* ignored by QDIO layer */ | ||
128 | #define ZFCP_MIN_OUTPUT_THRESHOLD 1 /* ignored by QDIO layer */ | ||
129 | |||
130 | #define QDIO_SCSI_QFMT 1 /* 1 for FSF */ | ||
131 | #define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) | ||
132 | |||
133 | /********************* FSF SPECIFIC DEFINES *********************************/ | 94 | /********************* FSF SPECIFIC DEFINES *********************************/ |
134 | 95 | ||
135 | #define ZFCP_ULP_INFO_VERSION 26 | ||
136 | #define ZFCP_QTCB_VERSION FSF_QTCB_CURRENT_VERSION | ||
137 | /* ATTENTION: value must not be used by hardware */ | 96 | /* ATTENTION: value must not be used by hardware */ |
138 | #define FSF_QTCB_UNSOLICITED_STATUS 0x6305 | 97 | #define FSF_QTCB_UNSOLICITED_STATUS 0x6305 |
139 | #define ZFCP_STATUS_READ_FAILED_THRESHOLD 3 | ||
140 | #define ZFCP_STATUS_READS_RECOM FSF_STATUS_READS_RECOM | ||
141 | |||
142 | /* Do 1st retry in 1 second, then double the timeout for each following retry */ | ||
143 | #define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP 1 | ||
144 | #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 7 | ||
145 | 98 | ||
146 | /* timeout value for "default timer" for fsf requests */ | 99 | /* timeout value for "default timer" for fsf requests */ |
147 | #define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ) | 100 | #define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ) |
@@ -153,17 +106,9 @@ typedef unsigned long long fcp_lun_t; | |||
153 | /* data length field may be at variable position in FCP-2 FCP_CMND IU */ | 106 | /* data length field may be at variable position in FCP-2 FCP_CMND IU */ |
154 | typedef unsigned int fcp_dl_t; | 107 | typedef unsigned int fcp_dl_t; |
155 | 108 | ||
156 | #define ZFCP_FC_SERVICE_CLASS_DEFAULT FSF_CLASS_3 | ||
157 | |||
158 | /* timeout for name-server lookup (in seconds) */ | 109 | /* timeout for name-server lookup (in seconds) */ |
159 | #define ZFCP_NS_GID_PN_TIMEOUT 10 | 110 | #define ZFCP_NS_GID_PN_TIMEOUT 10 |
160 | 111 | ||
161 | /* largest SCSI command we can process */ | ||
162 | /* FCP-2 (FCP_CMND IU) allows up to (255-3+16) */ | ||
163 | #define ZFCP_MAX_SCSI_CMND_LENGTH 255 | ||
164 | /* maximum number of commands in LUN queue (tagged queueing) */ | ||
165 | #define ZFCP_CMND_PER_LUN 32 | ||
166 | |||
167 | /* task attribute values in FCP-2 FCP_CMND IU */ | 112 | /* task attribute values in FCP-2 FCP_CMND IU */ |
168 | #define SIMPLE_Q 0 | 113 | #define SIMPLE_Q 0 |
169 | #define HEAD_OF_Q 1 | 114 | #define HEAD_OF_Q 1 |
@@ -224,9 +169,9 @@ struct fcp_rsp_iu { | |||
224 | #define RSP_CODE_TASKMAN_FAILED 5 | 169 | #define RSP_CODE_TASKMAN_FAILED 5 |
225 | 170 | ||
226 | /* see fc-fs */ | 171 | /* see fc-fs */ |
227 | #define LS_RSCN 0x61040000 | 172 | #define LS_RSCN 0x61 |
228 | #define LS_LOGO 0x05000000 | 173 | #define LS_LOGO 0x05 |
229 | #define LS_PLOGI 0x03000000 | 174 | #define LS_PLOGI 0x03 |
230 | 175 | ||
231 | struct fcp_rscn_head { | 176 | struct fcp_rscn_head { |
232 | u8 command; | 177 | u8 command; |
@@ -266,7 +211,6 @@ struct fcp_logo { | |||
266 | * FC-FS stuff | 211 | * FC-FS stuff |
267 | */ | 212 | */ |
268 | #define R_A_TOV 10 /* seconds */ | 213 | #define R_A_TOV 10 /* seconds */ |
269 | #define ZFCP_ELS_TIMEOUT (2 * R_A_TOV) | ||
270 | 214 | ||
271 | #define ZFCP_LS_RLS 0x0f | 215 | #define ZFCP_LS_RLS 0x0f |
272 | #define ZFCP_LS_ADISC 0x52 | 216 | #define ZFCP_LS_ADISC 0x52 |
@@ -311,7 +255,10 @@ struct zfcp_rc_entry { | |||
311 | #define ZFCP_CT_DIRECTORY_SERVICE 0xFC | 255 | #define ZFCP_CT_DIRECTORY_SERVICE 0xFC |
312 | #define ZFCP_CT_NAME_SERVER 0x02 | 256 | #define ZFCP_CT_NAME_SERVER 0x02 |
313 | #define ZFCP_CT_SYNCHRONOUS 0x00 | 257 | #define ZFCP_CT_SYNCHRONOUS 0x00 |
258 | #define ZFCP_CT_SCSI_FCP 0x08 | ||
259 | #define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09 | ||
314 | #define ZFCP_CT_GID_PN 0x0121 | 260 | #define ZFCP_CT_GID_PN 0x0121 |
261 | #define ZFCP_CT_GPN_FT 0x0172 | ||
315 | #define ZFCP_CT_MAX_SIZE 0x1020 | 262 | #define ZFCP_CT_MAX_SIZE 0x1020 |
316 | #define ZFCP_CT_ACCEPT 0x8002 | 263 | #define ZFCP_CT_ACCEPT 0x8002 |
317 | #define ZFCP_CT_REJECT 0x8001 | 264 | #define ZFCP_CT_REJECT 0x8001 |
@@ -321,107 +268,6 @@ struct zfcp_rc_entry { | |||
321 | */ | 268 | */ |
322 | #define ZFCP_CT_TIMEOUT (3 * R_A_TOV) | 269 | #define ZFCP_CT_TIMEOUT (3 * R_A_TOV) |
323 | 270 | ||
324 | /******************** LOGGING MACROS AND DEFINES *****************************/ | ||
325 | |||
326 | /* | ||
327 | * Logging may be applied on certain kinds of driver operations | ||
328 | * independently. Additionally, different log-levels are supported for | ||
329 | * each of these areas. | ||
330 | */ | ||
331 | |||
332 | #define ZFCP_NAME "zfcp" | ||
333 | |||
334 | /* independent log areas */ | ||
335 | #define ZFCP_LOG_AREA_OTHER 0 | ||
336 | #define ZFCP_LOG_AREA_SCSI 1 | ||
337 | #define ZFCP_LOG_AREA_FSF 2 | ||
338 | #define ZFCP_LOG_AREA_CONFIG 3 | ||
339 | #define ZFCP_LOG_AREA_CIO 4 | ||
340 | #define ZFCP_LOG_AREA_QDIO 5 | ||
341 | #define ZFCP_LOG_AREA_ERP 6 | ||
342 | #define ZFCP_LOG_AREA_FC 7 | ||
343 | |||
344 | /* log level values*/ | ||
345 | #define ZFCP_LOG_LEVEL_NORMAL 0 | ||
346 | #define ZFCP_LOG_LEVEL_INFO 1 | ||
347 | #define ZFCP_LOG_LEVEL_DEBUG 2 | ||
348 | #define ZFCP_LOG_LEVEL_TRACE 3 | ||
349 | |||
350 | /* | ||
351 | * this allows removal of logging code by the preprocessor | ||
352 | * (the most detailed log level still to be compiled in is specified, | ||
353 | * higher log levels are removed) | ||
354 | */ | ||
355 | #define ZFCP_LOG_LEVEL_LIMIT ZFCP_LOG_LEVEL_TRACE | ||
356 | |||
357 | /* get "loglevel" nibble assignment */ | ||
358 | #define ZFCP_GET_LOG_VALUE(zfcp_lognibble) \ | ||
359 | ((atomic_read(&zfcp_data.loglevel) >> (zfcp_lognibble<<2)) & 0xF) | ||
360 | |||
361 | /* set "loglevel" nibble */ | ||
362 | #define ZFCP_SET_LOG_NIBBLE(value, zfcp_lognibble) \ | ||
363 | (value << (zfcp_lognibble << 2)) | ||
364 | |||
365 | /* all log-level defaults are combined to generate initial log-level */ | ||
366 | #define ZFCP_LOG_LEVEL_DEFAULTS \ | ||
367 | (ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_OTHER) | \ | ||
368 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_SCSI) | \ | ||
369 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_FSF) | \ | ||
370 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_CONFIG) | \ | ||
371 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_CIO) | \ | ||
372 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_QDIO) | \ | ||
373 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_ERP) | \ | ||
374 | ZFCP_SET_LOG_NIBBLE(ZFCP_LOG_LEVEL_NORMAL, ZFCP_LOG_AREA_FC)) | ||
375 | |||
376 | /* check whether we have the right level for logging */ | ||
377 | #define ZFCP_LOG_CHECK(level) \ | ||
378 | ((ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA)) >= level) | ||
379 | |||
380 | /* logging routine for zfcp */ | ||
381 | #define _ZFCP_LOG(fmt, args...) \ | ||
382 | printk(KERN_ERR ZFCP_NAME": %s(%d): " fmt, __func__, \ | ||
383 | __LINE__ , ##args) | ||
384 | |||
385 | #define ZFCP_LOG(level, fmt, args...) \ | ||
386 | do { \ | ||
387 | if (ZFCP_LOG_CHECK(level)) \ | ||
388 | _ZFCP_LOG(fmt, ##args); \ | ||
389 | } while (0) | ||
390 | |||
391 | #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL | ||
392 | # define ZFCP_LOG_NORMAL(fmt, args...) do { } while (0) | ||
393 | #else | ||
394 | # define ZFCP_LOG_NORMAL(fmt, args...) \ | ||
395 | do { \ | ||
396 | if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_NORMAL)) \ | ||
397 | printk(KERN_ERR ZFCP_NAME": " fmt, ##args); \ | ||
398 | } while (0) | ||
399 | #endif | ||
400 | |||
401 | #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_INFO | ||
402 | # define ZFCP_LOG_INFO(fmt, args...) do { } while (0) | ||
403 | #else | ||
404 | # define ZFCP_LOG_INFO(fmt, args...) \ | ||
405 | do { \ | ||
406 | if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_INFO)) \ | ||
407 | printk(KERN_ERR ZFCP_NAME": " fmt, ##args); \ | ||
408 | } while (0) | ||
409 | #endif | ||
410 | |||
411 | #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_DEBUG | ||
412 | # define ZFCP_LOG_DEBUG(fmt, args...) do { } while (0) | ||
413 | #else | ||
414 | # define ZFCP_LOG_DEBUG(fmt, args...) \ | ||
415 | ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, fmt , ##args) | ||
416 | #endif | ||
417 | |||
418 | #if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_TRACE | ||
419 | # define ZFCP_LOG_TRACE(fmt, args...) do { } while (0) | ||
420 | #else | ||
421 | # define ZFCP_LOG_TRACE(fmt, args...) \ | ||
422 | ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, fmt , ##args) | ||
423 | #endif | ||
424 | |||
425 | /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/ | 271 | /*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/ |
426 | 272 | ||
427 | /* | 273 | /* |
@@ -441,6 +287,7 @@ do { \ | |||
441 | #define ZFCP_STATUS_COMMON_ERP_INUSE 0x01000000 | 287 | #define ZFCP_STATUS_COMMON_ERP_INUSE 0x01000000 |
442 | #define ZFCP_STATUS_COMMON_ACCESS_DENIED 0x00800000 | 288 | #define ZFCP_STATUS_COMMON_ACCESS_DENIED 0x00800000 |
443 | #define ZFCP_STATUS_COMMON_ACCESS_BOXED 0x00400000 | 289 | #define ZFCP_STATUS_COMMON_ACCESS_BOXED 0x00400000 |
290 | #define ZFCP_STATUS_COMMON_NOESC 0x00200000 | ||
444 | 291 | ||
445 | /* adapter status */ | 292 | /* adapter status */ |
446 | #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 | 293 | #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 |
@@ -496,77 +343,6 @@ do { \ | |||
496 | #define ZFCP_STATUS_FSFREQ_RETRY 0x00000800 | 343 | #define ZFCP_STATUS_FSFREQ_RETRY 0x00000800 |
497 | #define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000 | 344 | #define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000 |
498 | 345 | ||
499 | /*********************** ERROR RECOVERY PROCEDURE DEFINES ********************/ | ||
500 | |||
501 | #define ZFCP_MAX_ERPS 3 | ||
502 | |||
503 | #define ZFCP_ERP_FSFREQ_TIMEOUT (30 * HZ) | ||
504 | #define ZFCP_ERP_MEMWAIT_TIMEOUT HZ | ||
505 | |||
506 | #define ZFCP_STATUS_ERP_TIMEDOUT 0x10000000 | ||
507 | #define ZFCP_STATUS_ERP_CLOSE_ONLY 0x01000000 | ||
508 | #define ZFCP_STATUS_ERP_DISMISSING 0x00100000 | ||
509 | #define ZFCP_STATUS_ERP_DISMISSED 0x00200000 | ||
510 | #define ZFCP_STATUS_ERP_LOWMEM 0x00400000 | ||
511 | |||
512 | #define ZFCP_ERP_STEP_UNINITIALIZED 0x00000000 | ||
513 | #define ZFCP_ERP_STEP_FSF_XCONFIG 0x00000001 | ||
514 | #define ZFCP_ERP_STEP_PHYS_PORT_CLOSING 0x00000010 | ||
515 | #define ZFCP_ERP_STEP_PORT_CLOSING 0x00000100 | ||
516 | #define ZFCP_ERP_STEP_NAMESERVER_OPEN 0x00000200 | ||
517 | #define ZFCP_ERP_STEP_NAMESERVER_LOOKUP 0x00000400 | ||
518 | #define ZFCP_ERP_STEP_PORT_OPENING 0x00000800 | ||
519 | #define ZFCP_ERP_STEP_UNIT_CLOSING 0x00001000 | ||
520 | #define ZFCP_ERP_STEP_UNIT_OPENING 0x00002000 | ||
521 | |||
522 | /* Ordered by escalation level (necessary for proper erp-code operation) */ | ||
523 | #define ZFCP_ERP_ACTION_REOPEN_ADAPTER 0x4 | ||
524 | #define ZFCP_ERP_ACTION_REOPEN_PORT_FORCED 0x3 | ||
525 | #define ZFCP_ERP_ACTION_REOPEN_PORT 0x2 | ||
526 | #define ZFCP_ERP_ACTION_REOPEN_UNIT 0x1 | ||
527 | |||
528 | #define ZFCP_ERP_ACTION_RUNNING 0x1 | ||
529 | #define ZFCP_ERP_ACTION_READY 0x2 | ||
530 | |||
531 | #define ZFCP_ERP_SUCCEEDED 0x0 | ||
532 | #define ZFCP_ERP_FAILED 0x1 | ||
533 | #define ZFCP_ERP_CONTINUES 0x2 | ||
534 | #define ZFCP_ERP_EXIT 0x3 | ||
535 | #define ZFCP_ERP_DISMISSED 0x4 | ||
536 | #define ZFCP_ERP_NOMEM 0x5 | ||
537 | |||
538 | |||
539 | /******************** CFDC SPECIFIC STUFF *****************************/ | ||
540 | |||
541 | /* Firewall data channel sense data record */ | ||
542 | struct zfcp_cfdc_sense_data { | ||
543 | u32 signature; /* Request signature */ | ||
544 | u32 devno; /* FCP adapter device number */ | ||
545 | u32 command; /* Command code */ | ||
546 | u32 fsf_status; /* FSF request status and status qualifier */ | ||
547 | u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; | ||
548 | u8 payloads[256]; /* Access conflicts list */ | ||
549 | u8 control_file[0]; /* Access control table */ | ||
550 | }; | ||
551 | |||
552 | #define ZFCP_CFDC_SIGNATURE 0xCFDCACDF | ||
553 | |||
554 | #define ZFCP_CFDC_CMND_DOWNLOAD_NORMAL 0x00010001 | ||
555 | #define ZFCP_CFDC_CMND_DOWNLOAD_FORCE 0x00010101 | ||
556 | #define ZFCP_CFDC_CMND_FULL_ACCESS 0x00000201 | ||
557 | #define ZFCP_CFDC_CMND_RESTRICTED_ACCESS 0x00000401 | ||
558 | #define ZFCP_CFDC_CMND_UPLOAD 0x00010002 | ||
559 | |||
560 | #define ZFCP_CFDC_DOWNLOAD 0x00000001 | ||
561 | #define ZFCP_CFDC_UPLOAD 0x00000002 | ||
562 | #define ZFCP_CFDC_WITH_CONTROL_FILE 0x00010000 | ||
563 | |||
564 | #define ZFCP_CFDC_DEV_NAME "zfcp_cfdc" | ||
565 | #define ZFCP_CFDC_DEV_MAJOR MISC_MAJOR | ||
566 | #define ZFCP_CFDC_DEV_MINOR MISC_DYNAMIC_MINOR | ||
567 | |||
568 | #define ZFCP_CFDC_MAX_CONTROL_FILE_SIZE 127 * 1024 | ||
569 | |||
570 | /************************* STRUCTURE DEFINITIONS *****************************/ | 346 | /************************* STRUCTURE DEFINITIONS *****************************/ |
571 | 347 | ||
572 | struct zfcp_fsf_req; | 348 | struct zfcp_fsf_req; |
@@ -623,7 +399,6 @@ typedef void (*zfcp_send_ct_handler_t)(unsigned long); | |||
623 | * @resp_count: number of elements in response scatter-gather list | 399 | * @resp_count: number of elements in response scatter-gather list |
624 | * @handler: handler function (called for response to the request) | 400 | * @handler: handler function (called for response to the request) |
625 | * @handler_data: data passed to handler function | 401 | * @handler_data: data passed to handler function |
626 | * @pool: pointer to memory pool for ct request structure | ||
627 | * @timeout: FSF timeout for this request | 402 | * @timeout: FSF timeout for this request |
628 | * @completion: completion for synchronization purposes | 403 | * @completion: completion for synchronization purposes |
629 | * @status: used to pass error status to calling function | 404 | * @status: used to pass error status to calling function |
@@ -636,7 +411,6 @@ struct zfcp_send_ct { | |||
636 | unsigned int resp_count; | 411 | unsigned int resp_count; |
637 | zfcp_send_ct_handler_t handler; | 412 | zfcp_send_ct_handler_t handler; |
638 | unsigned long handler_data; | 413 | unsigned long handler_data; |
639 | mempool_t *pool; | ||
640 | int timeout; | 414 | int timeout; |
641 | struct completion *completion; | 415 | struct completion *completion; |
642 | int status; | 416 | int status; |
@@ -685,13 +459,13 @@ struct zfcp_send_els { | |||
685 | }; | 459 | }; |
686 | 460 | ||
687 | struct zfcp_qdio_queue { | 461 | struct zfcp_qdio_queue { |
688 | struct qdio_buffer *buffer[QDIO_MAX_BUFFERS_PER_Q]; /* SBALs */ | 462 | struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; /* SBALs */ |
689 | u8 free_index; /* index of next free bfr | 463 | u8 first; /* index of next free bfr |
690 | in queue (free_count>0) */ | 464 | in queue (free_count>0) */ |
691 | atomic_t free_count; /* number of free buffers | 465 | atomic_t count; /* number of free buffers |
692 | in queue */ | 466 | in queue */ |
693 | rwlock_t queue_lock; /* lock for operations on queue */ | 467 | spinlock_t lock; /* lock for operations on queue */ |
694 | int distance_from_int; /* SBALs used since PCI indication | 468 | int pci_batch; /* SBALs since PCI indication |
695 | was last set */ | 469 | was last set */ |
696 | }; | 470 | }; |
697 | 471 | ||
@@ -708,6 +482,24 @@ struct zfcp_erp_action { | |||
708 | struct timer_list timer; | 482 | struct timer_list timer; |
709 | }; | 483 | }; |
710 | 484 | ||
485 | struct fsf_latency_record { | ||
486 | u32 min; | ||
487 | u32 max; | ||
488 | u64 sum; | ||
489 | }; | ||
490 | |||
491 | struct latency_cont { | ||
492 | struct fsf_latency_record channel; | ||
493 | struct fsf_latency_record fabric; | ||
494 | u64 counter; | ||
495 | }; | ||
496 | |||
497 | struct zfcp_latencies { | ||
498 | struct latency_cont read; | ||
499 | struct latency_cont write; | ||
500 | struct latency_cont cmd; | ||
501 | spinlock_t lock; | ||
502 | }; | ||
711 | 503 | ||
712 | struct zfcp_adapter { | 504 | struct zfcp_adapter { |
713 | struct list_head list; /* list of adapters */ | 505 | struct list_head list; /* list of adapters */ |
@@ -723,24 +515,25 @@ struct zfcp_adapter { | |||
723 | u32 adapter_features; /* FCP channel features */ | 515 | u32 adapter_features; /* FCP channel features */ |
724 | u32 connection_features; /* host connection features */ | 516 | u32 connection_features; /* host connection features */ |
725 | u32 hardware_version; /* of FCP channel */ | 517 | u32 hardware_version; /* of FCP channel */ |
518 | u16 timer_ticks; /* time int for a tick */ | ||
726 | struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ | 519 | struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ |
727 | struct list_head port_list_head; /* remote port list */ | 520 | struct list_head port_list_head; /* remote port list */ |
728 | struct list_head port_remove_lh; /* head of ports to be | 521 | struct list_head port_remove_lh; /* head of ports to be |
729 | removed */ | 522 | removed */ |
730 | u32 ports; /* number of remote ports */ | 523 | u32 ports; /* number of remote ports */ |
731 | atomic_t reqs_active; /* # active FSF reqs */ | ||
732 | unsigned long req_no; /* unique FSF req number */ | 524 | unsigned long req_no; /* unique FSF req number */ |
733 | struct list_head *req_list; /* list of pending reqs */ | 525 | struct list_head *req_list; /* list of pending reqs */ |
734 | spinlock_t req_list_lock; /* request list lock */ | 526 | spinlock_t req_list_lock; /* request list lock */ |
735 | struct zfcp_qdio_queue request_queue; /* request queue */ | 527 | struct zfcp_qdio_queue req_q; /* request queue */ |
736 | u32 fsf_req_seq_no; /* FSF cmnd seq number */ | 528 | u32 fsf_req_seq_no; /* FSF cmnd seq number */ |
737 | wait_queue_head_t request_wq; /* can be used to wait for | 529 | wait_queue_head_t request_wq; /* can be used to wait for |
738 | more avaliable SBALs */ | 530 | more avaliable SBALs */ |
739 | struct zfcp_qdio_queue response_queue; /* response queue */ | 531 | struct zfcp_qdio_queue resp_q; /* response queue */ |
740 | rwlock_t abort_lock; /* Protects against SCSI | 532 | rwlock_t abort_lock; /* Protects against SCSI |
741 | stack abort/command | 533 | stack abort/command |
742 | completion races */ | 534 | completion races */ |
743 | u16 status_read_failed; /* # failed status reads */ | 535 | atomic_t stat_miss; /* # missing status reads*/ |
536 | struct work_struct stat_work; | ||
744 | atomic_t status; /* status of this adapter */ | 537 | atomic_t status; /* status of this adapter */ |
745 | struct list_head erp_ready_head; /* error recovery for this | 538 | struct list_head erp_ready_head; /* error recovery for this |
746 | adapter/devices */ | 539 | adapter/devices */ |
@@ -774,13 +567,9 @@ struct zfcp_adapter { | |||
774 | struct fc_host_statistics *fc_stats; | 567 | struct fc_host_statistics *fc_stats; |
775 | struct fsf_qtcb_bottom_port *stats_reset_data; | 568 | struct fsf_qtcb_bottom_port *stats_reset_data; |
776 | unsigned long stats_reset; | 569 | unsigned long stats_reset; |
570 | struct work_struct scan_work; | ||
777 | }; | 571 | }; |
778 | 572 | ||
779 | /* | ||
780 | * the struct device sysfs_device must be at the beginning of this structure. | ||
781 | * pointer to struct device is used to free port structure in release function | ||
782 | * of the device. don't change! | ||
783 | */ | ||
784 | struct zfcp_port { | 573 | struct zfcp_port { |
785 | struct device sysfs_device; /* sysfs device */ | 574 | struct device sysfs_device; /* sysfs device */ |
786 | struct fc_rport *rport; /* rport of fc transport class */ | 575 | struct fc_rport *rport; /* rport of fc transport class */ |
@@ -804,10 +593,6 @@ struct zfcp_port { | |||
804 | u32 supported_classes; | 593 | u32 supported_classes; |
805 | }; | 594 | }; |
806 | 595 | ||
807 | /* the struct device sysfs_device must be at the beginning of this structure. | ||
808 | * pointer to struct device is used to free unit structure in release function | ||
809 | * of the device. don't change! | ||
810 | */ | ||
811 | struct zfcp_unit { | 596 | struct zfcp_unit { |
812 | struct device sysfs_device; /* sysfs device */ | 597 | struct device sysfs_device; /* sysfs device */ |
813 | struct list_head list; /* list of logical units */ | 598 | struct list_head list; /* list of logical units */ |
@@ -822,6 +607,7 @@ struct zfcp_unit { | |||
822 | struct scsi_device *device; /* scsi device struct pointer */ | 607 | struct scsi_device *device; /* scsi device struct pointer */ |
823 | struct zfcp_erp_action erp_action; /* pending error recovery */ | 608 | struct zfcp_erp_action erp_action; /* pending error recovery */ |
824 | atomic_t erp_counter; | 609 | atomic_t erp_counter; |
610 | struct zfcp_latencies latencies; | ||
825 | }; | 611 | }; |
826 | 612 | ||
827 | /* FSF request */ | 613 | /* FSF request */ |
@@ -831,19 +617,19 @@ struct zfcp_fsf_req { | |||
831 | struct zfcp_adapter *adapter; /* adapter request belongs to */ | 617 | struct zfcp_adapter *adapter; /* adapter request belongs to */ |
832 | u8 sbal_number; /* nr of SBALs free for use */ | 618 | u8 sbal_number; /* nr of SBALs free for use */ |
833 | u8 sbal_first; /* first SBAL for this request */ | 619 | u8 sbal_first; /* first SBAL for this request */ |
834 | u8 sbal_last; /* last possible SBAL for | 620 | u8 sbal_last; /* last SBAL for this request */ |
621 | u8 sbal_limit; /* last possible SBAL for | ||
835 | this reuest */ | 622 | this reuest */ |
836 | u8 sbal_curr; /* current SBAL during creation | ||
837 | of request */ | ||
838 | u8 sbale_curr; /* current SBALE during creation | 623 | u8 sbale_curr; /* current SBALE during creation |
839 | of request */ | 624 | of request */ |
625 | u8 sbal_response; /* SBAL used in interrupt */ | ||
840 | wait_queue_head_t completion_wq; /* can be used by a routine | 626 | wait_queue_head_t completion_wq; /* can be used by a routine |
841 | to wait for completion */ | 627 | to wait for completion */ |
842 | volatile u32 status; /* status of this request */ | 628 | volatile u32 status; /* status of this request */ |
843 | u32 fsf_command; /* FSF Command copy */ | 629 | u32 fsf_command; /* FSF Command copy */ |
844 | struct fsf_qtcb *qtcb; /* address of associated QTCB */ | 630 | struct fsf_qtcb *qtcb; /* address of associated QTCB */ |
845 | u32 seq_no; /* Sequence number of request */ | 631 | u32 seq_no; /* Sequence number of request */ |
846 | unsigned long data; /* private data of request */ | 632 | void *data; /* private data of request */ |
847 | struct timer_list timer; /* used for erp or scsi er */ | 633 | struct timer_list timer; /* used for erp or scsi er */ |
848 | struct zfcp_erp_action *erp_action; /* used if this request is | 634 | struct zfcp_erp_action *erp_action; /* used if this request is |
849 | issued on behalf of erp */ | 635 | issued on behalf of erp */ |
@@ -851,10 +637,9 @@ struct zfcp_fsf_req { | |||
851 | from emergency pool */ | 637 | from emergency pool */ |
852 | unsigned long long issued; /* request sent time (STCK) */ | 638 | unsigned long long issued; /* request sent time (STCK) */ |
853 | struct zfcp_unit *unit; | 639 | struct zfcp_unit *unit; |
640 | void (*handler)(struct zfcp_fsf_req *); | ||
854 | }; | 641 | }; |
855 | 642 | ||
856 | typedef void zfcp_fsf_req_handler_t(struct zfcp_fsf_req*); | ||
857 | |||
858 | /* driver data */ | 643 | /* driver data */ |
859 | struct zfcp_data { | 644 | struct zfcp_data { |
860 | struct scsi_host_template scsi_host_template; | 645 | struct scsi_host_template scsi_host_template; |
@@ -873,29 +658,11 @@ struct zfcp_data { | |||
873 | char init_busid[BUS_ID_SIZE]; | 658 | char init_busid[BUS_ID_SIZE]; |
874 | wwn_t init_wwpn; | 659 | wwn_t init_wwpn; |
875 | fcp_lun_t init_fcp_lun; | 660 | fcp_lun_t init_fcp_lun; |
876 | char *driver_version; | ||
877 | struct kmem_cache *fsf_req_qtcb_cache; | 661 | struct kmem_cache *fsf_req_qtcb_cache; |
878 | struct kmem_cache *sr_buffer_cache; | 662 | struct kmem_cache *sr_buffer_cache; |
879 | struct kmem_cache *gid_pn_cache; | 663 | struct kmem_cache *gid_pn_cache; |
880 | }; | 664 | }; |
881 | 665 | ||
882 | /** | ||
883 | * struct zfcp_sg_list - struct describing a scatter-gather list | ||
884 | * @sg: pointer to array of (struct scatterlist) | ||
885 | * @count: number of elements in scatter-gather list | ||
886 | */ | ||
887 | struct zfcp_sg_list { | ||
888 | struct scatterlist *sg; | ||
889 | unsigned int count; | ||
890 | }; | ||
891 | |||
892 | /* number of elements for various memory pools */ | ||
893 | #define ZFCP_POOL_FSF_REQ_ERP_NR 1 | ||
894 | #define ZFCP_POOL_FSF_REQ_SCSI_NR 1 | ||
895 | #define ZFCP_POOL_FSF_REQ_ABORT_NR 1 | ||
896 | #define ZFCP_POOL_STATUS_READ_NR ZFCP_STATUS_READS_RECOM | ||
897 | #define ZFCP_POOL_DATA_GID_PN_NR 1 | ||
898 | |||
899 | /* struct used by memory pools for fsf_requests */ | 666 | /* struct used by memory pools for fsf_requests */ |
900 | struct zfcp_fsf_req_qtcb { | 667 | struct zfcp_fsf_req_qtcb { |
901 | struct zfcp_fsf_req fsf_req; | 668 | struct zfcp_fsf_req fsf_req; |
@@ -905,7 +672,6 @@ struct zfcp_fsf_req_qtcb { | |||
905 | /********************** ZFCP SPECIFIC DEFINES ********************************/ | 672 | /********************** ZFCP SPECIFIC DEFINES ********************************/ |
906 | 673 | ||
907 | #define ZFCP_REQ_AUTO_CLEANUP 0x00000002 | 674 | #define ZFCP_REQ_AUTO_CLEANUP 0x00000002 |
908 | #define ZFCP_WAIT_FOR_SBAL 0x00000004 | ||
909 | #define ZFCP_REQ_NO_QTCB 0x00000008 | 675 | #define ZFCP_REQ_NO_QTCB 0x00000008 |
910 | 676 | ||
911 | #define ZFCP_SET 0x00000100 | 677 | #define ZFCP_SET 0x00000100 |
@@ -916,12 +682,6 @@ struct zfcp_fsf_req_qtcb { | |||
916 | ((atomic_read(target) & mask) == mask) | 682 | ((atomic_read(target) & mask) == mask) |
917 | #endif | 683 | #endif |
918 | 684 | ||
919 | extern void _zfcp_hex_dump(char *, int); | ||
920 | #define ZFCP_HEX_DUMP(level, addr, count) \ | ||
921 | if (ZFCP_LOG_CHECK(level)) { \ | ||
922 | _zfcp_hex_dump(addr, count); \ | ||
923 | } | ||
924 | |||
925 | #define zfcp_get_busid_by_adapter(adapter) (adapter->ccw_device->dev.bus_id) | 685 | #define zfcp_get_busid_by_adapter(adapter) (adapter->ccw_device->dev.bus_id) |
926 | #define zfcp_get_busid_by_port(port) (zfcp_get_busid_by_adapter(port->adapter)) | 686 | #define zfcp_get_busid_by_port(port) (zfcp_get_busid_by_adapter(port->adapter)) |
927 | #define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port)) | 687 | #define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port)) |
@@ -934,15 +694,6 @@ static inline int zfcp_reqlist_hash(unsigned long req_id) | |||
934 | return req_id % REQUEST_LIST_SIZE; | 694 | return req_id % REQUEST_LIST_SIZE; |
935 | } | 695 | } |
936 | 696 | ||
937 | static inline void zfcp_reqlist_add(struct zfcp_adapter *adapter, | ||
938 | struct zfcp_fsf_req *fsf_req) | ||
939 | { | ||
940 | unsigned int idx; | ||
941 | |||
942 | idx = zfcp_reqlist_hash(fsf_req->req_id); | ||
943 | list_add_tail(&fsf_req->list, &adapter->req_list[idx]); | ||
944 | } | ||
945 | |||
946 | static inline void zfcp_reqlist_remove(struct zfcp_adapter *adapter, | 697 | static inline void zfcp_reqlist_remove(struct zfcp_adapter *adapter, |
947 | struct zfcp_fsf_req *fsf_req) | 698 | struct zfcp_fsf_req *fsf_req) |
948 | { | 699 | { |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 805484658dd9..643ac4bba5b5 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -1,641 +1,406 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Error Recovery Procedures (ERP). |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP | ||
23 | |||
24 | #include "zfcp_ext.h" | 9 | #include "zfcp_ext.h" |
25 | 10 | ||
26 | static int zfcp_erp_adisc(struct zfcp_port *); | 11 | #define ZFCP_MAX_ERPS 3 |
27 | static void zfcp_erp_adisc_handler(unsigned long); | ||
28 | |||
29 | static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int, u8, | ||
30 | void *); | ||
31 | static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int, u8, | ||
32 | void *); | ||
33 | static int zfcp_erp_port_reopen_internal(struct zfcp_port *, int, u8, void *); | ||
34 | static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *, int, u8, void *); | ||
35 | |||
36 | static int zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *, int, u8, | ||
37 | void *); | ||
38 | static int zfcp_erp_unit_reopen_all_internal(struct zfcp_port *, int, u8, | ||
39 | void *); | ||
40 | |||
41 | static void zfcp_erp_adapter_block(struct zfcp_adapter *, int); | ||
42 | static void zfcp_erp_adapter_unblock(struct zfcp_adapter *); | ||
43 | static void zfcp_erp_port_block(struct zfcp_port *, int); | ||
44 | static void zfcp_erp_port_unblock(struct zfcp_port *); | ||
45 | static void zfcp_erp_unit_block(struct zfcp_unit *, int); | ||
46 | static void zfcp_erp_unit_unblock(struct zfcp_unit *); | ||
47 | |||
48 | static int zfcp_erp_thread(void *); | ||
49 | |||
50 | static int zfcp_erp_strategy(struct zfcp_erp_action *); | ||
51 | |||
52 | static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *); | ||
53 | static int zfcp_erp_strategy_memwait(struct zfcp_erp_action *); | ||
54 | static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *, int); | ||
55 | static int zfcp_erp_strategy_check_unit(struct zfcp_unit *, int); | ||
56 | static int zfcp_erp_strategy_check_port(struct zfcp_port *, int); | ||
57 | static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int); | ||
58 | static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *, | ||
59 | struct zfcp_port *, | ||
60 | struct zfcp_unit *, int); | ||
61 | static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32); | ||
62 | static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *, | ||
63 | struct zfcp_port *, | ||
64 | struct zfcp_unit *, int); | ||
65 | static int zfcp_erp_strategy_check_queues(struct zfcp_adapter *); | ||
66 | static int zfcp_erp_strategy_check_action(struct zfcp_erp_action *, int); | ||
67 | |||
68 | static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *); | ||
69 | static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *, int); | ||
70 | static int zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *); | ||
71 | static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *); | ||
72 | static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *); | ||
73 | static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *); | ||
74 | static int zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *); | ||
75 | static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *); | ||
76 | static int zfcp_erp_adapter_strategy_open_fsf_statusread( | ||
77 | struct zfcp_erp_action *); | ||
78 | |||
79 | static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *); | ||
80 | static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *); | ||
81 | |||
82 | static int zfcp_erp_port_strategy(struct zfcp_erp_action *); | ||
83 | static int zfcp_erp_port_strategy_clearstati(struct zfcp_port *); | ||
84 | static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *); | ||
85 | static int zfcp_erp_port_strategy_open(struct zfcp_erp_action *); | ||
86 | static int zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *); | ||
87 | static int zfcp_erp_port_strategy_open_nameserver_wakeup( | ||
88 | struct zfcp_erp_action *); | ||
89 | static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *); | ||
90 | static int zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *); | ||
91 | static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *); | ||
92 | |||
93 | static int zfcp_erp_unit_strategy(struct zfcp_erp_action *); | ||
94 | static int zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *); | ||
95 | static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *); | ||
96 | static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *); | ||
97 | |||
98 | static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *); | ||
99 | static void zfcp_erp_action_dismiss_port(struct zfcp_port *); | ||
100 | static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *); | ||
101 | static void zfcp_erp_action_dismiss(struct zfcp_erp_action *); | ||
102 | |||
103 | static int zfcp_erp_action_enqueue(int, struct zfcp_adapter *, | ||
104 | struct zfcp_port *, struct zfcp_unit *, | ||
105 | u8 id, void *ref); | ||
106 | static int zfcp_erp_action_dequeue(struct zfcp_erp_action *); | ||
107 | static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *, | ||
108 | struct zfcp_port *, struct zfcp_unit *, | ||
109 | int); | ||
110 | |||
111 | static void zfcp_erp_action_ready(struct zfcp_erp_action *); | ||
112 | static int zfcp_erp_action_exists(struct zfcp_erp_action *); | ||
113 | |||
114 | static void zfcp_erp_action_to_ready(struct zfcp_erp_action *); | ||
115 | static void zfcp_erp_action_to_running(struct zfcp_erp_action *); | ||
116 | |||
117 | static void zfcp_erp_memwait_handler(unsigned long); | ||
118 | 12 | ||
119 | /** | 13 | enum zfcp_erp_act_flags { |
120 | * zfcp_close_qdio - close qdio queues for an adapter | 14 | ZFCP_STATUS_ERP_TIMEDOUT = 0x10000000, |
121 | */ | 15 | ZFCP_STATUS_ERP_CLOSE_ONLY = 0x01000000, |
122 | static void zfcp_close_qdio(struct zfcp_adapter *adapter) | 16 | ZFCP_STATUS_ERP_DISMISSING = 0x00100000, |
123 | { | 17 | ZFCP_STATUS_ERP_DISMISSED = 0x00200000, |
124 | struct zfcp_qdio_queue *req_queue; | 18 | ZFCP_STATUS_ERP_LOWMEM = 0x00400000, |
125 | int first, count; | 19 | }; |
126 | 20 | ||
127 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) | 21 | enum zfcp_erp_steps { |
128 | return; | 22 | ZFCP_ERP_STEP_UNINITIALIZED = 0x0000, |
23 | ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001, | ||
24 | ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010, | ||
25 | ZFCP_ERP_STEP_PORT_CLOSING = 0x0100, | ||
26 | ZFCP_ERP_STEP_NAMESERVER_OPEN = 0x0200, | ||
27 | ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400, | ||
28 | ZFCP_ERP_STEP_PORT_OPENING = 0x0800, | ||
29 | ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000, | ||
30 | ZFCP_ERP_STEP_UNIT_OPENING = 0x2000, | ||
31 | }; | ||
129 | 32 | ||
130 | /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ | 33 | enum zfcp_erp_act_type { |
131 | req_queue = &adapter->request_queue; | 34 | ZFCP_ERP_ACTION_REOPEN_UNIT = 1, |
132 | write_lock_irq(&req_queue->queue_lock); | 35 | ZFCP_ERP_ACTION_REOPEN_PORT = 2, |
133 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); | 36 | ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3, |
134 | write_unlock_irq(&req_queue->queue_lock); | 37 | ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4, |
135 | 38 | }; | |
136 | while (qdio_shutdown(adapter->ccw_device, | 39 | |
137 | QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) | 40 | enum zfcp_erp_act_state { |
138 | ssleep(1); | 41 | ZFCP_ERP_ACTION_RUNNING = 1, |
139 | 42 | ZFCP_ERP_ACTION_READY = 2, | |
140 | /* cleanup used outbound sbals */ | 43 | }; |
141 | count = atomic_read(&req_queue->free_count); | 44 | |
142 | if (count < QDIO_MAX_BUFFERS_PER_Q) { | 45 | enum zfcp_erp_act_result { |
143 | first = (req_queue->free_index+count) % QDIO_MAX_BUFFERS_PER_Q; | 46 | ZFCP_ERP_SUCCEEDED = 0, |
144 | count = QDIO_MAX_BUFFERS_PER_Q - count; | 47 | ZFCP_ERP_FAILED = 1, |
145 | zfcp_qdio_zero_sbals(req_queue->buffer, first, count); | 48 | ZFCP_ERP_CONTINUES = 2, |
146 | } | 49 | ZFCP_ERP_EXIT = 3, |
147 | req_queue->free_index = 0; | 50 | ZFCP_ERP_DISMISSED = 4, |
148 | atomic_set(&req_queue->free_count, 0); | 51 | ZFCP_ERP_NOMEM = 5, |
149 | req_queue->distance_from_int = 0; | 52 | }; |
150 | adapter->response_queue.free_index = 0; | 53 | |
151 | atomic_set(&adapter->response_queue.free_count, 0); | 54 | static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask) |
55 | { | ||
56 | zfcp_erp_modify_adapter_status(adapter, 15, NULL, | ||
57 | ZFCP_STATUS_COMMON_UNBLOCKED | mask, | ||
58 | ZFCP_CLEAR); | ||
152 | } | 59 | } |
153 | 60 | ||
154 | /** | 61 | static int zfcp_erp_action_exists(struct zfcp_erp_action *act) |
155 | * zfcp_close_fsf - stop FSF operations for an adapter | ||
156 | * | ||
157 | * Dismiss and cleanup all pending fsf_reqs (this wakes up all initiators of | ||
158 | * requests waiting for completion; especially this returns SCSI commands | ||
159 | * with error state). | ||
160 | */ | ||
161 | static void zfcp_close_fsf(struct zfcp_adapter *adapter) | ||
162 | { | 62 | { |
163 | /* close queues to ensure that buffers are not accessed by adapter */ | 63 | struct zfcp_erp_action *curr_act; |
164 | zfcp_close_qdio(adapter); | 64 | |
165 | zfcp_fsf_req_dismiss_all(adapter); | 65 | list_for_each_entry(curr_act, &act->adapter->erp_running_head, list) |
166 | /* reset FSF request sequence number */ | 66 | if (act == curr_act) |
167 | adapter->fsf_req_seq_no = 0; | 67 | return ZFCP_ERP_ACTION_RUNNING; |
168 | /* all ports and units are closed */ | 68 | return 0; |
169 | zfcp_erp_modify_adapter_status(adapter, 24, NULL, | ||
170 | ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); | ||
171 | } | 69 | } |
172 | 70 | ||
173 | /** | 71 | static void zfcp_erp_action_ready(struct zfcp_erp_action *act) |
174 | * zfcp_fsf_request_timeout_handler - called if a request timed out | ||
175 | * @data: pointer to adapter for handler function | ||
176 | * | ||
177 | * This function needs to be called if requests (ELS, Generic Service, | ||
178 | * or SCSI commands) exceed a certain time limit. The assumption is | ||
179 | * that after the time limit the adapter get stuck. So we trigger a reopen of | ||
180 | * the adapter. | ||
181 | */ | ||
182 | static void zfcp_fsf_request_timeout_handler(unsigned long data) | ||
183 | { | 72 | { |
184 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; | 73 | struct zfcp_adapter *adapter = act->adapter; |
185 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 62, | 74 | |
186 | NULL); | 75 | list_move(&act->list, &act->adapter->erp_ready_head); |
76 | zfcp_rec_dbf_event_action(146, act); | ||
77 | up(&adapter->erp_ready_sem); | ||
78 | zfcp_rec_dbf_event_thread(2, adapter); | ||
187 | } | 79 | } |
188 | 80 | ||
189 | void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout) | 81 | static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) |
190 | { | 82 | { |
191 | fsf_req->timer.function = zfcp_fsf_request_timeout_handler; | 83 | act->status |= ZFCP_STATUS_ERP_DISMISSED; |
192 | fsf_req->timer.data = (unsigned long) fsf_req->adapter; | 84 | if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING) |
193 | fsf_req->timer.expires = jiffies + timeout; | 85 | zfcp_erp_action_ready(act); |
194 | add_timer(&fsf_req->timer); | ||
195 | } | 86 | } |
196 | 87 | ||
197 | /* | 88 | static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) |
198 | * function: | ||
199 | * | ||
200 | * purpose: called if an adapter failed, | ||
201 | * initiates adapter recovery which is done | ||
202 | * asynchronously | ||
203 | * | ||
204 | * returns: 0 - initiated action successfully | ||
205 | * <0 - failed to initiate action | ||
206 | */ | ||
207 | static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, | ||
208 | int clear_mask, u8 id, void *ref) | ||
209 | { | 89 | { |
210 | int retval; | 90 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE) |
91 | zfcp_erp_action_dismiss(&unit->erp_action); | ||
92 | } | ||
211 | 93 | ||
212 | ZFCP_LOG_DEBUG("reopen adapter %s\n", | 94 | static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) |
213 | zfcp_get_busid_by_adapter(adapter)); | 95 | { |
96 | struct zfcp_unit *unit; | ||
214 | 97 | ||
215 | zfcp_erp_adapter_block(adapter, clear_mask); | 98 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE) |
99 | zfcp_erp_action_dismiss(&port->erp_action); | ||
100 | else | ||
101 | list_for_each_entry(unit, &port->unit_list_head, list) | ||
102 | zfcp_erp_action_dismiss_unit(unit); | ||
103 | } | ||
216 | 104 | ||
217 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { | 105 | static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) |
218 | ZFCP_LOG_DEBUG("skipped reopen of failed adapter %s\n", | 106 | { |
219 | zfcp_get_busid_by_adapter(adapter)); | 107 | struct zfcp_port *port; |
220 | /* ensure propagation of failed status to new devices */ | ||
221 | zfcp_erp_adapter_failed(adapter, 13, NULL); | ||
222 | retval = -EIO; | ||
223 | goto out; | ||
224 | } | ||
225 | retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, | ||
226 | adapter, NULL, NULL, id, ref); | ||
227 | 108 | ||
228 | out: | 109 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE) |
229 | return retval; | 110 | zfcp_erp_action_dismiss(&adapter->erp_action); |
111 | else | ||
112 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
113 | zfcp_erp_action_dismiss_port(port); | ||
230 | } | 114 | } |
231 | 115 | ||
232 | /* | 116 | static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, |
233 | * function: | 117 | struct zfcp_port *port, |
234 | * | 118 | struct zfcp_unit *unit) |
235 | * purpose: Wrappper for zfcp_erp_adapter_reopen_internal | ||
236 | * used to ensure the correct locking | ||
237 | * | ||
238 | * returns: 0 - initiated action successfully | ||
239 | * <0 - failed to initiate action | ||
240 | */ | ||
241 | int zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear_mask, | ||
242 | u8 id, void *ref) | ||
243 | { | 119 | { |
244 | int retval; | 120 | int need = want; |
245 | unsigned long flags; | 121 | int u_status, p_status, a_status; |
246 | 122 | ||
247 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 123 | switch (want) { |
248 | write_lock(&adapter->erp_lock); | 124 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
249 | retval = zfcp_erp_adapter_reopen_internal(adapter, clear_mask, id, ref); | 125 | u_status = atomic_read(&unit->status); |
250 | write_unlock(&adapter->erp_lock); | 126 | if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE) |
251 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 127 | return 0; |
128 | p_status = atomic_read(&port->status); | ||
129 | if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) || | ||
130 | p_status & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
131 | return 0; | ||
132 | if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED)) | ||
133 | need = ZFCP_ERP_ACTION_REOPEN_PORT; | ||
134 | /* fall through */ | ||
135 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
136 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
137 | p_status = atomic_read(&port->status); | ||
138 | if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE) | ||
139 | return 0; | ||
140 | a_status = atomic_read(&adapter->status); | ||
141 | if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) || | ||
142 | a_status & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
143 | return 0; | ||
144 | if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED)) | ||
145 | need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; | ||
146 | /* fall through */ | ||
147 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
148 | a_status = atomic_read(&adapter->status); | ||
149 | if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE) | ||
150 | return 0; | ||
151 | } | ||
252 | 152 | ||
253 | return retval; | 153 | return need; |
254 | } | 154 | } |
255 | 155 | ||
256 | int zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear_mask, | 156 | static struct zfcp_erp_action *zfcp_erp_setup_act(int need, |
257 | u8 id, void *ref) | 157 | struct zfcp_adapter *adapter, |
158 | struct zfcp_port *port, | ||
159 | struct zfcp_unit *unit) | ||
258 | { | 160 | { |
259 | int retval; | 161 | struct zfcp_erp_action *erp_action; |
162 | u32 status = 0; | ||
260 | 163 | ||
261 | retval = zfcp_erp_adapter_reopen(adapter, | 164 | switch (need) { |
262 | ZFCP_STATUS_COMMON_RUNNING | | 165 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
263 | ZFCP_STATUS_COMMON_ERP_FAILED | | 166 | zfcp_unit_get(unit); |
264 | clear_mask, id, ref); | 167 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); |
168 | erp_action = &unit->erp_action; | ||
169 | if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) | ||
170 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | ||
171 | break; | ||
265 | 172 | ||
266 | return retval; | 173 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
267 | } | 174 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
175 | zfcp_port_get(port); | ||
176 | zfcp_erp_action_dismiss_port(port); | ||
177 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); | ||
178 | erp_action = &port->erp_action; | ||
179 | if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) | ||
180 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | ||
181 | break; | ||
268 | 182 | ||
269 | int zfcp_erp_port_shutdown(struct zfcp_port *port, int clear_mask, u8 id, | 183 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
270 | void *ref) | 184 | zfcp_adapter_get(adapter); |
271 | { | 185 | zfcp_erp_action_dismiss_adapter(adapter); |
272 | int retval; | 186 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); |
187 | erp_action = &adapter->erp_action; | ||
188 | if (!(atomic_read(&adapter->status) & | ||
189 | ZFCP_STATUS_COMMON_RUNNING)) | ||
190 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | ||
191 | break; | ||
273 | 192 | ||
274 | retval = zfcp_erp_port_reopen(port, | 193 | default: |
275 | ZFCP_STATUS_COMMON_RUNNING | | 194 | return NULL; |
276 | ZFCP_STATUS_COMMON_ERP_FAILED | | 195 | } |
277 | clear_mask, id, ref); | ||
278 | 196 | ||
279 | return retval; | 197 | memset(erp_action, 0, sizeof(struct zfcp_erp_action)); |
198 | erp_action->adapter = adapter; | ||
199 | erp_action->port = port; | ||
200 | erp_action->unit = unit; | ||
201 | erp_action->action = need; | ||
202 | erp_action->status = status; | ||
203 | |||
204 | return erp_action; | ||
280 | } | 205 | } |
281 | 206 | ||
282 | int zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask, u8 id, | 207 | static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, |
283 | void *ref) | 208 | struct zfcp_port *port, |
209 | struct zfcp_unit *unit, u8 id, void *ref) | ||
284 | { | 210 | { |
285 | int retval; | 211 | int retval = 1, need; |
212 | struct zfcp_erp_action *act = NULL; | ||
213 | |||
214 | if (!(atomic_read(&adapter->status) & | ||
215 | ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)) | ||
216 | return -EIO; | ||
286 | 217 | ||
287 | retval = zfcp_erp_unit_reopen(unit, | 218 | need = zfcp_erp_required_act(want, adapter, port, unit); |
288 | ZFCP_STATUS_COMMON_RUNNING | | 219 | if (!need) |
289 | ZFCP_STATUS_COMMON_ERP_FAILED | | 220 | goto out; |
290 | clear_mask, id, ref); | ||
291 | 221 | ||
222 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); | ||
223 | act = zfcp_erp_setup_act(need, adapter, port, unit); | ||
224 | if (!act) | ||
225 | goto out; | ||
226 | ++adapter->erp_total_count; | ||
227 | list_add_tail(&act->list, &adapter->erp_ready_head); | ||
228 | up(&adapter->erp_ready_sem); | ||
229 | zfcp_rec_dbf_event_thread(1, adapter); | ||
230 | retval = 0; | ||
231 | out: | ||
232 | zfcp_rec_dbf_event_trigger(id, ref, want, need, act, | ||
233 | adapter, port, unit); | ||
292 | return retval; | 234 | return retval; |
293 | } | 235 | } |
294 | 236 | ||
295 | 237 | static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, | |
296 | /** | 238 | int clear_mask, u8 id, void *ref) |
297 | * zfcp_erp_adisc - send ADISC ELS command | ||
298 | * @port: port structure | ||
299 | */ | ||
300 | static int | ||
301 | zfcp_erp_adisc(struct zfcp_port *port) | ||
302 | { | 239 | { |
303 | struct zfcp_adapter *adapter = port->adapter; | 240 | zfcp_erp_adapter_block(adapter, clear_mask); |
304 | struct zfcp_send_els *send_els; | ||
305 | struct zfcp_ls_adisc *adisc; | ||
306 | void *address = NULL; | ||
307 | int retval = 0; | ||
308 | |||
309 | send_els = kzalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC); | ||
310 | if (send_els == NULL) | ||
311 | goto nomem; | ||
312 | |||
313 | send_els->req = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC); | ||
314 | if (send_els->req == NULL) | ||
315 | goto nomem; | ||
316 | sg_init_table(send_els->req, 1); | ||
317 | |||
318 | send_els->resp = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC); | ||
319 | if (send_els->resp == NULL) | ||
320 | goto nomem; | ||
321 | sg_init_table(send_els->resp, 1); | ||
322 | |||
323 | address = (void *) get_zeroed_page(GFP_ATOMIC); | ||
324 | if (address == NULL) | ||
325 | goto nomem; | ||
326 | |||
327 | zfcp_address_to_sg(address, send_els->req, sizeof(struct zfcp_ls_adisc)); | ||
328 | address += PAGE_SIZE >> 1; | ||
329 | zfcp_address_to_sg(address, send_els->resp, sizeof(struct zfcp_ls_adisc_acc)); | ||
330 | send_els->req_count = send_els->resp_count = 1; | ||
331 | |||
332 | send_els->adapter = adapter; | ||
333 | send_els->port = port; | ||
334 | send_els->d_id = port->d_id; | ||
335 | send_els->handler = zfcp_erp_adisc_handler; | ||
336 | send_els->handler_data = (unsigned long) send_els; | ||
337 | |||
338 | adisc = zfcp_sg_to_address(send_els->req); | ||
339 | send_els->ls_code = adisc->code = ZFCP_LS_ADISC; | ||
340 | |||
341 | /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports | ||
342 | without FC-AL-2 capability, so we don't set it */ | ||
343 | adisc->wwpn = fc_host_port_name(adapter->scsi_host); | ||
344 | adisc->wwnn = fc_host_node_name(adapter->scsi_host); | ||
345 | adisc->nport_id = fc_host_port_id(adapter->scsi_host); | ||
346 | ZFCP_LOG_INFO("ADISC request from s_id 0x%06x to d_id 0x%06x " | ||
347 | "(wwpn=0x%016Lx, wwnn=0x%016Lx, " | ||
348 | "hard_nport_id=0x%06x, nport_id=0x%06x)\n", | ||
349 | adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn, | ||
350 | (wwn_t) adisc->wwnn, adisc->hard_nport_id, | ||
351 | adisc->nport_id); | ||
352 | |||
353 | retval = zfcp_fsf_send_els(send_els); | ||
354 | if (retval != 0) { | ||
355 | ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port " | ||
356 | "0x%06x on adapter %s\n", send_els->d_id, | ||
357 | zfcp_get_busid_by_adapter(adapter)); | ||
358 | goto freemem; | ||
359 | } | ||
360 | 241 | ||
361 | goto out; | 242 | /* ensure propagation of failed status to new devices */ |
362 | 243 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { | |
363 | nomem: | 244 | zfcp_erp_adapter_failed(adapter, 13, NULL); |
364 | retval = -ENOMEM; | 245 | return -EIO; |
365 | freemem: | ||
366 | if (address != NULL) | ||
367 | __free_pages(sg_page(send_els->req), 0); | ||
368 | if (send_els != NULL) { | ||
369 | kfree(send_els->req); | ||
370 | kfree(send_els->resp); | ||
371 | kfree(send_els); | ||
372 | } | 246 | } |
373 | out: | 247 | return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, |
374 | return retval; | 248 | adapter, NULL, NULL, id, ref); |
375 | } | 249 | } |
376 | 250 | ||
377 | |||
378 | /** | 251 | /** |
379 | * zfcp_erp_adisc_handler - handler for ADISC ELS command | 252 | * zfcp_erp_adapter_reopen - Reopen adapter. |
380 | * @data: pointer to struct zfcp_send_els | 253 | * @adapter: Adapter to reopen. |
381 | * | 254 | * @clear: Status flags to clear. |
382 | * If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered. | 255 | * @id: Id for debug trace event. |
256 | * @ref: Reference for debug trace event. | ||
383 | */ | 257 | */ |
384 | static void | 258 | void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, |
385 | zfcp_erp_adisc_handler(unsigned long data) | 259 | u8 id, void *ref) |
386 | { | 260 | { |
387 | struct zfcp_send_els *send_els; | 261 | unsigned long flags; |
388 | struct zfcp_port *port; | ||
389 | struct zfcp_adapter *adapter; | ||
390 | u32 d_id; | ||
391 | struct zfcp_ls_adisc_acc *adisc; | ||
392 | |||
393 | send_els = (struct zfcp_send_els *) data; | ||
394 | adapter = send_els->adapter; | ||
395 | port = send_els->port; | ||
396 | d_id = send_els->d_id; | ||
397 | |||
398 | /* request rejected or timed out */ | ||
399 | if (send_els->status != 0) { | ||
400 | ZFCP_LOG_NORMAL("ELS request rejected/timed out, " | ||
401 | "force physical port reopen " | ||
402 | "(adapter %s, port d_id=0x%06x)\n", | ||
403 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
404 | if (zfcp_erp_port_forced_reopen(port, 0, 63, NULL)) | ||
405 | ZFCP_LOG_NORMAL("failed reopen of port " | ||
406 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
407 | zfcp_get_busid_by_port(port), | ||
408 | port->wwpn); | ||
409 | goto out; | ||
410 | } | ||
411 | |||
412 | adisc = zfcp_sg_to_address(send_els->resp); | ||
413 | |||
414 | ZFCP_LOG_INFO("ADISC response from d_id 0x%06x to s_id " | ||
415 | "0x%06x (wwpn=0x%016Lx, wwnn=0x%016Lx, " | ||
416 | "hard_nport_id=0x%06x, nport_id=0x%06x)\n", | ||
417 | d_id, fc_host_port_id(adapter->scsi_host), | ||
418 | (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn, | ||
419 | adisc->hard_nport_id, adisc->nport_id); | ||
420 | |||
421 | /* set wwnn for port */ | ||
422 | if (port->wwnn == 0) | ||
423 | port->wwnn = adisc->wwnn; | ||
424 | |||
425 | if (port->wwpn != adisc->wwpn) { | ||
426 | ZFCP_LOG_NORMAL("d_id assignment changed, reopening " | ||
427 | "port (adapter %s, wwpn=0x%016Lx, " | ||
428 | "adisc_resp_wwpn=0x%016Lx)\n", | ||
429 | zfcp_get_busid_by_port(port), | ||
430 | port->wwpn, (wwn_t) adisc->wwpn); | ||
431 | if (zfcp_erp_port_reopen(port, 0, 64, NULL)) | ||
432 | ZFCP_LOG_NORMAL("failed reopen of port " | ||
433 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
434 | zfcp_get_busid_by_port(port), | ||
435 | port->wwpn); | ||
436 | } | ||
437 | 262 | ||
438 | out: | 263 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
439 | zfcp_port_put(port); | 264 | write_lock(&adapter->erp_lock); |
440 | __free_pages(sg_page(send_els->req), 0); | 265 | _zfcp_erp_adapter_reopen(adapter, clear, id, ref); |
441 | kfree(send_els->req); | 266 | write_unlock(&adapter->erp_lock); |
442 | kfree(send_els->resp); | 267 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
443 | kfree(send_els); | ||
444 | } | 268 | } |
445 | 269 | ||
446 | |||
447 | /** | 270 | /** |
448 | * zfcp_test_link - lightweight link test procedure | 271 | * zfcp_erp_adapter_shutdown - Shutdown adapter. |
449 | * @port: port to be tested | 272 | * @adapter: Adapter to shut down. |
450 | * | 273 | * @clear: Status flags to clear. |
451 | * Test status of a link to a remote port using the ELS command ADISC. | 274 | * @id: Id for debug trace event. |
275 | * @ref: Reference for debug trace event. | ||
452 | */ | 276 | */ |
453 | int | 277 | void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, |
454 | zfcp_test_link(struct zfcp_port *port) | 278 | u8 id, void *ref) |
455 | { | 279 | { |
456 | int retval; | 280 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; |
457 | 281 | zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref); | |
458 | zfcp_port_get(port); | ||
459 | retval = zfcp_erp_adisc(port); | ||
460 | if (retval != 0 && retval != -EBUSY) { | ||
461 | zfcp_port_put(port); | ||
462 | ZFCP_LOG_NORMAL("reopen needed for port 0x%016Lx " | ||
463 | "on adapter %s\n ", port->wwpn, | ||
464 | zfcp_get_busid_by_port(port)); | ||
465 | retval = zfcp_erp_port_forced_reopen(port, 0, 65, NULL); | ||
466 | if (retval != 0) { | ||
467 | ZFCP_LOG_NORMAL("reopen of remote port 0x%016Lx " | ||
468 | "on adapter %s failed\n", port->wwpn, | ||
469 | zfcp_get_busid_by_port(port)); | ||
470 | retval = -EPERM; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | return retval; | ||
475 | } | 282 | } |
476 | 283 | ||
477 | 284 | /** | |
478 | /* | 285 | * zfcp_erp_port_shutdown - Shutdown port |
479 | * function: | 286 | * @port: Port to shut down. |
480 | * | 287 | * @clear: Status flags to clear. |
481 | * purpose: called if a port failed to be opened normally | 288 | * @id: Id for debug trace event. |
482 | * initiates Forced Reopen recovery which is done | 289 | * @ref: Reference for debug trace event. |
483 | * asynchronously | ||
484 | * | ||
485 | * returns: 0 - initiated action successfully | ||
486 | * <0 - failed to initiate action | ||
487 | */ | 290 | */ |
488 | static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, | 291 | void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, u8 id, void *ref) |
489 | int clear_mask, u8 id, | ||
490 | void *ref) | ||
491 | { | 292 | { |
492 | int retval; | 293 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; |
294 | zfcp_erp_port_reopen(port, clear | flags, id, ref); | ||
295 | } | ||
493 | 296 | ||
494 | ZFCP_LOG_DEBUG("forced reopen of port 0x%016Lx on adapter %s\n", | 297 | /** |
495 | port->wwpn, zfcp_get_busid_by_port(port)); | 298 | * zfcp_erp_unit_shutdown - Shutdown unit |
299 | * @unit: Unit to shut down. | ||
300 | * @clear: Status flags to clear. | ||
301 | * @id: Id for debug trace event. | ||
302 | * @ref: Reference for debug trace event. | ||
303 | */ | ||
304 | void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, u8 id, void *ref) | ||
305 | { | ||
306 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; | ||
307 | zfcp_erp_unit_reopen(unit, clear | flags, id, ref); | ||
308 | } | ||
496 | 309 | ||
497 | zfcp_erp_port_block(port, clear_mask); | 310 | static void zfcp_erp_port_block(struct zfcp_port *port, int clear) |
311 | { | ||
312 | zfcp_erp_modify_port_status(port, 17, NULL, | ||
313 | ZFCP_STATUS_COMMON_UNBLOCKED | clear, | ||
314 | ZFCP_CLEAR); | ||
315 | } | ||
498 | 316 | ||
499 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { | 317 | static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, |
500 | ZFCP_LOG_DEBUG("skipped forced reopen of failed port 0x%016Lx " | 318 | int clear, u8 id, void *ref) |
501 | "on adapter %s\n", port->wwpn, | 319 | { |
502 | zfcp_get_busid_by_port(port)); | 320 | zfcp_erp_port_block(port, clear); |
503 | retval = -EIO; | ||
504 | goto out; | ||
505 | } | ||
506 | 321 | ||
507 | retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, | 322 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) |
508 | port->adapter, port, NULL, id, ref); | 323 | return; |
509 | 324 | ||
510 | out: | 325 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, |
511 | return retval; | 326 | port->adapter, port, NULL, id, ref); |
512 | } | 327 | } |
513 | 328 | ||
514 | /* | 329 | /** |
515 | * function: | 330 | * zfcp_erp_port_forced_reopen - Forced close of port and open again |
516 | * | 331 | * @port: Port to force close and to reopen. |
517 | * purpose: Wrappper for zfcp_erp_port_forced_reopen_internal | 332 | * @id: Id for debug trace event. |
518 | * used to ensure the correct locking | 333 | * @ref: Reference for debug trace event. |
519 | * | ||
520 | * returns: 0 - initiated action successfully | ||
521 | * <0 - failed to initiate action | ||
522 | */ | 334 | */ |
523 | int zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask, u8 id, | 335 | void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, u8 id, |
524 | void *ref) | 336 | void *ref) |
525 | { | 337 | { |
526 | int retval; | ||
527 | unsigned long flags; | 338 | unsigned long flags; |
528 | struct zfcp_adapter *adapter; | 339 | struct zfcp_adapter *adapter = port->adapter; |
529 | 340 | ||
530 | adapter = port->adapter; | ||
531 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 341 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
532 | write_lock(&adapter->erp_lock); | 342 | write_lock(&adapter->erp_lock); |
533 | retval = zfcp_erp_port_forced_reopen_internal(port, clear_mask, id, | 343 | _zfcp_erp_port_forced_reopen(port, clear, id, ref); |
534 | ref); | ||
535 | write_unlock(&adapter->erp_lock); | 344 | write_unlock(&adapter->erp_lock); |
536 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 345 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
537 | |||
538 | return retval; | ||
539 | } | 346 | } |
540 | 347 | ||
541 | /* | 348 | static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id, |
542 | * function: | 349 | void *ref) |
543 | * | ||
544 | * purpose: called if a port is to be opened | ||
545 | * initiates Reopen recovery which is done | ||
546 | * asynchronously | ||
547 | * | ||
548 | * returns: 0 - initiated action successfully | ||
549 | * <0 - failed to initiate action | ||
550 | */ | ||
551 | static int zfcp_erp_port_reopen_internal(struct zfcp_port *port, int clear_mask, | ||
552 | u8 id, void *ref) | ||
553 | { | 350 | { |
554 | int retval; | 351 | zfcp_erp_port_block(port, clear); |
555 | |||
556 | ZFCP_LOG_DEBUG("reopen of port 0x%016Lx on adapter %s\n", | ||
557 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
558 | 352 | ||
559 | zfcp_erp_port_block(port, clear_mask); | 353 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
560 | |||
561 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { | ||
562 | ZFCP_LOG_DEBUG("skipped reopen of failed port 0x%016Lx " | ||
563 | "on adapter %s\n", port->wwpn, | ||
564 | zfcp_get_busid_by_port(port)); | ||
565 | /* ensure propagation of failed status to new devices */ | 354 | /* ensure propagation of failed status to new devices */ |
566 | zfcp_erp_port_failed(port, 14, NULL); | 355 | zfcp_erp_port_failed(port, 14, NULL); |
567 | retval = -EIO; | 356 | return -EIO; |
568 | goto out; | ||
569 | } | 357 | } |
570 | 358 | ||
571 | retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, | 359 | return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, |
572 | port->adapter, port, NULL, id, ref); | 360 | port->adapter, port, NULL, id, ref); |
573 | |||
574 | out: | ||
575 | return retval; | ||
576 | } | 361 | } |
577 | 362 | ||
578 | /** | 363 | /** |
579 | * zfcp_erp_port_reopen - initiate reopen of a remote port | 364 | * zfcp_erp_port_reopen - trigger remote port recovery |
580 | * @port: port to be reopened | 365 | * @port: port to recover |
581 | * @clear_mask: specifies flags in port status to be cleared | 366 | * @clear_mask: flags in port status to be cleared |
582 | * Return: 0 on success, < 0 on error | ||
583 | * | 367 | * |
584 | * This is a wrappper function for zfcp_erp_port_reopen_internal. It ensures | 368 | * Returns 0 if recovery has been triggered, < 0 if not. |
585 | * correct locking. An error recovery task is initiated to do the reopen. | ||
586 | * To wait for the completion of the reopen zfcp_erp_wait should be used. | ||
587 | */ | 369 | */ |
588 | int zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask, u8 id, | 370 | int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id, void *ref) |
589 | void *ref) | ||
590 | { | 371 | { |
591 | int retval; | ||
592 | unsigned long flags; | 372 | unsigned long flags; |
373 | int retval; | ||
593 | struct zfcp_adapter *adapter = port->adapter; | 374 | struct zfcp_adapter *adapter = port->adapter; |
594 | 375 | ||
595 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 376 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
596 | write_lock(&adapter->erp_lock); | 377 | write_lock(&adapter->erp_lock); |
597 | retval = zfcp_erp_port_reopen_internal(port, clear_mask, id, ref); | 378 | retval = _zfcp_erp_port_reopen(port, clear, id, ref); |
598 | write_unlock(&adapter->erp_lock); | 379 | write_unlock(&adapter->erp_lock); |
599 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 380 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
600 | 381 | ||
601 | return retval; | 382 | return retval; |
602 | } | 383 | } |
603 | 384 | ||
604 | /* | 385 | static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) |
605 | * function: | ||
606 | * | ||
607 | * purpose: called if a unit is to be opened | ||
608 | * initiates Reopen recovery which is done | ||
609 | * asynchronously | ||
610 | * | ||
611 | * returns: 0 - initiated action successfully | ||
612 | * <0 - failed to initiate action | ||
613 | */ | ||
614 | static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *unit, int clear_mask, | ||
615 | u8 id, void *ref) | ||
616 | { | 386 | { |
617 | int retval; | 387 | zfcp_erp_modify_unit_status(unit, 19, NULL, |
618 | struct zfcp_adapter *adapter = unit->port->adapter; | 388 | ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, |
389 | ZFCP_CLEAR); | ||
390 | } | ||
619 | 391 | ||
620 | ZFCP_LOG_DEBUG("reopen of unit 0x%016Lx on port 0x%016Lx " | 392 | static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id, |
621 | "on adapter %s\n", unit->fcp_lun, | 393 | void *ref) |
622 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | 394 | { |
395 | struct zfcp_adapter *adapter = unit->port->adapter; | ||
623 | 396 | ||
624 | zfcp_erp_unit_block(unit, clear_mask); | 397 | zfcp_erp_unit_block(unit, clear); |
625 | 398 | ||
626 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) { | 399 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) |
627 | ZFCP_LOG_DEBUG("skipped reopen of failed unit 0x%016Lx " | 400 | return; |
628 | "on port 0x%016Lx on adapter %s\n", | ||
629 | unit->fcp_lun, unit->port->wwpn, | ||
630 | zfcp_get_busid_by_unit(unit)); | ||
631 | retval = -EIO; | ||
632 | goto out; | ||
633 | } | ||
634 | 401 | ||
635 | retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, | 402 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, |
636 | adapter, unit->port, unit, id, ref); | 403 | adapter, unit->port, unit, id, ref); |
637 | out: | ||
638 | return retval; | ||
639 | } | 404 | } |
640 | 405 | ||
641 | /** | 406 | /** |
@@ -643,987 +408,182 @@ static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *unit, int clear_mask, | |||
643 | * @unit: unit to be reopened | 408 | * @unit: unit to be reopened |
644 | * @clear_mask: specifies flags in unit status to be cleared | 409 | * @clear_mask: specifies flags in unit status to be cleared |
645 | * Return: 0 on success, < 0 on error | 410 | * Return: 0 on success, < 0 on error |
646 | * | ||
647 | * This is a wrappper for zfcp_erp_unit_reopen_internal. It ensures correct | ||
648 | * locking. An error recovery task is initiated to do the reopen. | ||
649 | * To wait for the completion of the reopen zfcp_erp_wait should be used. | ||
650 | */ | 411 | */ |
651 | int zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear_mask, u8 id, | 412 | void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id, void *ref) |
652 | void *ref) | ||
653 | { | 413 | { |
654 | int retval; | ||
655 | unsigned long flags; | 414 | unsigned long flags; |
656 | struct zfcp_adapter *adapter; | 415 | struct zfcp_port *port = unit->port; |
657 | struct zfcp_port *port; | 416 | struct zfcp_adapter *adapter = port->adapter; |
658 | |||
659 | port = unit->port; | ||
660 | adapter = port->adapter; | ||
661 | 417 | ||
662 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 418 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
663 | write_lock(&adapter->erp_lock); | 419 | write_lock(&adapter->erp_lock); |
664 | retval = zfcp_erp_unit_reopen_internal(unit, clear_mask, id, ref); | 420 | _zfcp_erp_unit_reopen(unit, clear, id, ref); |
665 | write_unlock(&adapter->erp_lock); | 421 | write_unlock(&adapter->erp_lock); |
666 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 422 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
667 | |||
668 | return retval; | ||
669 | } | 423 | } |
670 | 424 | ||
671 | /** | 425 | static int status_change_set(unsigned long mask, atomic_t *status) |
672 | * zfcp_erp_adapter_block - mark adapter as blocked, block scsi requests | ||
673 | */ | ||
674 | static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask) | ||
675 | { | ||
676 | zfcp_erp_modify_adapter_status(adapter, 15, NULL, | ||
677 | ZFCP_STATUS_COMMON_UNBLOCKED | | ||
678 | clear_mask, ZFCP_CLEAR); | ||
679 | } | ||
680 | |||
681 | /* FIXME: isn't really atomic */ | ||
682 | /* | ||
683 | * returns the mask which has not been set so far, i.e. | ||
684 | * 0 if no bit has been changed, !0 if some bit has been changed | ||
685 | */ | ||
686 | static int atomic_test_and_set_mask(unsigned long mask, atomic_t *v) | ||
687 | { | 426 | { |
688 | int changed_bits = (atomic_read(v) /*XOR*/^ mask) & mask; | 427 | return (atomic_read(status) ^ mask) & mask; |
689 | atomic_set_mask(mask, v); | ||
690 | return changed_bits; | ||
691 | } | 428 | } |
692 | 429 | ||
693 | /* FIXME: isn't really atomic */ | 430 | static int status_change_clear(unsigned long mask, atomic_t *status) |
694 | /* | ||
695 | * returns the mask which has not been cleared so far, i.e. | ||
696 | * 0 if no bit has been changed, !0 if some bit has been changed | ||
697 | */ | ||
698 | static int atomic_test_and_clear_mask(unsigned long mask, atomic_t *v) | ||
699 | { | 431 | { |
700 | int changed_bits = atomic_read(v) & mask; | 432 | return atomic_read(status) & mask; |
701 | atomic_clear_mask(mask, v); | ||
702 | return changed_bits; | ||
703 | } | 433 | } |
704 | 434 | ||
705 | /** | ||
706 | * zfcp_erp_adapter_unblock - mark adapter as unblocked, allow scsi requests | ||
707 | */ | ||
708 | static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) | 435 | static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) |
709 | { | 436 | { |
710 | if (atomic_test_and_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 437 | if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) |
711 | &adapter->status)) | ||
712 | zfcp_rec_dbf_event_adapter(16, NULL, adapter); | 438 | zfcp_rec_dbf_event_adapter(16, NULL, adapter); |
439 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); | ||
713 | } | 440 | } |
714 | 441 | ||
715 | /* | 442 | static void zfcp_erp_port_unblock(struct zfcp_port *port) |
716 | * function: | ||
717 | * | ||
718 | * purpose: disable I/O, | ||
719 | * return any open requests and clean them up, | ||
720 | * aim: no pending and incoming I/O | ||
721 | * | ||
722 | * returns: | ||
723 | */ | ||
724 | static void | ||
725 | zfcp_erp_port_block(struct zfcp_port *port, int clear_mask) | ||
726 | { | ||
727 | zfcp_erp_modify_port_status(port, 17, NULL, | ||
728 | ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, | ||
729 | ZFCP_CLEAR); | ||
730 | } | ||
731 | |||
732 | /* | ||
733 | * function: | ||
734 | * | ||
735 | * purpose: enable I/O | ||
736 | * | ||
737 | * returns: | ||
738 | */ | ||
739 | static void | ||
740 | zfcp_erp_port_unblock(struct zfcp_port *port) | ||
741 | { | 443 | { |
742 | if (atomic_test_and_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 444 | if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) |
743 | &port->status)) | ||
744 | zfcp_rec_dbf_event_port(18, NULL, port); | 445 | zfcp_rec_dbf_event_port(18, NULL, port); |
446 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); | ||
745 | } | 447 | } |
746 | 448 | ||
747 | /* | 449 | static void zfcp_erp_unit_unblock(struct zfcp_unit *unit) |
748 | * function: | ||
749 | * | ||
750 | * purpose: disable I/O, | ||
751 | * return any open requests and clean them up, | ||
752 | * aim: no pending and incoming I/O | ||
753 | * | ||
754 | * returns: | ||
755 | */ | ||
756 | static void | ||
757 | zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) | ||
758 | { | ||
759 | zfcp_erp_modify_unit_status(unit, 19, NULL, | ||
760 | ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, | ||
761 | ZFCP_CLEAR); | ||
762 | } | ||
763 | |||
764 | /* | ||
765 | * function: | ||
766 | * | ||
767 | * purpose: enable I/O | ||
768 | * | ||
769 | * returns: | ||
770 | */ | ||
771 | static void | ||
772 | zfcp_erp_unit_unblock(struct zfcp_unit *unit) | ||
773 | { | 450 | { |
774 | if (atomic_test_and_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 451 | if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) |
775 | &unit->status)) | ||
776 | zfcp_rec_dbf_event_unit(20, NULL, unit); | 452 | zfcp_rec_dbf_event_unit(20, NULL, unit); |
453 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); | ||
777 | } | 454 | } |
778 | 455 | ||
779 | static void | 456 | static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) |
780 | zfcp_erp_action_ready(struct zfcp_erp_action *erp_action) | ||
781 | { | 457 | { |
782 | struct zfcp_adapter *adapter = erp_action->adapter; | 458 | list_move(&erp_action->list, &erp_action->adapter->erp_running_head); |
783 | 459 | zfcp_rec_dbf_event_action(145, erp_action); | |
784 | zfcp_erp_action_to_ready(erp_action); | ||
785 | up(&adapter->erp_ready_sem); | ||
786 | zfcp_rec_dbf_event_thread(2, adapter, 0); | ||
787 | } | 460 | } |
788 | 461 | ||
789 | /* | 462 | static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) |
790 | * function: | ||
791 | * | ||
792 | * purpose: | ||
793 | * | ||
794 | * returns: <0 erp_action not found in any list | ||
795 | * ZFCP_ERP_ACTION_READY erp_action is in ready list | ||
796 | * ZFCP_ERP_ACTION_RUNNING erp_action is in running list | ||
797 | * | ||
798 | * locks: erp_lock must be held | ||
799 | */ | ||
800 | static int | ||
801 | zfcp_erp_action_exists(struct zfcp_erp_action *erp_action) | ||
802 | { | 463 | { |
803 | int retval = -EINVAL; | 464 | struct zfcp_adapter *adapter = act->adapter; |
804 | struct list_head *entry; | ||
805 | struct zfcp_erp_action *entry_erp_action; | ||
806 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
807 | |||
808 | /* search in running list */ | ||
809 | list_for_each(entry, &adapter->erp_running_head) { | ||
810 | entry_erp_action = | ||
811 | list_entry(entry, struct zfcp_erp_action, list); | ||
812 | if (entry_erp_action == erp_action) { | ||
813 | retval = ZFCP_ERP_ACTION_RUNNING; | ||
814 | goto out; | ||
815 | } | ||
816 | } | ||
817 | /* search in ready list */ | ||
818 | list_for_each(entry, &adapter->erp_ready_head) { | ||
819 | entry_erp_action = | ||
820 | list_entry(entry, struct zfcp_erp_action, list); | ||
821 | if (entry_erp_action == erp_action) { | ||
822 | retval = ZFCP_ERP_ACTION_READY; | ||
823 | goto out; | ||
824 | } | ||
825 | } | ||
826 | 465 | ||
827 | out: | 466 | if (!act->fsf_req) |
828 | return retval; | 467 | return; |
829 | } | ||
830 | |||
831 | /* | ||
832 | * purpose: checks current status of action (timed out, dismissed, ...) | ||
833 | * and does appropriate preparations (dismiss fsf request, ...) | ||
834 | * | ||
835 | * locks: called under erp_lock (disabled interrupts) | ||
836 | */ | ||
837 | static void | ||
838 | zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) | ||
839 | { | ||
840 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
841 | 468 | ||
842 | if (erp_action->fsf_req) { | 469 | spin_lock(&adapter->req_list_lock); |
843 | /* take lock to ensure that request is not deleted meanwhile */ | 470 | if (zfcp_reqlist_find_safe(adapter, act->fsf_req) && |
844 | spin_lock(&adapter->req_list_lock); | 471 | act->fsf_req->erp_action == act) { |
845 | if (zfcp_reqlist_find_safe(adapter, erp_action->fsf_req) && | 472 | if (act->status & (ZFCP_STATUS_ERP_DISMISSED | |
846 | erp_action->fsf_req->erp_action == erp_action) { | 473 | ZFCP_STATUS_ERP_TIMEDOUT)) { |
847 | /* fsf_req still exists */ | 474 | act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; |
848 | /* dismiss fsf_req of timed out/dismissed erp_action */ | 475 | zfcp_rec_dbf_event_action(142, act); |
849 | if (erp_action->status & (ZFCP_STATUS_ERP_DISMISSED | | ||
850 | ZFCP_STATUS_ERP_TIMEDOUT)) { | ||
851 | erp_action->fsf_req->status |= | ||
852 | ZFCP_STATUS_FSFREQ_DISMISSED; | ||
853 | zfcp_rec_dbf_event_action(142, erp_action); | ||
854 | } | ||
855 | if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { | ||
856 | zfcp_rec_dbf_event_action(143, erp_action); | ||
857 | ZFCP_LOG_NORMAL("error: erp step timed out " | ||
858 | "(action=%d, fsf_req=%p)\n ", | ||
859 | erp_action->action, | ||
860 | erp_action->fsf_req); | ||
861 | } | ||
862 | /* | ||
863 | * If fsf_req is neither dismissed nor completed | ||
864 | * then keep it running asynchronously and don't mess | ||
865 | * with the association of erp_action and fsf_req. | ||
866 | */ | ||
867 | if (erp_action->fsf_req->status & | ||
868 | (ZFCP_STATUS_FSFREQ_COMPLETED | | ||
869 | ZFCP_STATUS_FSFREQ_DISMISSED)) { | ||
870 | /* forget about association between fsf_req | ||
871 | and erp_action */ | ||
872 | erp_action->fsf_req = NULL; | ||
873 | } | ||
874 | } else { | ||
875 | /* | ||
876 | * even if this fsf_req has gone, forget about | ||
877 | * association between erp_action and fsf_req | ||
878 | */ | ||
879 | erp_action->fsf_req = NULL; | ||
880 | } | 476 | } |
881 | spin_unlock(&adapter->req_list_lock); | 477 | if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) |
882 | } | 478 | zfcp_rec_dbf_event_action(143, act); |
479 | if (act->fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED | | ||
480 | ZFCP_STATUS_FSFREQ_DISMISSED)) | ||
481 | act->fsf_req = NULL; | ||
482 | } else | ||
483 | act->fsf_req = NULL; | ||
484 | spin_unlock(&adapter->req_list_lock); | ||
883 | } | 485 | } |
884 | 486 | ||
885 | /** | 487 | /** |
886 | * zfcp_erp_async_handler_nolock - complete erp_action | 488 | * zfcp_erp_notify - Trigger ERP action. |
887 | * | 489 | * @erp_action: ERP action to continue. |
888 | * Used for normal completion, time-out, dismissal and failure after | 490 | * @set_mask: ERP action status flags to set. |
889 | * low memory condition. | ||
890 | */ | 491 | */ |
891 | static void zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action, | 492 | void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask) |
892 | unsigned long set_mask) | ||
893 | { | ||
894 | if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { | ||
895 | erp_action->status |= set_mask; | ||
896 | zfcp_erp_action_ready(erp_action); | ||
897 | } else { | ||
898 | /* action is ready or gone - nothing to do */ | ||
899 | } | ||
900 | } | ||
901 | |||
902 | /** | ||
903 | * zfcp_erp_async_handler - wrapper for erp_async_handler_nolock w/ locking | ||
904 | */ | ||
905 | void zfcp_erp_async_handler(struct zfcp_erp_action *erp_action, | ||
906 | unsigned long set_mask) | ||
907 | { | 493 | { |
908 | struct zfcp_adapter *adapter = erp_action->adapter; | 494 | struct zfcp_adapter *adapter = erp_action->adapter; |
909 | unsigned long flags; | 495 | unsigned long flags; |
910 | 496 | ||
911 | write_lock_irqsave(&adapter->erp_lock, flags); | 497 | write_lock_irqsave(&adapter->erp_lock, flags); |
912 | zfcp_erp_async_handler_nolock(erp_action, set_mask); | 498 | if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { |
913 | write_unlock_irqrestore(&adapter->erp_lock, flags); | 499 | erp_action->status |= set_mask; |
914 | } | ||
915 | |||
916 | /* | ||
917 | * purpose: is called for erp_action which was slept waiting for | ||
918 | * memory becoming avaliable, | ||
919 | * will trigger that this action will be continued | ||
920 | */ | ||
921 | static void | ||
922 | zfcp_erp_memwait_handler(unsigned long data) | ||
923 | { | ||
924 | struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; | ||
925 | |||
926 | zfcp_erp_async_handler(erp_action, 0); | ||
927 | } | ||
928 | |||
929 | /* | ||
930 | * purpose: is called if an asynchronous erp step timed out, | ||
931 | * action gets an appropriate flag and will be processed | ||
932 | * accordingly | ||
933 | */ | ||
934 | static void zfcp_erp_timeout_handler(unsigned long data) | ||
935 | { | ||
936 | struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; | ||
937 | |||
938 | zfcp_erp_async_handler(erp_action, ZFCP_STATUS_ERP_TIMEDOUT); | ||
939 | } | ||
940 | |||
941 | /** | ||
942 | * zfcp_erp_action_dismiss - dismiss an erp_action | ||
943 | * | ||
944 | * adapter->erp_lock must be held | ||
945 | * | ||
946 | * Dismissal of an erp_action is usually required if an erp_action of | ||
947 | * higher priority is generated. | ||
948 | */ | ||
949 | static void zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action) | ||
950 | { | ||
951 | erp_action->status |= ZFCP_STATUS_ERP_DISMISSED; | ||
952 | if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) | ||
953 | zfcp_erp_action_ready(erp_action); | 500 | zfcp_erp_action_ready(erp_action); |
954 | } | ||
955 | |||
956 | int | ||
957 | zfcp_erp_thread_setup(struct zfcp_adapter *adapter) | ||
958 | { | ||
959 | int retval = 0; | ||
960 | |||
961 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
962 | |||
963 | retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); | ||
964 | if (retval < 0) { | ||
965 | ZFCP_LOG_NORMAL("error: creation of erp thread failed for " | ||
966 | "adapter %s\n", | ||
967 | zfcp_get_busid_by_adapter(adapter)); | ||
968 | } else { | ||
969 | wait_event(adapter->erp_thread_wqh, | ||
970 | atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, | ||
971 | &adapter->status)); | ||
972 | } | 501 | } |
973 | 502 | write_unlock_irqrestore(&adapter->erp_lock, flags); | |
974 | return (retval < 0); | ||
975 | } | ||
976 | |||
977 | /* | ||
978 | * function: | ||
979 | * | ||
980 | * purpose: | ||
981 | * | ||
982 | * returns: | ||
983 | * | ||
984 | * context: process (i.e. proc-fs or rmmod/insmod) | ||
985 | * | ||
986 | * note: The caller of this routine ensures that the specified | ||
987 | * adapter has been shut down and that this operation | ||
988 | * has been completed. Thus, there are no pending erp_actions | ||
989 | * which would need to be handled here. | ||
990 | */ | ||
991 | int | ||
992 | zfcp_erp_thread_kill(struct zfcp_adapter *adapter) | ||
993 | { | ||
994 | int retval = 0; | ||
995 | |||
996 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); | ||
997 | up(&adapter->erp_ready_sem); | ||
998 | zfcp_rec_dbf_event_thread(2, adapter, 1); | ||
999 | |||
1000 | wait_event(adapter->erp_thread_wqh, | ||
1001 | !atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, | ||
1002 | &adapter->status)); | ||
1003 | |||
1004 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, | ||
1005 | &adapter->status); | ||
1006 | |||
1007 | return retval; | ||
1008 | } | ||
1009 | |||
1010 | /* | ||
1011 | * purpose: is run as a kernel thread, | ||
1012 | * goes through list of error recovery actions of associated adapter | ||
1013 | * and delegates single action to execution | ||
1014 | * | ||
1015 | * returns: 0 | ||
1016 | */ | ||
1017 | static int | ||
1018 | zfcp_erp_thread(void *data) | ||
1019 | { | ||
1020 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; | ||
1021 | struct list_head *next; | ||
1022 | struct zfcp_erp_action *erp_action; | ||
1023 | unsigned long flags; | ||
1024 | |||
1025 | daemonize("zfcperp%s", zfcp_get_busid_by_adapter(adapter)); | ||
1026 | /* Block all signals */ | ||
1027 | siginitsetinv(¤t->blocked, 0); | ||
1028 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1029 | wake_up(&adapter->erp_thread_wqh); | ||
1030 | |||
1031 | while (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, | ||
1032 | &adapter->status)) { | ||
1033 | |||
1034 | write_lock_irqsave(&adapter->erp_lock, flags); | ||
1035 | next = adapter->erp_ready_head.next; | ||
1036 | write_unlock_irqrestore(&adapter->erp_lock, flags); | ||
1037 | |||
1038 | if (next != &adapter->erp_ready_head) { | ||
1039 | erp_action = | ||
1040 | list_entry(next, struct zfcp_erp_action, list); | ||
1041 | /* | ||
1042 | * process action (incl. [re]moving it | ||
1043 | * from 'ready' queue) | ||
1044 | */ | ||
1045 | zfcp_erp_strategy(erp_action); | ||
1046 | } | ||
1047 | |||
1048 | /* | ||
1049 | * sleep as long as there is nothing to do, i.e. | ||
1050 | * no action in 'ready' queue to be processed and | ||
1051 | * thread is not to be killed | ||
1052 | */ | ||
1053 | zfcp_rec_dbf_event_thread(4, adapter, 1); | ||
1054 | down_interruptible(&adapter->erp_ready_sem); | ||
1055 | zfcp_rec_dbf_event_thread(5, adapter, 1); | ||
1056 | } | ||
1057 | |||
1058 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1059 | wake_up(&adapter->erp_thread_wqh); | ||
1060 | |||
1061 | return 0; | ||
1062 | } | ||
1063 | |||
1064 | /* | ||
1065 | * function: | ||
1066 | * | ||
1067 | * purpose: drives single error recovery action and schedules higher and | ||
1068 | * subordinate actions, if necessary | ||
1069 | * | ||
1070 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
1071 | * ZFCP_ERP_SUCCEEDED - action finished successfully (deqd) | ||
1072 | * ZFCP_ERP_FAILED - action finished unsuccessfully (deqd) | ||
1073 | * ZFCP_ERP_EXIT - action finished (dequeued), offline | ||
1074 | * ZFCP_ERP_DISMISSED - action canceled (dequeued) | ||
1075 | */ | ||
1076 | static int | ||
1077 | zfcp_erp_strategy(struct zfcp_erp_action *erp_action) | ||
1078 | { | ||
1079 | int retval = 0; | ||
1080 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1081 | struct zfcp_port *port = erp_action->port; | ||
1082 | struct zfcp_unit *unit = erp_action->unit; | ||
1083 | int action = erp_action->action; | ||
1084 | u32 status = erp_action->status; | ||
1085 | unsigned long flags; | ||
1086 | |||
1087 | /* serialise dismissing, timing out, moving, enqueueing */ | ||
1088 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1089 | write_lock(&adapter->erp_lock); | ||
1090 | |||
1091 | /* dequeue dismissed action and leave, if required */ | ||
1092 | retval = zfcp_erp_strategy_check_action(erp_action, retval); | ||
1093 | if (retval == ZFCP_ERP_DISMISSED) { | ||
1094 | goto unlock; | ||
1095 | } | ||
1096 | |||
1097 | /* | ||
1098 | * move action to 'running' queue before processing it | ||
1099 | * (to avoid a race condition regarding moving the | ||
1100 | * action to the 'running' queue and back) | ||
1101 | */ | ||
1102 | zfcp_erp_action_to_running(erp_action); | ||
1103 | |||
1104 | /* | ||
1105 | * try to process action as far as possible, | ||
1106 | * no lock to allow for blocking operations (kmalloc, qdio, ...), | ||
1107 | * afterwards the lock is required again for the following reasons: | ||
1108 | * - dequeueing of finished action and enqueueing of | ||
1109 | * follow-up actions must be atomic so that any other | ||
1110 | * reopen-routine does not believe there is nothing to do | ||
1111 | * and that it is safe to enqueue something else, | ||
1112 | * - we want to force any control thread which is dismissing | ||
1113 | * actions to finish this before we decide about | ||
1114 | * necessary steps to be taken here further | ||
1115 | */ | ||
1116 | write_unlock(&adapter->erp_lock); | ||
1117 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1118 | retval = zfcp_erp_strategy_do_action(erp_action); | ||
1119 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1120 | write_lock(&adapter->erp_lock); | ||
1121 | |||
1122 | /* | ||
1123 | * check for dismissed status again to avoid follow-up actions, | ||
1124 | * failing of targets and so on for dismissed actions, | ||
1125 | * we go through down() here because there has been an up() | ||
1126 | */ | ||
1127 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) | ||
1128 | retval = ZFCP_ERP_CONTINUES; | ||
1129 | |||
1130 | switch (retval) { | ||
1131 | case ZFCP_ERP_NOMEM: | ||
1132 | /* no memory to continue immediately, let it sleep */ | ||
1133 | if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { | ||
1134 | ++adapter->erp_low_mem_count; | ||
1135 | erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; | ||
1136 | } | ||
1137 | /* This condition is true if there is no memory available | ||
1138 | for any erp_action on this adapter. This implies that there | ||
1139 | are no elements in the memory pool(s) left for erp_actions. | ||
1140 | This might happen if an erp_action that used a memory pool | ||
1141 | element was timed out. | ||
1142 | */ | ||
1143 | if (adapter->erp_total_count == adapter->erp_low_mem_count) { | ||
1144 | ZFCP_LOG_NORMAL("error: no mempool elements available, " | ||
1145 | "restarting I/O on adapter %s " | ||
1146 | "to free mempool\n", | ||
1147 | zfcp_get_busid_by_adapter(adapter)); | ||
1148 | zfcp_erp_adapter_reopen_internal(adapter, 0, 66, NULL); | ||
1149 | } else { | ||
1150 | retval = zfcp_erp_strategy_memwait(erp_action); | ||
1151 | } | ||
1152 | goto unlock; | ||
1153 | case ZFCP_ERP_CONTINUES: | ||
1154 | /* leave since this action runs asynchronously */ | ||
1155 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { | ||
1156 | --adapter->erp_low_mem_count; | ||
1157 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; | ||
1158 | } | ||
1159 | goto unlock; | ||
1160 | } | ||
1161 | /* ok, finished action (whatever its result is) */ | ||
1162 | |||
1163 | /* check for unrecoverable targets */ | ||
1164 | retval = zfcp_erp_strategy_check_target(erp_action, retval); | ||
1165 | |||
1166 | /* action must be dequeued (here to allow for further ones) */ | ||
1167 | zfcp_erp_action_dequeue(erp_action); | ||
1168 | |||
1169 | /* | ||
1170 | * put this target through the erp mill again if someone has | ||
1171 | * requested to change the status of a target being online | ||
1172 | * to offline or the other way around | ||
1173 | * (old retval is preserved if nothing has to be done here) | ||
1174 | */ | ||
1175 | retval = zfcp_erp_strategy_statechange(action, status, adapter, | ||
1176 | port, unit, retval); | ||
1177 | |||
1178 | /* | ||
1179 | * leave if target is in permanent error state or if | ||
1180 | * action is repeated in order to process state change | ||
1181 | */ | ||
1182 | if (retval == ZFCP_ERP_EXIT) { | ||
1183 | goto unlock; | ||
1184 | } | ||
1185 | |||
1186 | /* trigger follow up actions */ | ||
1187 | zfcp_erp_strategy_followup_actions(action, adapter, port, unit, retval); | ||
1188 | |||
1189 | unlock: | ||
1190 | write_unlock(&adapter->erp_lock); | ||
1191 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1192 | |||
1193 | if (retval != ZFCP_ERP_CONTINUES) | ||
1194 | zfcp_erp_action_cleanup(action, adapter, port, unit, retval); | ||
1195 | |||
1196 | /* | ||
1197 | * a few tasks remain when the erp queues are empty | ||
1198 | * (don't do that if the last action evaluated was dismissed | ||
1199 | * since this clearly indicates that there is more to come) : | ||
1200 | * - close the name server port if it is open yet | ||
1201 | * (enqueues another [probably] final action) | ||
1202 | * - otherwise, wake up whoever wants to be woken when we are | ||
1203 | * done with erp | ||
1204 | */ | ||
1205 | if (retval != ZFCP_ERP_DISMISSED) | ||
1206 | zfcp_erp_strategy_check_queues(adapter); | ||
1207 | |||
1208 | return retval; | ||
1209 | } | 503 | } |
1210 | 504 | ||
1211 | /* | 505 | /** |
1212 | * function: | 506 | * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request |
1213 | * | 507 | * @data: ERP action (from timer data) |
1214 | * purpose: | ||
1215 | * | ||
1216 | * returns: ZFCP_ERP_DISMISSED - if action has been dismissed | ||
1217 | * retval - otherwise | ||
1218 | */ | 508 | */ |
1219 | static int | 509 | void zfcp_erp_timeout_handler(unsigned long data) |
1220 | zfcp_erp_strategy_check_action(struct zfcp_erp_action *erp_action, int retval) | ||
1221 | { | 510 | { |
1222 | zfcp_erp_strategy_check_fsfreq(erp_action); | 511 | struct zfcp_erp_action *act = (struct zfcp_erp_action *) data; |
1223 | 512 | zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT); | |
1224 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { | ||
1225 | zfcp_erp_action_dequeue(erp_action); | ||
1226 | retval = ZFCP_ERP_DISMISSED; | ||
1227 | } | ||
1228 | |||
1229 | return retval; | ||
1230 | } | 513 | } |
1231 | 514 | ||
1232 | static int | 515 | static void zfcp_erp_memwait_handler(unsigned long data) |
1233 | zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) | ||
1234 | { | 516 | { |
1235 | int retval = ZFCP_ERP_FAILED; | 517 | zfcp_erp_notify((struct zfcp_erp_action *)data, 0); |
1236 | |||
1237 | /* | ||
1238 | * try to execute/continue action as far as possible, | ||
1239 | * note: no lock in subsequent strategy routines | ||
1240 | * (this allows these routine to call schedule, e.g. | ||
1241 | * kmalloc with such flags or qdio_initialize & friends) | ||
1242 | * Note: in case of timeout, the separate strategies will fail | ||
1243 | * anyhow. No need for a special action. Even worse, a nameserver | ||
1244 | * failure would not wake up waiting ports without the call. | ||
1245 | */ | ||
1246 | switch (erp_action->action) { | ||
1247 | |||
1248 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1249 | retval = zfcp_erp_adapter_strategy(erp_action); | ||
1250 | break; | ||
1251 | |||
1252 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
1253 | retval = zfcp_erp_port_forced_strategy(erp_action); | ||
1254 | break; | ||
1255 | |||
1256 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
1257 | retval = zfcp_erp_port_strategy(erp_action); | ||
1258 | break; | ||
1259 | |||
1260 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
1261 | retval = zfcp_erp_unit_strategy(erp_action); | ||
1262 | break; | ||
1263 | |||
1264 | default: | ||
1265 | ZFCP_LOG_NORMAL("bug: unknown erp action requested on " | ||
1266 | "adapter %s (action=%d)\n", | ||
1267 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
1268 | erp_action->action); | ||
1269 | } | ||
1270 | |||
1271 | return retval; | ||
1272 | } | 518 | } |
1273 | 519 | ||
1274 | /* | 520 | static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) |
1275 | * function: | ||
1276 | * | ||
1277 | * purpose: triggers retry of this action after a certain amount of time | ||
1278 | * by means of timer provided by erp_action | ||
1279 | * | ||
1280 | * returns: ZFCP_ERP_CONTINUES - erp_action sleeps in erp running queue | ||
1281 | */ | ||
1282 | static int | ||
1283 | zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) | ||
1284 | { | 521 | { |
1285 | int retval = ZFCP_ERP_CONTINUES; | ||
1286 | |||
1287 | init_timer(&erp_action->timer); | 522 | init_timer(&erp_action->timer); |
1288 | erp_action->timer.function = zfcp_erp_memwait_handler; | 523 | erp_action->timer.function = zfcp_erp_memwait_handler; |
1289 | erp_action->timer.data = (unsigned long) erp_action; | 524 | erp_action->timer.data = (unsigned long) erp_action; |
1290 | erp_action->timer.expires = jiffies + ZFCP_ERP_MEMWAIT_TIMEOUT; | 525 | erp_action->timer.expires = jiffies + HZ; |
1291 | add_timer(&erp_action->timer); | 526 | add_timer(&erp_action->timer); |
1292 | |||
1293 | return retval; | ||
1294 | } | 527 | } |
1295 | 528 | ||
1296 | /* | 529 | static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, |
1297 | * function: zfcp_erp_adapter_failed | 530 | int clear, u8 id, void *ref) |
1298 | * | ||
1299 | * purpose: sets the adapter and all underlying devices to ERP_FAILED | ||
1300 | * | ||
1301 | */ | ||
1302 | void | ||
1303 | zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, u8 id, void *ref) | ||
1304 | { | ||
1305 | zfcp_erp_modify_adapter_status(adapter, id, ref, | ||
1306 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1307 | ZFCP_LOG_NORMAL("adapter erp failed on adapter %s\n", | ||
1308 | zfcp_get_busid_by_adapter(adapter)); | ||
1309 | } | ||
1310 | |||
1311 | /* | ||
1312 | * function: zfcp_erp_port_failed | ||
1313 | * | ||
1314 | * purpose: sets the port and all underlying devices to ERP_FAILED | ||
1315 | * | ||
1316 | */ | ||
1317 | void | ||
1318 | zfcp_erp_port_failed(struct zfcp_port *port, u8 id, void *ref) | ||
1319 | { | ||
1320 | zfcp_erp_modify_port_status(port, id, ref, | ||
1321 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1322 | |||
1323 | if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) | ||
1324 | ZFCP_LOG_NORMAL("port erp failed (adapter %s, " | ||
1325 | "port d_id=0x%06x)\n", | ||
1326 | zfcp_get_busid_by_port(port), port->d_id); | ||
1327 | else | ||
1328 | ZFCP_LOG_NORMAL("port erp failed (adapter %s, wwpn=0x%016Lx)\n", | ||
1329 | zfcp_get_busid_by_port(port), port->wwpn); | ||
1330 | } | ||
1331 | |||
1332 | /* | ||
1333 | * function: zfcp_erp_unit_failed | ||
1334 | * | ||
1335 | * purpose: sets the unit to ERP_FAILED | ||
1336 | * | ||
1337 | */ | ||
1338 | void | ||
1339 | zfcp_erp_unit_failed(struct zfcp_unit *unit, u8 id, void *ref) | ||
1340 | { | ||
1341 | zfcp_erp_modify_unit_status(unit, id, ref, | ||
1342 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1343 | |||
1344 | ZFCP_LOG_NORMAL("unit erp failed on unit 0x%016Lx on port 0x%016Lx " | ||
1345 | " on adapter %s\n", unit->fcp_lun, | ||
1346 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | ||
1347 | } | ||
1348 | |||
1349 | /* | ||
1350 | * function: zfcp_erp_strategy_check_target | ||
1351 | * | ||
1352 | * purpose: increments the erp action count on the device currently in | ||
1353 | * recovery if the action failed or resets the count in case of | ||
1354 | * success. If a maximum count is exceeded the device is marked | ||
1355 | * as ERP_FAILED. | ||
1356 | * The 'blocked' state of a target which has been recovered | ||
1357 | * successfully is reset. | ||
1358 | * | ||
1359 | * returns: ZFCP_ERP_CONTINUES - action continues (not considered) | ||
1360 | * ZFCP_ERP_SUCCEEDED - action finished successfully | ||
1361 | * ZFCP_ERP_EXIT - action failed and will not continue | ||
1362 | */ | ||
1363 | static int | ||
1364 | zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, int result) | ||
1365 | { | ||
1366 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1367 | struct zfcp_port *port = erp_action->port; | ||
1368 | struct zfcp_unit *unit = erp_action->unit; | ||
1369 | |||
1370 | switch (erp_action->action) { | ||
1371 | |||
1372 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
1373 | result = zfcp_erp_strategy_check_unit(unit, result); | ||
1374 | break; | ||
1375 | |||
1376 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
1377 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
1378 | result = zfcp_erp_strategy_check_port(port, result); | ||
1379 | break; | ||
1380 | |||
1381 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1382 | result = zfcp_erp_strategy_check_adapter(adapter, result); | ||
1383 | break; | ||
1384 | } | ||
1385 | |||
1386 | return result; | ||
1387 | } | ||
1388 | |||
1389 | static int | ||
1390 | zfcp_erp_strategy_statechange(int action, | ||
1391 | u32 status, | ||
1392 | struct zfcp_adapter *adapter, | ||
1393 | struct zfcp_port *port, | ||
1394 | struct zfcp_unit *unit, int retval) | ||
1395 | { | ||
1396 | switch (action) { | ||
1397 | |||
1398 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1399 | if (zfcp_erp_strategy_statechange_detected(&adapter->status, | ||
1400 | status)) { | ||
1401 | zfcp_erp_adapter_reopen_internal(adapter, | ||
1402 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
1403 | 67, NULL); | ||
1404 | retval = ZFCP_ERP_EXIT; | ||
1405 | } | ||
1406 | break; | ||
1407 | |||
1408 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
1409 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
1410 | if (zfcp_erp_strategy_statechange_detected(&port->status, | ||
1411 | status)) { | ||
1412 | zfcp_erp_port_reopen_internal(port, | ||
1413 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
1414 | 68, NULL); | ||
1415 | retval = ZFCP_ERP_EXIT; | ||
1416 | } | ||
1417 | break; | ||
1418 | |||
1419 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
1420 | if (zfcp_erp_strategy_statechange_detected(&unit->status, | ||
1421 | status)) { | ||
1422 | zfcp_erp_unit_reopen_internal(unit, | ||
1423 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
1424 | 69, NULL); | ||
1425 | retval = ZFCP_ERP_EXIT; | ||
1426 | } | ||
1427 | break; | ||
1428 | } | ||
1429 | |||
1430 | return retval; | ||
1431 | } | ||
1432 | |||
1433 | static int | ||
1434 | zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status) | ||
1435 | { | 531 | { |
1436 | return | 532 | struct zfcp_port *port; |
1437 | /* take it online */ | ||
1438 | (atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, target_status) && | ||
1439 | (ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status)) || | ||
1440 | /* take it offline */ | ||
1441 | (!atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, target_status) && | ||
1442 | !(ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status)); | ||
1443 | } | ||
1444 | |||
1445 | static int | ||
1446 | zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) | ||
1447 | { | ||
1448 | switch (result) { | ||
1449 | case ZFCP_ERP_SUCCEEDED : | ||
1450 | atomic_set(&unit->erp_counter, 0); | ||
1451 | zfcp_erp_unit_unblock(unit); | ||
1452 | break; | ||
1453 | case ZFCP_ERP_FAILED : | ||
1454 | atomic_inc(&unit->erp_counter); | ||
1455 | if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) | ||
1456 | zfcp_erp_unit_failed(unit, 21, NULL); | ||
1457 | break; | ||
1458 | case ZFCP_ERP_EXIT : | ||
1459 | /* nothing */ | ||
1460 | break; | ||
1461 | } | ||
1462 | |||
1463 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) { | ||
1464 | zfcp_erp_unit_block(unit, 0); /* for ZFCP_ERP_SUCCEEDED */ | ||
1465 | result = ZFCP_ERP_EXIT; | ||
1466 | } | ||
1467 | |||
1468 | return result; | ||
1469 | } | ||
1470 | |||
1471 | static int | ||
1472 | zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) | ||
1473 | { | ||
1474 | switch (result) { | ||
1475 | case ZFCP_ERP_SUCCEEDED : | ||
1476 | atomic_set(&port->erp_counter, 0); | ||
1477 | zfcp_erp_port_unblock(port); | ||
1478 | break; | ||
1479 | case ZFCP_ERP_FAILED : | ||
1480 | atomic_inc(&port->erp_counter); | ||
1481 | if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) | ||
1482 | zfcp_erp_port_failed(port, 22, NULL); | ||
1483 | break; | ||
1484 | case ZFCP_ERP_EXIT : | ||
1485 | /* nothing */ | ||
1486 | break; | ||
1487 | } | ||
1488 | |||
1489 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { | ||
1490 | zfcp_erp_port_block(port, 0); /* for ZFCP_ERP_SUCCEEDED */ | ||
1491 | result = ZFCP_ERP_EXIT; | ||
1492 | } | ||
1493 | 533 | ||
1494 | return result; | 534 | list_for_each_entry(port, &adapter->port_list_head, list) |
535 | if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA)) | ||
536 | _zfcp_erp_port_reopen(port, clear, id, ref); | ||
1495 | } | 537 | } |
1496 | 538 | ||
1497 | static int | 539 | static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, u8 id, |
1498 | zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result) | 540 | void *ref) |
1499 | { | 541 | { |
1500 | switch (result) { | 542 | struct zfcp_unit *unit; |
1501 | case ZFCP_ERP_SUCCEEDED : | ||
1502 | atomic_set(&adapter->erp_counter, 0); | ||
1503 | zfcp_erp_adapter_unblock(adapter); | ||
1504 | break; | ||
1505 | case ZFCP_ERP_FAILED : | ||
1506 | atomic_inc(&adapter->erp_counter); | ||
1507 | if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) | ||
1508 | zfcp_erp_adapter_failed(adapter, 23, NULL); | ||
1509 | break; | ||
1510 | case ZFCP_ERP_EXIT : | ||
1511 | /* nothing */ | ||
1512 | break; | ||
1513 | } | ||
1514 | |||
1515 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { | ||
1516 | zfcp_erp_adapter_block(adapter, 0); /* for ZFCP_ERP_SUCCEEDED */ | ||
1517 | result = ZFCP_ERP_EXIT; | ||
1518 | } | ||
1519 | |||
1520 | return result; | ||
1521 | } | ||
1522 | |||
1523 | struct zfcp_erp_add_work { | ||
1524 | struct zfcp_unit *unit; | ||
1525 | struct work_struct work; | ||
1526 | }; | ||
1527 | 543 | ||
1528 | /** | 544 | list_for_each_entry(unit, &port->unit_list_head, list) |
1529 | * zfcp_erp_scsi_scan | 545 | _zfcp_erp_unit_reopen(unit, clear, id, ref); |
1530 | * @data: pointer to a struct zfcp_erp_add_work | ||
1531 | * | ||
1532 | * Registers a logical unit with the SCSI stack. | ||
1533 | */ | ||
1534 | static void zfcp_erp_scsi_scan(struct work_struct *work) | ||
1535 | { | ||
1536 | struct zfcp_erp_add_work *p = | ||
1537 | container_of(work, struct zfcp_erp_add_work, work); | ||
1538 | struct zfcp_unit *unit = p->unit; | ||
1539 | struct fc_rport *rport = unit->port->rport; | ||
1540 | scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, | ||
1541 | unit->scsi_lun, 0); | ||
1542 | atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | ||
1543 | zfcp_unit_put(unit); | ||
1544 | kfree(p); | ||
1545 | } | 546 | } |
1546 | 547 | ||
1547 | /** | 548 | static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act) |
1548 | * zfcp_erp_schedule_work | ||
1549 | * @unit: pointer to unit which should be registered with SCSI stack | ||
1550 | * | ||
1551 | * Schedules work which registers a unit with the SCSI stack | ||
1552 | */ | ||
1553 | static void | ||
1554 | zfcp_erp_schedule_work(struct zfcp_unit *unit) | ||
1555 | { | 549 | { |
1556 | struct zfcp_erp_add_work *p; | 550 | struct zfcp_adapter *adapter = act->adapter; |
551 | struct zfcp_port *port = act->port; | ||
552 | struct zfcp_unit *unit = act->unit; | ||
553 | u32 status = act->status; | ||
1557 | 554 | ||
1558 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
1559 | if (!p) { | ||
1560 | ZFCP_LOG_NORMAL("error: Out of resources. Could not register " | ||
1561 | "the FCP-LUN 0x%Lx connected to " | ||
1562 | "the port with WWPN 0x%Lx connected to " | ||
1563 | "the adapter %s with the SCSI stack.\n", | ||
1564 | unit->fcp_lun, | ||
1565 | unit->port->wwpn, | ||
1566 | zfcp_get_busid_by_unit(unit)); | ||
1567 | return; | ||
1568 | } | ||
1569 | |||
1570 | zfcp_unit_get(unit); | ||
1571 | atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | ||
1572 | INIT_WORK(&p->work, zfcp_erp_scsi_scan); | ||
1573 | p->unit = unit; | ||
1574 | schedule_work(&p->work); | ||
1575 | } | ||
1576 | |||
1577 | /* | ||
1578 | * function: | ||
1579 | * | ||
1580 | * purpose: remaining things in good cases, | ||
1581 | * escalation in bad cases | ||
1582 | * | ||
1583 | * returns: | ||
1584 | */ | ||
1585 | static int | ||
1586 | zfcp_erp_strategy_followup_actions(int action, | ||
1587 | struct zfcp_adapter *adapter, | ||
1588 | struct zfcp_port *port, | ||
1589 | struct zfcp_unit *unit, int status) | ||
1590 | { | ||
1591 | /* initiate follow-up actions depending on success of finished action */ | 555 | /* initiate follow-up actions depending on success of finished action */ |
1592 | switch (action) { | 556 | switch (act->action) { |
1593 | 557 | ||
1594 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 558 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
1595 | if (status == ZFCP_ERP_SUCCEEDED) | 559 | if (status == ZFCP_ERP_SUCCEEDED) |
1596 | zfcp_erp_port_reopen_all_internal(adapter, 0, 70, NULL); | 560 | _zfcp_erp_port_reopen_all(adapter, 0, 70, NULL); |
1597 | else | 561 | else |
1598 | zfcp_erp_adapter_reopen_internal(adapter, 0, 71, NULL); | 562 | _zfcp_erp_adapter_reopen(adapter, 0, 71, NULL); |
1599 | break; | 563 | break; |
1600 | 564 | ||
1601 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 565 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
1602 | if (status == ZFCP_ERP_SUCCEEDED) | 566 | if (status == ZFCP_ERP_SUCCEEDED) |
1603 | zfcp_erp_port_reopen_internal(port, 0, 72, NULL); | 567 | _zfcp_erp_port_reopen(port, 0, 72, NULL); |
1604 | else | 568 | else |
1605 | zfcp_erp_adapter_reopen_internal(adapter, 0, 73, NULL); | 569 | _zfcp_erp_adapter_reopen(adapter, 0, 73, NULL); |
1606 | break; | 570 | break; |
1607 | 571 | ||
1608 | case ZFCP_ERP_ACTION_REOPEN_PORT: | 572 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
1609 | if (status == ZFCP_ERP_SUCCEEDED) | 573 | if (status == ZFCP_ERP_SUCCEEDED) |
1610 | zfcp_erp_unit_reopen_all_internal(port, 0, 74, NULL); | 574 | _zfcp_erp_unit_reopen_all(port, 0, 74, NULL); |
1611 | else | 575 | else |
1612 | zfcp_erp_port_forced_reopen_internal(port, 0, 75, NULL); | 576 | _zfcp_erp_port_forced_reopen(port, 0, 75, NULL); |
1613 | break; | 577 | break; |
1614 | 578 | ||
1615 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 579 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
1616 | /* Nothing to do if status == ZFCP_ERP_SUCCEEDED */ | ||
1617 | if (status != ZFCP_ERP_SUCCEEDED) | 580 | if (status != ZFCP_ERP_SUCCEEDED) |
1618 | zfcp_erp_port_reopen_internal(unit->port, 0, 76, NULL); | 581 | _zfcp_erp_port_reopen(unit->port, 0, 76, NULL); |
1619 | break; | 582 | break; |
1620 | } | 583 | } |
1621 | |||
1622 | return 0; | ||
1623 | } | 584 | } |
1624 | 585 | ||
1625 | static int | 586 | static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) |
1626 | zfcp_erp_strategy_check_queues(struct zfcp_adapter *adapter) | ||
1627 | { | 587 | { |
1628 | unsigned long flags; | 588 | unsigned long flags; |
1629 | 589 | ||
@@ -1637,1277 +597,622 @@ zfcp_erp_strategy_check_queues(struct zfcp_adapter *adapter) | |||
1637 | } | 597 | } |
1638 | read_unlock(&adapter->erp_lock); | 598 | read_unlock(&adapter->erp_lock); |
1639 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 599 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
1640 | |||
1641 | return 0; | ||
1642 | } | 600 | } |
1643 | 601 | ||
1644 | /** | 602 | static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) |
1645 | * zfcp_erp_wait - wait for completion of error recovery on an adapter | ||
1646 | * @adapter: adapter for which to wait for completion of its error recovery | ||
1647 | * Return: 0 | ||
1648 | */ | ||
1649 | int | ||
1650 | zfcp_erp_wait(struct zfcp_adapter *adapter) | ||
1651 | { | 603 | { |
1652 | int retval = 0; | 604 | if (zfcp_qdio_open(act->adapter)) |
1653 | 605 | return ZFCP_ERP_FAILED; | |
1654 | wait_event(adapter->erp_done_wqh, | 606 | init_waitqueue_head(&act->adapter->request_wq); |
1655 | !atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, | 607 | atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status); |
1656 | &adapter->status)); | 608 | return ZFCP_ERP_SUCCEEDED; |
1657 | |||
1658 | return retval; | ||
1659 | } | 609 | } |
1660 | 610 | ||
1661 | void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, u8 id, | 611 | static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter) |
1662 | void *ref, u32 mask, int set_or_clear) | ||
1663 | { | 612 | { |
1664 | struct zfcp_port *port; | 613 | struct zfcp_port *port; |
1665 | u32 changed, common_mask = mask & ZFCP_COMMON_FLAGS; | 614 | port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0, |
1666 | 615 | adapter->peer_d_id); | |
1667 | if (set_or_clear == ZFCP_SET) { | 616 | if (IS_ERR(port)) /* error or port already attached */ |
1668 | changed = atomic_test_and_set_mask(mask, &adapter->status); | 617 | return; |
1669 | } else { | 618 | _zfcp_erp_port_reopen(port, 0, 150, NULL); |
1670 | changed = atomic_test_and_clear_mask(mask, &adapter->status); | ||
1671 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
1672 | atomic_set(&adapter->erp_counter, 0); | ||
1673 | } | ||
1674 | if (changed) | ||
1675 | zfcp_rec_dbf_event_adapter(id, ref, adapter); | ||
1676 | |||
1677 | /* Deal with all underlying devices, only pass common_mask */ | ||
1678 | if (common_mask) | ||
1679 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
1680 | zfcp_erp_modify_port_status(port, id, ref, common_mask, | ||
1681 | set_or_clear); | ||
1682 | } | 619 | } |
1683 | 620 | ||
1684 | /* | 621 | static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) |
1685 | * function: zfcp_erp_modify_port_status | ||
1686 | * | ||
1687 | * purpose: sets the port and all underlying devices to ERP_FAILED | ||
1688 | * | ||
1689 | */ | ||
1690 | void zfcp_erp_modify_port_status(struct zfcp_port *port, u8 id, void *ref, | ||
1691 | u32 mask, int set_or_clear) | ||
1692 | { | 622 | { |
1693 | struct zfcp_unit *unit; | 623 | int retries; |
1694 | u32 changed, common_mask = mask & ZFCP_COMMON_FLAGS; | 624 | int sleep = 1; |
1695 | 625 | struct zfcp_adapter *adapter = erp_action->adapter; | |
1696 | if (set_or_clear == ZFCP_SET) { | ||
1697 | changed = atomic_test_and_set_mask(mask, &port->status); | ||
1698 | } else { | ||
1699 | changed = atomic_test_and_clear_mask(mask, &port->status); | ||
1700 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
1701 | atomic_set(&port->erp_counter, 0); | ||
1702 | } | ||
1703 | if (changed) | ||
1704 | zfcp_rec_dbf_event_port(id, ref, port); | ||
1705 | |||
1706 | /* Modify status of all underlying devices, only pass common mask */ | ||
1707 | if (common_mask) | ||
1708 | list_for_each_entry(unit, &port->unit_list_head, list) | ||
1709 | zfcp_erp_modify_unit_status(unit, id, ref, common_mask, | ||
1710 | set_or_clear); | ||
1711 | } | ||
1712 | 626 | ||
1713 | /* | 627 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); |
1714 | * function: zfcp_erp_modify_unit_status | ||
1715 | * | ||
1716 | * purpose: sets the unit to ERP_FAILED | ||
1717 | * | ||
1718 | */ | ||
1719 | void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u8 id, void *ref, | ||
1720 | u32 mask, int set_or_clear) | ||
1721 | { | ||
1722 | u32 changed; | ||
1723 | 628 | ||
1724 | if (set_or_clear == ZFCP_SET) { | 629 | for (retries = 7; retries; retries--) { |
1725 | changed = atomic_test_and_set_mask(mask, &unit->status); | 630 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, |
1726 | } else { | 631 | &adapter->status); |
1727 | changed = atomic_test_and_clear_mask(mask, &unit->status); | 632 | write_lock_irq(&adapter->erp_lock); |
1728 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { | 633 | zfcp_erp_action_to_running(erp_action); |
1729 | atomic_set(&unit->erp_counter, 0); | 634 | write_unlock_irq(&adapter->erp_lock); |
635 | if (zfcp_fsf_exchange_config_data(erp_action)) { | ||
636 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | ||
637 | &adapter->status); | ||
638 | return ZFCP_ERP_FAILED; | ||
1730 | } | 639 | } |
1731 | } | ||
1732 | if (changed) | ||
1733 | zfcp_rec_dbf_event_unit(id, ref, unit); | ||
1734 | } | ||
1735 | 640 | ||
1736 | /* | 641 | zfcp_rec_dbf_event_thread_lock(6, adapter); |
1737 | * function: | 642 | down(&adapter->erp_ready_sem); |
1738 | * | 643 | zfcp_rec_dbf_event_thread_lock(7, adapter); |
1739 | * purpose: Wrappper for zfcp_erp_port_reopen_all_internal | 644 | if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) |
1740 | * used to ensure the correct locking | 645 | break; |
1741 | * | ||
1742 | * returns: 0 - initiated action successfully | ||
1743 | * <0 - failed to initiate action | ||
1744 | */ | ||
1745 | int zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, int clear_mask, | ||
1746 | u8 id, void *ref) | ||
1747 | { | ||
1748 | int retval; | ||
1749 | unsigned long flags; | ||
1750 | |||
1751 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1752 | write_lock(&adapter->erp_lock); | ||
1753 | retval = zfcp_erp_port_reopen_all_internal(adapter, clear_mask, id, | ||
1754 | ref); | ||
1755 | write_unlock(&adapter->erp_lock); | ||
1756 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1757 | |||
1758 | return retval; | ||
1759 | } | ||
1760 | 646 | ||
1761 | static int zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, | 647 | if (!(atomic_read(&adapter->status) & |
1762 | int clear_mask, u8 id, void *ref) | 648 | ZFCP_STATUS_ADAPTER_HOST_CON_INIT)) |
1763 | { | 649 | break; |
1764 | int retval = 0; | ||
1765 | struct zfcp_port *port; | ||
1766 | 650 | ||
1767 | list_for_each_entry(port, &adapter->port_list_head, list) | 651 | ssleep(sleep); |
1768 | if (!atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) | 652 | sleep *= 2; |
1769 | zfcp_erp_port_reopen_internal(port, clear_mask, id, | 653 | } |
1770 | ref); | ||
1771 | 654 | ||
1772 | return retval; | 655 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, |
1773 | } | 656 | &adapter->status); |
1774 | 657 | ||
1775 | /* | 658 | if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK)) |
1776 | * function: | 659 | return ZFCP_ERP_FAILED; |
1777 | * | ||
1778 | * purpose: | ||
1779 | * | ||
1780 | * returns: FIXME | ||
1781 | */ | ||
1782 | static int zfcp_erp_unit_reopen_all_internal(struct zfcp_port *port, | ||
1783 | int clear_mask, u8 id, void *ref) | ||
1784 | { | ||
1785 | int retval = 0; | ||
1786 | struct zfcp_unit *unit; | ||
1787 | 660 | ||
1788 | list_for_each_entry(unit, &port->unit_list_head, list) | 661 | if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) |
1789 | zfcp_erp_unit_reopen_internal(unit, clear_mask, id, ref); | 662 | zfcp_erp_enqueue_ptp_port(adapter); |
1790 | 663 | ||
1791 | return retval; | 664 | return ZFCP_ERP_SUCCEEDED; |
1792 | } | 665 | } |
1793 | 666 | ||
1794 | /* | 667 | static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act) |
1795 | * function: | ||
1796 | * | ||
1797 | * purpose: this routine executes the 'Reopen Adapter' action | ||
1798 | * (the entire action is processed synchronously, since | ||
1799 | * there are no actions which might be run concurrently | ||
1800 | * per definition) | ||
1801 | * | ||
1802 | * returns: ZFCP_ERP_SUCCEEDED - action finished successfully | ||
1803 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
1804 | */ | ||
1805 | static int | ||
1806 | zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action) | ||
1807 | { | 668 | { |
1808 | int retval; | 669 | int ret; |
1809 | struct zfcp_adapter *adapter = erp_action->adapter; | 670 | struct zfcp_adapter *adapter = act->adapter; |
1810 | |||
1811 | retval = zfcp_erp_adapter_strategy_close(erp_action); | ||
1812 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | ||
1813 | retval = ZFCP_ERP_EXIT; | ||
1814 | else | ||
1815 | retval = zfcp_erp_adapter_strategy_open(erp_action); | ||
1816 | 671 | ||
1817 | if (retval == ZFCP_ERP_FAILED) { | 672 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); |
1818 | ZFCP_LOG_INFO("Waiting to allow the adapter %s " | ||
1819 | "to recover itself\n", | ||
1820 | zfcp_get_busid_by_adapter(adapter)); | ||
1821 | ssleep(ZFCP_TYPE2_RECOVERY_TIME); | ||
1822 | } | ||
1823 | 673 | ||
1824 | return retval; | 674 | write_lock_irq(&adapter->erp_lock); |
1825 | } | 675 | zfcp_erp_action_to_running(act); |
676 | write_unlock_irq(&adapter->erp_lock); | ||
1826 | 677 | ||
1827 | /* | 678 | ret = zfcp_fsf_exchange_port_data(act); |
1828 | * function: | 679 | if (ret == -EOPNOTSUPP) |
1829 | * | 680 | return ZFCP_ERP_SUCCEEDED; |
1830 | * purpose: | 681 | if (ret) |
1831 | * | 682 | return ZFCP_ERP_FAILED; |
1832 | * returns: ZFCP_ERP_SUCCEEDED - action finished successfully | ||
1833 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
1834 | */ | ||
1835 | static int | ||
1836 | zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *erp_action) | ||
1837 | { | ||
1838 | int retval; | ||
1839 | 683 | ||
1840 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, | 684 | zfcp_rec_dbf_event_thread_lock(8, adapter); |
1841 | &erp_action->adapter->status); | 685 | down(&adapter->erp_ready_sem); |
1842 | retval = zfcp_erp_adapter_strategy_generic(erp_action, 1); | 686 | zfcp_rec_dbf_event_thread_lock(9, adapter); |
1843 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, | 687 | if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) |
1844 | &erp_action->adapter->status); | 688 | return ZFCP_ERP_FAILED; |
1845 | 689 | ||
1846 | return retval; | 690 | return ZFCP_ERP_SUCCEEDED; |
1847 | } | 691 | } |
1848 | 692 | ||
1849 | /* | 693 | static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act) |
1850 | * function: | ||
1851 | * | ||
1852 | * purpose: | ||
1853 | * | ||
1854 | * returns: ZFCP_ERP_SUCCEEDED - action finished successfully | ||
1855 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
1856 | */ | ||
1857 | static int | ||
1858 | zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *erp_action) | ||
1859 | { | 694 | { |
1860 | int retval; | 695 | if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED) |
696 | return ZFCP_ERP_FAILED; | ||
1861 | 697 | ||
1862 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, | 698 | if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED) |
1863 | &erp_action->adapter->status); | 699 | return ZFCP_ERP_FAILED; |
1864 | retval = zfcp_erp_adapter_strategy_generic(erp_action, 0); | ||
1865 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, | ||
1866 | &erp_action->adapter->status); | ||
1867 | 700 | ||
1868 | return retval; | 701 | atomic_set(&act->adapter->stat_miss, 16); |
702 | if (zfcp_status_read_refill(act->adapter)) | ||
703 | return ZFCP_ERP_FAILED; | ||
704 | |||
705 | return ZFCP_ERP_SUCCEEDED; | ||
1869 | } | 706 | } |
1870 | 707 | ||
1871 | /* | 708 | static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *act, |
1872 | * function: zfcp_register_adapter | 709 | int close) |
1873 | * | ||
1874 | * purpose: allocate the irq associated with this devno and register | ||
1875 | * the FSF adapter with the SCSI stack | ||
1876 | * | ||
1877 | * returns: | ||
1878 | */ | ||
1879 | static int | ||
1880 | zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) | ||
1881 | { | 710 | { |
1882 | int retval = ZFCP_ERP_SUCCEEDED; | 711 | int retval = ZFCP_ERP_SUCCEEDED; |
712 | struct zfcp_adapter *adapter = act->adapter; | ||
1883 | 713 | ||
1884 | if (close) | 714 | if (close) |
1885 | goto close_only; | 715 | goto close_only; |
1886 | 716 | ||
1887 | retval = zfcp_erp_adapter_strategy_open_qdio(erp_action); | 717 | retval = zfcp_erp_adapter_strategy_open_qdio(act); |
1888 | if (retval != ZFCP_ERP_SUCCEEDED) | 718 | if (retval != ZFCP_ERP_SUCCEEDED) |
1889 | goto failed_qdio; | 719 | goto failed_qdio; |
1890 | 720 | ||
1891 | retval = zfcp_erp_adapter_strategy_open_fsf(erp_action); | 721 | retval = zfcp_erp_adapter_strategy_open_fsf(act); |
1892 | if (retval != ZFCP_ERP_SUCCEEDED) | 722 | if (retval != ZFCP_ERP_SUCCEEDED) |
1893 | goto failed_openfcp; | 723 | goto failed_openfcp; |
1894 | 724 | ||
1895 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &erp_action->adapter->status); | 725 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &act->adapter->status); |
1896 | goto out; | 726 | schedule_work(&act->adapter->scan_work); |
727 | |||
728 | return ZFCP_ERP_SUCCEEDED; | ||
1897 | 729 | ||
1898 | close_only: | 730 | close_only: |
1899 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, | 731 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, |
1900 | &erp_action->adapter->status); | 732 | &act->adapter->status); |
1901 | 733 | ||
1902 | failed_openfcp: | 734 | failed_openfcp: |
1903 | zfcp_close_fsf(erp_action->adapter); | 735 | /* close queues to ensure that buffers are not accessed by adapter */ |
736 | zfcp_qdio_close(adapter); | ||
737 | zfcp_fsf_req_dismiss_all(adapter); | ||
738 | adapter->fsf_req_seq_no = 0; | ||
739 | /* all ports and units are closed */ | ||
740 | zfcp_erp_modify_adapter_status(adapter, 24, NULL, | ||
741 | ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); | ||
1904 | failed_qdio: | 742 | failed_qdio: |
1905 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | | 743 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | |
1906 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | 744 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | |
1907 | ZFCP_STATUS_ADAPTER_XPORT_OK, | 745 | ZFCP_STATUS_ADAPTER_XPORT_OK, |
1908 | &erp_action->adapter->status); | 746 | &act->adapter->status); |
1909 | out: | ||
1910 | return retval; | 747 | return retval; |
1911 | } | 748 | } |
1912 | 749 | ||
1913 | /* | 750 | static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act) |
1914 | * function: zfcp_qdio_init | ||
1915 | * | ||
1916 | * purpose: setup QDIO operation for specified adapter | ||
1917 | * | ||
1918 | * returns: 0 - successful setup | ||
1919 | * !0 - failed setup | ||
1920 | */ | ||
1921 | static int | ||
1922 | zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) | ||
1923 | { | 751 | { |
1924 | int retval; | 752 | int retval; |
1925 | int i; | ||
1926 | volatile struct qdio_buffer_element *sbale; | ||
1927 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1928 | |||
1929 | if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) { | ||
1930 | ZFCP_LOG_NORMAL("bug: second attempt to set up QDIO on " | ||
1931 | "adapter %s\n", | ||
1932 | zfcp_get_busid_by_adapter(adapter)); | ||
1933 | goto failed_sanity; | ||
1934 | } | ||
1935 | |||
1936 | if (qdio_establish(&adapter->qdio_init_data) != 0) { | ||
1937 | ZFCP_LOG_INFO("error: establishment of QDIO queues failed " | ||
1938 | "on adapter %s\n", | ||
1939 | zfcp_get_busid_by_adapter(adapter)); | ||
1940 | goto failed_qdio_establish; | ||
1941 | } | ||
1942 | |||
1943 | if (qdio_activate(adapter->ccw_device, 0) != 0) { | ||
1944 | ZFCP_LOG_INFO("error: activation of QDIO queues failed " | ||
1945 | "on adapter %s\n", | ||
1946 | zfcp_get_busid_by_adapter(adapter)); | ||
1947 | goto failed_qdio_activate; | ||
1948 | } | ||
1949 | |||
1950 | /* | ||
1951 | * put buffers into response queue, | ||
1952 | */ | ||
1953 | for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { | ||
1954 | sbale = &(adapter->response_queue.buffer[i]->element[0]); | ||
1955 | sbale->length = 0; | ||
1956 | sbale->flags = SBAL_FLAGS_LAST_ENTRY; | ||
1957 | sbale->addr = NULL; | ||
1958 | } | ||
1959 | |||
1960 | ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, " | ||
1961 | "queue_no=%i, index_in_queue=%i, count=%i)\n", | ||
1962 | zfcp_get_busid_by_adapter(adapter), | ||
1963 | QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q); | ||
1964 | |||
1965 | retval = do_QDIO(adapter->ccw_device, | ||
1966 | QDIO_FLAG_SYNC_INPUT, | ||
1967 | 0, 0, QDIO_MAX_BUFFERS_PER_Q, NULL); | ||
1968 | |||
1969 | if (retval) { | ||
1970 | ZFCP_LOG_NORMAL("bug: setup of QDIO failed (retval=%d)\n", | ||
1971 | retval); | ||
1972 | goto failed_do_qdio; | ||
1973 | } else { | ||
1974 | adapter->response_queue.free_index = 0; | ||
1975 | atomic_set(&adapter->response_queue.free_count, 0); | ||
1976 | ZFCP_LOG_DEBUG("%i buffers successfully enqueued to " | ||
1977 | "response queue\n", QDIO_MAX_BUFFERS_PER_Q); | ||
1978 | } | ||
1979 | /* set index of first avalable SBALS / number of available SBALS */ | ||
1980 | adapter->request_queue.free_index = 0; | ||
1981 | atomic_set(&adapter->request_queue.free_count, QDIO_MAX_BUFFERS_PER_Q); | ||
1982 | adapter->request_queue.distance_from_int = 0; | ||
1983 | |||
1984 | /* initialize waitqueue used to wait for free SBALs in requests queue */ | ||
1985 | init_waitqueue_head(&adapter->request_wq); | ||
1986 | 753 | ||
1987 | /* ok, we did it - skip all cleanups for different failures */ | 754 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status); |
1988 | atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); | 755 | zfcp_erp_adapter_strategy_generic(act, 1); /* close */ |
1989 | retval = ZFCP_ERP_SUCCEEDED; | 756 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status); |
1990 | goto out; | 757 | if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY) |
758 | return ZFCP_ERP_EXIT; | ||
1991 | 759 | ||
1992 | failed_do_qdio: | 760 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status); |
1993 | /* NOP */ | 761 | retval = zfcp_erp_adapter_strategy_generic(act, 0); /* open */ |
762 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status); | ||
1994 | 763 | ||
1995 | failed_qdio_activate: | 764 | if (retval == ZFCP_ERP_FAILED) |
1996 | while (qdio_shutdown(adapter->ccw_device, | 765 | ssleep(8); |
1997 | QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) | ||
1998 | ssleep(1); | ||
1999 | |||
2000 | failed_qdio_establish: | ||
2001 | failed_sanity: | ||
2002 | retval = ZFCP_ERP_FAILED; | ||
2003 | 766 | ||
2004 | out: | ||
2005 | return retval; | 767 | return retval; |
2006 | } | 768 | } |
2007 | 769 | ||
2008 | 770 | static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act) | |
2009 | static int | ||
2010 | zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action) | ||
2011 | { | 771 | { |
2012 | int retval; | 772 | int retval; |
2013 | 773 | ||
2014 | retval = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action); | 774 | retval = zfcp_fsf_close_physical_port(act); |
2015 | if (retval == ZFCP_ERP_FAILED) | 775 | if (retval == -ENOMEM) |
776 | return ZFCP_ERP_NOMEM; | ||
777 | act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING; | ||
778 | if (retval) | ||
2016 | return ZFCP_ERP_FAILED; | 779 | return ZFCP_ERP_FAILED; |
2017 | 780 | ||
2018 | retval = zfcp_erp_adapter_strategy_open_fsf_xport(erp_action); | 781 | return ZFCP_ERP_CONTINUES; |
2019 | if (retval == ZFCP_ERP_FAILED) | ||
2020 | return ZFCP_ERP_FAILED; | ||
2021 | |||
2022 | return zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action); | ||
2023 | } | 782 | } |
2024 | 783 | ||
2025 | static int | 784 | static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port) |
2026 | zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) | ||
2027 | { | 785 | { |
2028 | int retval = ZFCP_ERP_SUCCEEDED; | 786 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | |
2029 | int retries; | 787 | ZFCP_STATUS_COMMON_CLOSING | |
2030 | int sleep = ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP; | 788 | ZFCP_STATUS_COMMON_ACCESS_DENIED | |
2031 | struct zfcp_adapter *adapter = erp_action->adapter; | 789 | ZFCP_STATUS_PORT_DID_DID | |
2032 | 790 | ZFCP_STATUS_PORT_PHYS_CLOSING | | |
2033 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); | 791 | ZFCP_STATUS_PORT_INVALID_WWPN, |
2034 | 792 | &port->status); | |
2035 | for (retries = ZFCP_EXCHANGE_CONFIG_DATA_RETRIES; retries; retries--) { | 793 | } |
2036 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | ||
2037 | &adapter->status); | ||
2038 | ZFCP_LOG_DEBUG("Doing exchange config data\n"); | ||
2039 | write_lock_irq(&adapter->erp_lock); | ||
2040 | zfcp_erp_action_to_running(erp_action); | ||
2041 | write_unlock_irq(&adapter->erp_lock); | ||
2042 | if (zfcp_fsf_exchange_config_data(erp_action)) { | ||
2043 | retval = ZFCP_ERP_FAILED; | ||
2044 | ZFCP_LOG_INFO("error: initiation of exchange of " | ||
2045 | "configuration data failed for " | ||
2046 | "adapter %s\n", | ||
2047 | zfcp_get_busid_by_adapter(adapter)); | ||
2048 | break; | ||
2049 | } | ||
2050 | ZFCP_LOG_DEBUG("Xchange underway\n"); | ||
2051 | |||
2052 | /* | ||
2053 | * Why this works: | ||
2054 | * Both the normal completion handler as well as the timeout | ||
2055 | * handler will do an 'up' when the 'exchange config data' | ||
2056 | * request completes or times out. Thus, the signal to go on | ||
2057 | * won't be lost utilizing this semaphore. | ||
2058 | * Furthermore, this 'adapter_reopen' action is | ||
2059 | * guaranteed to be the only action being there (highest action | ||
2060 | * which prevents other actions from being created). | ||
2061 | * Resulting from that, the wake signal recognized here | ||
2062 | * _must_ be the one belonging to the 'exchange config | ||
2063 | * data' request. | ||
2064 | */ | ||
2065 | zfcp_rec_dbf_event_thread(6, adapter, 1); | ||
2066 | down(&adapter->erp_ready_sem); | ||
2067 | zfcp_rec_dbf_event_thread(7, adapter, 1); | ||
2068 | if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { | ||
2069 | ZFCP_LOG_INFO("error: exchange of configuration data " | ||
2070 | "for adapter %s timed out\n", | ||
2071 | zfcp_get_busid_by_adapter(adapter)); | ||
2072 | break; | ||
2073 | } | ||
2074 | |||
2075 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | ||
2076 | &adapter->status)) | ||
2077 | break; | ||
2078 | 794 | ||
2079 | ZFCP_LOG_DEBUG("host connection still initialising... " | 795 | static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) |
2080 | "waiting and retrying...\n"); | 796 | { |
2081 | /* sleep a little bit before retry */ | 797 | struct zfcp_port *port = erp_action->port; |
2082 | ssleep(sleep); | 798 | int status = atomic_read(&port->status); |
2083 | sleep *= 2; | ||
2084 | } | ||
2085 | 799 | ||
2086 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | 800 | switch (erp_action->step) { |
2087 | &adapter->status); | 801 | case ZFCP_ERP_STEP_UNINITIALIZED: |
802 | zfcp_erp_port_strategy_clearstati(port); | ||
803 | if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) && | ||
804 | (status & ZFCP_STATUS_COMMON_OPEN)) | ||
805 | return zfcp_erp_port_forced_strategy_close(erp_action); | ||
806 | else | ||
807 | return ZFCP_ERP_FAILED; | ||
2088 | 808 | ||
2089 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | 809 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: |
2090 | &adapter->status)) { | 810 | if (status & ZFCP_STATUS_PORT_PHYS_OPEN) |
2091 | ZFCP_LOG_INFO("error: exchange of configuration data for " | 811 | return ZFCP_ERP_SUCCEEDED; |
2092 | "adapter %s failed\n", | ||
2093 | zfcp_get_busid_by_adapter(adapter)); | ||
2094 | retval = ZFCP_ERP_FAILED; | ||
2095 | } | 812 | } |
2096 | 813 | return ZFCP_ERP_FAILED; | |
2097 | return retval; | ||
2098 | } | 814 | } |
2099 | 815 | ||
2100 | static int | 816 | static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action) |
2101 | zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action) | ||
2102 | { | 817 | { |
2103 | int ret; | 818 | int retval; |
2104 | struct zfcp_adapter *adapter; | ||
2105 | |||
2106 | adapter = erp_action->adapter; | ||
2107 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); | ||
2108 | |||
2109 | write_lock_irq(&adapter->erp_lock); | ||
2110 | zfcp_erp_action_to_running(erp_action); | ||
2111 | write_unlock_irq(&adapter->erp_lock); | ||
2112 | 819 | ||
2113 | ret = zfcp_fsf_exchange_port_data(erp_action); | 820 | retval = zfcp_fsf_close_port(erp_action); |
2114 | if (ret == -EOPNOTSUPP) { | 821 | if (retval == -ENOMEM) |
2115 | return ZFCP_ERP_SUCCEEDED; | 822 | return ZFCP_ERP_NOMEM; |
2116 | } else if (ret) { | 823 | erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING; |
824 | if (retval) | ||
2117 | return ZFCP_ERP_FAILED; | 825 | return ZFCP_ERP_FAILED; |
2118 | } | 826 | return ZFCP_ERP_CONTINUES; |
2119 | |||
2120 | ret = ZFCP_ERP_SUCCEEDED; | ||
2121 | zfcp_rec_dbf_event_thread(8, adapter, 1); | ||
2122 | down(&adapter->erp_ready_sem); | ||
2123 | zfcp_rec_dbf_event_thread(9, adapter, 1); | ||
2124 | if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { | ||
2125 | ZFCP_LOG_INFO("error: exchange port data timed out (adapter " | ||
2126 | "%s)\n", zfcp_get_busid_by_adapter(adapter)); | ||
2127 | ret = ZFCP_ERP_FAILED; | ||
2128 | } | ||
2129 | |||
2130 | /* don't treat as error for the sake of compatibility */ | ||
2131 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status)) | ||
2132 | ZFCP_LOG_INFO("warning: exchange port data failed (adapter " | ||
2133 | "%s\n", zfcp_get_busid_by_adapter(adapter)); | ||
2134 | |||
2135 | return ret; | ||
2136 | } | 827 | } |
2137 | 828 | ||
2138 | static int | 829 | static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action) |
2139 | zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action | ||
2140 | *erp_action) | ||
2141 | { | 830 | { |
2142 | int retval = ZFCP_ERP_SUCCEEDED; | 831 | int retval; |
2143 | int temp_ret; | ||
2144 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2145 | int i; | ||
2146 | |||
2147 | adapter->status_read_failed = 0; | ||
2148 | for (i = 0; i < ZFCP_STATUS_READS_RECOM; i++) { | ||
2149 | temp_ret = zfcp_fsf_status_read(adapter, ZFCP_WAIT_FOR_SBAL); | ||
2150 | if (temp_ret < 0) { | ||
2151 | ZFCP_LOG_INFO("error: set-up of unsolicited status " | ||
2152 | "notification failed on adapter %s\n", | ||
2153 | zfcp_get_busid_by_adapter(adapter)); | ||
2154 | retval = ZFCP_ERP_FAILED; | ||
2155 | i--; | ||
2156 | break; | ||
2157 | } | ||
2158 | } | ||
2159 | 832 | ||
2160 | return retval; | 833 | retval = zfcp_fsf_open_port(erp_action); |
834 | if (retval == -ENOMEM) | ||
835 | return ZFCP_ERP_NOMEM; | ||
836 | erp_action->step = ZFCP_ERP_STEP_PORT_OPENING; | ||
837 | if (retval) | ||
838 | return ZFCP_ERP_FAILED; | ||
839 | return ZFCP_ERP_CONTINUES; | ||
2161 | } | 840 | } |
2162 | 841 | ||
2163 | /* | 842 | static void zfcp_erp_port_strategy_open_ns_wake(struct zfcp_erp_action *ns_act) |
2164 | * function: | ||
2165 | * | ||
2166 | * purpose: this routine executes the 'Reopen Physical Port' action | ||
2167 | * | ||
2168 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2169 | * ZFCP_ERP_SUCCEEDED - action finished successfully | ||
2170 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2171 | */ | ||
2172 | static int | ||
2173 | zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) | ||
2174 | { | 843 | { |
2175 | int retval = ZFCP_ERP_FAILED; | 844 | unsigned long flags; |
2176 | struct zfcp_port *port = erp_action->port; | 845 | struct zfcp_adapter *adapter = ns_act->adapter; |
2177 | 846 | struct zfcp_erp_action *act, *tmp; | |
2178 | switch (erp_action->step) { | 847 | int status; |
2179 | |||
2180 | /* | ||
2181 | * FIXME: | ||
2182 | * the ULP spec. begs for waiting for oustanding commands | ||
2183 | */ | ||
2184 | case ZFCP_ERP_STEP_UNINITIALIZED: | ||
2185 | zfcp_erp_port_strategy_clearstati(port); | ||
2186 | /* | ||
2187 | * it would be sufficient to test only the normal open flag | ||
2188 | * since the phys. open flag cannot be set if the normal | ||
2189 | * open flag is unset - however, this is for readabilty ... | ||
2190 | */ | ||
2191 | if (atomic_test_mask((ZFCP_STATUS_PORT_PHYS_OPEN | | ||
2192 | ZFCP_STATUS_COMMON_OPEN), | ||
2193 | &port->status)) { | ||
2194 | ZFCP_LOG_DEBUG("port 0x%016Lx is open -> trying " | ||
2195 | "close physical\n", port->wwpn); | ||
2196 | retval = | ||
2197 | zfcp_erp_port_forced_strategy_close(erp_action); | ||
2198 | } else | ||
2199 | retval = ZFCP_ERP_FAILED; | ||
2200 | break; | ||
2201 | 848 | ||
2202 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: | 849 | read_lock_irqsave(&adapter->erp_lock, flags); |
2203 | if (atomic_test_mask(ZFCP_STATUS_PORT_PHYS_OPEN, | 850 | list_for_each_entry_safe(act, tmp, &adapter->erp_running_head, list) { |
2204 | &port->status)) { | 851 | if (act->step == ZFCP_ERP_STEP_NAMESERVER_OPEN) { |
2205 | ZFCP_LOG_DEBUG("close physical failed for port " | 852 | status = atomic_read(&adapter->nameserver_port->status); |
2206 | "0x%016Lx\n", port->wwpn); | 853 | if (status & ZFCP_STATUS_COMMON_ERP_FAILED) |
2207 | retval = ZFCP_ERP_FAILED; | 854 | zfcp_erp_port_failed(act->port, 27, NULL); |
2208 | } else | 855 | zfcp_erp_action_ready(act); |
2209 | retval = ZFCP_ERP_SUCCEEDED; | 856 | } |
2210 | break; | ||
2211 | } | 857 | } |
2212 | 858 | read_unlock_irqrestore(&adapter->erp_lock, flags); | |
2213 | return retval; | ||
2214 | } | 859 | } |
2215 | 860 | ||
2216 | /* | 861 | static int zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *act) |
2217 | * function: | ||
2218 | * | ||
2219 | * purpose: this routine executes the 'Reopen Port' action | ||
2220 | * | ||
2221 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2222 | * ZFCP_ERP_SUCCEEDED - action finished successfully | ||
2223 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2224 | */ | ||
2225 | static int | ||
2226 | zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) | ||
2227 | { | 862 | { |
2228 | int retval = ZFCP_ERP_FAILED; | 863 | int retval; |
2229 | struct zfcp_port *port = erp_action->port; | ||
2230 | |||
2231 | switch (erp_action->step) { | ||
2232 | 864 | ||
2233 | /* | 865 | switch (act->step) { |
2234 | * FIXME: | ||
2235 | * the ULP spec. begs for waiting for oustanding commands | ||
2236 | */ | ||
2237 | case ZFCP_ERP_STEP_UNINITIALIZED: | 866 | case ZFCP_ERP_STEP_UNINITIALIZED: |
2238 | zfcp_erp_port_strategy_clearstati(port); | 867 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: |
2239 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { | ||
2240 | ZFCP_LOG_DEBUG("port 0x%016Lx is open -> trying " | ||
2241 | "close\n", port->wwpn); | ||
2242 | retval = zfcp_erp_port_strategy_close(erp_action); | ||
2243 | goto out; | ||
2244 | } /* else it's already closed, open it */ | ||
2245 | break; | ||
2246 | |||
2247 | case ZFCP_ERP_STEP_PORT_CLOSING: | 868 | case ZFCP_ERP_STEP_PORT_CLOSING: |
2248 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { | 869 | return zfcp_erp_port_strategy_open_port(act); |
2249 | ZFCP_LOG_DEBUG("close failed for port 0x%016Lx\n", | 870 | |
2250 | port->wwpn); | 871 | case ZFCP_ERP_STEP_PORT_OPENING: |
872 | if (atomic_read(&act->port->status) & ZFCP_STATUS_COMMON_OPEN) | ||
873 | retval = ZFCP_ERP_SUCCEEDED; | ||
874 | else | ||
2251 | retval = ZFCP_ERP_FAILED; | 875 | retval = ZFCP_ERP_FAILED; |
2252 | goto out; | 876 | /* this is needed anyway */ |
2253 | } /* else it's closed now, open it */ | 877 | zfcp_erp_port_strategy_open_ns_wake(act); |
2254 | break; | 878 | return retval; |
2255 | } | ||
2256 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | ||
2257 | retval = ZFCP_ERP_EXIT; | ||
2258 | else | ||
2259 | retval = zfcp_erp_port_strategy_open(erp_action); | ||
2260 | 879 | ||
2261 | out: | 880 | default: |
2262 | return retval; | 881 | return ZFCP_ERP_FAILED; |
882 | } | ||
2263 | } | 883 | } |
2264 | 884 | ||
2265 | static int | 885 | static int zfcp_erp_port_strategy_open_lookup(struct zfcp_erp_action *act) |
2266 | zfcp_erp_port_strategy_open(struct zfcp_erp_action *erp_action) | ||
2267 | { | 886 | { |
2268 | int retval; | 887 | int retval; |
2269 | 888 | ||
2270 | if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, | 889 | retval = zfcp_fc_ns_gid_pn_request(act); |
2271 | &erp_action->port->status)) | 890 | if (retval == -ENOMEM) |
2272 | retval = zfcp_erp_port_strategy_open_nameserver(erp_action); | 891 | return ZFCP_ERP_NOMEM; |
2273 | else | 892 | act->step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; |
2274 | retval = zfcp_erp_port_strategy_open_common(erp_action); | 893 | if (retval) |
2275 | 894 | return ZFCP_ERP_FAILED; | |
2276 | return retval; | 895 | return ZFCP_ERP_CONTINUES; |
2277 | } | 896 | } |
2278 | 897 | ||
2279 | static int | 898 | static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) |
2280 | zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action) | ||
2281 | { | 899 | { |
2282 | int retval = 0; | 900 | struct zfcp_adapter *adapter = act->adapter; |
2283 | struct zfcp_adapter *adapter = erp_action->adapter; | 901 | struct zfcp_port *port = act->port; |
2284 | struct zfcp_port *port = erp_action->port; | ||
2285 | 902 | ||
2286 | switch (erp_action->step) { | 903 | if (port->wwpn != adapter->peer_wwpn) { |
904 | dev_err(&adapter->ccw_device->dev, | ||
905 | "Failed to open port 0x%016Lx, " | ||
906 | "Peer WWPN 0x%016Lx does not " | ||
907 | "match.\n", port->wwpn, | ||
908 | adapter->peer_wwpn); | ||
909 | zfcp_erp_port_failed(port, 25, NULL); | ||
910 | return ZFCP_ERP_FAILED; | ||
911 | } | ||
912 | port->d_id = adapter->peer_d_id; | ||
913 | atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); | ||
914 | return zfcp_erp_port_strategy_open_port(act); | ||
915 | } | ||
916 | |||
917 | static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) | ||
918 | { | ||
919 | struct zfcp_adapter *adapter = act->adapter; | ||
920 | struct zfcp_port *port = act->port; | ||
921 | struct zfcp_port *ns_port = adapter->nameserver_port; | ||
922 | int p_status = atomic_read(&port->status); | ||
2287 | 923 | ||
924 | switch (act->step) { | ||
2288 | case ZFCP_ERP_STEP_UNINITIALIZED: | 925 | case ZFCP_ERP_STEP_UNINITIALIZED: |
2289 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: | 926 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: |
2290 | case ZFCP_ERP_STEP_PORT_CLOSING: | 927 | case ZFCP_ERP_STEP_PORT_CLOSING: |
2291 | if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) { | 928 | if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) |
2292 | if (port->wwpn != adapter->peer_wwpn) { | 929 | return zfcp_erp_open_ptp_port(act); |
2293 | ZFCP_LOG_NORMAL("Failed to open port 0x%016Lx " | 930 | if (!ns_port) { |
2294 | "on adapter %s.\nPeer WWPN " | 931 | dev_err(&adapter->ccw_device->dev, |
2295 | "0x%016Lx does not match\n", | 932 | "Nameserver port unavailable.\n"); |
2296 | port->wwpn, | 933 | return ZFCP_ERP_FAILED; |
2297 | zfcp_get_busid_by_adapter(adapter), | ||
2298 | adapter->peer_wwpn); | ||
2299 | zfcp_erp_port_failed(port, 25, NULL); | ||
2300 | retval = ZFCP_ERP_FAILED; | ||
2301 | break; | ||
2302 | } | ||
2303 | port->d_id = adapter->peer_d_id; | ||
2304 | atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); | ||
2305 | retval = zfcp_erp_port_strategy_open_port(erp_action); | ||
2306 | break; | ||
2307 | } | 934 | } |
2308 | if (!(adapter->nameserver_port)) { | 935 | if (!(atomic_read(&ns_port->status) & |
2309 | retval = zfcp_nameserver_enqueue(adapter); | 936 | ZFCP_STATUS_COMMON_UNBLOCKED)) { |
2310 | if (retval != 0) { | ||
2311 | ZFCP_LOG_NORMAL("error: nameserver port " | ||
2312 | "unavailable for adapter %s\n", | ||
2313 | zfcp_get_busid_by_adapter(adapter)); | ||
2314 | retval = ZFCP_ERP_FAILED; | ||
2315 | break; | ||
2316 | } | ||
2317 | } | ||
2318 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
2319 | &adapter->nameserver_port->status)) { | ||
2320 | ZFCP_LOG_DEBUG("nameserver port is not open -> open " | ||
2321 | "nameserver port\n"); | ||
2322 | /* nameserver port may live again */ | 937 | /* nameserver port may live again */ |
2323 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, | 938 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, |
2324 | &adapter->nameserver_port->status); | 939 | &ns_port->status); |
2325 | if (zfcp_erp_port_reopen(adapter->nameserver_port, 0, | 940 | if (zfcp_erp_port_reopen(ns_port, 0, 77, act) >= 0) { |
2326 | 77, erp_action) >= 0) { | 941 | act->step = ZFCP_ERP_STEP_NAMESERVER_OPEN; |
2327 | erp_action->step = | 942 | return ZFCP_ERP_CONTINUES; |
2328 | ZFCP_ERP_STEP_NAMESERVER_OPEN; | 943 | } |
2329 | retval = ZFCP_ERP_CONTINUES; | 944 | return ZFCP_ERP_FAILED; |
2330 | } else | ||
2331 | retval = ZFCP_ERP_FAILED; | ||
2332 | break; | ||
2333 | } | 945 | } |
2334 | /* else nameserver port is already open, fall through */ | 946 | /* else nameserver port is already open, fall through */ |
2335 | case ZFCP_ERP_STEP_NAMESERVER_OPEN: | 947 | case ZFCP_ERP_STEP_NAMESERVER_OPEN: |
2336 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, | 948 | if (!(atomic_read(&ns_port->status) & ZFCP_STATUS_COMMON_OPEN)) |
2337 | &adapter->nameserver_port->status)) { | 949 | return ZFCP_ERP_FAILED; |
2338 | ZFCP_LOG_DEBUG("open failed for nameserver port\n"); | 950 | return zfcp_erp_port_strategy_open_lookup(act); |
2339 | retval = ZFCP_ERP_FAILED; | ||
2340 | } else { | ||
2341 | ZFCP_LOG_DEBUG("nameserver port is open -> " | ||
2342 | "nameserver look-up for port 0x%016Lx\n", | ||
2343 | port->wwpn); | ||
2344 | retval = zfcp_erp_port_strategy_open_common_lookup | ||
2345 | (erp_action); | ||
2346 | } | ||
2347 | break; | ||
2348 | 951 | ||
2349 | case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: | 952 | case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: |
2350 | if (!atomic_test_mask(ZFCP_STATUS_PORT_DID_DID, &port->status)) { | 953 | if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) { |
2351 | if (atomic_test_mask | 954 | if (p_status & (ZFCP_STATUS_PORT_INVALID_WWPN)) { |
2352 | (ZFCP_STATUS_PORT_INVALID_WWPN, &port->status)) { | ||
2353 | ZFCP_LOG_DEBUG("nameserver look-up failed " | ||
2354 | "for port 0x%016Lx " | ||
2355 | "(misconfigured WWPN?)\n", | ||
2356 | port->wwpn); | ||
2357 | zfcp_erp_port_failed(port, 26, NULL); | 955 | zfcp_erp_port_failed(port, 26, NULL); |
2358 | retval = ZFCP_ERP_EXIT; | 956 | return ZFCP_ERP_EXIT; |
2359 | } else { | ||
2360 | ZFCP_LOG_DEBUG("nameserver look-up failed for " | ||
2361 | "port 0x%016Lx\n", port->wwpn); | ||
2362 | retval = ZFCP_ERP_FAILED; | ||
2363 | } | 957 | } |
2364 | } else { | 958 | return ZFCP_ERP_FAILED; |
2365 | ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> " | ||
2366 | "trying open\n", port->wwpn, port->d_id); | ||
2367 | retval = zfcp_erp_port_strategy_open_port(erp_action); | ||
2368 | } | 959 | } |
2369 | break; | 960 | return zfcp_erp_port_strategy_open_port(act); |
2370 | 961 | ||
2371 | case ZFCP_ERP_STEP_PORT_OPENING: | 962 | case ZFCP_ERP_STEP_PORT_OPENING: |
2372 | /* D_ID might have changed during open */ | 963 | /* D_ID might have changed during open */ |
2373 | if (atomic_test_mask((ZFCP_STATUS_COMMON_OPEN | | 964 | if ((p_status & ZFCP_STATUS_COMMON_OPEN) && |
2374 | ZFCP_STATUS_PORT_DID_DID), | 965 | (p_status & ZFCP_STATUS_PORT_DID_DID)) |
2375 | &port->status)) { | 966 | return ZFCP_ERP_SUCCEEDED; |
2376 | ZFCP_LOG_DEBUG("port 0x%016Lx is open\n", port->wwpn); | 967 | /* fall through otherwise */ |
2377 | retval = ZFCP_ERP_SUCCEEDED; | ||
2378 | } else { | ||
2379 | ZFCP_LOG_DEBUG("open failed for port 0x%016Lx\n", | ||
2380 | port->wwpn); | ||
2381 | retval = ZFCP_ERP_FAILED; | ||
2382 | } | ||
2383 | break; | ||
2384 | |||
2385 | default: | ||
2386 | ZFCP_LOG_NORMAL("bug: unknown erp step 0x%08x\n", | ||
2387 | erp_action->step); | ||
2388 | retval = ZFCP_ERP_FAILED; | ||
2389 | } | 968 | } |
969 | return ZFCP_ERP_FAILED; | ||
970 | } | ||
2390 | 971 | ||
2391 | return retval; | 972 | static int zfcp_erp_port_strategy_open(struct zfcp_erp_action *act) |
973 | { | ||
974 | if (atomic_read(&act->port->status) & (ZFCP_STATUS_PORT_WKA)) | ||
975 | return zfcp_erp_port_strategy_open_nameserver(act); | ||
976 | return zfcp_erp_port_strategy_open_common(act); | ||
2392 | } | 977 | } |
2393 | 978 | ||
2394 | static int | 979 | static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) |
2395 | zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action) | ||
2396 | { | 980 | { |
2397 | int retval; | ||
2398 | struct zfcp_port *port = erp_action->port; | 981 | struct zfcp_port *port = erp_action->port; |
2399 | 982 | ||
2400 | switch (erp_action->step) { | 983 | switch (erp_action->step) { |
2401 | |||
2402 | case ZFCP_ERP_STEP_UNINITIALIZED: | 984 | case ZFCP_ERP_STEP_UNINITIALIZED: |
2403 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: | 985 | zfcp_erp_port_strategy_clearstati(port); |
2404 | case ZFCP_ERP_STEP_PORT_CLOSING: | 986 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) |
2405 | ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> trying open\n", | 987 | return zfcp_erp_port_strategy_close(erp_action); |
2406 | port->wwpn, port->d_id); | ||
2407 | retval = zfcp_erp_port_strategy_open_port(erp_action); | ||
2408 | break; | 988 | break; |
2409 | 989 | ||
2410 | case ZFCP_ERP_STEP_PORT_OPENING: | 990 | case ZFCP_ERP_STEP_PORT_CLOSING: |
2411 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { | 991 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) |
2412 | ZFCP_LOG_DEBUG("WKA port is open\n"); | 992 | return ZFCP_ERP_FAILED; |
2413 | retval = ZFCP_ERP_SUCCEEDED; | ||
2414 | } else { | ||
2415 | ZFCP_LOG_DEBUG("open failed for WKA port\n"); | ||
2416 | retval = ZFCP_ERP_FAILED; | ||
2417 | } | ||
2418 | /* this is needed anyway (dont care for retval of wakeup) */ | ||
2419 | ZFCP_LOG_DEBUG("continue other open port operations\n"); | ||
2420 | zfcp_erp_port_strategy_open_nameserver_wakeup(erp_action); | ||
2421 | break; | 993 | break; |
2422 | |||
2423 | default: | ||
2424 | ZFCP_LOG_NORMAL("bug: unknown erp step 0x%08x\n", | ||
2425 | erp_action->step); | ||
2426 | retval = ZFCP_ERP_FAILED; | ||
2427 | } | 994 | } |
995 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | ||
996 | return ZFCP_ERP_EXIT; | ||
997 | else | ||
998 | return zfcp_erp_port_strategy_open(erp_action); | ||
2428 | 999 | ||
2429 | return retval; | 1000 | return ZFCP_ERP_FAILED; |
2430 | } | ||
2431 | |||
2432 | /* | ||
2433 | * function: | ||
2434 | * | ||
2435 | * purpose: makes the erp thread continue with reopen (physical) port | ||
2436 | * actions which have been paused until the name server port | ||
2437 | * is opened (or failed) | ||
2438 | * | ||
2439 | * returns: 0 (a kind of void retval, its not used) | ||
2440 | */ | ||
2441 | static int | ||
2442 | zfcp_erp_port_strategy_open_nameserver_wakeup(struct zfcp_erp_action | ||
2443 | *ns_erp_action) | ||
2444 | { | ||
2445 | int retval = 0; | ||
2446 | unsigned long flags; | ||
2447 | struct zfcp_adapter *adapter = ns_erp_action->adapter; | ||
2448 | struct zfcp_erp_action *erp_action, *tmp; | ||
2449 | |||
2450 | read_lock_irqsave(&adapter->erp_lock, flags); | ||
2451 | list_for_each_entry_safe(erp_action, tmp, &adapter->erp_running_head, | ||
2452 | list) { | ||
2453 | if (erp_action->step == ZFCP_ERP_STEP_NAMESERVER_OPEN) { | ||
2454 | if (atomic_test_mask( | ||
2455 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
2456 | &adapter->nameserver_port->status)) | ||
2457 | zfcp_erp_port_failed(erp_action->port, 27, | ||
2458 | NULL); | ||
2459 | zfcp_erp_action_ready(erp_action); | ||
2460 | } | ||
2461 | } | ||
2462 | read_unlock_irqrestore(&adapter->erp_lock, flags); | ||
2463 | |||
2464 | return retval; | ||
2465 | } | ||
2466 | |||
2467 | /* | ||
2468 | * function: | ||
2469 | * | ||
2470 | * purpose: | ||
2471 | * | ||
2472 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2473 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2474 | */ | ||
2475 | static int | ||
2476 | zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *erp_action) | ||
2477 | { | ||
2478 | int retval; | ||
2479 | |||
2480 | retval = zfcp_fsf_close_physical_port(erp_action); | ||
2481 | if (retval == -ENOMEM) { | ||
2482 | retval = ZFCP_ERP_NOMEM; | ||
2483 | goto out; | ||
2484 | } | ||
2485 | erp_action->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING; | ||
2486 | if (retval != 0) { | ||
2487 | /* could not send 'open', fail */ | ||
2488 | retval = ZFCP_ERP_FAILED; | ||
2489 | goto out; | ||
2490 | } | ||
2491 | retval = ZFCP_ERP_CONTINUES; | ||
2492 | out: | ||
2493 | return retval; | ||
2494 | } | 1001 | } |
2495 | 1002 | ||
2496 | static int | 1003 | static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) |
2497 | zfcp_erp_port_strategy_clearstati(struct zfcp_port *port) | ||
2498 | { | 1004 | { |
2499 | int retval = 0; | ||
2500 | |||
2501 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | | 1005 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | |
2502 | ZFCP_STATUS_COMMON_CLOSING | | 1006 | ZFCP_STATUS_COMMON_CLOSING | |
2503 | ZFCP_STATUS_COMMON_ACCESS_DENIED | | 1007 | ZFCP_STATUS_COMMON_ACCESS_DENIED | |
2504 | ZFCP_STATUS_PORT_DID_DID | | 1008 | ZFCP_STATUS_UNIT_SHARED | |
2505 | ZFCP_STATUS_PORT_PHYS_CLOSING | | 1009 | ZFCP_STATUS_UNIT_READONLY, |
2506 | ZFCP_STATUS_PORT_INVALID_WWPN, | 1010 | &unit->status); |
2507 | &port->status); | ||
2508 | return retval; | ||
2509 | } | ||
2510 | |||
2511 | /* | ||
2512 | * function: | ||
2513 | * | ||
2514 | * purpose: | ||
2515 | * | ||
2516 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2517 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2518 | */ | ||
2519 | static int | ||
2520 | zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action) | ||
2521 | { | ||
2522 | int retval; | ||
2523 | |||
2524 | retval = zfcp_fsf_close_port(erp_action); | ||
2525 | if (retval == -ENOMEM) { | ||
2526 | retval = ZFCP_ERP_NOMEM; | ||
2527 | goto out; | ||
2528 | } | ||
2529 | erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING; | ||
2530 | if (retval != 0) { | ||
2531 | /* could not send 'close', fail */ | ||
2532 | retval = ZFCP_ERP_FAILED; | ||
2533 | goto out; | ||
2534 | } | ||
2535 | retval = ZFCP_ERP_CONTINUES; | ||
2536 | out: | ||
2537 | return retval; | ||
2538 | } | 1011 | } |
2539 | 1012 | ||
2540 | /* | 1013 | static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) |
2541 | * function: | ||
2542 | * | ||
2543 | * purpose: | ||
2544 | * | ||
2545 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2546 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2547 | */ | ||
2548 | static int | ||
2549 | zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action) | ||
2550 | { | 1014 | { |
2551 | int retval; | 1015 | int retval = zfcp_fsf_close_unit(erp_action); |
2552 | 1016 | if (retval == -ENOMEM) | |
2553 | retval = zfcp_fsf_open_port(erp_action); | 1017 | return ZFCP_ERP_NOMEM; |
2554 | if (retval == -ENOMEM) { | 1018 | erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; |
2555 | retval = ZFCP_ERP_NOMEM; | 1019 | if (retval) |
2556 | goto out; | 1020 | return ZFCP_ERP_FAILED; |
2557 | } | 1021 | return ZFCP_ERP_CONTINUES; |
2558 | erp_action->step = ZFCP_ERP_STEP_PORT_OPENING; | ||
2559 | if (retval != 0) { | ||
2560 | /* could not send 'open', fail */ | ||
2561 | retval = ZFCP_ERP_FAILED; | ||
2562 | goto out; | ||
2563 | } | ||
2564 | retval = ZFCP_ERP_CONTINUES; | ||
2565 | out: | ||
2566 | return retval; | ||
2567 | } | 1022 | } |
2568 | 1023 | ||
2569 | /* | 1024 | static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) |
2570 | * function: | ||
2571 | * | ||
2572 | * purpose: | ||
2573 | * | ||
2574 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2575 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2576 | */ | ||
2577 | static int | ||
2578 | zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action) | ||
2579 | { | 1025 | { |
2580 | int retval; | 1026 | int retval = zfcp_fsf_open_unit(erp_action); |
2581 | 1027 | if (retval == -ENOMEM) | |
2582 | retval = zfcp_ns_gid_pn_request(erp_action); | 1028 | return ZFCP_ERP_NOMEM; |
2583 | if (retval == -ENOMEM) { | 1029 | erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; |
2584 | retval = ZFCP_ERP_NOMEM; | 1030 | if (retval) |
2585 | goto out; | 1031 | return ZFCP_ERP_FAILED; |
2586 | } | 1032 | return ZFCP_ERP_CONTINUES; |
2587 | erp_action->step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; | ||
2588 | if (retval != 0) { | ||
2589 | /* could not send nameserver request, fail */ | ||
2590 | retval = ZFCP_ERP_FAILED; | ||
2591 | goto out; | ||
2592 | } | ||
2593 | retval = ZFCP_ERP_CONTINUES; | ||
2594 | out: | ||
2595 | return retval; | ||
2596 | } | 1033 | } |
2597 | 1034 | ||
2598 | /* | 1035 | static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) |
2599 | * function: | ||
2600 | * | ||
2601 | * purpose: this routine executes the 'Reopen Unit' action | ||
2602 | * currently no retries | ||
2603 | * | ||
2604 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2605 | * ZFCP_ERP_SUCCEEDED - action finished successfully | ||
2606 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2607 | */ | ||
2608 | static int | ||
2609 | zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) | ||
2610 | { | 1036 | { |
2611 | int retval = ZFCP_ERP_FAILED; | ||
2612 | struct zfcp_unit *unit = erp_action->unit; | 1037 | struct zfcp_unit *unit = erp_action->unit; |
2613 | 1038 | ||
2614 | switch (erp_action->step) { | 1039 | switch (erp_action->step) { |
2615 | |||
2616 | /* | ||
2617 | * FIXME: | ||
2618 | * the ULP spec. begs for waiting for oustanding commands | ||
2619 | */ | ||
2620 | case ZFCP_ERP_STEP_UNINITIALIZED: | 1040 | case ZFCP_ERP_STEP_UNINITIALIZED: |
2621 | zfcp_erp_unit_strategy_clearstati(unit); | 1041 | zfcp_erp_unit_strategy_clearstati(unit); |
2622 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { | 1042 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) |
2623 | ZFCP_LOG_DEBUG("unit 0x%016Lx is open -> " | 1043 | return zfcp_erp_unit_strategy_close(erp_action); |
2624 | "trying close\n", unit->fcp_lun); | 1044 | /* already closed, fall through */ |
2625 | retval = zfcp_erp_unit_strategy_close(erp_action); | ||
2626 | break; | ||
2627 | } | ||
2628 | /* else it's already closed, fall through */ | ||
2629 | case ZFCP_ERP_STEP_UNIT_CLOSING: | 1045 | case ZFCP_ERP_STEP_UNIT_CLOSING: |
2630 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { | 1046 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) |
2631 | ZFCP_LOG_DEBUG("close failed for unit 0x%016Lx\n", | 1047 | return ZFCP_ERP_FAILED; |
2632 | unit->fcp_lun); | 1048 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) |
2633 | retval = ZFCP_ERP_FAILED; | 1049 | return ZFCP_ERP_EXIT; |
2634 | } else { | 1050 | return zfcp_erp_unit_strategy_open(erp_action); |
2635 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | ||
2636 | retval = ZFCP_ERP_EXIT; | ||
2637 | else { | ||
2638 | ZFCP_LOG_DEBUG("unit 0x%016Lx is not open -> " | ||
2639 | "trying open\n", unit->fcp_lun); | ||
2640 | retval = | ||
2641 | zfcp_erp_unit_strategy_open(erp_action); | ||
2642 | } | ||
2643 | } | ||
2644 | break; | ||
2645 | 1051 | ||
2646 | case ZFCP_ERP_STEP_UNIT_OPENING: | 1052 | case ZFCP_ERP_STEP_UNIT_OPENING: |
2647 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { | 1053 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) |
2648 | ZFCP_LOG_DEBUG("unit 0x%016Lx is open\n", | 1054 | return ZFCP_ERP_SUCCEEDED; |
2649 | unit->fcp_lun); | ||
2650 | retval = ZFCP_ERP_SUCCEEDED; | ||
2651 | } else { | ||
2652 | ZFCP_LOG_DEBUG("open failed for unit 0x%016Lx\n", | ||
2653 | unit->fcp_lun); | ||
2654 | retval = ZFCP_ERP_FAILED; | ||
2655 | } | ||
2656 | break; | ||
2657 | } | 1055 | } |
2658 | 1056 | return ZFCP_ERP_FAILED; | |
2659 | return retval; | ||
2660 | } | 1057 | } |
2661 | 1058 | ||
2662 | static int | 1059 | static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) |
2663 | zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) | ||
2664 | { | 1060 | { |
2665 | int retval = 0; | 1061 | switch (result) { |
2666 | 1062 | case ZFCP_ERP_SUCCEEDED : | |
2667 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | | 1063 | atomic_set(&unit->erp_counter, 0); |
2668 | ZFCP_STATUS_COMMON_CLOSING | | 1064 | zfcp_erp_unit_unblock(unit); |
2669 | ZFCP_STATUS_COMMON_ACCESS_DENIED | | 1065 | break; |
2670 | ZFCP_STATUS_UNIT_SHARED | | 1066 | case ZFCP_ERP_FAILED : |
2671 | ZFCP_STATUS_UNIT_READONLY, | 1067 | atomic_inc(&unit->erp_counter); |
2672 | &unit->status); | 1068 | if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) |
1069 | zfcp_erp_unit_failed(unit, 21, NULL); | ||
1070 | break; | ||
1071 | } | ||
2673 | 1072 | ||
2674 | return retval; | 1073 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
1074 | zfcp_erp_unit_block(unit, 0); | ||
1075 | result = ZFCP_ERP_EXIT; | ||
1076 | } | ||
1077 | return result; | ||
2675 | } | 1078 | } |
2676 | 1079 | ||
2677 | /* | 1080 | static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) |
2678 | * function: | ||
2679 | * | ||
2680 | * purpose: | ||
2681 | * | ||
2682 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2683 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2684 | */ | ||
2685 | static int | ||
2686 | zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) | ||
2687 | { | 1081 | { |
2688 | int retval; | 1082 | switch (result) { |
1083 | case ZFCP_ERP_SUCCEEDED : | ||
1084 | atomic_set(&port->erp_counter, 0); | ||
1085 | zfcp_erp_port_unblock(port); | ||
1086 | break; | ||
2689 | 1087 | ||
2690 | retval = zfcp_fsf_close_unit(erp_action); | 1088 | case ZFCP_ERP_FAILED : |
2691 | if (retval == -ENOMEM) { | 1089 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) { |
2692 | retval = ZFCP_ERP_NOMEM; | 1090 | zfcp_erp_port_block(port, 0); |
2693 | goto out; | 1091 | result = ZFCP_ERP_EXIT; |
2694 | } | 1092 | } |
2695 | erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; | 1093 | atomic_inc(&port->erp_counter); |
2696 | if (retval != 0) { | 1094 | if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) |
2697 | /* could not send 'close', fail */ | 1095 | zfcp_erp_port_failed(port, 22, NULL); |
2698 | retval = ZFCP_ERP_FAILED; | 1096 | break; |
2699 | goto out; | ||
2700 | } | 1097 | } |
2701 | retval = ZFCP_ERP_CONTINUES; | ||
2702 | 1098 | ||
2703 | out: | 1099 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
2704 | return retval; | 1100 | zfcp_erp_port_block(port, 0); |
1101 | result = ZFCP_ERP_EXIT; | ||
1102 | } | ||
1103 | return result; | ||
2705 | } | 1104 | } |
2706 | 1105 | ||
2707 | /* | 1106 | static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, |
2708 | * function: | 1107 | int result) |
2709 | * | ||
2710 | * purpose: | ||
2711 | * | ||
2712 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2713 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2714 | */ | ||
2715 | static int | ||
2716 | zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) | ||
2717 | { | 1108 | { |
2718 | int retval; | 1109 | switch (result) { |
1110 | case ZFCP_ERP_SUCCEEDED : | ||
1111 | atomic_set(&adapter->erp_counter, 0); | ||
1112 | zfcp_erp_adapter_unblock(adapter); | ||
1113 | break; | ||
2719 | 1114 | ||
2720 | retval = zfcp_fsf_open_unit(erp_action); | 1115 | case ZFCP_ERP_FAILED : |
2721 | if (retval == -ENOMEM) { | 1116 | atomic_inc(&adapter->erp_counter); |
2722 | retval = ZFCP_ERP_NOMEM; | 1117 | if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) |
2723 | goto out; | 1118 | zfcp_erp_adapter_failed(adapter, 23, NULL); |
2724 | } | 1119 | break; |
2725 | erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; | ||
2726 | if (retval != 0) { | ||
2727 | /* could not send 'open', fail */ | ||
2728 | retval = ZFCP_ERP_FAILED; | ||
2729 | goto out; | ||
2730 | } | 1120 | } |
2731 | retval = ZFCP_ERP_CONTINUES; | ||
2732 | out: | ||
2733 | return retval; | ||
2734 | } | ||
2735 | 1121 | ||
2736 | void zfcp_erp_start_timer(struct zfcp_fsf_req *fsf_req) | 1122 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
2737 | { | 1123 | zfcp_erp_adapter_block(adapter, 0); |
2738 | BUG_ON(!fsf_req->erp_action); | 1124 | result = ZFCP_ERP_EXIT; |
2739 | fsf_req->timer.function = zfcp_erp_timeout_handler; | 1125 | } |
2740 | fsf_req->timer.data = (unsigned long) fsf_req->erp_action; | 1126 | return result; |
2741 | fsf_req->timer.expires = jiffies + ZFCP_ERP_FSFREQ_TIMEOUT; | ||
2742 | add_timer(&fsf_req->timer); | ||
2743 | } | 1127 | } |
2744 | 1128 | ||
2745 | /* | 1129 | static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, |
2746 | * function: | 1130 | int result) |
2747 | * | ||
2748 | * purpose: enqueue the specified error recovery action, if needed | ||
2749 | * | ||
2750 | * returns: | ||
2751 | */ | ||
2752 | static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, | ||
2753 | struct zfcp_port *port, | ||
2754 | struct zfcp_unit *unit, u8 id, void *ref) | ||
2755 | { | 1131 | { |
2756 | int retval = 1, need = want; | 1132 | struct zfcp_adapter *adapter = erp_action->adapter; |
2757 | struct zfcp_erp_action *erp_action = NULL; | 1133 | struct zfcp_port *port = erp_action->port; |
2758 | u32 status = 0; | 1134 | struct zfcp_unit *unit = erp_action->unit; |
2759 | 1135 | ||
2760 | /* | 1136 | switch (erp_action->action) { |
2761 | * We need some rules here which check whether we really need | ||
2762 | * this action or whether we should just drop it. | ||
2763 | * E.g. if there is a unfinished 'Reopen Port' request then we drop a | ||
2764 | * 'Reopen Unit' request for an associated unit since we can't | ||
2765 | * satisfy this request now. A 'Reopen Port' action will trigger | ||
2766 | * 'Reopen Unit' actions when it completes. | ||
2767 | * Thus, there are only actions in the queue which can immediately be | ||
2768 | * executed. This makes the processing of the action queue more | ||
2769 | * efficient. | ||
2770 | */ | ||
2771 | |||
2772 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, | ||
2773 | &adapter->status)) | ||
2774 | return -EIO; | ||
2775 | 1137 | ||
2776 | /* check whether we really need this */ | ||
2777 | switch (want) { | ||
2778 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 1138 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
2779 | if (atomic_test_mask | 1139 | result = zfcp_erp_strategy_check_unit(unit, result); |
2780 | (ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)) { | 1140 | break; |
2781 | goto out; | ||
2782 | } | ||
2783 | if (!atomic_test_mask | ||
2784 | (ZFCP_STATUS_COMMON_RUNNING, &port->status) || | ||
2785 | atomic_test_mask | ||
2786 | (ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { | ||
2787 | goto out; | ||
2788 | } | ||
2789 | if (!atomic_test_mask | ||
2790 | (ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) | ||
2791 | need = ZFCP_ERP_ACTION_REOPEN_PORT; | ||
2792 | /* fall through !!! */ | ||
2793 | |||
2794 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
2795 | if (atomic_test_mask | ||
2796 | (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)) { | ||
2797 | goto out; | ||
2798 | } | ||
2799 | /* fall through !!! */ | ||
2800 | 1141 | ||
2801 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 1142 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
2802 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | 1143 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
2803 | &port->status)) { | 1144 | result = zfcp_erp_strategy_check_port(port, result); |
2804 | if (port->erp_action.action != | 1145 | break; |
2805 | ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) { | ||
2806 | ZFCP_LOG_INFO("dropped erp action %i (port " | ||
2807 | "0x%016Lx, action in use: %i)\n", | ||
2808 | want, port->wwpn, | ||
2809 | port->erp_action.action); | ||
2810 | } | ||
2811 | goto out; | ||
2812 | } | ||
2813 | if (!atomic_test_mask | ||
2814 | (ZFCP_STATUS_COMMON_RUNNING, &adapter->status) || | ||
2815 | atomic_test_mask | ||
2816 | (ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { | ||
2817 | goto out; | ||
2818 | } | ||
2819 | if (!atomic_test_mask | ||
2820 | (ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) | ||
2821 | need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; | ||
2822 | /* fall through !!! */ | ||
2823 | 1146 | ||
2824 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 1147 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
2825 | if (atomic_test_mask | 1148 | result = zfcp_erp_strategy_check_adapter(adapter, result); |
2826 | (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)) { | ||
2827 | goto out; | ||
2828 | } | ||
2829 | break; | 1149 | break; |
2830 | |||
2831 | default: | ||
2832 | ZFCP_LOG_NORMAL("bug: unknown erp action requested " | ||
2833 | "on adapter %s (action=%d)\n", | ||
2834 | zfcp_get_busid_by_adapter(adapter), want); | ||
2835 | goto out; | ||
2836 | } | 1150 | } |
1151 | return result; | ||
1152 | } | ||
2837 | 1153 | ||
2838 | /* check whether we need something stronger first */ | 1154 | static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status) |
2839 | if (need) { | 1155 | { |
2840 | ZFCP_LOG_DEBUG("stronger erp action %d needed before " | 1156 | int status = atomic_read(target_status); |
2841 | "erp action %d on adapter %s\n", | ||
2842 | need, want, zfcp_get_busid_by_adapter(adapter)); | ||
2843 | } | ||
2844 | 1157 | ||
2845 | /* mark adapter to have some error recovery pending */ | 1158 | if ((status & ZFCP_STATUS_COMMON_RUNNING) && |
2846 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); | 1159 | (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) |
1160 | return 1; /* take it online */ | ||
2847 | 1161 | ||
2848 | /* setup error recovery action */ | 1162 | if (!(status & ZFCP_STATUS_COMMON_RUNNING) && |
2849 | switch (need) { | 1163 | !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) |
1164 | return 1; /* take it offline */ | ||
2850 | 1165 | ||
2851 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 1166 | return 0; |
2852 | zfcp_unit_get(unit); | 1167 | } |
2853 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); | 1168 | |
2854 | erp_action = &unit->erp_action; | 1169 | static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) |
2855 | if (!atomic_test_mask | 1170 | { |
2856 | (ZFCP_STATUS_COMMON_RUNNING, &unit->status)) | 1171 | int action = act->action; |
2857 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | 1172 | struct zfcp_adapter *adapter = act->adapter; |
1173 | struct zfcp_port *port = act->port; | ||
1174 | struct zfcp_unit *unit = act->unit; | ||
1175 | u32 erp_status = act->status; | ||
1176 | |||
1177 | switch (action) { | ||
1178 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1179 | if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { | ||
1180 | _zfcp_erp_adapter_reopen(adapter, | ||
1181 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
1182 | 67, NULL); | ||
1183 | return ZFCP_ERP_EXIT; | ||
1184 | } | ||
2858 | break; | 1185 | break; |
2859 | 1186 | ||
2860 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
2861 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 1187 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
2862 | zfcp_port_get(port); | 1188 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
2863 | zfcp_erp_action_dismiss_port(port); | 1189 | if (zfcp_erp_strat_change_det(&port->status, erp_status)) { |
2864 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); | 1190 | _zfcp_erp_port_reopen(port, |
2865 | erp_action = &port->erp_action; | 1191 | ZFCP_STATUS_COMMON_ERP_FAILED, |
2866 | if (!atomic_test_mask | 1192 | 68, NULL); |
2867 | (ZFCP_STATUS_COMMON_RUNNING, &port->status)) | 1193 | return ZFCP_ERP_EXIT; |
2868 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | 1194 | } |
2869 | break; | 1195 | break; |
2870 | 1196 | ||
2871 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 1197 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
2872 | zfcp_adapter_get(adapter); | 1198 | if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { |
2873 | zfcp_erp_action_dismiss_adapter(adapter); | 1199 | _zfcp_erp_unit_reopen(unit, |
2874 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); | 1200 | ZFCP_STATUS_COMMON_ERP_FAILED, |
2875 | erp_action = &adapter->erp_action; | 1201 | 69, NULL); |
2876 | if (!atomic_test_mask | 1202 | return ZFCP_ERP_EXIT; |
2877 | (ZFCP_STATUS_COMMON_RUNNING, &adapter->status)) | 1203 | } |
2878 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | ||
2879 | break; | 1204 | break; |
2880 | } | 1205 | } |
2881 | 1206 | return ret; | |
2882 | memset(erp_action, 0, sizeof (struct zfcp_erp_action)); | ||
2883 | erp_action->adapter = adapter; | ||
2884 | erp_action->port = port; | ||
2885 | erp_action->unit = unit; | ||
2886 | erp_action->action = need; | ||
2887 | erp_action->status = status; | ||
2888 | |||
2889 | ++adapter->erp_total_count; | ||
2890 | |||
2891 | /* finally put it into 'ready' queue and kick erp thread */ | ||
2892 | list_add_tail(&erp_action->list, &adapter->erp_ready_head); | ||
2893 | up(&adapter->erp_ready_sem); | ||
2894 | zfcp_rec_dbf_event_thread(1, adapter, 0); | ||
2895 | retval = 0; | ||
2896 | out: | ||
2897 | zfcp_rec_dbf_event_trigger(id, ref, want, need, erp_action, | ||
2898 | adapter, port, unit); | ||
2899 | return retval; | ||
2900 | } | 1207 | } |
2901 | 1208 | ||
2902 | static int | 1209 | static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) |
2903 | zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) | ||
2904 | { | 1210 | { |
2905 | int retval = 0; | ||
2906 | struct zfcp_adapter *adapter = erp_action->adapter; | 1211 | struct zfcp_adapter *adapter = erp_action->adapter; |
2907 | 1212 | ||
2908 | --adapter->erp_total_count; | 1213 | adapter->erp_total_count--; |
2909 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { | 1214 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { |
2910 | --adapter->erp_low_mem_count; | 1215 | adapter->erp_low_mem_count--; |
2911 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; | 1216 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; |
2912 | } | 1217 | } |
2913 | 1218 | ||
@@ -2919,141 +1224,458 @@ zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) | |||
2919 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | 1224 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, |
2920 | &erp_action->unit->status); | 1225 | &erp_action->unit->status); |
2921 | break; | 1226 | break; |
1227 | |||
2922 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 1228 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
2923 | case ZFCP_ERP_ACTION_REOPEN_PORT: | 1229 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
2924 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | 1230 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, |
2925 | &erp_action->port->status); | 1231 | &erp_action->port->status); |
2926 | break; | 1232 | break; |
1233 | |||
2927 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 1234 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
2928 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | 1235 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, |
2929 | &erp_action->adapter->status); | 1236 | &erp_action->adapter->status); |
2930 | break; | 1237 | break; |
2931 | default: | ||
2932 | /* bug */ | ||
2933 | break; | ||
2934 | } | 1238 | } |
2935 | return retval; | ||
2936 | } | 1239 | } |
2937 | 1240 | ||
2938 | /** | 1241 | struct zfcp_erp_add_work { |
2939 | * zfcp_erp_action_cleanup | 1242 | struct zfcp_unit *unit; |
2940 | * | 1243 | struct work_struct work; |
2941 | * Register unit with scsi stack if appropriate and fix reference counts. | 1244 | }; |
2942 | * Note: Temporary units are not registered with scsi stack. | 1245 | |
2943 | */ | 1246 | static void zfcp_erp_scsi_scan(struct work_struct *work) |
2944 | static void | ||
2945 | zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, | ||
2946 | struct zfcp_port *port, struct zfcp_unit *unit, | ||
2947 | int result) | ||
2948 | { | 1247 | { |
2949 | switch (action) { | 1248 | struct zfcp_erp_add_work *p = |
1249 | container_of(work, struct zfcp_erp_add_work, work); | ||
1250 | struct zfcp_unit *unit = p->unit; | ||
1251 | struct fc_rport *rport = unit->port->rport; | ||
1252 | scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, | ||
1253 | unit->scsi_lun, 0); | ||
1254 | atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | ||
1255 | zfcp_unit_put(unit); | ||
1256 | kfree(p); | ||
1257 | } | ||
1258 | |||
1259 | static void zfcp_erp_schedule_work(struct zfcp_unit *unit) | ||
1260 | { | ||
1261 | struct zfcp_erp_add_work *p; | ||
1262 | |||
1263 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
1264 | if (!p) { | ||
1265 | dev_err(&unit->port->adapter->ccw_device->dev, | ||
1266 | "Out of resources. Could not register unit " | ||
1267 | "0x%016Lx on port 0x%016Lx with SCSI stack.\n", | ||
1268 | unit->fcp_lun, unit->port->wwpn); | ||
1269 | return; | ||
1270 | } | ||
1271 | |||
1272 | zfcp_unit_get(unit); | ||
1273 | atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | ||
1274 | INIT_WORK(&p->work, zfcp_erp_scsi_scan); | ||
1275 | p->unit = unit; | ||
1276 | schedule_work(&p->work); | ||
1277 | } | ||
1278 | |||
1279 | static void zfcp_erp_rport_register(struct zfcp_port *port) | ||
1280 | { | ||
1281 | struct fc_rport_identifiers ids; | ||
1282 | ids.node_name = port->wwnn; | ||
1283 | ids.port_name = port->wwpn; | ||
1284 | ids.port_id = port->d_id; | ||
1285 | ids.roles = FC_RPORT_ROLE_FCP_TARGET; | ||
1286 | port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); | ||
1287 | if (!port->rport) { | ||
1288 | dev_err(&port->adapter->ccw_device->dev, | ||
1289 | "Failed registration of rport " | ||
1290 | "0x%016Lx.\n", port->wwpn); | ||
1291 | return; | ||
1292 | } | ||
1293 | |||
1294 | scsi_target_unblock(&port->rport->dev); | ||
1295 | port->rport->maxframe_size = port->maxframe_size; | ||
1296 | port->rport->supported_classes = port->supported_classes; | ||
1297 | } | ||
1298 | |||
1299 | static void zfcp_erp_rports_del(struct zfcp_adapter *adapter) | ||
1300 | { | ||
1301 | struct zfcp_port *port; | ||
1302 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
1303 | if (port->rport && !(atomic_read(&port->status) & | ||
1304 | ZFCP_STATUS_PORT_WKA)) { | ||
1305 | fc_remote_port_delete(port->rport); | ||
1306 | port->rport = NULL; | ||
1307 | } | ||
1308 | } | ||
1309 | |||
1310 | static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | ||
1311 | { | ||
1312 | struct zfcp_adapter *adapter = act->adapter; | ||
1313 | struct zfcp_port *port = act->port; | ||
1314 | struct zfcp_unit *unit = act->unit; | ||
1315 | |||
1316 | switch (act->action) { | ||
2950 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 1317 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
2951 | if ((result == ZFCP_ERP_SUCCEEDED) | 1318 | if ((result == ZFCP_ERP_SUCCEEDED) && |
2952 | && (!atomic_test_mask(ZFCP_STATUS_UNIT_TEMPORARY, | 1319 | !unit->device && port->rport) { |
2953 | &unit->status)) | ||
2954 | && !unit->device | ||
2955 | && port->rport) { | ||
2956 | atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, | 1320 | atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, |
2957 | &unit->status); | 1321 | &unit->status); |
2958 | if (atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, | 1322 | if (!(atomic_read(&unit->status) & |
2959 | &unit->status) == 0) | 1323 | ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)) |
2960 | zfcp_erp_schedule_work(unit); | 1324 | zfcp_erp_schedule_work(unit); |
2961 | } | 1325 | } |
2962 | zfcp_unit_put(unit); | 1326 | zfcp_unit_put(unit); |
2963 | break; | 1327 | break; |
1328 | |||
2964 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 1329 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
2965 | case ZFCP_ERP_ACTION_REOPEN_PORT: | 1330 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
2966 | if (atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, | 1331 | if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN) { |
2967 | &port->status)) { | ||
2968 | zfcp_port_put(port); | 1332 | zfcp_port_put(port); |
2969 | break; | 1333 | return; |
2970 | } | ||
2971 | |||
2972 | if ((result == ZFCP_ERP_SUCCEEDED) | ||
2973 | && !port->rport) { | ||
2974 | struct fc_rport_identifiers ids; | ||
2975 | ids.node_name = port->wwnn; | ||
2976 | ids.port_name = port->wwpn; | ||
2977 | ids.port_id = port->d_id; | ||
2978 | ids.roles = FC_RPORT_ROLE_FCP_TARGET; | ||
2979 | port->rport = | ||
2980 | fc_remote_port_add(adapter->scsi_host, 0, &ids); | ||
2981 | if (!port->rport) | ||
2982 | ZFCP_LOG_NORMAL("failed registration of rport" | ||
2983 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
2984 | zfcp_get_busid_by_port(port), | ||
2985 | port->wwpn); | ||
2986 | else { | ||
2987 | scsi_target_unblock(&port->rport->dev); | ||
2988 | port->rport->maxframe_size = port->maxframe_size; | ||
2989 | port->rport->supported_classes = | ||
2990 | port->supported_classes; | ||
2991 | } | ||
2992 | } | 1334 | } |
1335 | if ((result == ZFCP_ERP_SUCCEEDED) && !port->rport) | ||
1336 | zfcp_erp_rport_register(port); | ||
2993 | if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) { | 1337 | if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) { |
2994 | fc_remote_port_delete(port->rport); | 1338 | fc_remote_port_delete(port->rport); |
2995 | port->rport = NULL; | 1339 | port->rport = NULL; |
2996 | } | 1340 | } |
2997 | zfcp_port_put(port); | 1341 | zfcp_port_put(port); |
2998 | break; | 1342 | break; |
1343 | |||
2999 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 1344 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
3000 | if (result != ZFCP_ERP_SUCCEEDED) { | 1345 | if (result != ZFCP_ERP_SUCCEEDED) |
3001 | list_for_each_entry(port, &adapter->port_list_head, list) | 1346 | zfcp_erp_rports_del(adapter); |
3002 | if (port->rport && | ||
3003 | !atomic_test_mask(ZFCP_STATUS_PORT_WKA, | ||
3004 | &port->status)) { | ||
3005 | fc_remote_port_delete(port->rport); | ||
3006 | port->rport = NULL; | ||
3007 | } | ||
3008 | } | ||
3009 | zfcp_adapter_put(adapter); | 1347 | zfcp_adapter_put(adapter); |
3010 | break; | 1348 | break; |
3011 | default: | ||
3012 | break; | ||
3013 | } | 1349 | } |
3014 | } | 1350 | } |
3015 | 1351 | ||
1352 | static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) | ||
1353 | { | ||
1354 | switch (erp_action->action) { | ||
1355 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1356 | return zfcp_erp_adapter_strategy(erp_action); | ||
1357 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
1358 | return zfcp_erp_port_forced_strategy(erp_action); | ||
1359 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
1360 | return zfcp_erp_port_strategy(erp_action); | ||
1361 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
1362 | return zfcp_erp_unit_strategy(erp_action); | ||
1363 | } | ||
1364 | return ZFCP_ERP_FAILED; | ||
1365 | } | ||
3016 | 1366 | ||
3017 | static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) | 1367 | static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) |
3018 | { | 1368 | { |
3019 | struct zfcp_port *port; | 1369 | int retval; |
1370 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1371 | unsigned long flags; | ||
3020 | 1372 | ||
3021 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)) | 1373 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
3022 | zfcp_erp_action_dismiss(&adapter->erp_action); | 1374 | write_lock(&adapter->erp_lock); |
3023 | else | 1375 | |
3024 | list_for_each_entry(port, &adapter->port_list_head, list) | 1376 | zfcp_erp_strategy_check_fsfreq(erp_action); |
3025 | zfcp_erp_action_dismiss_port(port); | 1377 | |
1378 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { | ||
1379 | zfcp_erp_action_dequeue(erp_action); | ||
1380 | retval = ZFCP_ERP_DISMISSED; | ||
1381 | goto unlock; | ||
1382 | } | ||
1383 | |||
1384 | zfcp_erp_action_to_running(erp_action); | ||
1385 | |||
1386 | /* no lock to allow for blocking operations */ | ||
1387 | write_unlock(&adapter->erp_lock); | ||
1388 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1389 | retval = zfcp_erp_strategy_do_action(erp_action); | ||
1390 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1391 | write_lock(&adapter->erp_lock); | ||
1392 | |||
1393 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) | ||
1394 | retval = ZFCP_ERP_CONTINUES; | ||
1395 | |||
1396 | switch (retval) { | ||
1397 | case ZFCP_ERP_NOMEM: | ||
1398 | if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { | ||
1399 | ++adapter->erp_low_mem_count; | ||
1400 | erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; | ||
1401 | } | ||
1402 | if (adapter->erp_total_count == adapter->erp_low_mem_count) | ||
1403 | _zfcp_erp_adapter_reopen(adapter, 0, 66, NULL); | ||
1404 | else { | ||
1405 | zfcp_erp_strategy_memwait(erp_action); | ||
1406 | retval = ZFCP_ERP_CONTINUES; | ||
1407 | } | ||
1408 | goto unlock; | ||
1409 | |||
1410 | case ZFCP_ERP_CONTINUES: | ||
1411 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { | ||
1412 | --adapter->erp_low_mem_count; | ||
1413 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; | ||
1414 | } | ||
1415 | goto unlock; | ||
1416 | } | ||
1417 | |||
1418 | retval = zfcp_erp_strategy_check_target(erp_action, retval); | ||
1419 | zfcp_erp_action_dequeue(erp_action); | ||
1420 | retval = zfcp_erp_strategy_statechange(erp_action, retval); | ||
1421 | if (retval == ZFCP_ERP_EXIT) | ||
1422 | goto unlock; | ||
1423 | zfcp_erp_strategy_followup_actions(erp_action); | ||
1424 | |||
1425 | unlock: | ||
1426 | write_unlock(&adapter->erp_lock); | ||
1427 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1428 | |||
1429 | if (retval != ZFCP_ERP_CONTINUES) | ||
1430 | zfcp_erp_action_cleanup(erp_action, retval); | ||
1431 | |||
1432 | return retval; | ||
3026 | } | 1433 | } |
3027 | 1434 | ||
3028 | static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) | 1435 | static int zfcp_erp_thread(void *data) |
3029 | { | 1436 | { |
3030 | struct zfcp_unit *unit; | 1437 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; |
1438 | struct list_head *next; | ||
1439 | struct zfcp_erp_action *act; | ||
1440 | unsigned long flags; | ||
3031 | 1441 | ||
3032 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)) | 1442 | daemonize("zfcperp%s", adapter->ccw_device->dev.bus_id); |
3033 | zfcp_erp_action_dismiss(&port->erp_action); | 1443 | /* Block all signals */ |
1444 | siginitsetinv(¤t->blocked, 0); | ||
1445 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1446 | wake_up(&adapter->erp_thread_wqh); | ||
1447 | |||
1448 | while (!(atomic_read(&adapter->status) & | ||
1449 | ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { | ||
1450 | write_lock_irqsave(&adapter->erp_lock, flags); | ||
1451 | next = adapter->erp_ready_head.next; | ||
1452 | write_unlock_irqrestore(&adapter->erp_lock, flags); | ||
1453 | |||
1454 | if (next != &adapter->erp_ready_head) { | ||
1455 | act = list_entry(next, struct zfcp_erp_action, list); | ||
1456 | |||
1457 | /* there is more to come after dismission, no notify */ | ||
1458 | if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED) | ||
1459 | zfcp_erp_wakeup(adapter); | ||
1460 | } | ||
1461 | |||
1462 | zfcp_rec_dbf_event_thread(4, adapter); | ||
1463 | down_interruptible(&adapter->erp_ready_sem); | ||
1464 | zfcp_rec_dbf_event_thread(5, adapter); | ||
1465 | } | ||
1466 | |||
1467 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1468 | wake_up(&adapter->erp_thread_wqh); | ||
1469 | |||
1470 | return 0; | ||
1471 | } | ||
1472 | |||
1473 | /** | ||
1474 | * zfcp_erp_thread_setup - Start ERP thread for adapter | ||
1475 | * @adapter: Adapter to start the ERP thread for | ||
1476 | * | ||
1477 | * Returns 0 on success or error code from kernel_thread() | ||
1478 | */ | ||
1479 | int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) | ||
1480 | { | ||
1481 | int retval; | ||
1482 | |||
1483 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1484 | retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); | ||
1485 | if (retval < 0) { | ||
1486 | dev_err(&adapter->ccw_device->dev, | ||
1487 | "Creation of ERP thread failed.\n"); | ||
1488 | return retval; | ||
1489 | } | ||
1490 | wait_event(adapter->erp_thread_wqh, | ||
1491 | atomic_read(&adapter->status) & | ||
1492 | ZFCP_STATUS_ADAPTER_ERP_THREAD_UP); | ||
1493 | return 0; | ||
1494 | } | ||
1495 | |||
1496 | /** | ||
1497 | * zfcp_erp_thread_kill - Stop ERP thread. | ||
1498 | * @adapter: Adapter where the ERP thread should be stopped. | ||
1499 | * | ||
1500 | * The caller of this routine ensures that the specified adapter has | ||
1501 | * been shut down and that this operation has been completed. Thus, | ||
1502 | * there are no pending erp_actions which would need to be handled | ||
1503 | * here. | ||
1504 | */ | ||
1505 | void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) | ||
1506 | { | ||
1507 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); | ||
1508 | up(&adapter->erp_ready_sem); | ||
1509 | zfcp_rec_dbf_event_thread_lock(2, adapter); | ||
1510 | |||
1511 | wait_event(adapter->erp_thread_wqh, | ||
1512 | !(atomic_read(&adapter->status) & | ||
1513 | ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)); | ||
1514 | |||
1515 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, | ||
1516 | &adapter->status); | ||
1517 | } | ||
1518 | |||
1519 | /** | ||
1520 | * zfcp_erp_adapter_failed - Set adapter status to failed. | ||
1521 | * @adapter: Failed adapter. | ||
1522 | * @id: Event id for debug trace. | ||
1523 | * @ref: Reference for debug trace. | ||
1524 | */ | ||
1525 | void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, u8 id, void *ref) | ||
1526 | { | ||
1527 | zfcp_erp_modify_adapter_status(adapter, id, ref, | ||
1528 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1529 | dev_err(&adapter->ccw_device->dev, "Adapter ERP failed.\n"); | ||
1530 | } | ||
1531 | |||
1532 | /** | ||
1533 | * zfcp_erp_port_failed - Set port status to failed. | ||
1534 | * @port: Failed port. | ||
1535 | * @id: Event id for debug trace. | ||
1536 | * @ref: Reference for debug trace. | ||
1537 | */ | ||
1538 | void zfcp_erp_port_failed(struct zfcp_port *port, u8 id, void *ref) | ||
1539 | { | ||
1540 | zfcp_erp_modify_port_status(port, id, ref, | ||
1541 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1542 | |||
1543 | if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA) | ||
1544 | dev_err(&port->adapter->ccw_device->dev, | ||
1545 | "Port ERP failed for WKA port d_id=0x%06x.\n", | ||
1546 | port->d_id); | ||
3034 | else | 1547 | else |
3035 | list_for_each_entry(unit, &port->unit_list_head, list) | 1548 | dev_err(&port->adapter->ccw_device->dev, |
3036 | zfcp_erp_action_dismiss_unit(unit); | 1549 | "Port ERP failed for port wwpn=0x%016Lx.\n", |
1550 | port->wwpn); | ||
3037 | } | 1551 | } |
3038 | 1552 | ||
3039 | static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) | 1553 | /** |
1554 | * zfcp_erp_unit_failed - Set unit status to failed. | ||
1555 | * @unit: Failed unit. | ||
1556 | * @id: Event id for debug trace. | ||
1557 | * @ref: Reference for debug trace. | ||
1558 | */ | ||
1559 | void zfcp_erp_unit_failed(struct zfcp_unit *unit, u8 id, void *ref) | ||
3040 | { | 1560 | { |
3041 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)) | 1561 | zfcp_erp_modify_unit_status(unit, id, ref, |
3042 | zfcp_erp_action_dismiss(&unit->erp_action); | 1562 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); |
1563 | |||
1564 | dev_err(&unit->port->adapter->ccw_device->dev, | ||
1565 | "Unit ERP failed for unit 0x%016Lx on port 0x%016Lx.\n", | ||
1566 | unit->fcp_lun, unit->port->wwpn); | ||
3043 | } | 1567 | } |
3044 | 1568 | ||
3045 | static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) | 1569 | /** |
1570 | * zfcp_erp_wait - wait for completion of error recovery on an adapter | ||
1571 | * @adapter: adapter for which to wait for completion of its error recovery | ||
1572 | */ | ||
1573 | void zfcp_erp_wait(struct zfcp_adapter *adapter) | ||
3046 | { | 1574 | { |
3047 | list_move(&erp_action->list, &erp_action->adapter->erp_running_head); | 1575 | wait_event(adapter->erp_done_wqh, |
3048 | zfcp_rec_dbf_event_action(145, erp_action); | 1576 | !(atomic_read(&adapter->status) & |
1577 | ZFCP_STATUS_ADAPTER_ERP_PENDING)); | ||
1578 | } | ||
1579 | |||
1580 | /** | ||
1581 | * zfcp_erp_modify_adapter_status - change adapter status bits | ||
1582 | * @adapter: adapter to change the status | ||
1583 | * @id: id for the debug trace | ||
1584 | * @ref: reference for the debug trace | ||
1585 | * @mask: status bits to change | ||
1586 | * @set_or_clear: ZFCP_SET or ZFCP_CLEAR | ||
1587 | * | ||
1588 | * Changes in common status bits are propagated to attached ports and units. | ||
1589 | */ | ||
1590 | void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, u8 id, | ||
1591 | void *ref, u32 mask, int set_or_clear) | ||
1592 | { | ||
1593 | struct zfcp_port *port; | ||
1594 | u32 common_mask = mask & ZFCP_COMMON_FLAGS; | ||
1595 | |||
1596 | if (set_or_clear == ZFCP_SET) { | ||
1597 | if (status_change_set(mask, &adapter->status)) | ||
1598 | zfcp_rec_dbf_event_adapter(id, ref, adapter); | ||
1599 | atomic_set_mask(mask, &adapter->status); | ||
1600 | } else { | ||
1601 | if (status_change_clear(mask, &adapter->status)) | ||
1602 | zfcp_rec_dbf_event_adapter(id, ref, adapter); | ||
1603 | atomic_clear_mask(mask, &adapter->status); | ||
1604 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
1605 | atomic_set(&adapter->erp_counter, 0); | ||
1606 | } | ||
1607 | |||
1608 | if (common_mask) | ||
1609 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
1610 | zfcp_erp_modify_port_status(port, id, ref, common_mask, | ||
1611 | set_or_clear); | ||
3049 | } | 1612 | } |
3050 | 1613 | ||
3051 | static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) | 1614 | /** |
1615 | * zfcp_erp_modify_port_status - change port status bits | ||
1616 | * @port: port to change the status bits | ||
1617 | * @id: id for the debug trace | ||
1618 | * @ref: reference for the debug trace | ||
1619 | * @mask: status bits to change | ||
1620 | * @set_or_clear: ZFCP_SET or ZFCP_CLEAR | ||
1621 | * | ||
1622 | * Changes in common status bits are propagated to attached units. | ||
1623 | */ | ||
1624 | void zfcp_erp_modify_port_status(struct zfcp_port *port, u8 id, void *ref, | ||
1625 | u32 mask, int set_or_clear) | ||
3052 | { | 1626 | { |
3053 | list_move(&erp_action->list, &erp_action->adapter->erp_ready_head); | 1627 | struct zfcp_unit *unit; |
3054 | zfcp_rec_dbf_event_action(146, erp_action); | 1628 | u32 common_mask = mask & ZFCP_COMMON_FLAGS; |
1629 | |||
1630 | if (set_or_clear == ZFCP_SET) { | ||
1631 | if (status_change_set(mask, &port->status)) | ||
1632 | zfcp_rec_dbf_event_port(id, ref, port); | ||
1633 | atomic_set_mask(mask, &port->status); | ||
1634 | } else { | ||
1635 | if (status_change_clear(mask, &port->status)) | ||
1636 | zfcp_rec_dbf_event_port(id, ref, port); | ||
1637 | atomic_clear_mask(mask, &port->status); | ||
1638 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
1639 | atomic_set(&port->erp_counter, 0); | ||
1640 | } | ||
1641 | |||
1642 | if (common_mask) | ||
1643 | list_for_each_entry(unit, &port->unit_list_head, list) | ||
1644 | zfcp_erp_modify_unit_status(unit, id, ref, common_mask, | ||
1645 | set_or_clear); | ||
3055 | } | 1646 | } |
3056 | 1647 | ||
1648 | /** | ||
1649 | * zfcp_erp_modify_unit_status - change unit status bits | ||
1650 | * @unit: unit to change the status bits | ||
1651 | * @id: id for the debug trace | ||
1652 | * @ref: reference for the debug trace | ||
1653 | * @mask: status bits to change | ||
1654 | * @set_or_clear: ZFCP_SET or ZFCP_CLEAR | ||
1655 | */ | ||
1656 | void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u8 id, void *ref, | ||
1657 | u32 mask, int set_or_clear) | ||
1658 | { | ||
1659 | if (set_or_clear == ZFCP_SET) { | ||
1660 | if (status_change_set(mask, &unit->status)) | ||
1661 | zfcp_rec_dbf_event_unit(id, ref, unit); | ||
1662 | atomic_set_mask(mask, &unit->status); | ||
1663 | } else { | ||
1664 | if (status_change_clear(mask, &unit->status)) | ||
1665 | zfcp_rec_dbf_event_unit(id, ref, unit); | ||
1666 | atomic_clear_mask(mask, &unit->status); | ||
1667 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { | ||
1668 | atomic_set(&unit->erp_counter, 0); | ||
1669 | } | ||
1670 | } | ||
1671 | } | ||
1672 | |||
1673 | /** | ||
1674 | * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP | ||
1675 | * @port: The "boxed" port. | ||
1676 | * @id: The debug trace id. | ||
1677 | * @id: Reference for the debug trace. | ||
1678 | */ | ||
3057 | void zfcp_erp_port_boxed(struct zfcp_port *port, u8 id, void *ref) | 1679 | void zfcp_erp_port_boxed(struct zfcp_port *port, u8 id, void *ref) |
3058 | { | 1680 | { |
3059 | unsigned long flags; | 1681 | unsigned long flags; |
@@ -3065,6 +1687,12 @@ void zfcp_erp_port_boxed(struct zfcp_port *port, u8 id, void *ref) | |||
3065 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); | 1687 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
3066 | } | 1688 | } |
3067 | 1689 | ||
1690 | /** | ||
1691 | * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP | ||
1692 | * @port: The "boxed" unit. | ||
1693 | * @id: The debug trace id. | ||
1694 | * @id: Reference for the debug trace. | ||
1695 | */ | ||
3068 | void zfcp_erp_unit_boxed(struct zfcp_unit *unit, u8 id, void *ref) | 1696 | void zfcp_erp_unit_boxed(struct zfcp_unit *unit, u8 id, void *ref) |
3069 | { | 1697 | { |
3070 | zfcp_erp_modify_unit_status(unit, id, ref, | 1698 | zfcp_erp_modify_unit_status(unit, id, ref, |
@@ -3072,6 +1700,15 @@ void zfcp_erp_unit_boxed(struct zfcp_unit *unit, u8 id, void *ref) | |||
3072 | zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); | 1700 | zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
3073 | } | 1701 | } |
3074 | 1702 | ||
1703 | /** | ||
1704 | * zfcp_erp_port_access_denied - Adapter denied access to port. | ||
1705 | * @port: port where access has been denied | ||
1706 | * @id: id for debug trace | ||
1707 | * @ref: reference for debug trace | ||
1708 | * | ||
1709 | * Since the adapter has denied access, stop using the port and the | ||
1710 | * attached units. | ||
1711 | */ | ||
3075 | void zfcp_erp_port_access_denied(struct zfcp_port *port, u8 id, void *ref) | 1712 | void zfcp_erp_port_access_denied(struct zfcp_port *port, u8 id, void *ref) |
3076 | { | 1713 | { |
3077 | unsigned long flags; | 1714 | unsigned long flags; |
@@ -3083,6 +1720,14 @@ void zfcp_erp_port_access_denied(struct zfcp_port *port, u8 id, void *ref) | |||
3083 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 1720 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
3084 | } | 1721 | } |
3085 | 1722 | ||
1723 | /** | ||
1724 | * zfcp_erp_unit_access_denied - Adapter denied access to unit. | ||
1725 | * @unit: unit where access has been denied | ||
1726 | * @id: id for debug trace | ||
1727 | * @ref: reference for debug trace | ||
1728 | * | ||
1729 | * Since the adapter has denied access, stop using the unit. | ||
1730 | */ | ||
3086 | void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, u8 id, void *ref) | 1731 | void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, u8 id, void *ref) |
3087 | { | 1732 | { |
3088 | zfcp_erp_modify_unit_status(unit, id, ref, | 1733 | zfcp_erp_modify_unit_status(unit, id, ref, |
@@ -3090,67 +1735,54 @@ void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, u8 id, void *ref) | |||
3090 | ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); | 1735 | ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); |
3091 | } | 1736 | } |
3092 | 1737 | ||
3093 | void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, u8 id, | 1738 | static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, u8 id, |
3094 | void *ref) | 1739 | void *ref) |
3095 | { | 1740 | { |
3096 | struct zfcp_port *port; | 1741 | int status = atomic_read(&unit->status); |
3097 | unsigned long flags; | 1742 | if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | |
3098 | 1743 | ZFCP_STATUS_COMMON_ACCESS_BOXED))) | |
3099 | if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) | ||
3100 | return; | 1744 | return; |
3101 | 1745 | ||
3102 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 1746 | zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
3103 | if (adapter->nameserver_port) | ||
3104 | zfcp_erp_port_access_changed(adapter->nameserver_port, id, ref); | ||
3105 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
3106 | if (port != adapter->nameserver_port) | ||
3107 | zfcp_erp_port_access_changed(port, id, ref); | ||
3108 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
3109 | } | 1747 | } |
3110 | 1748 | ||
3111 | void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id, void *ref) | 1749 | static void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id, |
1750 | void *ref) | ||
3112 | { | 1751 | { |
3113 | struct zfcp_adapter *adapter = port->adapter; | ||
3114 | struct zfcp_unit *unit; | 1752 | struct zfcp_unit *unit; |
1753 | int status = atomic_read(&port->status); | ||
3115 | 1754 | ||
3116 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, | 1755 | if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | |
3117 | &port->status) && | 1756 | ZFCP_STATUS_COMMON_ACCESS_BOXED))) { |
3118 | !atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED, | 1757 | if (!(status & ZFCP_STATUS_PORT_WKA)) |
3119 | &port->status)) { | ||
3120 | if (!atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) | ||
3121 | list_for_each_entry(unit, &port->unit_list_head, list) | 1758 | list_for_each_entry(unit, &port->unit_list_head, list) |
3122 | zfcp_erp_unit_access_changed(unit, id, ref); | 1759 | zfcp_erp_unit_access_changed(unit, id, ref); |
3123 | return; | 1760 | return; |
3124 | } | 1761 | } |
3125 | 1762 | ||
3126 | ZFCP_LOG_NORMAL("reopen of port 0x%016Lx on adapter %s " | 1763 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
3127 | "(due to ACT update)\n", | ||
3128 | port->wwpn, zfcp_get_busid_by_adapter(adapter)); | ||
3129 | if (zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref)) | ||
3130 | ZFCP_LOG_NORMAL("failed reopen of port" | ||
3131 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
3132 | zfcp_get_busid_by_adapter(adapter), port->wwpn); | ||
3133 | } | 1764 | } |
3134 | 1765 | ||
3135 | void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, u8 id, void *ref) | 1766 | /** |
1767 | * zfcp_erp_adapter_access_changed - Process change in adapter ACT | ||
1768 | * @adapter: Adapter where the Access Control Table (ACT) changed | ||
1769 | * @id: Id for debug trace | ||
1770 | * @ref: Reference for debug trace | ||
1771 | */ | ||
1772 | void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, u8 id, | ||
1773 | void *ref) | ||
3136 | { | 1774 | { |
3137 | struct zfcp_adapter *adapter = unit->port->adapter; | 1775 | struct zfcp_port *port; |
1776 | unsigned long flags; | ||
3138 | 1777 | ||
3139 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, | 1778 | if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) |
3140 | &unit->status) && | ||
3141 | !atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED, | ||
3142 | &unit->status)) | ||
3143 | return; | 1779 | return; |
3144 | 1780 | ||
3145 | ZFCP_LOG_NORMAL("reopen of unit 0x%016Lx on port 0x%016Lx " | 1781 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
3146 | " on adapter %s (due to ACT update)\n", | 1782 | if (adapter->nameserver_port) |
3147 | unit->fcp_lun, unit->port->wwpn, | 1783 | zfcp_erp_port_access_changed(adapter->nameserver_port, id, ref); |
3148 | zfcp_get_busid_by_adapter(adapter)); | 1784 | list_for_each_entry(port, &adapter->port_list_head, list) |
3149 | if (zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref)) | 1785 | if (port != adapter->nameserver_port) |
3150 | ZFCP_LOG_NORMAL("failed reopen of unit (adapter %s, " | 1786 | zfcp_erp_port_access_changed(port, id, ref); |
3151 | "wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n", | 1787 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
3152 | zfcp_get_busid_by_adapter(adapter), | ||
3153 | unit->port->wwpn, unit->fcp_lun); | ||
3154 | } | 1788 | } |
3155 | |||
3156 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 6abf178fda5d..8065b2b224b7 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -1,22 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * External function declarations. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #ifndef ZFCP_EXT_H | 9 | #ifndef ZFCP_EXT_H |
@@ -24,172 +11,51 @@ | |||
24 | 11 | ||
25 | #include "zfcp_def.h" | 12 | #include "zfcp_def.h" |
26 | 13 | ||
27 | extern struct zfcp_data zfcp_data; | 14 | /* zfcp_aux.c */ |
28 | 15 | extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, | |
29 | /******************************** SYSFS *************************************/ | 16 | fcp_lun_t); |
30 | extern struct attribute_group *zfcp_driver_attr_groups[]; | 17 | extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, |
31 | extern int zfcp_sysfs_adapter_create_files(struct device *); | 18 | wwn_t); |
32 | extern void zfcp_sysfs_adapter_remove_files(struct device *); | 19 | extern int zfcp_adapter_enqueue(struct ccw_device *); |
33 | extern int zfcp_sysfs_port_create_files(struct device *, u32); | 20 | extern void zfcp_adapter_dequeue(struct zfcp_adapter *); |
34 | extern void zfcp_sysfs_port_remove_files(struct device *, u32); | 21 | extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, u32, |
35 | extern int zfcp_sysfs_unit_create_files(struct device *); | 22 | u32); |
36 | extern void zfcp_sysfs_unit_remove_files(struct device *); | 23 | extern void zfcp_port_dequeue(struct zfcp_port *); |
37 | extern void zfcp_sysfs_port_release(struct device *); | ||
38 | extern void zfcp_sysfs_unit_release(struct device *); | ||
39 | |||
40 | /**************************** CONFIGURATION *********************************/ | ||
41 | extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, fcp_lun_t); | ||
42 | extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, wwn_t); | ||
43 | extern struct zfcp_port *zfcp_get_port_by_did(struct zfcp_adapter *, u32); | ||
44 | struct zfcp_adapter *zfcp_get_adapter_by_busid(char *); | ||
45 | extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *); | ||
46 | extern int zfcp_adapter_debug_register(struct zfcp_adapter *); | ||
47 | extern void zfcp_adapter_dequeue(struct zfcp_adapter *); | ||
48 | extern void zfcp_adapter_debug_unregister(struct zfcp_adapter *); | ||
49 | extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, | ||
50 | u32, u32); | ||
51 | extern void zfcp_port_dequeue(struct zfcp_port *); | ||
52 | extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t); | 24 | extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t); |
53 | extern void zfcp_unit_dequeue(struct zfcp_unit *); | 25 | extern void zfcp_unit_dequeue(struct zfcp_unit *); |
54 | 26 | extern int zfcp_reqlist_isempty(struct zfcp_adapter *); | |
55 | /******************************* S/390 IO ************************************/ | 27 | extern void zfcp_sg_free_table(struct scatterlist *, int); |
56 | extern int zfcp_ccw_register(void); | 28 | extern int zfcp_sg_setup_table(struct scatterlist *, int); |
57 | 29 | ||
58 | extern void zfcp_qdio_zero_sbals(struct qdio_buffer **, int, int); | 30 | /* zfcp_ccw.c */ |
59 | extern int zfcp_qdio_allocate(struct zfcp_adapter *); | 31 | extern int zfcp_ccw_register(void); |
60 | extern int zfcp_qdio_allocate_queues(struct zfcp_adapter *); | 32 | |
61 | extern void zfcp_qdio_free_queues(struct zfcp_adapter *); | 33 | /* zfcp_cfdc.c */ |
62 | extern int zfcp_qdio_determine_pci(struct zfcp_qdio_queue *, | 34 | extern struct miscdevice zfcp_cfdc_misc; |
63 | struct zfcp_fsf_req *); | 35 | |
64 | 36 | /* zfcp_dbf.c */ | |
65 | extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req | 37 | extern int zfcp_adapter_debug_register(struct zfcp_adapter *); |
66 | (struct zfcp_fsf_req *, int, int); | 38 | extern void zfcp_adapter_debug_unregister(struct zfcp_adapter *); |
67 | extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr | 39 | extern void zfcp_rec_dbf_event_thread(u8, struct zfcp_adapter *); |
68 | (struct zfcp_fsf_req *); | 40 | extern void zfcp_rec_dbf_event_thread_lock(u8, struct zfcp_adapter *); |
69 | extern int zfcp_qdio_sbals_from_sg | 41 | extern void zfcp_rec_dbf_event_adapter(u8, void *, struct zfcp_adapter *); |
70 | (struct zfcp_fsf_req *, unsigned long, struct scatterlist *, int, int); | 42 | extern void zfcp_rec_dbf_event_port(u8, void *, struct zfcp_port *); |
71 | extern int zfcp_qdio_sbals_from_scsicmnd | 43 | extern void zfcp_rec_dbf_event_unit(u8, void *, struct zfcp_unit *); |
72 | (struct zfcp_fsf_req *, unsigned long, struct scsi_cmnd *); | 44 | extern void zfcp_rec_dbf_event_trigger(u8, void *, u8, u8, void *, |
73 | 45 | struct zfcp_adapter *, | |
74 | |||
75 | /******************************** FSF ****************************************/ | ||
76 | extern int zfcp_fsf_open_port(struct zfcp_erp_action *); | ||
77 | extern int zfcp_fsf_close_port(struct zfcp_erp_action *); | ||
78 | extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *); | ||
79 | |||
80 | extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); | ||
81 | extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); | ||
82 | |||
83 | extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); | ||
84 | extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *, | ||
85 | struct fsf_qtcb_bottom_config *); | ||
86 | extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); | ||
87 | extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, | ||
88 | struct fsf_qtcb_bottom_port *); | ||
89 | extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **, | ||
90 | u32, u32, struct zfcp_sg_list *); | ||
91 | extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long); | ||
92 | extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); | ||
93 | extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); | ||
94 | extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); | ||
95 | extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *, | ||
96 | unsigned long *, struct zfcp_fsf_req **); | ||
97 | extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, | ||
98 | struct zfcp_erp_action *); | ||
99 | extern int zfcp_fsf_send_els(struct zfcp_send_els *); | ||
100 | extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, | ||
101 | struct zfcp_unit *, | ||
102 | struct scsi_cmnd *, int, int); | ||
103 | extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *); | ||
104 | extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *); | ||
105 | extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); | ||
106 | extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_command_task_management( | ||
107 | struct zfcp_adapter *, struct zfcp_unit *, u8, int); | ||
108 | extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command( | ||
109 | unsigned long, struct zfcp_adapter *, struct zfcp_unit *, int); | ||
110 | |||
111 | /******************************* FC/FCP **************************************/ | ||
112 | extern int zfcp_nameserver_enqueue(struct zfcp_adapter *); | ||
113 | extern int zfcp_ns_gid_pn_request(struct zfcp_erp_action *); | ||
114 | extern int zfcp_check_ct_response(struct ct_hdr *); | ||
115 | extern int zfcp_handle_els_rjt(u32, struct zfcp_ls_rjt_par *); | ||
116 | extern void zfcp_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); | ||
117 | |||
118 | /******************************* SCSI ****************************************/ | ||
119 | extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); | ||
120 | extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); | ||
121 | extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); | ||
122 | extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *); | ||
123 | extern void set_host_byte(int *, char); | ||
124 | extern void set_driver_byte(int *, char); | ||
125 | extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); | ||
126 | extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *); | ||
127 | |||
128 | extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *, | ||
129 | struct scsi_cmnd *, int); | ||
130 | extern int zfcp_scsi_command_sync(struct zfcp_unit *, struct scsi_cmnd *, int); | ||
131 | extern struct fc_function_template zfcp_transport_functions; | ||
132 | |||
133 | /******************************** ERP ****************************************/ | ||
134 | extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u8, void *, | ||
135 | u32, int); | ||
136 | extern int zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, u8, void *); | ||
137 | extern int zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, u8, void *); | ||
138 | extern void zfcp_erp_adapter_failed(struct zfcp_adapter *, u8, void *); | ||
139 | |||
140 | extern void zfcp_erp_modify_port_status(struct zfcp_port *, u8, void *, u32, | ||
141 | int); | ||
142 | extern int zfcp_erp_port_reopen(struct zfcp_port *, int, u8, void *); | ||
143 | extern int zfcp_erp_port_shutdown(struct zfcp_port *, int, u8, void *); | ||
144 | extern int zfcp_erp_port_forced_reopen(struct zfcp_port *, int, u8, void *); | ||
145 | extern void zfcp_erp_port_failed(struct zfcp_port *, u8, void *); | ||
146 | extern int zfcp_erp_port_reopen_all(struct zfcp_adapter *, int, u8, void *); | ||
147 | |||
148 | extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, u8, void *, u32, | ||
149 | int); | ||
150 | extern int zfcp_erp_unit_reopen(struct zfcp_unit *, int, u8, void *); | ||
151 | extern int zfcp_erp_unit_shutdown(struct zfcp_unit *, int, u8, void *); | ||
152 | extern void zfcp_erp_unit_failed(struct zfcp_unit *, u8, void *); | ||
153 | |||
154 | extern int zfcp_erp_thread_setup(struct zfcp_adapter *); | ||
155 | extern int zfcp_erp_thread_kill(struct zfcp_adapter *); | ||
156 | extern int zfcp_erp_wait(struct zfcp_adapter *); | ||
157 | extern void zfcp_erp_async_handler(struct zfcp_erp_action *, unsigned long); | ||
158 | |||
159 | extern int zfcp_test_link(struct zfcp_port *); | ||
160 | |||
161 | extern void zfcp_erp_port_boxed(struct zfcp_port *, u8 id, void *ref); | ||
162 | extern void zfcp_erp_unit_boxed(struct zfcp_unit *, u8 id, void *ref); | ||
163 | extern void zfcp_erp_port_access_denied(struct zfcp_port *, u8 id, void *ref); | ||
164 | extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, u8 id, void *ref); | ||
165 | extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, u8, void *); | ||
166 | extern void zfcp_erp_port_access_changed(struct zfcp_port *, u8, void *); | ||
167 | extern void zfcp_erp_unit_access_changed(struct zfcp_unit *, u8, void *); | ||
168 | |||
169 | /******************************** AUX ****************************************/ | ||
170 | extern void zfcp_rec_dbf_event_thread(u8 id, struct zfcp_adapter *adapter, | ||
171 | int lock); | ||
172 | extern void zfcp_rec_dbf_event_adapter(u8 id, void *ref, struct zfcp_adapter *); | ||
173 | extern void zfcp_rec_dbf_event_port(u8 id, void *ref, struct zfcp_port *port); | ||
174 | extern void zfcp_rec_dbf_event_unit(u8 id, void *ref, struct zfcp_unit *unit); | ||
175 | extern void zfcp_rec_dbf_event_trigger(u8 id, void *ref, u8 want, u8 need, | ||
176 | void *action, struct zfcp_adapter *, | ||
177 | struct zfcp_port *, struct zfcp_unit *); | 46 | struct zfcp_port *, struct zfcp_unit *); |
178 | extern void zfcp_rec_dbf_event_action(u8 id, struct zfcp_erp_action *); | 47 | extern void zfcp_rec_dbf_event_action(u8, struct zfcp_erp_action *); |
179 | |||
180 | extern void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *); | 48 | extern void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *); |
181 | extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *, | 49 | extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *, |
182 | struct fsf_status_read_buffer *); | 50 | struct fsf_status_read_buffer *); |
183 | extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, | 51 | extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, |
184 | unsigned int, unsigned int, unsigned int, | 52 | unsigned int, unsigned int, unsigned int, |
185 | int, int); | 53 | int, int); |
186 | |||
187 | extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *); | 54 | extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *); |
188 | extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *); | 55 | extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *); |
189 | extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *); | 56 | extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *); |
190 | extern void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *); | 57 | extern void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *); |
191 | extern void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *); | 58 | extern void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *); |
192 | |||
193 | extern void zfcp_scsi_dbf_event_result(const char *, int, struct zfcp_adapter *, | 59 | extern void zfcp_scsi_dbf_event_result(const char *, int, struct zfcp_adapter *, |
194 | struct scsi_cmnd *, | 60 | struct scsi_cmnd *, |
195 | struct zfcp_fsf_req *); | 61 | struct zfcp_fsf_req *); |
@@ -198,6 +64,101 @@ extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *, | |||
198 | unsigned long); | 64 | unsigned long); |
199 | extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, | 65 | extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, |
200 | struct scsi_cmnd *); | 66 | struct scsi_cmnd *); |
201 | extern int zfcp_reqlist_isempty(struct zfcp_adapter *); | 67 | |
68 | /* zfcp_erp.c */ | ||
69 | extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, u8, void *, | ||
70 | u32, int); | ||
71 | extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, u8, void *); | ||
72 | extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, u8, void *); | ||
73 | extern void zfcp_erp_adapter_failed(struct zfcp_adapter *, u8, void *); | ||
74 | extern void zfcp_erp_modify_port_status(struct zfcp_port *, u8, void *, u32, | ||
75 | int); | ||
76 | extern int zfcp_erp_port_reopen(struct zfcp_port *, int, u8, void *); | ||
77 | extern void zfcp_erp_port_shutdown(struct zfcp_port *, int, u8, void *); | ||
78 | extern void zfcp_erp_port_forced_reopen(struct zfcp_port *, int, u8, void *); | ||
79 | extern void zfcp_erp_port_failed(struct zfcp_port *, u8, void *); | ||
80 | extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, u8, void *, u32, | ||
81 | int); | ||
82 | extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, u8, void *); | ||
83 | extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, u8, void *); | ||
84 | extern void zfcp_erp_unit_failed(struct zfcp_unit *, u8, void *); | ||
85 | extern int zfcp_erp_thread_setup(struct zfcp_adapter *); | ||
86 | extern void zfcp_erp_thread_kill(struct zfcp_adapter *); | ||
87 | extern void zfcp_erp_wait(struct zfcp_adapter *); | ||
88 | extern void zfcp_erp_notify(struct zfcp_erp_action *, unsigned long); | ||
89 | extern void zfcp_erp_port_boxed(struct zfcp_port *, u8, void *); | ||
90 | extern void zfcp_erp_unit_boxed(struct zfcp_unit *, u8, void *); | ||
91 | extern void zfcp_erp_port_access_denied(struct zfcp_port *, u8, void *); | ||
92 | extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, u8, void *); | ||
93 | extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, u8, void *); | ||
94 | extern void zfcp_erp_timeout_handler(unsigned long); | ||
95 | |||
96 | /* zfcp_fc.c */ | ||
97 | extern int zfcp_scan_ports(struct zfcp_adapter *); | ||
98 | extern void _zfcp_scan_ports_later(struct work_struct *); | ||
99 | extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); | ||
100 | extern int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *); | ||
101 | extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); | ||
102 | extern void zfcp_test_link(struct zfcp_port *); | ||
103 | |||
104 | /* zfcp_fsf.c */ | ||
105 | extern int zfcp_fsf_open_port(struct zfcp_erp_action *); | ||
106 | extern int zfcp_fsf_close_port(struct zfcp_erp_action *); | ||
107 | extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *); | ||
108 | extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); | ||
109 | extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); | ||
110 | extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); | ||
111 | extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *, | ||
112 | struct fsf_qtcb_bottom_config *); | ||
113 | extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); | ||
114 | extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, | ||
115 | struct fsf_qtcb_bottom_port *); | ||
116 | extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *, | ||
117 | struct zfcp_fsf_cfdc *); | ||
118 | extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); | ||
119 | extern int zfcp_fsf_status_read(struct zfcp_adapter *); | ||
120 | extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); | ||
121 | extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, | ||
122 | struct zfcp_erp_action *); | ||
123 | extern int zfcp_fsf_send_els(struct zfcp_send_els *); | ||
124 | extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, | ||
125 | struct zfcp_unit *, | ||
126 | struct scsi_cmnd *, int, int); | ||
127 | extern void zfcp_fsf_req_complete(struct zfcp_fsf_req *); | ||
128 | extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); | ||
129 | extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *, | ||
130 | struct zfcp_unit *, u8, int); | ||
131 | extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long, | ||
132 | struct zfcp_adapter *, | ||
133 | struct zfcp_unit *, int); | ||
134 | |||
135 | /* zfcp_qdio.c */ | ||
136 | extern int zfcp_qdio_allocate(struct zfcp_adapter *); | ||
137 | extern void zfcp_qdio_free(struct zfcp_adapter *); | ||
138 | extern int zfcp_qdio_send(struct zfcp_fsf_req *); | ||
139 | extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req( | ||
140 | struct zfcp_fsf_req *); | ||
141 | extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr( | ||
142 | struct zfcp_fsf_req *); | ||
143 | extern int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *, unsigned long, | ||
144 | struct scatterlist *, int); | ||
145 | extern int zfcp_qdio_open(struct zfcp_adapter *); | ||
146 | extern void zfcp_qdio_close(struct zfcp_adapter *); | ||
147 | |||
148 | /* zfcp_scsi.c */ | ||
149 | extern struct zfcp_data zfcp_data; | ||
150 | extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); | ||
151 | extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); | ||
152 | extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); | ||
153 | extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); | ||
154 | extern struct fc_function_template zfcp_transport_functions; | ||
155 | |||
156 | /* zfcp_sysfs.c */ | ||
157 | extern struct attribute_group zfcp_sysfs_unit_attrs; | ||
158 | extern struct attribute_group zfcp_sysfs_adapter_attrs; | ||
159 | extern struct attribute_group zfcp_sysfs_ns_port_attrs; | ||
160 | extern struct attribute_group zfcp_sysfs_port_attrs; | ||
161 | extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; | ||
162 | extern struct device_attribute *zfcp_sysfs_shost_attrs[]; | ||
202 | 163 | ||
203 | #endif /* ZFCP_EXT_H */ | 164 | #endif /* ZFCP_EXT_H */ |
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c new file mode 100644 index 000000000000..e984469bb98b --- /dev/null +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -0,0 +1,567 @@ | |||
1 | /* | ||
2 | * zfcp device driver | ||
3 | * | ||
4 | * Fibre Channel related functions for the zfcp device driver. | ||
5 | * | ||
6 | * Copyright IBM Corporation 2008 | ||
7 | */ | ||
8 | |||
9 | #include "zfcp_ext.h" | ||
10 | |||
11 | struct ct_iu_gpn_ft_req { | ||
12 | struct ct_hdr header; | ||
13 | u8 flags; | ||
14 | u8 domain_id_scope; | ||
15 | u8 area_id_scope; | ||
16 | u8 fc4_type; | ||
17 | } __attribute__ ((packed)); | ||
18 | |||
19 | struct gpn_ft_resp_acc { | ||
20 | u8 control; | ||
21 | u8 port_id[3]; | ||
22 | u8 reserved[4]; | ||
23 | u64 wwpn; | ||
24 | } __attribute__ ((packed)); | ||
25 | |||
26 | #define ZFCP_GPN_FT_ENTRIES ((PAGE_SIZE - sizeof(struct ct_hdr)) \ | ||
27 | / sizeof(struct gpn_ft_resp_acc)) | ||
28 | #define ZFCP_GPN_FT_BUFFERS 4 | ||
29 | #define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1) | ||
30 | |||
31 | struct ct_iu_gpn_ft_resp { | ||
32 | struct ct_hdr header; | ||
33 | struct gpn_ft_resp_acc accept[ZFCP_GPN_FT_ENTRIES]; | ||
34 | } __attribute__ ((packed)); | ||
35 | |||
36 | struct zfcp_gpn_ft { | ||
37 | struct zfcp_send_ct ct; | ||
38 | struct scatterlist sg_req; | ||
39 | struct scatterlist sg_resp[ZFCP_GPN_FT_BUFFERS]; | ||
40 | }; | ||
41 | |||
42 | static struct zfcp_port *zfcp_get_port_by_did(struct zfcp_adapter *adapter, | ||
43 | u32 d_id) | ||
44 | { | ||
45 | struct zfcp_port *port; | ||
46 | |||
47 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
48 | if ((port->d_id == d_id) && | ||
49 | !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) | ||
50 | return port; | ||
51 | return NULL; | ||
52 | } | ||
53 | |||
54 | static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, | ||
55 | struct fcp_rscn_element *elem) | ||
56 | { | ||
57 | unsigned long flags; | ||
58 | struct zfcp_port *port; | ||
59 | |||
60 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
61 | list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { | ||
62 | if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) | ||
63 | continue; | ||
64 | /* FIXME: ZFCP_STATUS_PORT_DID_DID check is racy */ | ||
65 | if (!atomic_test_mask(ZFCP_STATUS_PORT_DID_DID, &port->status)) | ||
66 | /* Try to connect to unused ports anyway. */ | ||
67 | zfcp_erp_port_reopen(port, | ||
68 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
69 | 82, fsf_req); | ||
70 | else if ((port->d_id & range) == (elem->nport_did & range)) | ||
71 | /* Check connection status for connected ports */ | ||
72 | zfcp_test_link(port); | ||
73 | } | ||
74 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
75 | } | ||
76 | |||
77 | static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) | ||
78 | { | ||
79 | struct fsf_status_read_buffer *status_buffer = (void *)fsf_req->data; | ||
80 | struct fcp_rscn_head *fcp_rscn_head; | ||
81 | struct fcp_rscn_element *fcp_rscn_element; | ||
82 | u16 i; | ||
83 | u16 no_entries; | ||
84 | u32 range_mask; | ||
85 | |||
86 | fcp_rscn_head = (struct fcp_rscn_head *) status_buffer->payload.data; | ||
87 | fcp_rscn_element = (struct fcp_rscn_element *) fcp_rscn_head; | ||
88 | |||
89 | /* see FC-FS */ | ||
90 | no_entries = fcp_rscn_head->payload_len / | ||
91 | sizeof(struct fcp_rscn_element); | ||
92 | |||
93 | for (i = 1; i < no_entries; i++) { | ||
94 | /* skip head and start with 1st element */ | ||
95 | fcp_rscn_element++; | ||
96 | switch (fcp_rscn_element->addr_format) { | ||
97 | case ZFCP_PORT_ADDRESS: | ||
98 | range_mask = ZFCP_PORTS_RANGE_PORT; | ||
99 | break; | ||
100 | case ZFCP_AREA_ADDRESS: | ||
101 | range_mask = ZFCP_PORTS_RANGE_AREA; | ||
102 | break; | ||
103 | case ZFCP_DOMAIN_ADDRESS: | ||
104 | range_mask = ZFCP_PORTS_RANGE_DOMAIN; | ||
105 | break; | ||
106 | case ZFCP_FABRIC_ADDRESS: | ||
107 | range_mask = ZFCP_PORTS_RANGE_FABRIC; | ||
108 | break; | ||
109 | default: | ||
110 | continue; | ||
111 | } | ||
112 | _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); | ||
113 | } | ||
114 | schedule_work(&fsf_req->adapter->scan_work); | ||
115 | } | ||
116 | |||
117 | static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn) | ||
118 | { | ||
119 | struct zfcp_adapter *adapter = req->adapter; | ||
120 | struct zfcp_port *port; | ||
121 | unsigned long flags; | ||
122 | |||
123 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
124 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
125 | if (port->wwpn == wwpn) | ||
126 | break; | ||
127 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
128 | |||
129 | if (port && (port->wwpn == wwpn)) | ||
130 | zfcp_erp_port_forced_reopen(port, 0, 83, req); | ||
131 | } | ||
132 | |||
133 | static void zfcp_fc_incoming_plogi(struct zfcp_fsf_req *req) | ||
134 | { | ||
135 | struct fsf_status_read_buffer *status_buffer = | ||
136 | (struct fsf_status_read_buffer *)req->data; | ||
137 | struct fsf_plogi *els_plogi = | ||
138 | (struct fsf_plogi *) status_buffer->payload.data; | ||
139 | |||
140 | zfcp_fc_incoming_wwpn(req, els_plogi->serv_param.wwpn); | ||
141 | } | ||
142 | |||
143 | static void zfcp_fc_incoming_logo(struct zfcp_fsf_req *req) | ||
144 | { | ||
145 | struct fsf_status_read_buffer *status_buffer = | ||
146 | (struct fsf_status_read_buffer *)req->data; | ||
147 | struct fcp_logo *els_logo = | ||
148 | (struct fcp_logo *) status_buffer->payload.data; | ||
149 | |||
150 | zfcp_fc_incoming_wwpn(req, els_logo->nport_wwpn); | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * zfcp_fc_incoming_els - handle incoming ELS | ||
155 | * @fsf_req - request which contains incoming ELS | ||
156 | */ | ||
157 | void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req) | ||
158 | { | ||
159 | struct fsf_status_read_buffer *status_buffer = | ||
160 | (struct fsf_status_read_buffer *) fsf_req->data; | ||
161 | unsigned int els_type = status_buffer->payload.data[0]; | ||
162 | |||
163 | zfcp_san_dbf_event_incoming_els(fsf_req); | ||
164 | if (els_type == LS_PLOGI) | ||
165 | zfcp_fc_incoming_plogi(fsf_req); | ||
166 | else if (els_type == LS_LOGO) | ||
167 | zfcp_fc_incoming_logo(fsf_req); | ||
168 | else if (els_type == LS_RSCN) | ||
169 | zfcp_fc_incoming_rscn(fsf_req); | ||
170 | } | ||
171 | |||
172 | static void zfcp_ns_gid_pn_handler(unsigned long data) | ||
173 | { | ||
174 | struct zfcp_gid_pn_data *gid_pn = (struct zfcp_gid_pn_data *) data; | ||
175 | struct zfcp_send_ct *ct = &gid_pn->ct; | ||
176 | struct ct_iu_gid_pn_req *ct_iu_req = sg_virt(ct->req); | ||
177 | struct ct_iu_gid_pn_resp *ct_iu_resp = sg_virt(ct->resp); | ||
178 | struct zfcp_port *port = gid_pn->port; | ||
179 | |||
180 | if (ct->status) | ||
181 | goto out; | ||
182 | if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) { | ||
183 | atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); | ||
184 | goto out; | ||
185 | } | ||
186 | /* paranoia */ | ||
187 | if (ct_iu_req->wwpn != port->wwpn) | ||
188 | goto out; | ||
189 | /* looks like a valid d_id */ | ||
190 | port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; | ||
191 | atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); | ||
192 | out: | ||
193 | mempool_free(gid_pn, port->adapter->pool.data_gid_pn); | ||
194 | } | ||
195 | |||
196 | /** | ||
197 | * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request | ||
198 | * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed | ||
199 | * return: -ENOMEM on error, 0 otherwise | ||
200 | */ | ||
201 | int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action) | ||
202 | { | ||
203 | int ret; | ||
204 | struct zfcp_gid_pn_data *gid_pn; | ||
205 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
206 | |||
207 | gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC); | ||
208 | if (!gid_pn) | ||
209 | return -ENOMEM; | ||
210 | |||
211 | memset(gid_pn, 0, sizeof(*gid_pn)); | ||
212 | |||
213 | /* setup parameters for send generic command */ | ||
214 | gid_pn->port = erp_action->port; | ||
215 | gid_pn->ct.port = adapter->nameserver_port; | ||
216 | gid_pn->ct.handler = zfcp_ns_gid_pn_handler; | ||
217 | gid_pn->ct.handler_data = (unsigned long) gid_pn; | ||
218 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; | ||
219 | gid_pn->ct.req = &gid_pn->req; | ||
220 | gid_pn->ct.resp = &gid_pn->resp; | ||
221 | gid_pn->ct.req_count = 1; | ||
222 | gid_pn->ct.resp_count = 1; | ||
223 | sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, | ||
224 | sizeof(struct ct_iu_gid_pn_req)); | ||
225 | sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp, | ||
226 | sizeof(struct ct_iu_gid_pn_resp)); | ||
227 | |||
228 | /* setup nameserver request */ | ||
229 | gid_pn->ct_iu_req.header.revision = ZFCP_CT_REVISION; | ||
230 | gid_pn->ct_iu_req.header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; | ||
231 | gid_pn->ct_iu_req.header.gs_subtype = ZFCP_CT_NAME_SERVER; | ||
232 | gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; | ||
233 | gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN; | ||
234 | gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_MAX_SIZE; | ||
235 | gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; | ||
236 | |||
237 | ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, | ||
238 | erp_action); | ||
239 | if (ret) | ||
240 | mempool_free(gid_pn, adapter->pool.data_gid_pn); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * zfcp_fc_plogi_evaluate - evaluate PLOGI playload | ||
246 | * @port: zfcp_port structure | ||
247 | * @plogi: plogi payload | ||
248 | * | ||
249 | * Evaluate PLOGI playload and copy important fields into zfcp_port structure | ||
250 | */ | ||
251 | void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fsf_plogi *plogi) | ||
252 | { | ||
253 | port->maxframe_size = plogi->serv_param.common_serv_param[7] | | ||
254 | ((plogi->serv_param.common_serv_param[6] & 0x0F) << 8); | ||
255 | if (plogi->serv_param.class1_serv_param[0] & 0x80) | ||
256 | port->supported_classes |= FC_COS_CLASS1; | ||
257 | if (plogi->serv_param.class2_serv_param[0] & 0x80) | ||
258 | port->supported_classes |= FC_COS_CLASS2; | ||
259 | if (plogi->serv_param.class3_serv_param[0] & 0x80) | ||
260 | port->supported_classes |= FC_COS_CLASS3; | ||
261 | if (plogi->serv_param.class4_serv_param[0] & 0x80) | ||
262 | port->supported_classes |= FC_COS_CLASS4; | ||
263 | } | ||
264 | |||
265 | struct zfcp_els_adisc { | ||
266 | struct zfcp_send_els els; | ||
267 | struct scatterlist req; | ||
268 | struct scatterlist resp; | ||
269 | struct zfcp_ls_adisc ls_adisc; | ||
270 | struct zfcp_ls_adisc_acc ls_adisc_acc; | ||
271 | }; | ||
272 | |||
273 | static void zfcp_fc_adisc_handler(unsigned long data) | ||
274 | { | ||
275 | struct zfcp_els_adisc *adisc = (struct zfcp_els_adisc *) data; | ||
276 | struct zfcp_port *port = adisc->els.port; | ||
277 | struct zfcp_ls_adisc_acc *ls_adisc = &adisc->ls_adisc_acc; | ||
278 | |||
279 | if (adisc->els.status) { | ||
280 | /* request rejected or timed out */ | ||
281 | zfcp_erp_port_forced_reopen(port, 0, 63, NULL); | ||
282 | goto out; | ||
283 | } | ||
284 | |||
285 | if (!port->wwnn) | ||
286 | port->wwnn = ls_adisc->wwnn; | ||
287 | |||
288 | if (port->wwpn != ls_adisc->wwpn) | ||
289 | zfcp_erp_port_reopen(port, 0, 64, NULL); | ||
290 | |||
291 | out: | ||
292 | zfcp_port_put(port); | ||
293 | kfree(adisc); | ||
294 | } | ||
295 | |||
296 | static int zfcp_fc_adisc(struct zfcp_port *port) | ||
297 | { | ||
298 | struct zfcp_els_adisc *adisc; | ||
299 | struct zfcp_adapter *adapter = port->adapter; | ||
300 | |||
301 | adisc = kzalloc(sizeof(struct zfcp_els_adisc), GFP_ATOMIC); | ||
302 | if (!adisc) | ||
303 | return -ENOMEM; | ||
304 | |||
305 | adisc->els.req = &adisc->req; | ||
306 | adisc->els.resp = &adisc->resp; | ||
307 | sg_init_one(adisc->els.req, &adisc->ls_adisc, | ||
308 | sizeof(struct zfcp_ls_adisc)); | ||
309 | sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, | ||
310 | sizeof(struct zfcp_ls_adisc_acc)); | ||
311 | |||
312 | adisc->els.req_count = 1; | ||
313 | adisc->els.resp_count = 1; | ||
314 | adisc->els.adapter = adapter; | ||
315 | adisc->els.port = port; | ||
316 | adisc->els.d_id = port->d_id; | ||
317 | adisc->els.handler = zfcp_fc_adisc_handler; | ||
318 | adisc->els.handler_data = (unsigned long) adisc; | ||
319 | adisc->els.ls_code = adisc->ls_adisc.code = ZFCP_LS_ADISC; | ||
320 | |||
321 | /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports | ||
322 | without FC-AL-2 capability, so we don't set it */ | ||
323 | adisc->ls_adisc.wwpn = fc_host_port_name(adapter->scsi_host); | ||
324 | adisc->ls_adisc.wwnn = fc_host_node_name(adapter->scsi_host); | ||
325 | adisc->ls_adisc.nport_id = fc_host_port_id(adapter->scsi_host); | ||
326 | |||
327 | return zfcp_fsf_send_els(&adisc->els); | ||
328 | } | ||
329 | |||
330 | /** | ||
331 | * zfcp_test_link - lightweight link test procedure | ||
332 | * @port: port to be tested | ||
333 | * | ||
334 | * Test status of a link to a remote port using the ELS command ADISC. | ||
335 | * If there is a problem with the remote port, error recovery steps | ||
336 | * will be triggered. | ||
337 | */ | ||
338 | void zfcp_test_link(struct zfcp_port *port) | ||
339 | { | ||
340 | int retval; | ||
341 | |||
342 | zfcp_port_get(port); | ||
343 | retval = zfcp_fc_adisc(port); | ||
344 | if (retval == 0 || retval == -EBUSY) | ||
345 | return; | ||
346 | |||
347 | /* send of ADISC was not possible */ | ||
348 | zfcp_port_put(port); | ||
349 | zfcp_erp_port_forced_reopen(port, 0, 65, NULL); | ||
350 | } | ||
351 | |||
352 | static int zfcp_scan_get_nameserver(struct zfcp_adapter *adapter) | ||
353 | { | ||
354 | int ret; | ||
355 | |||
356 | if (!adapter->nameserver_port) | ||
357 | return -EINTR; | ||
358 | |||
359 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
360 | &adapter->nameserver_port->status)) { | ||
361 | ret = zfcp_erp_port_reopen(adapter->nameserver_port, 0, 148, | ||
362 | NULL); | ||
363 | if (ret) | ||
364 | return ret; | ||
365 | zfcp_erp_wait(adapter); | ||
366 | zfcp_port_put(adapter->nameserver_port); | ||
367 | } | ||
368 | return !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
369 | &adapter->nameserver_port->status); | ||
370 | } | ||
371 | |||
372 | static void zfcp_gpn_ft_handler(unsigned long _done) | ||
373 | { | ||
374 | complete((struct completion *)_done); | ||
375 | } | ||
376 | |||
377 | static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft) | ||
378 | { | ||
379 | struct scatterlist *sg = &gpn_ft->sg_req; | ||
380 | |||
381 | kfree(sg_virt(sg)); /* free request buffer */ | ||
382 | zfcp_sg_free_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS); | ||
383 | |||
384 | kfree(gpn_ft); | ||
385 | } | ||
386 | |||
387 | static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) | ||
388 | { | ||
389 | struct zfcp_gpn_ft *gpn_ft; | ||
390 | struct ct_iu_gpn_ft_req *req; | ||
391 | |||
392 | gpn_ft = kzalloc(sizeof(*gpn_ft), GFP_KERNEL); | ||
393 | if (!gpn_ft) | ||
394 | return NULL; | ||
395 | |||
396 | req = kzalloc(sizeof(struct ct_iu_gpn_ft_req), GFP_KERNEL); | ||
397 | if (!req) { | ||
398 | kfree(gpn_ft); | ||
399 | gpn_ft = NULL; | ||
400 | goto out; | ||
401 | } | ||
402 | sg_init_one(&gpn_ft->sg_req, req, sizeof(*req)); | ||
403 | |||
404 | if (zfcp_sg_setup_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS)) { | ||
405 | zfcp_free_sg_env(gpn_ft); | ||
406 | gpn_ft = NULL; | ||
407 | } | ||
408 | out: | ||
409 | return gpn_ft; | ||
410 | } | ||
411 | |||
412 | |||
413 | static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, | ||
414 | struct zfcp_adapter *adapter) | ||
415 | { | ||
416 | struct zfcp_send_ct *ct = &gpn_ft->ct; | ||
417 | struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); | ||
418 | struct completion done; | ||
419 | int ret; | ||
420 | |||
421 | /* prepare CT IU for GPN_FT */ | ||
422 | req->header.revision = ZFCP_CT_REVISION; | ||
423 | req->header.gs_type = ZFCP_CT_DIRECTORY_SERVICE; | ||
424 | req->header.gs_subtype = ZFCP_CT_NAME_SERVER; | ||
425 | req->header.options = ZFCP_CT_SYNCHRONOUS; | ||
426 | req->header.cmd_rsp_code = ZFCP_CT_GPN_FT; | ||
427 | req->header.max_res_size = (sizeof(struct gpn_ft_resp_acc) * | ||
428 | (ZFCP_GPN_FT_MAX_ENTRIES - 1)) >> 2; | ||
429 | req->flags = 0; | ||
430 | req->domain_id_scope = 0; | ||
431 | req->area_id_scope = 0; | ||
432 | req->fc4_type = ZFCP_CT_SCSI_FCP; | ||
433 | |||
434 | /* prepare zfcp_send_ct */ | ||
435 | ct->port = adapter->nameserver_port; | ||
436 | ct->handler = zfcp_gpn_ft_handler; | ||
437 | ct->handler_data = (unsigned long)&done; | ||
438 | ct->timeout = 10; | ||
439 | ct->req = &gpn_ft->sg_req; | ||
440 | ct->resp = gpn_ft->sg_resp; | ||
441 | ct->req_count = 1; | ||
442 | ct->resp_count = ZFCP_GPN_FT_BUFFERS; | ||
443 | |||
444 | init_completion(&done); | ||
445 | ret = zfcp_fsf_send_ct(ct, NULL, NULL); | ||
446 | if (!ret) | ||
447 | wait_for_completion(&done); | ||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | static void zfcp_validate_port(struct zfcp_port *port) | ||
452 | { | ||
453 | struct zfcp_adapter *adapter = port->adapter; | ||
454 | |||
455 | atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); | ||
456 | |||
457 | if (port == adapter->nameserver_port) | ||
458 | return; | ||
459 | if ((port->supported_classes != 0) || (port->units != 0)) { | ||
460 | zfcp_port_put(port); | ||
461 | return; | ||
462 | } | ||
463 | zfcp_erp_port_shutdown(port, 0, 151, NULL); | ||
464 | zfcp_erp_wait(adapter); | ||
465 | zfcp_port_put(port); | ||
466 | zfcp_port_dequeue(port); | ||
467 | } | ||
468 | |||
469 | static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) | ||
470 | { | ||
471 | struct zfcp_send_ct *ct = &gpn_ft->ct; | ||
472 | struct scatterlist *sg = gpn_ft->sg_resp; | ||
473 | struct ct_hdr *hdr = sg_virt(sg); | ||
474 | struct gpn_ft_resp_acc *acc = sg_virt(sg); | ||
475 | struct zfcp_adapter *adapter = ct->port->adapter; | ||
476 | struct zfcp_port *port, *tmp; | ||
477 | u32 d_id; | ||
478 | int ret = 0, x; | ||
479 | |||
480 | if (ct->status) | ||
481 | return -EIO; | ||
482 | |||
483 | if (hdr->cmd_rsp_code != ZFCP_CT_ACCEPT) { | ||
484 | if (hdr->reason_code == ZFCP_CT_UNABLE_TO_PERFORM_CMD) | ||
485 | return -EAGAIN; /* might be a temporary condition */ | ||
486 | return -EIO; | ||
487 | } | ||
488 | |||
489 | if (hdr->max_res_size) | ||
490 | return -E2BIG; | ||
491 | |||
492 | down(&zfcp_data.config_sema); | ||
493 | |||
494 | /* first entry is the header */ | ||
495 | for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES; x++) { | ||
496 | if (x % (ZFCP_GPN_FT_ENTRIES + 1)) | ||
497 | acc++; | ||
498 | else | ||
499 | acc = sg_virt(++sg); | ||
500 | |||
501 | d_id = acc->port_id[0] << 16 | acc->port_id[1] << 8 | | ||
502 | acc->port_id[2]; | ||
503 | |||
504 | /* skip the adapter's port and known remote ports */ | ||
505 | if (acc->wwpn == fc_host_port_name(adapter->scsi_host) || | ||
506 | zfcp_get_port_by_did(adapter, d_id)) | ||
507 | continue; | ||
508 | |||
509 | port = zfcp_port_enqueue(adapter, acc->wwpn, | ||
510 | ZFCP_STATUS_PORT_DID_DID | | ||
511 | ZFCP_STATUS_COMMON_NOESC, d_id); | ||
512 | if (IS_ERR(port)) | ||
513 | ret = PTR_ERR(port); | ||
514 | else | ||
515 | zfcp_erp_port_reopen(port, 0, 149, NULL); | ||
516 | if (acc->control & 0x80) /* last entry */ | ||
517 | break; | ||
518 | } | ||
519 | |||
520 | zfcp_erp_wait(adapter); | ||
521 | list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list) | ||
522 | zfcp_validate_port(port); | ||
523 | up(&zfcp_data.config_sema); | ||
524 | return ret; | ||
525 | } | ||
526 | |||
527 | /** | ||
528 | * zfcp_scan_ports - scan remote ports and attach new ports | ||
529 | * @adapter: pointer to struct zfcp_adapter | ||
530 | */ | ||
531 | int zfcp_scan_ports(struct zfcp_adapter *adapter) | ||
532 | { | ||
533 | int ret, i; | ||
534 | struct zfcp_gpn_ft *gpn_ft; | ||
535 | |||
536 | zfcp_erp_wait(adapter); /* wait until adapter is finished with ERP */ | ||
537 | if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) | ||
538 | return 0; | ||
539 | |||
540 | ret = zfcp_scan_get_nameserver(adapter); | ||
541 | if (ret) | ||
542 | return ret; | ||
543 | |||
544 | gpn_ft = zfcp_alloc_sg_env(); | ||
545 | if (!gpn_ft) | ||
546 | return -ENOMEM; | ||
547 | |||
548 | for (i = 0; i < 3; i++) { | ||
549 | ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter); | ||
550 | if (!ret) { | ||
551 | ret = zfcp_scan_eval_gpn_ft(gpn_ft); | ||
552 | if (ret == -EAGAIN) | ||
553 | ssleep(1); | ||
554 | else | ||
555 | break; | ||
556 | } | ||
557 | } | ||
558 | zfcp_free_sg_env(gpn_ft); | ||
559 | |||
560 | return ret; | ||
561 | } | ||
562 | |||
563 | |||
564 | void _zfcp_scan_ports_later(struct work_struct *work) | ||
565 | { | ||
566 | zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); | ||
567 | } | ||
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index b2ea4ea051f5..19c1ca913874 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -1,54 +1,37 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Implementation of FSF commands. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #include "zfcp_ext.h" | 9 | #include "zfcp_ext.h" |
23 | 10 | ||
24 | static int zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *); | 11 | static void zfcp_fsf_request_timeout_handler(unsigned long data) |
25 | static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *); | 12 | { |
26 | static int zfcp_fsf_open_port_handler(struct zfcp_fsf_req *); | 13 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; |
27 | static int zfcp_fsf_close_port_handler(struct zfcp_fsf_req *); | 14 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 62, |
28 | static int zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *); | 15 | NULL); |
29 | static int zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *); | 16 | } |
30 | static int zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *); | 17 | |
31 | static int zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *); | 18 | static void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, |
32 | static int zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *); | 19 | unsigned long timeout) |
33 | static int zfcp_fsf_send_fcp_command_task_management_handler( | 20 | { |
34 | struct zfcp_fsf_req *); | 21 | fsf_req->timer.function = zfcp_fsf_request_timeout_handler; |
35 | static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *); | 22 | fsf_req->timer.data = (unsigned long) fsf_req->adapter; |
36 | static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *); | 23 | fsf_req->timer.expires = jiffies + timeout; |
37 | static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *); | 24 | add_timer(&fsf_req->timer); |
38 | static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *); | 25 | } |
39 | static int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *); | 26 | |
40 | static inline int zfcp_fsf_req_sbal_check( | 27 | static void zfcp_fsf_start_erp_timer(struct zfcp_fsf_req *fsf_req) |
41 | unsigned long *, struct zfcp_qdio_queue *, int); | 28 | { |
42 | static inline int zfcp_use_one_sbal( | 29 | BUG_ON(!fsf_req->erp_action); |
43 | struct scatterlist *, int, struct scatterlist *, int); | 30 | fsf_req->timer.function = zfcp_erp_timeout_handler; |
44 | static struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int); | 31 | fsf_req->timer.data = (unsigned long) fsf_req->erp_action; |
45 | static int zfcp_fsf_req_send(struct zfcp_fsf_req *); | 32 | fsf_req->timer.expires = jiffies + 30 * HZ; |
46 | static int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *); | 33 | add_timer(&fsf_req->timer); |
47 | static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *); | 34 | } |
48 | static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *); | ||
49 | static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *, u8, | ||
50 | struct fsf_link_down_info *); | ||
51 | static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *); | ||
52 | 35 | ||
53 | /* association between FSF command and FSF QTCB type */ | 36 | /* association between FSF command and FSF QTCB type */ |
54 | static u32 fsf_qtcb_type[] = { | 37 | static u32 fsf_qtcb_type[] = { |
@@ -67,96 +50,77 @@ static u32 fsf_qtcb_type[] = { | |||
67 | [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND | 50 | [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND |
68 | }; | 51 | }; |
69 | 52 | ||
70 | static const char zfcp_act_subtable_type[5][8] = { | 53 | static const char *zfcp_act_subtable_type[] = { |
71 | "unknown", "OS", "WWPN", "DID", "LUN" | 54 | "unknown", "OS", "WWPN", "DID", "LUN" |
72 | }; | 55 | }; |
73 | 56 | ||
74 | /****************************************************************/ | 57 | static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) |
75 | /*************** FSF related Functions *************************/ | ||
76 | /****************************************************************/ | ||
77 | |||
78 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF | ||
79 | |||
80 | /* | ||
81 | * function: zfcp_fsf_req_alloc | ||
82 | * | ||
83 | * purpose: Obtains an fsf_req and potentially a qtcb (for all but | ||
84 | * unsolicited requests) via helper functions | ||
85 | * Does some initial fsf request set-up. | ||
86 | * | ||
87 | * returns: pointer to allocated fsf_req if successfull | ||
88 | * NULL otherwise | ||
89 | * | ||
90 | * locks: none | ||
91 | * | ||
92 | */ | ||
93 | static struct zfcp_fsf_req * | ||
94 | zfcp_fsf_req_alloc(mempool_t *pool, int req_flags) | ||
95 | { | 58 | { |
96 | size_t size; | 59 | u16 subtable = table >> 16; |
97 | void *ptr; | 60 | u16 rule = table & 0xffff; |
98 | struct zfcp_fsf_req *fsf_req = NULL; | ||
99 | 61 | ||
100 | if (req_flags & ZFCP_REQ_NO_QTCB) | 62 | if (subtable && subtable < ARRAY_SIZE(zfcp_act_subtable_type)) |
101 | size = sizeof(struct zfcp_fsf_req); | 63 | dev_warn(&adapter->ccw_device->dev, |
102 | else | 64 | "Access denied in subtable %s, rule %d.\n", |
103 | size = sizeof(struct zfcp_fsf_req_qtcb); | 65 | zfcp_act_subtable_type[subtable], rule); |
104 | 66 | } | |
105 | if (likely(pool)) | ||
106 | ptr = mempool_alloc(pool, GFP_ATOMIC); | ||
107 | else { | ||
108 | if (req_flags & ZFCP_REQ_NO_QTCB) | ||
109 | ptr = kmalloc(size, GFP_ATOMIC); | ||
110 | else | ||
111 | ptr = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache, | ||
112 | GFP_ATOMIC); | ||
113 | } | ||
114 | |||
115 | if (unlikely(!ptr)) | ||
116 | goto out; | ||
117 | |||
118 | memset(ptr, 0, size); | ||
119 | 67 | ||
120 | if (req_flags & ZFCP_REQ_NO_QTCB) { | 68 | static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req, |
121 | fsf_req = (struct zfcp_fsf_req *) ptr; | 69 | struct zfcp_port *port) |
122 | } else { | 70 | { |
123 | fsf_req = &((struct zfcp_fsf_req_qtcb *) ptr)->fsf_req; | 71 | struct fsf_qtcb_header *header = &req->qtcb->header; |
124 | fsf_req->qtcb = &((struct zfcp_fsf_req_qtcb *) ptr)->qtcb; | 72 | dev_warn(&req->adapter->ccw_device->dev, |
125 | } | 73 | "Access denied, cannot send command to port 0x%016Lx.\n", |
74 | port->wwpn); | ||
75 | zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); | ||
76 | zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); | ||
77 | zfcp_erp_port_access_denied(port, 55, req); | ||
78 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
79 | } | ||
126 | 80 | ||
127 | fsf_req->pool = pool; | 81 | static void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req, |
82 | struct zfcp_unit *unit) | ||
83 | { | ||
84 | struct fsf_qtcb_header *header = &req->qtcb->header; | ||
85 | dev_warn(&req->adapter->ccw_device->dev, | ||
86 | "Access denied for unit 0x%016Lx on port 0x%016Lx.\n", | ||
87 | unit->fcp_lun, unit->port->wwpn); | ||
88 | zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); | ||
89 | zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); | ||
90 | zfcp_erp_unit_access_denied(unit, 59, req); | ||
91 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
92 | } | ||
128 | 93 | ||
129 | out: | 94 | static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req) |
130 | return fsf_req; | 95 | { |
96 | dev_err(&req->adapter->ccw_device->dev, | ||
97 | "Required FC class not supported by adapter, " | ||
98 | "shutting down adapter.\n"); | ||
99 | zfcp_erp_adapter_shutdown(req->adapter, 0, 123, req); | ||
100 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
131 | } | 101 | } |
132 | 102 | ||
133 | /* | 103 | /** |
134 | * function: zfcp_fsf_req_free | 104 | * zfcp_fsf_req_free - free memory used by fsf request |
135 | * | 105 | * @fsf_req: pointer to struct zfcp_fsf_req |
136 | * purpose: Frees the memory of an fsf_req (and potentially a qtcb) or | ||
137 | * returns it into the pool via helper functions. | ||
138 | * | ||
139 | * returns: sod all | ||
140 | * | ||
141 | * locks: none | ||
142 | */ | 106 | */ |
143 | void | 107 | void zfcp_fsf_req_free(struct zfcp_fsf_req *req) |
144 | zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) | ||
145 | { | 108 | { |
146 | if (likely(fsf_req->pool)) { | 109 | if (likely(req->pool)) { |
147 | mempool_free(fsf_req, fsf_req->pool); | 110 | mempool_free(req, req->pool); |
148 | return; | 111 | return; |
149 | } | 112 | } |
150 | 113 | ||
151 | if (fsf_req->qtcb) { | 114 | if (req->qtcb) { |
152 | kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, fsf_req); | 115 | kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, req); |
153 | return; | 116 | return; |
154 | } | 117 | } |
155 | |||
156 | kfree(fsf_req); | ||
157 | } | 118 | } |
158 | 119 | ||
159 | /* | 120 | /** |
121 | * zfcp_fsf_req_dismiss_all - dismiss all fsf requests | ||
122 | * @adapter: pointer to struct zfcp_adapter | ||
123 | * | ||
160 | * Never ever call this without shutting down the adapter first. | 124 | * Never ever call this without shutting down the adapter first. |
161 | * Otherwise the adapter would continue using and corrupting s390 storage. | 125 | * Otherwise the adapter would continue using and corrupting s390 storage. |
162 | * Included BUG_ON() call to ensure this is done. | 126 | * Included BUG_ON() call to ensure this is done. |
@@ -164,2353 +128,1359 @@ zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) | |||
164 | */ | 128 | */ |
165 | void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) | 129 | void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) |
166 | { | 130 | { |
167 | struct zfcp_fsf_req *fsf_req, *tmp; | 131 | struct zfcp_fsf_req *req, *tmp; |
168 | unsigned long flags; | 132 | unsigned long flags; |
169 | LIST_HEAD(remove_queue); | 133 | LIST_HEAD(remove_queue); |
170 | unsigned int i; | 134 | unsigned int i; |
171 | 135 | ||
172 | BUG_ON(atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)); | 136 | BUG_ON(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP); |
173 | spin_lock_irqsave(&adapter->req_list_lock, flags); | 137 | spin_lock_irqsave(&adapter->req_list_lock, flags); |
174 | atomic_set(&adapter->reqs_active, 0); | ||
175 | for (i = 0; i < REQUEST_LIST_SIZE; i++) | 138 | for (i = 0; i < REQUEST_LIST_SIZE; i++) |
176 | list_splice_init(&adapter->req_list[i], &remove_queue); | 139 | list_splice_init(&adapter->req_list[i], &remove_queue); |
177 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); | 140 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); |
178 | 141 | ||
179 | list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) { | 142 | list_for_each_entry_safe(req, tmp, &remove_queue, list) { |
180 | list_del(&fsf_req->list); | 143 | list_del(&req->list); |
181 | fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; | 144 | req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; |
182 | zfcp_fsf_req_complete(fsf_req); | 145 | zfcp_fsf_req_complete(req); |
183 | } | 146 | } |
184 | } | 147 | } |
185 | 148 | ||
186 | /* | 149 | static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req) |
187 | * function: zfcp_fsf_req_complete | ||
188 | * | ||
189 | * purpose: Updates active counts and timers for openfcp-reqs | ||
190 | * May cleanup request after req_eval returns | ||
191 | * | ||
192 | * returns: 0 - success | ||
193 | * !0 - failure | ||
194 | * | ||
195 | * context: | ||
196 | */ | ||
197 | int | ||
198 | zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) | ||
199 | { | 150 | { |
200 | int retval = 0; | 151 | struct fsf_status_read_buffer *sr_buf = req->data; |
201 | int cleanup; | 152 | struct zfcp_adapter *adapter = req->adapter; |
202 | 153 | struct zfcp_port *port; | |
203 | if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { | 154 | int d_id = sr_buf->d_id & ZFCP_DID_MASK; |
204 | ZFCP_LOG_DEBUG("Status read response received\n"); | 155 | unsigned long flags; |
205 | /* | ||
206 | * Note: all cleanup handling is done in the callchain of | ||
207 | * the function call-chain below. | ||
208 | */ | ||
209 | zfcp_fsf_status_read_handler(fsf_req); | ||
210 | goto out; | ||
211 | } else { | ||
212 | del_timer(&fsf_req->timer); | ||
213 | zfcp_fsf_protstatus_eval(fsf_req); | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * fsf_req may be deleted due to waking up functions, so | ||
218 | * cleanup is saved here and used later | ||
219 | */ | ||
220 | if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) | ||
221 | cleanup = 1; | ||
222 | else | ||
223 | cleanup = 0; | ||
224 | |||
225 | fsf_req->status |= ZFCP_STATUS_FSFREQ_COMPLETED; | ||
226 | 156 | ||
227 | /* cleanup request if requested by initiator */ | 157 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
228 | if (likely(cleanup)) { | 158 | list_for_each_entry(port, &adapter->port_list_head, list) |
229 | ZFCP_LOG_TRACE("removing FSF request %p\n", fsf_req); | 159 | if (port->d_id == d_id) { |
230 | /* | 160 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
231 | * lock must not be held here since it will be | 161 | switch (sr_buf->status_subtype) { |
232 | * grabed by the called routine, too | 162 | case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT: |
233 | */ | 163 | zfcp_erp_port_reopen(port, 0, 101, req); |
234 | zfcp_fsf_req_free(fsf_req); | 164 | break; |
235 | } else { | 165 | case FSF_STATUS_READ_SUB_ERROR_PORT: |
236 | /* notify initiator waiting for the requests completion */ | 166 | zfcp_erp_port_shutdown(port, 0, 122, req); |
237 | ZFCP_LOG_TRACE("waking initiator of FSF request %p\n",fsf_req); | 167 | break; |
238 | /* | 168 | } |
239 | * FIXME: Race! We must not access fsf_req here as it might have been | 169 | return; |
240 | * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED | 170 | } |
241 | * flag. It's an improbable case. But, we have the same paranoia for | 171 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
242 | * the cleanup flag already. | 172 | } |
243 | * Might better be handled using complete()? | ||
244 | * (setting the flag and doing wakeup ought to be atomic | ||
245 | * with regard to checking the flag as long as waitqueue is | ||
246 | * part of the to be released structure) | ||
247 | */ | ||
248 | wake_up(&fsf_req->completion_wq); | ||
249 | } | ||
250 | 173 | ||
251 | out: | 174 | static void zfcp_fsf_bit_error_threshold(struct zfcp_fsf_req *req) |
252 | return retval; | 175 | { |
176 | struct zfcp_adapter *adapter = req->adapter; | ||
177 | struct fsf_status_read_buffer *sr_buf = req->data; | ||
178 | struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error; | ||
179 | |||
180 | dev_warn(&adapter->ccw_device->dev, | ||
181 | "Warning: bit error threshold data " | ||
182 | "received for the adapter: " | ||
183 | "link failures = %i, loss of sync errors = %i, " | ||
184 | "loss of signal errors = %i, " | ||
185 | "primitive sequence errors = %i, " | ||
186 | "invalid transmission word errors = %i, " | ||
187 | "CRC errors = %i).\n", | ||
188 | err->link_failure_error_count, | ||
189 | err->loss_of_sync_error_count, | ||
190 | err->loss_of_signal_error_count, | ||
191 | err->primitive_sequence_error_count, | ||
192 | err->invalid_transmission_word_error_count, | ||
193 | err->crc_error_count); | ||
194 | dev_warn(&adapter->ccw_device->dev, | ||
195 | "Additional bit error threshold data of the adapter: " | ||
196 | "primitive sequence event time-outs = %i, " | ||
197 | "elastic buffer overrun errors = %i, " | ||
198 | "advertised receive buffer-to-buffer credit = %i, " | ||
199 | "current receice buffer-to-buffer credit = %i, " | ||
200 | "advertised transmit buffer-to-buffer credit = %i, " | ||
201 | "current transmit buffer-to-buffer credit = %i).\n", | ||
202 | err->primitive_sequence_event_timeout_count, | ||
203 | err->elastic_buffer_overrun_error_count, | ||
204 | err->advertised_receive_b2b_credit, | ||
205 | err->current_receive_b2b_credit, | ||
206 | err->advertised_transmit_b2b_credit, | ||
207 | err->current_transmit_b2b_credit); | ||
253 | } | 208 | } |
254 | 209 | ||
255 | /* | 210 | static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, u8 id, |
256 | * function: zfcp_fsf_protstatus_eval | 211 | struct fsf_link_down_info *link_down) |
257 | * | ||
258 | * purpose: evaluates the QTCB of the finished FSF request | ||
259 | * and initiates appropriate actions | ||
260 | * (usually calling FSF command specific handlers) | ||
261 | * | ||
262 | * returns: | ||
263 | * | ||
264 | * context: | ||
265 | * | ||
266 | * locks: | ||
267 | */ | ||
268 | static int | ||
269 | zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) | ||
270 | { | 212 | { |
271 | int retval = 0; | 213 | struct zfcp_adapter *adapter = req->adapter; |
272 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
273 | struct fsf_qtcb *qtcb = fsf_req->qtcb; | ||
274 | union fsf_prot_status_qual *prot_status_qual = | ||
275 | &qtcb->prefix.prot_status_qual; | ||
276 | |||
277 | zfcp_hba_dbf_event_fsf_response(fsf_req); | ||
278 | |||
279 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { | ||
280 | ZFCP_LOG_DEBUG("fsf_req 0x%lx has been dismissed\n", | ||
281 | (unsigned long) fsf_req); | ||
282 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | ||
283 | ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */ | ||
284 | goto skip_protstatus; | ||
285 | } | ||
286 | 214 | ||
287 | /* evaluate FSF Protocol Status */ | 215 | if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) |
288 | switch (qtcb->prefix.prot_status) { | 216 | return; |
289 | 217 | ||
290 | case FSF_PROT_GOOD: | 218 | atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); |
291 | case FSF_PROT_FSF_STATUS_PRESENTED: | ||
292 | break; | ||
293 | 219 | ||
294 | case FSF_PROT_QTCB_VERSION_ERROR: | 220 | if (!link_down) |
295 | ZFCP_LOG_NORMAL("error: The adapter %s contains " | 221 | goto out; |
296 | "microcode of version 0x%x, the device driver " | ||
297 | "only supports 0x%x. Aborting.\n", | ||
298 | zfcp_get_busid_by_adapter(adapter), | ||
299 | prot_status_qual->version_error.fsf_version, | ||
300 | ZFCP_QTCB_VERSION); | ||
301 | zfcp_erp_adapter_shutdown(adapter, 0, 117, fsf_req); | ||
302 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
303 | break; | ||
304 | 222 | ||
305 | case FSF_PROT_SEQ_NUMB_ERROR: | 223 | switch (link_down->error_code) { |
306 | ZFCP_LOG_NORMAL("bug: Sequence number mismatch between " | 224 | case FSF_PSQ_LINK_NO_LIGHT: |
307 | "driver (0x%x) and adapter %s (0x%x). " | 225 | dev_warn(&req->adapter->ccw_device->dev, |
308 | "Restarting all operations on this adapter.\n", | 226 | "The local link is down: no light detected.\n"); |
309 | qtcb->prefix.req_seq_no, | ||
310 | zfcp_get_busid_by_adapter(adapter), | ||
311 | prot_status_qual->sequence_error.exp_req_seq_no); | ||
312 | zfcp_erp_adapter_reopen(adapter, 0, 98, fsf_req); | ||
313 | fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY; | ||
314 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
315 | break; | 227 | break; |
316 | 228 | case FSF_PSQ_LINK_WRAP_PLUG: | |
317 | case FSF_PROT_UNSUPP_QTCB_TYPE: | 229 | dev_warn(&req->adapter->ccw_device->dev, |
318 | ZFCP_LOG_NORMAL("error: Packet header type used by the " | 230 | "The local link is down: wrap plug detected.\n"); |
319 | "device driver is incompatible with " | ||
320 | "that used on adapter %s. " | ||
321 | "Stopping all operations on this adapter.\n", | ||
322 | zfcp_get_busid_by_adapter(adapter)); | ||
323 | zfcp_erp_adapter_shutdown(adapter, 0, 118, fsf_req); | ||
324 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
325 | break; | 231 | break; |
326 | 232 | case FSF_PSQ_LINK_NO_FCP: | |
327 | case FSF_PROT_HOST_CONNECTION_INITIALIZING: | 233 | dev_warn(&req->adapter->ccw_device->dev, |
328 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 234 | "The local link is down: " |
329 | atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | 235 | "adjacent node on link does not support FCP.\n"); |
330 | &(adapter->status)); | ||
331 | break; | 236 | break; |
332 | 237 | case FSF_PSQ_LINK_FIRMWARE_UPDATE: | |
333 | case FSF_PROT_DUPLICATE_REQUEST_ID: | 238 | dev_warn(&req->adapter->ccw_device->dev, |
334 | ZFCP_LOG_NORMAL("bug: The request identifier 0x%Lx " | 239 | "The local link is down: " |
335 | "to the adapter %s is ambiguous. " | 240 | "firmware update in progress.\n"); |
336 | "Stopping all operations on this adapter.\n", | ||
337 | *(unsigned long long*) | ||
338 | (&qtcb->bottom.support.req_handle), | ||
339 | zfcp_get_busid_by_adapter(adapter)); | ||
340 | zfcp_erp_adapter_shutdown(adapter, 0, 78, fsf_req); | ||
341 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
342 | break; | 241 | break; |
343 | 242 | case FSF_PSQ_LINK_INVALID_WWPN: | |
344 | case FSF_PROT_LINK_DOWN: | 243 | dev_warn(&req->adapter->ccw_device->dev, |
345 | zfcp_fsf_link_down_info_eval(fsf_req, 37, | 244 | "The local link is down: " |
346 | &prot_status_qual->link_down_info); | 245 | "duplicate or invalid WWPN detected.\n"); |
347 | /* FIXME: reopening adapter now? better wait for link up */ | ||
348 | zfcp_erp_adapter_reopen(adapter, 0, 79, fsf_req); | ||
349 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
350 | break; | 246 | break; |
351 | 247 | case FSF_PSQ_LINK_NO_NPIV_SUPPORT: | |
352 | case FSF_PROT_REEST_QUEUE: | 248 | dev_warn(&req->adapter->ccw_device->dev, |
353 | ZFCP_LOG_NORMAL("The local link to adapter with " | 249 | "The local link is down: " |
354 | "%s was re-plugged. " | 250 | "no support for NPIV by Fabric.\n"); |
355 | "Re-starting operations on this adapter.\n", | ||
356 | zfcp_get_busid_by_adapter(adapter)); | ||
357 | /* All ports should be marked as ready to run again */ | ||
358 | zfcp_erp_modify_adapter_status(adapter, 28, NULL, | ||
359 | ZFCP_STATUS_COMMON_RUNNING, | ||
360 | ZFCP_SET); | ||
361 | zfcp_erp_adapter_reopen(adapter, | ||
362 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ||
363 | | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
364 | 99, fsf_req); | ||
365 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
366 | break; | 251 | break; |
367 | 252 | case FSF_PSQ_LINK_NO_FCP_RESOURCES: | |
368 | case FSF_PROT_ERROR_STATE: | 253 | dev_warn(&req->adapter->ccw_device->dev, |
369 | ZFCP_LOG_NORMAL("error: The adapter %s " | 254 | "The local link is down: " |
370 | "has entered the error state. " | 255 | "out of resource in FCP daughtercard.\n"); |
371 | "Restarting all operations on this " | 256 | break; |
372 | "adapter.\n", | 257 | case FSF_PSQ_LINK_NO_FABRIC_RESOURCES: |
373 | zfcp_get_busid_by_adapter(adapter)); | 258 | dev_warn(&req->adapter->ccw_device->dev, |
374 | zfcp_erp_adapter_reopen(adapter, 0, 100, fsf_req); | 259 | "The local link is down: " |
375 | fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY; | 260 | "out of resource in Fabric.\n"); |
376 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 261 | break; |
262 | case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE: | ||
263 | dev_warn(&req->adapter->ccw_device->dev, | ||
264 | "The local link is down: " | ||
265 | "unable to login to Fabric.\n"); | ||
266 | break; | ||
267 | case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED: | ||
268 | dev_warn(&req->adapter->ccw_device->dev, | ||
269 | "WWPN assignment file corrupted on adapter.\n"); | ||
270 | break; | ||
271 | case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED: | ||
272 | dev_warn(&req->adapter->ccw_device->dev, | ||
273 | "Mode table corrupted on adapter.\n"); | ||
274 | break; | ||
275 | case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT: | ||
276 | dev_warn(&req->adapter->ccw_device->dev, | ||
277 | "No WWPN for assignment table on adapter.\n"); | ||
377 | break; | 278 | break; |
378 | |||
379 | default: | 279 | default: |
380 | ZFCP_LOG_NORMAL("bug: Transfer protocol status information " | 280 | dev_warn(&req->adapter->ccw_device->dev, |
381 | "provided by the adapter %s " | 281 | "The local link to adapter is down.\n"); |
382 | "is not compatible with the device driver. " | ||
383 | "Stopping all operations on this adapter. " | ||
384 | "(debug info 0x%x).\n", | ||
385 | zfcp_get_busid_by_adapter(adapter), | ||
386 | qtcb->prefix.prot_status); | ||
387 | zfcp_erp_adapter_shutdown(adapter, 0, 119, fsf_req); | ||
388 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
389 | } | 282 | } |
283 | out: | ||
284 | zfcp_erp_adapter_failed(adapter, id, req); | ||
285 | } | ||
390 | 286 | ||
391 | skip_protstatus: | 287 | static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) |
392 | /* | 288 | { |
393 | * always call specific handlers to give them a chance to do | 289 | struct zfcp_adapter *adapter = req->adapter; |
394 | * something meaningful even in error cases | 290 | struct fsf_status_read_buffer *sr_buf = req->data; |
395 | */ | 291 | struct fsf_link_down_info *ldi = |
396 | zfcp_fsf_fsfstatus_eval(fsf_req); | 292 | (struct fsf_link_down_info *) &sr_buf->payload; |
397 | return retval; | 293 | |
294 | switch (sr_buf->status_subtype) { | ||
295 | case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: | ||
296 | dev_warn(&adapter->ccw_device->dev, | ||
297 | "Physical link is down.\n"); | ||
298 | zfcp_fsf_link_down_info_eval(req, 38, ldi); | ||
299 | break; | ||
300 | case FSF_STATUS_READ_SUB_FDISC_FAILED: | ||
301 | dev_warn(&adapter->ccw_device->dev, | ||
302 | "Local link is down " | ||
303 | "due to failed FDISC login.\n"); | ||
304 | zfcp_fsf_link_down_info_eval(req, 39, ldi); | ||
305 | break; | ||
306 | case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: | ||
307 | dev_warn(&adapter->ccw_device->dev, | ||
308 | "Local link is down " | ||
309 | "due to firmware update on adapter.\n"); | ||
310 | zfcp_fsf_link_down_info_eval(req, 40, NULL); | ||
311 | }; | ||
398 | } | 312 | } |
399 | 313 | ||
400 | /* | 314 | static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) |
401 | * function: zfcp_fsf_fsfstatus_eval | ||
402 | * | ||
403 | * purpose: evaluates FSF status of completed FSF request | ||
404 | * and acts accordingly | ||
405 | * | ||
406 | * returns: | ||
407 | */ | ||
408 | static int | ||
409 | zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req) | ||
410 | { | 315 | { |
411 | int retval = 0; | 316 | struct zfcp_adapter *adapter = req->adapter; |
317 | struct fsf_status_read_buffer *sr_buf = req->data; | ||
412 | 318 | ||
413 | if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { | 319 | if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { |
414 | goto skip_fsfstatus; | 320 | zfcp_hba_dbf_event_fsf_unsol("dism", adapter, sr_buf); |
321 | mempool_free(sr_buf, adapter->pool.data_status_read); | ||
322 | zfcp_fsf_req_free(req); | ||
323 | return; | ||
415 | } | 324 | } |
416 | 325 | ||
417 | /* evaluate FSF Status */ | 326 | zfcp_hba_dbf_event_fsf_unsol("read", adapter, sr_buf); |
418 | switch (fsf_req->qtcb->header.fsf_status) { | ||
419 | case FSF_UNKNOWN_COMMAND: | ||
420 | ZFCP_LOG_NORMAL("bug: Command issued by the device driver is " | ||
421 | "not known by the adapter %s " | ||
422 | "Stopping all operations on this adapter. " | ||
423 | "(debug info 0x%x).\n", | ||
424 | zfcp_get_busid_by_adapter(fsf_req->adapter), | ||
425 | fsf_req->qtcb->header.fsf_command); | ||
426 | zfcp_erp_adapter_shutdown(fsf_req->adapter, 0, 120, fsf_req); | ||
427 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
428 | break; | ||
429 | 327 | ||
430 | case FSF_FCP_RSP_AVAILABLE: | 328 | switch (sr_buf->status_type) { |
431 | ZFCP_LOG_DEBUG("FCP Sense data will be presented to the " | 329 | case FSF_STATUS_READ_PORT_CLOSED: |
432 | "SCSI stack.\n"); | 330 | zfcp_fsf_status_read_port_closed(req); |
433 | break; | 331 | break; |
434 | 332 | case FSF_STATUS_READ_INCOMING_ELS: | |
435 | case FSF_ADAPTER_STATUS_AVAILABLE: | 333 | zfcp_fc_incoming_els(req); |
436 | zfcp_fsf_fsfstatus_qual_eval(fsf_req); | 334 | break; |
335 | case FSF_STATUS_READ_SENSE_DATA_AVAIL: | ||
336 | break; | ||
337 | case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: | ||
338 | zfcp_fsf_bit_error_threshold(req); | ||
339 | break; | ||
340 | case FSF_STATUS_READ_LINK_DOWN: | ||
341 | zfcp_fsf_status_read_link_down(req); | ||
342 | break; | ||
343 | case FSF_STATUS_READ_LINK_UP: | ||
344 | dev_info(&adapter->ccw_device->dev, | ||
345 | "Local link was replugged.\n"); | ||
346 | /* All ports should be marked as ready to run again */ | ||
347 | zfcp_erp_modify_adapter_status(adapter, 30, NULL, | ||
348 | ZFCP_STATUS_COMMON_RUNNING, | ||
349 | ZFCP_SET); | ||
350 | zfcp_erp_adapter_reopen(adapter, | ||
351 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | ||
352 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
353 | 102, req); | ||
354 | break; | ||
355 | case FSF_STATUS_READ_NOTIFICATION_LOST: | ||
356 | if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) | ||
357 | zfcp_erp_adapter_access_changed(adapter, 135, req); | ||
358 | if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) | ||
359 | schedule_work(&adapter->scan_work); | ||
360 | break; | ||
361 | case FSF_STATUS_READ_CFDC_UPDATED: | ||
362 | zfcp_erp_adapter_access_changed(adapter, 136, req); | ||
363 | break; | ||
364 | case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: | ||
365 | adapter->adapter_features = sr_buf->payload.word[0]; | ||
437 | break; | 366 | break; |
438 | } | 367 | } |
439 | 368 | ||
440 | skip_fsfstatus: | 369 | mempool_free(sr_buf, adapter->pool.data_status_read); |
441 | /* | 370 | zfcp_fsf_req_free(req); |
442 | * always call specific handlers to give them a chance to do | ||
443 | * something meaningful even in error cases | ||
444 | */ | ||
445 | zfcp_fsf_req_dispatch(fsf_req); | ||
446 | 371 | ||
447 | return retval; | 372 | atomic_inc(&adapter->stat_miss); |
373 | schedule_work(&adapter->stat_work); | ||
448 | } | 374 | } |
449 | 375 | ||
450 | /* | 376 | static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req) |
451 | * function: zfcp_fsf_fsfstatus_qual_eval | ||
452 | * | ||
453 | * purpose: evaluates FSF status-qualifier of completed FSF request | ||
454 | * and acts accordingly | ||
455 | * | ||
456 | * returns: | ||
457 | */ | ||
458 | static int | ||
459 | zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req) | ||
460 | { | 377 | { |
461 | int retval = 0; | 378 | switch (req->qtcb->header.fsf_status_qual.word[0]) { |
462 | |||
463 | switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) { | ||
464 | case FSF_SQ_FCP_RSP_AVAILABLE: | 379 | case FSF_SQ_FCP_RSP_AVAILABLE: |
465 | break; | ||
466 | case FSF_SQ_RETRY_IF_POSSIBLE: | ||
467 | /* The SCSI-stack may now issue retries or escalate */ | ||
468 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
469 | break; | ||
470 | case FSF_SQ_COMMAND_ABORTED: | ||
471 | /* Carry the aborted state on to upper layer */ | ||
472 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTED; | ||
473 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
474 | break; | ||
475 | case FSF_SQ_NO_RECOM: | ||
476 | ZFCP_LOG_NORMAL("bug: No recommendation could be given for a " | ||
477 | "problem on the adapter %s " | ||
478 | "Stopping all operations on this adapter. ", | ||
479 | zfcp_get_busid_by_adapter(fsf_req->adapter)); | ||
480 | zfcp_erp_adapter_shutdown(fsf_req->adapter, 0, 121, fsf_req); | ||
481 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
482 | break; | ||
483 | case FSF_SQ_ULP_PROGRAMMING_ERROR: | ||
484 | ZFCP_LOG_NORMAL("error: not enough SBALs for data transfer " | ||
485 | "(adapter %s)\n", | ||
486 | zfcp_get_busid_by_adapter(fsf_req->adapter)); | ||
487 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
488 | break; | ||
489 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 380 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
490 | case FSF_SQ_NO_RETRY_POSSIBLE: | 381 | case FSF_SQ_NO_RETRY_POSSIBLE: |
491 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 382 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
492 | /* dealt with in the respective functions */ | 383 | return; |
384 | case FSF_SQ_COMMAND_ABORTED: | ||
385 | req->status |= ZFCP_STATUS_FSFREQ_ABORTED; | ||
493 | break; | 386 | break; |
494 | default: | 387 | case FSF_SQ_NO_RECOM: |
495 | ZFCP_LOG_NORMAL("bug: Additional status info could " | 388 | dev_err(&req->adapter->ccw_device->dev, |
496 | "not be interpreted properly.\n"); | 389 | "No recommendation could be given for a " |
497 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, | 390 | "problem on the adapter.\n"); |
498 | (char *) &fsf_req->qtcb->header.fsf_status_qual, | 391 | zfcp_erp_adapter_shutdown(req->adapter, 0, 121, req); |
499 | sizeof (union fsf_status_qual)); | ||
500 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
501 | break; | 392 | break; |
502 | } | 393 | } |
503 | 394 | /* all non-return stats set FSFREQ_ERROR*/ | |
504 | return retval; | 395 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
505 | } | 396 | } |
506 | 397 | ||
507 | /** | 398 | static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req) |
508 | * zfcp_fsf_link_down_info_eval - evaluate link down information block | ||
509 | */ | ||
510 | static void | ||
511 | zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *fsf_req, u8 id, | ||
512 | struct fsf_link_down_info *link_down) | ||
513 | { | 399 | { |
514 | struct zfcp_adapter *adapter = fsf_req->adapter; | 400 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) |
515 | |||
516 | if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, | ||
517 | &adapter->status)) | ||
518 | return; | 401 | return; |
519 | 402 | ||
520 | atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); | 403 | switch (req->qtcb->header.fsf_status) { |
521 | 404 | case FSF_UNKNOWN_COMMAND: | |
522 | if (link_down == NULL) | 405 | dev_err(&req->adapter->ccw_device->dev, |
523 | goto out; | 406 | "Command issued by the device driver (0x%x) is " |
524 | 407 | "not known by the adapter.\n", | |
525 | switch (link_down->error_code) { | 408 | req->qtcb->header.fsf_command); |
526 | case FSF_PSQ_LINK_NO_LIGHT: | 409 | zfcp_erp_adapter_shutdown(req->adapter, 0, 120, req); |
527 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 410 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
528 | "(no light detected)\n", | ||
529 | zfcp_get_busid_by_adapter(adapter)); | ||
530 | break; | ||
531 | case FSF_PSQ_LINK_WRAP_PLUG: | ||
532 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | ||
533 | "(wrap plug detected)\n", | ||
534 | zfcp_get_busid_by_adapter(adapter)); | ||
535 | break; | ||
536 | case FSF_PSQ_LINK_NO_FCP: | ||
537 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | ||
538 | "(adjacent node on link does not support FCP)\n", | ||
539 | zfcp_get_busid_by_adapter(adapter)); | ||
540 | break; | 411 | break; |
541 | case FSF_PSQ_LINK_FIRMWARE_UPDATE: | 412 | case FSF_ADAPTER_STATUS_AVAILABLE: |
542 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 413 | zfcp_fsf_fsfstatus_qual_eval(req); |
543 | "(firmware update in progress)\n", | ||
544 | zfcp_get_busid_by_adapter(adapter)); | ||
545 | break; | ||
546 | case FSF_PSQ_LINK_INVALID_WWPN: | ||
547 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | ||
548 | "(duplicate or invalid WWPN detected)\n", | ||
549 | zfcp_get_busid_by_adapter(adapter)); | ||
550 | break; | 414 | break; |
551 | case FSF_PSQ_LINK_NO_NPIV_SUPPORT: | 415 | } |
552 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 416 | } |
553 | "(no support for NPIV by Fabric)\n", | 417 | |
554 | zfcp_get_busid_by_adapter(adapter)); | 418 | static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) |
419 | { | ||
420 | struct zfcp_adapter *adapter = req->adapter; | ||
421 | struct fsf_qtcb *qtcb = req->qtcb; | ||
422 | union fsf_prot_status_qual *psq = &qtcb->prefix.prot_status_qual; | ||
423 | |||
424 | zfcp_hba_dbf_event_fsf_response(req); | ||
425 | |||
426 | if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { | ||
427 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | | ||
428 | ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */ | ||
429 | return; | ||
430 | } | ||
431 | |||
432 | switch (qtcb->prefix.prot_status) { | ||
433 | case FSF_PROT_GOOD: | ||
434 | case FSF_PROT_FSF_STATUS_PRESENTED: | ||
435 | return; | ||
436 | case FSF_PROT_QTCB_VERSION_ERROR: | ||
437 | dev_err(&adapter->ccw_device->dev, | ||
438 | "The QTCB version requested by zfcp (0x%x) is not " | ||
439 | "supported by the FCP adapter (lowest supported " | ||
440 | "0x%x, highest supported 0x%x).\n", | ||
441 | FSF_QTCB_CURRENT_VERSION, psq->word[0], | ||
442 | psq->word[1]); | ||
443 | zfcp_erp_adapter_shutdown(adapter, 0, 117, req); | ||
555 | break; | 444 | break; |
556 | case FSF_PSQ_LINK_NO_FCP_RESOURCES: | 445 | case FSF_PROT_ERROR_STATE: |
557 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 446 | case FSF_PROT_SEQ_NUMB_ERROR: |
558 | "(out of resource in FCP daughtercard)\n", | 447 | zfcp_erp_adapter_reopen(adapter, 0, 98, req); |
559 | zfcp_get_busid_by_adapter(adapter)); | 448 | req->status |= ZFCP_STATUS_FSFREQ_RETRY; |
560 | break; | 449 | break; |
561 | case FSF_PSQ_LINK_NO_FABRIC_RESOURCES: | 450 | case FSF_PROT_UNSUPP_QTCB_TYPE: |
562 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 451 | dev_err(&adapter->ccw_device->dev, |
563 | "(out of resource in Fabric)\n", | 452 | "Packet header type used by the device driver is " |
564 | zfcp_get_busid_by_adapter(adapter)); | 453 | "incompatible with that used on the adapter.\n"); |
454 | zfcp_erp_adapter_shutdown(adapter, 0, 118, req); | ||
565 | break; | 455 | break; |
566 | case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE: | 456 | case FSF_PROT_HOST_CONNECTION_INITIALIZING: |
567 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 457 | atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, |
568 | "(unable to Fabric login)\n", | 458 | &adapter->status); |
569 | zfcp_get_busid_by_adapter(adapter)); | ||
570 | break; | 459 | break; |
571 | case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED: | 460 | case FSF_PROT_DUPLICATE_REQUEST_ID: |
572 | ZFCP_LOG_NORMAL("WWPN assignment file corrupted on adapter %s\n", | 461 | dev_err(&adapter->ccw_device->dev, |
573 | zfcp_get_busid_by_adapter(adapter)); | 462 | "The request identifier 0x%Lx is ambiguous.\n", |
463 | (unsigned long long)qtcb->bottom.support.req_handle); | ||
464 | zfcp_erp_adapter_shutdown(adapter, 0, 78, req); | ||
574 | break; | 465 | break; |
575 | case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED: | 466 | case FSF_PROT_LINK_DOWN: |
576 | ZFCP_LOG_NORMAL("Mode table corrupted on adapter %s\n", | 467 | zfcp_fsf_link_down_info_eval(req, 37, &psq->link_down_info); |
577 | zfcp_get_busid_by_adapter(adapter)); | 468 | /* FIXME: reopening adapter now? better wait for link up */ |
469 | zfcp_erp_adapter_reopen(adapter, 0, 79, req); | ||
578 | break; | 470 | break; |
579 | case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT: | 471 | case FSF_PROT_REEST_QUEUE: |
580 | ZFCP_LOG_NORMAL("No WWPN for assignment table on adapter %s\n", | 472 | /* All ports should be marked as ready to run again */ |
581 | zfcp_get_busid_by_adapter(adapter)); | 473 | zfcp_erp_modify_adapter_status(adapter, 28, NULL, |
474 | ZFCP_STATUS_COMMON_RUNNING, | ||
475 | ZFCP_SET); | ||
476 | zfcp_erp_adapter_reopen(adapter, | ||
477 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | ||
478 | ZFCP_STATUS_COMMON_ERP_FAILED, 99, req); | ||
582 | break; | 479 | break; |
583 | default: | 480 | default: |
584 | ZFCP_LOG_NORMAL("The local link to adapter %s is down " | 481 | dev_err(&adapter->ccw_device->dev, |
585 | "(warning: unknown reason code %d)\n", | 482 | "Transfer protocol status information" |
586 | zfcp_get_busid_by_adapter(adapter), | 483 | "provided by the adapter (0x%x) " |
587 | link_down->error_code); | 484 | "is not compatible with the device driver.\n", |
588 | } | 485 | qtcb->prefix.prot_status); |
589 | 486 | zfcp_erp_adapter_shutdown(adapter, 0, 119, req); | |
590 | if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) | 487 | } |
591 | ZFCP_LOG_DEBUG("Debug information to link down: " | 488 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
592 | "primary_status=0x%02x " | ||
593 | "ioerr_code=0x%02x " | ||
594 | "action_code=0x%02x " | ||
595 | "reason_code=0x%02x " | ||
596 | "explanation_code=0x%02x " | ||
597 | "vendor_specific_code=0x%02x\n", | ||
598 | link_down->primary_status, | ||
599 | link_down->ioerr_code, | ||
600 | link_down->action_code, | ||
601 | link_down->reason_code, | ||
602 | link_down->explanation_code, | ||
603 | link_down->vendor_specific_code); | ||
604 | |||
605 | out: | ||
606 | zfcp_erp_adapter_failed(adapter, id, fsf_req); | ||
607 | } | 489 | } |
608 | 490 | ||
609 | /* | 491 | /** |
610 | * function: zfcp_fsf_req_dispatch | 492 | * zfcp_fsf_req_complete - process completion of a FSF request |
611 | * | 493 | * @fsf_req: The FSF request that has been completed. |
612 | * purpose: calls the appropriate command specific handler | ||
613 | * | 494 | * |
614 | * returns: | 495 | * When a request has been completed either from the FCP adapter, |
496 | * or it has been dismissed due to a queue shutdown, this function | ||
497 | * is called to process the completion status and trigger further | ||
498 | * events related to the FSF request. | ||
615 | */ | 499 | */ |
616 | static int | 500 | void zfcp_fsf_req_complete(struct zfcp_fsf_req *req) |
617 | zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) | ||
618 | { | 501 | { |
619 | struct zfcp_erp_action *erp_action = fsf_req->erp_action; | 502 | if (unlikely(req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { |
620 | struct zfcp_adapter *adapter = fsf_req->adapter; | 503 | zfcp_fsf_status_read_handler(req); |
621 | int retval = 0; | 504 | return; |
505 | } | ||
622 | 506 | ||
507 | del_timer(&req->timer); | ||
508 | zfcp_fsf_protstatus_eval(req); | ||
509 | zfcp_fsf_fsfstatus_eval(req); | ||
510 | req->handler(req); | ||
623 | 511 | ||
624 | switch (fsf_req->fsf_command) { | 512 | if (req->erp_action) |
513 | zfcp_erp_notify(req->erp_action, 0); | ||
514 | req->status |= ZFCP_STATUS_FSFREQ_COMPLETED; | ||
625 | 515 | ||
626 | case FSF_QTCB_FCP_CMND: | 516 | if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) |
627 | zfcp_fsf_send_fcp_command_handler(fsf_req); | 517 | zfcp_fsf_req_free(req); |
628 | break; | 518 | else |
519 | /* notify initiator waiting for the requests completion */ | ||
520 | /* | ||
521 | * FIXME: Race! We must not access fsf_req here as it might have been | ||
522 | * cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED | ||
523 | * flag. It's an improbable case. But, we have the same paranoia for | ||
524 | * the cleanup flag already. | ||
525 | * Might better be handled using complete()? | ||
526 | * (setting the flag and doing wakeup ought to be atomic | ||
527 | * with regard to checking the flag as long as waitqueue is | ||
528 | * part of the to be released structure) | ||
529 | */ | ||
530 | wake_up(&req->completion_wq); | ||
531 | } | ||
629 | 532 | ||
630 | case FSF_QTCB_ABORT_FCP_CMND: | 533 | static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) |
631 | zfcp_fsf_abort_fcp_command_handler(fsf_req); | 534 | { |
632 | break; | 535 | struct fsf_qtcb_bottom_config *bottom; |
536 | struct zfcp_adapter *adapter = req->adapter; | ||
537 | struct Scsi_Host *shost = adapter->scsi_host; | ||
633 | 538 | ||
634 | case FSF_QTCB_SEND_GENERIC: | 539 | bottom = &req->qtcb->bottom.config; |
635 | zfcp_fsf_send_ct_handler(fsf_req); | ||
636 | break; | ||
637 | 540 | ||
638 | case FSF_QTCB_OPEN_PORT_WITH_DID: | 541 | if (req->data) |
639 | zfcp_fsf_open_port_handler(fsf_req); | 542 | memcpy(req->data, bottom, sizeof(*bottom)); |
640 | break; | ||
641 | 543 | ||
642 | case FSF_QTCB_OPEN_LUN: | 544 | fc_host_node_name(shost) = bottom->nport_serv_param.wwnn; |
643 | zfcp_fsf_open_unit_handler(fsf_req); | 545 | fc_host_port_name(shost) = bottom->nport_serv_param.wwpn; |
644 | break; | 546 | fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK; |
547 | fc_host_speed(shost) = bottom->fc_link_speed; | ||
548 | fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; | ||
645 | 549 | ||
646 | case FSF_QTCB_CLOSE_LUN: | 550 | adapter->hydra_version = bottom->adapter_type; |
647 | zfcp_fsf_close_unit_handler(fsf_req); | 551 | adapter->timer_ticks = bottom->timer_interval; |
648 | break; | ||
649 | 552 | ||
650 | case FSF_QTCB_CLOSE_PORT: | 553 | if (fc_host_permanent_port_name(shost) == -1) |
651 | zfcp_fsf_close_port_handler(fsf_req); | 554 | fc_host_permanent_port_name(shost) = fc_host_port_name(shost); |
652 | break; | ||
653 | 555 | ||
654 | case FSF_QTCB_CLOSE_PHYSICAL_PORT: | 556 | switch (bottom->fc_topology) { |
655 | zfcp_fsf_close_physical_port_handler(fsf_req); | 557 | case FSF_TOPO_P2P: |
656 | break; | 558 | adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK; |
559 | adapter->peer_wwpn = bottom->plogi_payload.wwpn; | ||
560 | adapter->peer_wwnn = bottom->plogi_payload.wwnn; | ||
561 | fc_host_port_type(shost) = FC_PORTTYPE_PTP; | ||
562 | if (req->erp_action) | ||
563 | dev_info(&adapter->ccw_device->dev, | ||
564 | "Point-to-Point fibrechannel " | ||
565 | "configuration detected.\n"); | ||
566 | break; | ||
567 | case FSF_TOPO_FABRIC: | ||
568 | fc_host_port_type(shost) = FC_PORTTYPE_NPORT; | ||
569 | if (req->erp_action) | ||
570 | dev_info(&adapter->ccw_device->dev, | ||
571 | "Switched fabric fibrechannel " | ||
572 | "network detected.\n"); | ||
573 | break; | ||
574 | case FSF_TOPO_AL: | ||
575 | fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; | ||
576 | dev_err(&adapter->ccw_device->dev, | ||
577 | "Unsupported arbitrated loop fibrechannel " | ||
578 | "topology detected, shutting down " | ||
579 | "adapter.\n"); | ||
580 | zfcp_erp_adapter_shutdown(adapter, 0, 127, req); | ||
581 | return -EIO; | ||
582 | default: | ||
583 | fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; | ||
584 | dev_err(&adapter->ccw_device->dev, | ||
585 | "The fibrechannel topology reported by the" | ||
586 | " adapter is not known by the zfcp driver," | ||
587 | " shutting down adapter.\n"); | ||
588 | zfcp_erp_adapter_shutdown(adapter, 0, 128, req); | ||
589 | return -EIO; | ||
590 | } | ||
657 | 591 | ||
658 | case FSF_QTCB_EXCHANGE_CONFIG_DATA: | 592 | return 0; |
659 | zfcp_fsf_exchange_config_data_handler(fsf_req); | 593 | } |
660 | break; | ||
661 | 594 | ||
662 | case FSF_QTCB_EXCHANGE_PORT_DATA: | 595 | static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) |
663 | zfcp_fsf_exchange_port_data_handler(fsf_req); | 596 | { |
664 | break; | 597 | struct zfcp_adapter *adapter = req->adapter; |
598 | struct fsf_qtcb *qtcb = req->qtcb; | ||
599 | struct fsf_qtcb_bottom_config *bottom = &qtcb->bottom.config; | ||
600 | struct Scsi_Host *shost = adapter->scsi_host; | ||
665 | 601 | ||
666 | case FSF_QTCB_SEND_ELS: | 602 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
667 | zfcp_fsf_send_els_handler(fsf_req); | 603 | return; |
668 | break; | ||
669 | 604 | ||
670 | case FSF_QTCB_DOWNLOAD_CONTROL_FILE: | 605 | adapter->fsf_lic_version = bottom->lic_version; |
671 | zfcp_fsf_control_file_handler(fsf_req); | 606 | adapter->adapter_features = bottom->adapter_features; |
672 | break; | 607 | adapter->connection_features = bottom->connection_features; |
608 | adapter->peer_wwpn = 0; | ||
609 | adapter->peer_wwnn = 0; | ||
610 | adapter->peer_d_id = 0; | ||
673 | 611 | ||
674 | case FSF_QTCB_UPLOAD_CONTROL_FILE: | 612 | switch (qtcb->header.fsf_status) { |
675 | zfcp_fsf_control_file_handler(fsf_req); | 613 | case FSF_GOOD: |
614 | if (zfcp_fsf_exchange_config_evaluate(req)) | ||
615 | return; | ||
616 | |||
617 | if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) { | ||
618 | dev_err(&adapter->ccw_device->dev, | ||
619 | "Maximum QTCB size (%d bytes) allowed by " | ||
620 | "the adapter is lower than the minimum " | ||
621 | "required by the driver (%ld bytes).\n", | ||
622 | bottom->max_qtcb_size, | ||
623 | sizeof(struct fsf_qtcb)); | ||
624 | zfcp_erp_adapter_shutdown(adapter, 0, 129, req); | ||
625 | return; | ||
626 | } | ||
627 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | ||
628 | &adapter->status); | ||
676 | break; | 629 | break; |
630 | case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: | ||
631 | fc_host_node_name(shost) = 0; | ||
632 | fc_host_port_name(shost) = 0; | ||
633 | fc_host_port_id(shost) = 0; | ||
634 | fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; | ||
635 | fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; | ||
636 | adapter->hydra_version = 0; | ||
677 | 637 | ||
638 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | ||
639 | &adapter->status); | ||
640 | |||
641 | zfcp_fsf_link_down_info_eval(req, 42, | ||
642 | &qtcb->header.fsf_status_qual.link_down_info); | ||
643 | break; | ||
678 | default: | 644 | default: |
679 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 645 | zfcp_erp_adapter_shutdown(adapter, 0, 130, req); |
680 | ZFCP_LOG_NORMAL("bug: Command issued by the device driver is " | 646 | return; |
681 | "not supported by the adapter %s\n", | ||
682 | zfcp_get_busid_by_adapter(adapter)); | ||
683 | if (fsf_req->fsf_command != fsf_req->qtcb->header.fsf_command) | ||
684 | ZFCP_LOG_NORMAL | ||
685 | ("bug: Command issued by the device driver differs " | ||
686 | "from the command returned by the adapter %s " | ||
687 | "(debug info 0x%x, 0x%x).\n", | ||
688 | zfcp_get_busid_by_adapter(adapter), | ||
689 | fsf_req->fsf_command, | ||
690 | fsf_req->qtcb->header.fsf_command); | ||
691 | } | 647 | } |
692 | 648 | ||
693 | if (!erp_action) | 649 | if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { |
694 | return retval; | 650 | adapter->hardware_version = bottom->hardware_version; |
695 | 651 | memcpy(fc_host_serial_number(shost), bottom->serial_number, | |
696 | zfcp_erp_async_handler(erp_action, 0); | 652 | min(FC_SERIAL_NUMBER_SIZE, 17)); |
653 | EBCASC(fc_host_serial_number(shost), | ||
654 | min(FC_SERIAL_NUMBER_SIZE, 17)); | ||
655 | } | ||
697 | 656 | ||
698 | return retval; | 657 | if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) { |
658 | dev_err(&adapter->ccw_device->dev, | ||
659 | "The adapter only supports newer control block " | ||
660 | "versions, try updated device driver.\n"); | ||
661 | zfcp_erp_adapter_shutdown(adapter, 0, 125, req); | ||
662 | return; | ||
663 | } | ||
664 | if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) { | ||
665 | dev_err(&adapter->ccw_device->dev, | ||
666 | "The adapter only supports older control block " | ||
667 | "versions, consider a microcode upgrade.\n"); | ||
668 | zfcp_erp_adapter_shutdown(adapter, 0, 126, req); | ||
669 | } | ||
699 | } | 670 | } |
700 | 671 | ||
701 | /* | 672 | static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req) |
702 | * function: zfcp_fsf_status_read | ||
703 | * | ||
704 | * purpose: initiates a Status Read command at the specified adapter | ||
705 | * | ||
706 | * returns: | ||
707 | */ | ||
708 | int | ||
709 | zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) | ||
710 | { | 673 | { |
711 | struct zfcp_fsf_req *fsf_req; | 674 | struct zfcp_adapter *adapter = req->adapter; |
712 | struct fsf_status_read_buffer *status_buffer; | 675 | struct fsf_qtcb_bottom_port *bottom = &req->qtcb->bottom.port; |
713 | unsigned long lock_flags; | 676 | struct Scsi_Host *shost = adapter->scsi_host; |
714 | volatile struct qdio_buffer_element *sbale; | ||
715 | int retval = 0; | ||
716 | |||
717 | /* setup new FSF request */ | ||
718 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, | ||
719 | req_flags | ZFCP_REQ_NO_QTCB, | ||
720 | adapter->pool.fsf_req_status_read, | ||
721 | &lock_flags, &fsf_req); | ||
722 | if (retval < 0) { | ||
723 | ZFCP_LOG_INFO("error: Could not create unsolicited status " | ||
724 | "buffer for adapter %s.\n", | ||
725 | zfcp_get_busid_by_adapter(adapter)); | ||
726 | goto failed_req_create; | ||
727 | } | ||
728 | |||
729 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | ||
730 | sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS; | ||
731 | sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
732 | fsf_req->sbale_curr = 2; | ||
733 | 677 | ||
734 | status_buffer = | 678 | if (req->data) |
735 | mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC); | 679 | memcpy(req->data, bottom, sizeof(*bottom)); |
736 | if (!status_buffer) { | ||
737 | ZFCP_LOG_NORMAL("bug: could not get some buffer\n"); | ||
738 | goto failed_buf; | ||
739 | } | ||
740 | memset(status_buffer, 0, sizeof (struct fsf_status_read_buffer)); | ||
741 | fsf_req->data = (unsigned long) status_buffer; | ||
742 | 680 | ||
743 | /* insert pointer to respective buffer */ | 681 | if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) |
744 | sbale = zfcp_qdio_sbale_curr(fsf_req); | 682 | fc_host_permanent_port_name(shost) = bottom->wwpn; |
745 | sbale->addr = (void *) status_buffer; | 683 | else |
746 | sbale->length = sizeof(struct fsf_status_read_buffer); | 684 | fc_host_permanent_port_name(shost) = fc_host_port_name(shost); |
685 | fc_host_maxframe_size(shost) = bottom->maximum_frame_size; | ||
686 | fc_host_supported_speeds(shost) = bottom->supported_speed; | ||
687 | } | ||
747 | 688 | ||
748 | retval = zfcp_fsf_req_send(fsf_req); | 689 | static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) |
749 | if (retval) { | 690 | { |
750 | ZFCP_LOG_DEBUG("error: Could not set-up unsolicited status " | 691 | struct zfcp_adapter *adapter = req->adapter; |
751 | "environment.\n"); | 692 | struct fsf_qtcb *qtcb = req->qtcb; |
752 | goto failed_req_send; | ||
753 | } | ||
754 | 693 | ||
755 | ZFCP_LOG_TRACE("Status Read request initiated (adapter%s)\n", | 694 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
756 | zfcp_get_busid_by_adapter(adapter)); | 695 | return; |
757 | goto out; | ||
758 | 696 | ||
759 | failed_req_send: | 697 | switch (qtcb->header.fsf_status) { |
760 | mempool_free(status_buffer, adapter->pool.data_status_read); | 698 | case FSF_GOOD: |
699 | zfcp_fsf_exchange_port_evaluate(req); | ||
700 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); | ||
701 | break; | ||
702 | case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: | ||
703 | zfcp_fsf_exchange_port_evaluate(req); | ||
704 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); | ||
705 | zfcp_fsf_link_down_info_eval(req, 43, | ||
706 | &qtcb->header.fsf_status_qual.link_down_info); | ||
707 | break; | ||
708 | } | ||
709 | } | ||
761 | 710 | ||
762 | failed_buf: | 711 | static int zfcp_fsf_sbal_check(struct zfcp_qdio_queue *queue) |
763 | zfcp_fsf_req_free(fsf_req); | 712 | { |
764 | failed_req_create: | 713 | spin_lock(&queue->lock); |
765 | zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); | 714 | if (atomic_read(&queue->count)) |
766 | out: | 715 | return 1; |
767 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 716 | spin_unlock(&queue->lock); |
768 | return retval; | 717 | return 0; |
769 | } | 718 | } |
770 | 719 | ||
771 | static int | 720 | static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter) |
772 | zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req) | ||
773 | { | 721 | { |
774 | struct fsf_status_read_buffer *status_buffer; | 722 | long ret; |
775 | struct zfcp_adapter *adapter; | 723 | struct zfcp_qdio_queue *req_q = &adapter->req_q; |
776 | struct zfcp_port *port; | ||
777 | unsigned long flags; | ||
778 | 724 | ||
779 | status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; | 725 | spin_unlock(&req_q->lock); |
780 | adapter = fsf_req->adapter; | 726 | ret = wait_event_interruptible_timeout(adapter->request_wq, |
727 | zfcp_fsf_sbal_check(req_q), 5 * HZ); | ||
728 | if (ret > 0) | ||
729 | return 0; | ||
781 | 730 | ||
782 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 731 | spin_lock(&req_q->lock); |
783 | list_for_each_entry(port, &adapter->port_list_head, list) | 732 | return -EIO; |
784 | if (port->d_id == (status_buffer->d_id & ZFCP_DID_MASK)) | 733 | } |
785 | break; | ||
786 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
787 | 734 | ||
788 | if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) { | 735 | static struct zfcp_fsf_req *zfcp_fsf_alloc_noqtcb(mempool_t *pool) |
789 | ZFCP_LOG_NORMAL("bug: Reopen port indication received for " | 736 | { |
790 | "nonexisting port with d_id 0x%06x on " | 737 | struct zfcp_fsf_req *req; |
791 | "adapter %s. Ignored.\n", | 738 | req = mempool_alloc(pool, GFP_ATOMIC); |
792 | status_buffer->d_id & ZFCP_DID_MASK, | 739 | if (!req) |
793 | zfcp_get_busid_by_adapter(adapter)); | 740 | return NULL; |
794 | goto out; | 741 | memset(req, 0, sizeof(*req)); |
795 | } | 742 | return req; |
743 | } | ||
796 | 744 | ||
797 | switch (status_buffer->status_subtype) { | 745 | static struct zfcp_fsf_req *zfcp_fsf_alloc_qtcb(mempool_t *pool) |
746 | { | ||
747 | struct zfcp_fsf_req_qtcb *qtcb; | ||
798 | 748 | ||
799 | case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT: | 749 | if (likely(pool)) |
800 | zfcp_erp_port_reopen(port, 0, 101, fsf_req); | 750 | qtcb = mempool_alloc(pool, GFP_ATOMIC); |
801 | break; | 751 | else |
752 | qtcb = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache, | ||
753 | GFP_ATOMIC); | ||
754 | if (unlikely(!qtcb)) | ||
755 | return NULL; | ||
802 | 756 | ||
803 | case FSF_STATUS_READ_SUB_ERROR_PORT: | 757 | memset(qtcb, 0, sizeof(*qtcb)); |
804 | zfcp_erp_port_shutdown(port, 0, 122, fsf_req); | 758 | qtcb->fsf_req.qtcb = &qtcb->qtcb; |
805 | break; | 759 | qtcb->fsf_req.pool = pool; |
806 | 760 | ||
807 | default: | 761 | return &qtcb->fsf_req; |
808 | ZFCP_LOG_NORMAL("bug: Undefined status subtype received " | ||
809 | "for a reopen indication on port with " | ||
810 | "d_id 0x%06x on the adapter %s. " | ||
811 | "Ignored. (debug info 0x%x)\n", | ||
812 | status_buffer->d_id, | ||
813 | zfcp_get_busid_by_adapter(adapter), | ||
814 | status_buffer->status_subtype); | ||
815 | } | ||
816 | out: | ||
817 | return 0; | ||
818 | } | 762 | } |
819 | 763 | ||
820 | /* | 764 | static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, |
821 | * function: zfcp_fsf_status_read_handler | 765 | u32 fsf_cmd, int req_flags, |
822 | * | 766 | mempool_t *pool) |
823 | * purpose: is called for finished Open Port command | ||
824 | * | ||
825 | * returns: | ||
826 | */ | ||
827 | static int | ||
828 | zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) | ||
829 | { | 767 | { |
830 | int retval = 0; | 768 | volatile struct qdio_buffer_element *sbale; |
831 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
832 | struct fsf_status_read_buffer *status_buffer = | ||
833 | (struct fsf_status_read_buffer *) fsf_req->data; | ||
834 | struct fsf_bit_error_payload *fsf_bit_error; | ||
835 | |||
836 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { | ||
837 | zfcp_hba_dbf_event_fsf_unsol("dism", adapter, status_buffer); | ||
838 | mempool_free(status_buffer, adapter->pool.data_status_read); | ||
839 | zfcp_fsf_req_free(fsf_req); | ||
840 | goto out; | ||
841 | } | ||
842 | 769 | ||
843 | zfcp_hba_dbf_event_fsf_unsol("read", adapter, status_buffer); | 770 | struct zfcp_fsf_req *req; |
771 | struct zfcp_qdio_queue *req_q = &adapter->req_q; | ||
844 | 772 | ||
845 | switch (status_buffer->status_type) { | 773 | if (req_flags & ZFCP_REQ_NO_QTCB) |
774 | req = zfcp_fsf_alloc_noqtcb(pool); | ||
775 | else | ||
776 | req = zfcp_fsf_alloc_qtcb(pool); | ||
846 | 777 | ||
847 | case FSF_STATUS_READ_PORT_CLOSED: | 778 | if (unlikely(!req)) |
848 | zfcp_fsf_status_read_port_closed(fsf_req); | 779 | return ERR_PTR(-EIO); |
849 | break; | ||
850 | 780 | ||
851 | case FSF_STATUS_READ_INCOMING_ELS: | 781 | if (adapter->req_no == 0) |
852 | zfcp_fsf_incoming_els(fsf_req); | 782 | adapter->req_no++; |
853 | break; | ||
854 | 783 | ||
855 | case FSF_STATUS_READ_SENSE_DATA_AVAIL: | 784 | INIT_LIST_HEAD(&req->list); |
856 | ZFCP_LOG_INFO("unsolicited sense data received (adapter %s)\n", | 785 | init_timer(&req->timer); |
857 | zfcp_get_busid_by_adapter(adapter)); | 786 | init_waitqueue_head(&req->completion_wq); |
858 | break; | ||
859 | 787 | ||
860 | case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: | 788 | req->adapter = adapter; |
861 | fsf_bit_error = (struct fsf_bit_error_payload *) | 789 | req->fsf_command = fsf_cmd; |
862 | status_buffer->payload; | 790 | req->req_id = adapter->req_no++; |
863 | ZFCP_LOG_NORMAL("Warning: bit error threshold data " | 791 | req->sbal_number = 1; |
864 | "received (adapter %s, " | 792 | req->sbal_first = req_q->first; |
865 | "link failures = %i, loss of sync errors = %i, " | 793 | req->sbal_last = req_q->first; |
866 | "loss of signal errors = %i, " | 794 | req->sbale_curr = 1; |
867 | "primitive sequence errors = %i, " | ||
868 | "invalid transmission word errors = %i, " | ||
869 | "CRC errors = %i)\n", | ||
870 | zfcp_get_busid_by_adapter(adapter), | ||
871 | fsf_bit_error->link_failure_error_count, | ||
872 | fsf_bit_error->loss_of_sync_error_count, | ||
873 | fsf_bit_error->loss_of_signal_error_count, | ||
874 | fsf_bit_error->primitive_sequence_error_count, | ||
875 | fsf_bit_error->invalid_transmission_word_error_count, | ||
876 | fsf_bit_error->crc_error_count); | ||
877 | ZFCP_LOG_INFO("Additional bit error threshold data " | ||
878 | "(adapter %s, " | ||
879 | "primitive sequence event time-outs = %i, " | ||
880 | "elastic buffer overrun errors = %i, " | ||
881 | "advertised receive buffer-to-buffer credit = %i, " | ||
882 | "current receice buffer-to-buffer credit = %i, " | ||
883 | "advertised transmit buffer-to-buffer credit = %i, " | ||
884 | "current transmit buffer-to-buffer credit = %i)\n", | ||
885 | zfcp_get_busid_by_adapter(adapter), | ||
886 | fsf_bit_error->primitive_sequence_event_timeout_count, | ||
887 | fsf_bit_error->elastic_buffer_overrun_error_count, | ||
888 | fsf_bit_error->advertised_receive_b2b_credit, | ||
889 | fsf_bit_error->current_receive_b2b_credit, | ||
890 | fsf_bit_error->advertised_transmit_b2b_credit, | ||
891 | fsf_bit_error->current_transmit_b2b_credit); | ||
892 | break; | ||
893 | 795 | ||
894 | case FSF_STATUS_READ_LINK_DOWN: | 796 | sbale = zfcp_qdio_sbale_req(req); |
895 | switch (status_buffer->status_subtype) { | 797 | sbale[0].addr = (void *) req->req_id; |
896 | case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: | 798 | sbale[0].flags |= SBAL_FLAGS0_COMMAND; |
897 | ZFCP_LOG_INFO("Physical link to adapter %s is down\n", | ||
898 | zfcp_get_busid_by_adapter(adapter)); | ||
899 | zfcp_fsf_link_down_info_eval(fsf_req, 38, | ||
900 | (struct fsf_link_down_info *) | ||
901 | &status_buffer->payload); | ||
902 | break; | ||
903 | case FSF_STATUS_READ_SUB_FDISC_FAILED: | ||
904 | ZFCP_LOG_INFO("Local link to adapter %s is down " | ||
905 | "due to failed FDISC login\n", | ||
906 | zfcp_get_busid_by_adapter(adapter)); | ||
907 | zfcp_fsf_link_down_info_eval(fsf_req, 39, | ||
908 | (struct fsf_link_down_info *) | ||
909 | &status_buffer->payload); | ||
910 | break; | ||
911 | case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: | ||
912 | ZFCP_LOG_INFO("Local link to adapter %s is down " | ||
913 | "due to firmware update on adapter\n", | ||
914 | zfcp_get_busid_by_adapter(adapter)); | ||
915 | zfcp_fsf_link_down_info_eval(fsf_req, 40, NULL); | ||
916 | break; | ||
917 | default: | ||
918 | ZFCP_LOG_INFO("Local link to adapter %s is down " | ||
919 | "due to unknown reason\n", | ||
920 | zfcp_get_busid_by_adapter(adapter)); | ||
921 | zfcp_fsf_link_down_info_eval(fsf_req, 41, NULL); | ||
922 | }; | ||
923 | break; | ||
924 | 799 | ||
925 | case FSF_STATUS_READ_LINK_UP: | 800 | if (likely(req->qtcb)) { |
926 | ZFCP_LOG_NORMAL("Local link to adapter %s was replugged. " | 801 | req->qtcb->prefix.req_seq_no = req->adapter->fsf_req_seq_no; |
927 | "Restarting operations on this adapter\n", | 802 | req->qtcb->prefix.req_id = req->req_id; |
928 | zfcp_get_busid_by_adapter(adapter)); | 803 | req->qtcb->prefix.ulp_info = 26; |
929 | /* All ports should be marked as ready to run again */ | 804 | req->qtcb->prefix.qtcb_type = fsf_qtcb_type[req->fsf_command]; |
930 | zfcp_erp_modify_adapter_status(adapter, 30, NULL, | 805 | req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION; |
931 | ZFCP_STATUS_COMMON_RUNNING, | 806 | req->qtcb->header.req_handle = req->req_id; |
932 | ZFCP_SET); | 807 | req->qtcb->header.fsf_command = req->fsf_command; |
933 | zfcp_erp_adapter_reopen(adapter, | 808 | req->seq_no = adapter->fsf_req_seq_no; |
934 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | 809 | req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; |
935 | | ZFCP_STATUS_COMMON_ERP_FAILED, | 810 | sbale[1].addr = (void *) req->qtcb; |
936 | 102, fsf_req); | 811 | sbale[1].length = sizeof(struct fsf_qtcb); |
937 | break; | 812 | } |
938 | 813 | ||
939 | case FSF_STATUS_READ_NOTIFICATION_LOST: | 814 | if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) { |
940 | ZFCP_LOG_NORMAL("Unsolicited status notification(s) lost: " | 815 | zfcp_fsf_req_free(req); |
941 | "adapter %s%s%s%s%s%s%s%s%s\n", | 816 | return ERR_PTR(-EIO); |
942 | zfcp_get_busid_by_adapter(adapter), | 817 | } |
943 | (status_buffer->status_subtype & | ||
944 | FSF_STATUS_READ_SUB_INCOMING_ELS) ? | ||
945 | ", incoming ELS" : "", | ||
946 | (status_buffer->status_subtype & | ||
947 | FSF_STATUS_READ_SUB_SENSE_DATA) ? | ||
948 | ", sense data" : "", | ||
949 | (status_buffer->status_subtype & | ||
950 | FSF_STATUS_READ_SUB_LINK_STATUS) ? | ||
951 | ", link status change" : "", | ||
952 | (status_buffer->status_subtype & | ||
953 | FSF_STATUS_READ_SUB_PORT_CLOSED) ? | ||
954 | ", port close" : "", | ||
955 | (status_buffer->status_subtype & | ||
956 | FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD) ? | ||
957 | ", bit error exception" : "", | ||
958 | (status_buffer->status_subtype & | ||
959 | FSF_STATUS_READ_SUB_ACT_UPDATED) ? | ||
960 | ", ACT update" : "", | ||
961 | (status_buffer->status_subtype & | ||
962 | FSF_STATUS_READ_SUB_ACT_HARDENED) ? | ||
963 | ", ACT hardening" : "", | ||
964 | (status_buffer->status_subtype & | ||
965 | FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT) ? | ||
966 | ", adapter feature change" : ""); | ||
967 | |||
968 | if (status_buffer->status_subtype & | ||
969 | FSF_STATUS_READ_SUB_ACT_UPDATED) | ||
970 | zfcp_erp_adapter_access_changed(adapter, 135, fsf_req); | ||
971 | break; | ||
972 | 818 | ||
973 | case FSF_STATUS_READ_CFDC_UPDATED: | 819 | if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) |
974 | ZFCP_LOG_NORMAL("CFDC has been updated on the adapter %s\n", | 820 | req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; |
975 | zfcp_get_busid_by_adapter(adapter)); | ||
976 | zfcp_erp_adapter_access_changed(adapter, 136, fsf_req); | ||
977 | break; | ||
978 | 821 | ||
979 | case FSF_STATUS_READ_CFDC_HARDENED: | 822 | return req; |
980 | switch (status_buffer->status_subtype) { | 823 | } |
981 | case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE: | ||
982 | ZFCP_LOG_NORMAL("CFDC of adapter %s saved on SE\n", | ||
983 | zfcp_get_busid_by_adapter(adapter)); | ||
984 | break; | ||
985 | case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2: | ||
986 | ZFCP_LOG_NORMAL("CFDC of adapter %s has been copied " | ||
987 | "to the secondary SE\n", | ||
988 | zfcp_get_busid_by_adapter(adapter)); | ||
989 | break; | ||
990 | default: | ||
991 | ZFCP_LOG_NORMAL("CFDC of adapter %s has been hardened\n", | ||
992 | zfcp_get_busid_by_adapter(adapter)); | ||
993 | } | ||
994 | break; | ||
995 | 824 | ||
996 | case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: | 825 | static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) |
997 | ZFCP_LOG_INFO("List of supported features on adapter %s has " | 826 | { |
998 | "been changed from 0x%08X to 0x%08X\n", | 827 | struct zfcp_adapter *adapter = req->adapter; |
999 | zfcp_get_busid_by_adapter(adapter), | 828 | struct zfcp_qdio_queue *req_q = &adapter->req_q; |
1000 | *(u32*) (status_buffer->payload + 4), | 829 | int idx; |
1001 | *(u32*) (status_buffer->payload)); | ||
1002 | adapter->adapter_features = *(u32*) status_buffer->payload; | ||
1003 | break; | ||
1004 | 830 | ||
1005 | default: | 831 | /* put allocated FSF request into hash table */ |
1006 | ZFCP_LOG_NORMAL("warning: An unsolicited status packet of unknown " | 832 | spin_lock(&adapter->req_list_lock); |
1007 | "type was received (debug info 0x%x)\n", | 833 | idx = zfcp_reqlist_hash(req->req_id); |
1008 | status_buffer->status_type); | 834 | list_add_tail(&req->list, &adapter->req_list[idx]); |
1009 | ZFCP_LOG_DEBUG("Dump of status_read_buffer %p:\n", | 835 | spin_unlock(&adapter->req_list_lock); |
1010 | status_buffer); | 836 | |
1011 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 837 | req->issued = get_clock(); |
1012 | (char *) status_buffer, | 838 | if (zfcp_qdio_send(req)) { |
1013 | sizeof (struct fsf_status_read_buffer)); | 839 | /* Queues are down..... */ |
1014 | break; | 840 | del_timer(&req->timer); |
1015 | } | 841 | spin_lock(&adapter->req_list_lock); |
1016 | mempool_free(status_buffer, adapter->pool.data_status_read); | 842 | zfcp_reqlist_remove(adapter, req); |
1017 | zfcp_fsf_req_free(fsf_req); | 843 | spin_unlock(&adapter->req_list_lock); |
1018 | /* | 844 | /* undo changes in request queue made for this request */ |
1019 | * recycle buffer and start new request repeat until outbound | 845 | atomic_add(req->sbal_number, &req_q->count); |
1020 | * queue is empty or adapter shutdown is requested | 846 | req_q->first -= req->sbal_number; |
1021 | */ | 847 | req_q->first += QDIO_MAX_BUFFERS_PER_Q; |
1022 | /* | 848 | req_q->first %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */ |
1023 | * FIXME(qdio): | 849 | zfcp_erp_adapter_reopen(adapter, 0, 116, req); |
1024 | * we may wait in the req_create for 5s during shutdown, so | 850 | return -EIO; |
1025 | * qdio_cleanup will have to wait at least that long before returning | ||
1026 | * with failure to allow us a proper cleanup under all circumstances | ||
1027 | */ | ||
1028 | /* | ||
1029 | * FIXME: | ||
1030 | * allocation failure possible? (Is this code needed?) | ||
1031 | */ | ||
1032 | retval = zfcp_fsf_status_read(adapter, 0); | ||
1033 | if (retval < 0) { | ||
1034 | ZFCP_LOG_INFO("Failed to create unsolicited status read " | ||
1035 | "request for the adapter %s.\n", | ||
1036 | zfcp_get_busid_by_adapter(adapter)); | ||
1037 | /* temporary fix to avoid status read buffer shortage */ | ||
1038 | adapter->status_read_failed++; | ||
1039 | if ((ZFCP_STATUS_READS_RECOM - adapter->status_read_failed) | ||
1040 | < ZFCP_STATUS_READ_FAILED_THRESHOLD) { | ||
1041 | ZFCP_LOG_INFO("restart adapter %s due to status read " | ||
1042 | "buffer shortage\n", | ||
1043 | zfcp_get_busid_by_adapter(adapter)); | ||
1044 | zfcp_erp_adapter_reopen(adapter, 0, 103, fsf_req); | ||
1045 | } | ||
1046 | } | 851 | } |
1047 | out: | 852 | |
1048 | return retval; | 853 | /* Don't increase for unsolicited status */ |
854 | if (req->qtcb) | ||
855 | adapter->fsf_req_seq_no++; | ||
856 | |||
857 | return 0; | ||
1049 | } | 858 | } |
1050 | 859 | ||
1051 | /* | 860 | /** |
1052 | * function: zfcp_fsf_abort_fcp_command | 861 | * zfcp_fsf_status_read - send status read request |
1053 | * | 862 | * @adapter: pointer to struct zfcp_adapter |
1054 | * purpose: tells FSF to abort a running SCSI command | 863 | * @req_flags: request flags |
1055 | * | 864 | * Returns: 0 on success, ERROR otherwise |
1056 | * returns: address of initiated FSF request | ||
1057 | * NULL - request could not be initiated | ||
1058 | * | ||
1059 | * FIXME(design): should be watched by a timeout !!! | ||
1060 | * FIXME(design) shouldn't this be modified to return an int | ||
1061 | * also...don't know how though | ||
1062 | */ | 865 | */ |
1063 | struct zfcp_fsf_req * | 866 | int zfcp_fsf_status_read(struct zfcp_adapter *adapter) |
1064 | zfcp_fsf_abort_fcp_command(unsigned long old_req_id, | ||
1065 | struct zfcp_adapter *adapter, | ||
1066 | struct zfcp_unit *unit, int req_flags) | ||
1067 | { | 867 | { |
868 | struct zfcp_fsf_req *req; | ||
869 | struct fsf_status_read_buffer *sr_buf; | ||
1068 | volatile struct qdio_buffer_element *sbale; | 870 | volatile struct qdio_buffer_element *sbale; |
1069 | struct zfcp_fsf_req *fsf_req = NULL; | 871 | int retval = -EIO; |
1070 | unsigned long lock_flags; | ||
1071 | int retval = 0; | ||
1072 | |||
1073 | /* setup new FSF request */ | ||
1074 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, | ||
1075 | req_flags, adapter->pool.fsf_req_abort, | ||
1076 | &lock_flags, &fsf_req); | ||
1077 | if (retval < 0) { | ||
1078 | ZFCP_LOG_INFO("error: Failed to create an abort command " | ||
1079 | "request for lun 0x%016Lx on port 0x%016Lx " | ||
1080 | "on adapter %s.\n", | ||
1081 | unit->fcp_lun, | ||
1082 | unit->port->wwpn, | ||
1083 | zfcp_get_busid_by_adapter(adapter)); | ||
1084 | goto out; | ||
1085 | } | ||
1086 | |||
1087 | if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
1088 | &unit->status))) | ||
1089 | goto unit_blocked; | ||
1090 | 872 | ||
1091 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 873 | spin_lock(&adapter->req_q.lock); |
1092 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 874 | if (zfcp_fsf_req_sbal_get(adapter)) |
1093 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 875 | goto out; |
1094 | 876 | ||
1095 | fsf_req->data = (unsigned long) unit; | 877 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS, |
878 | ZFCP_REQ_NO_QTCB, | ||
879 | adapter->pool.fsf_req_status_read); | ||
880 | if (unlikely(IS_ERR(req))) { | ||
881 | retval = PTR_ERR(req); | ||
882 | goto out; | ||
883 | } | ||
1096 | 884 | ||
1097 | /* set handles of unit and its parent port in QTCB */ | 885 | sbale = zfcp_qdio_sbale_req(req); |
1098 | fsf_req->qtcb->header.lun_handle = unit->handle; | 886 | sbale[0].flags |= SBAL_FLAGS0_TYPE_STATUS; |
1099 | fsf_req->qtcb->header.port_handle = unit->port->handle; | 887 | sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY; |
888 | req->sbale_curr = 2; | ||
1100 | 889 | ||
1101 | /* set handle of request which should be aborted */ | 890 | sr_buf = mempool_alloc(adapter->pool.data_status_read, GFP_ATOMIC); |
1102 | fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id; | 891 | if (!sr_buf) { |
892 | retval = -ENOMEM; | ||
893 | goto failed_buf; | ||
894 | } | ||
895 | memset(sr_buf, 0, sizeof(*sr_buf)); | ||
896 | req->data = sr_buf; | ||
897 | sbale = zfcp_qdio_sbale_curr(req); | ||
898 | sbale->addr = (void *) sr_buf; | ||
899 | sbale->length = sizeof(*sr_buf); | ||
1103 | 900 | ||
1104 | zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT); | 901 | retval = zfcp_fsf_req_send(req); |
1105 | retval = zfcp_fsf_req_send(fsf_req); | 902 | if (retval) |
1106 | if (!retval) | 903 | goto failed_req_send; |
1107 | goto out; | ||
1108 | 904 | ||
1109 | unit_blocked: | 905 | goto out; |
1110 | zfcp_fsf_req_free(fsf_req); | ||
1111 | fsf_req = NULL; | ||
1112 | 906 | ||
1113 | out: | 907 | failed_req_send: |
1114 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 908 | mempool_free(sr_buf, adapter->pool.data_status_read); |
1115 | return fsf_req; | 909 | failed_buf: |
910 | zfcp_fsf_req_free(req); | ||
911 | zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); | ||
912 | out: | ||
913 | spin_unlock(&adapter->req_q.lock); | ||
914 | return retval; | ||
1116 | } | 915 | } |
1117 | 916 | ||
1118 | /* | 917 | static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) |
1119 | * function: zfcp_fsf_abort_fcp_command_handler | ||
1120 | * | ||
1121 | * purpose: is called for finished Abort FCP Command request | ||
1122 | * | ||
1123 | * returns: | ||
1124 | */ | ||
1125 | static int | ||
1126 | zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) | ||
1127 | { | 918 | { |
1128 | int retval = -EINVAL; | 919 | struct zfcp_unit *unit = req->data; |
1129 | struct zfcp_unit *unit; | 920 | union fsf_status_qual *fsq = &req->qtcb->header.fsf_status_qual; |
1130 | union fsf_status_qual *fsf_stat_qual = | ||
1131 | &new_fsf_req->qtcb->header.fsf_status_qual; | ||
1132 | |||
1133 | if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
1134 | /* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */ | ||
1135 | goto skip_fsfstatus; | ||
1136 | } | ||
1137 | |||
1138 | unit = (struct zfcp_unit *) new_fsf_req->data; | ||
1139 | 921 | ||
1140 | /* evaluate FSF status in QTCB */ | 922 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
1141 | switch (new_fsf_req->qtcb->header.fsf_status) { | 923 | return; |
1142 | 924 | ||
925 | switch (req->qtcb->header.fsf_status) { | ||
1143 | case FSF_PORT_HANDLE_NOT_VALID: | 926 | case FSF_PORT_HANDLE_NOT_VALID: |
1144 | if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) { | 927 | if (fsq->word[0] == fsq->word[1]) { |
1145 | /* | ||
1146 | * In this case a command that was sent prior to a port | ||
1147 | * reopen was aborted (handles are different). This is | ||
1148 | * fine. | ||
1149 | */ | ||
1150 | } else { | ||
1151 | ZFCP_LOG_INFO("Temporary port identifier 0x%x for " | ||
1152 | "port 0x%016Lx on adapter %s invalid. " | ||
1153 | "This may happen occasionally.\n", | ||
1154 | unit->port->handle, | ||
1155 | unit->port->wwpn, | ||
1156 | zfcp_get_busid_by_unit(unit)); | ||
1157 | ZFCP_LOG_INFO("status qualifier:\n"); | ||
1158 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, | ||
1159 | (char *) &new_fsf_req->qtcb->header. | ||
1160 | fsf_status_qual, | ||
1161 | sizeof (union fsf_status_qual)); | ||
1162 | /* Let's hope this sorts out the mess */ | ||
1163 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 104, | 928 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 104, |
1164 | new_fsf_req); | 929 | req); |
1165 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 930 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1166 | } | 931 | } |
1167 | break; | 932 | break; |
1168 | |||
1169 | case FSF_LUN_HANDLE_NOT_VALID: | 933 | case FSF_LUN_HANDLE_NOT_VALID: |
1170 | if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) { | 934 | if (fsq->word[0] == fsq->word[1]) { |
1171 | /* | 935 | zfcp_erp_port_reopen(unit->port, 0, 105, req); |
1172 | * In this case a command that was sent prior to a unit | 936 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1173 | * reopen was aborted (handles are different). | ||
1174 | * This is fine. | ||
1175 | */ | ||
1176 | } else { | ||
1177 | ZFCP_LOG_INFO | ||
1178 | ("Warning: Temporary LUN identifier 0x%x of LUN " | ||
1179 | "0x%016Lx on port 0x%016Lx on adapter %s is " | ||
1180 | "invalid. This may happen in rare cases. " | ||
1181 | "Trying to re-establish link.\n", | ||
1182 | unit->handle, | ||
1183 | unit->fcp_lun, | ||
1184 | unit->port->wwpn, | ||
1185 | zfcp_get_busid_by_unit(unit)); | ||
1186 | ZFCP_LOG_DEBUG("Status qualifier data:\n"); | ||
1187 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
1188 | (char *) &new_fsf_req->qtcb->header. | ||
1189 | fsf_status_qual, | ||
1190 | sizeof (union fsf_status_qual)); | ||
1191 | /* Let's hope this sorts out the mess */ | ||
1192 | zfcp_erp_port_reopen(unit->port, 0, 105, new_fsf_req); | ||
1193 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1194 | } | 937 | } |
1195 | break; | 938 | break; |
1196 | |||
1197 | case FSF_FCP_COMMAND_DOES_NOT_EXIST: | 939 | case FSF_FCP_COMMAND_DOES_NOT_EXIST: |
1198 | retval = 0; | 940 | req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED; |
1199 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED; | ||
1200 | break; | 941 | break; |
1201 | |||
1202 | case FSF_PORT_BOXED: | 942 | case FSF_PORT_BOXED: |
1203 | ZFCP_LOG_INFO("Remote port 0x%016Lx on adapter %s needs to " | 943 | zfcp_erp_port_boxed(unit->port, 47, req); |
1204 | "be reopened\n", unit->port->wwpn, | 944 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
1205 | zfcp_get_busid_by_unit(unit)); | 945 | ZFCP_STATUS_FSFREQ_RETRY; |
1206 | zfcp_erp_port_boxed(unit->port, 47, new_fsf_req); | ||
1207 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ||
1208 | | ZFCP_STATUS_FSFREQ_RETRY; | ||
1209 | break; | 946 | break; |
1210 | |||
1211 | case FSF_LUN_BOXED: | 947 | case FSF_LUN_BOXED: |
1212 | ZFCP_LOG_INFO( | 948 | zfcp_erp_unit_boxed(unit, 48, req); |
1213 | "unit 0x%016Lx on port 0x%016Lx on adapter %s needs " | 949 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
1214 | "to be reopened\n", | 950 | ZFCP_STATUS_FSFREQ_RETRY; |
1215 | unit->fcp_lun, unit->port->wwpn, | ||
1216 | zfcp_get_busid_by_unit(unit)); | ||
1217 | zfcp_erp_unit_boxed(unit, 48, new_fsf_req); | ||
1218 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ||
1219 | | ZFCP_STATUS_FSFREQ_RETRY; | ||
1220 | break; | 951 | break; |
1221 | |||
1222 | case FSF_ADAPTER_STATUS_AVAILABLE: | 952 | case FSF_ADAPTER_STATUS_AVAILABLE: |
1223 | switch (new_fsf_req->qtcb->header.fsf_status_qual.word[0]) { | 953 | switch (fsq->word[0]) { |
1224 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 954 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
1225 | zfcp_test_link(unit->port); | 955 | zfcp_test_link(unit->port); |
1226 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1227 | break; | ||
1228 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 956 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
1229 | /* SCSI stack will escalate */ | 957 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1230 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1231 | break; | ||
1232 | default: | ||
1233 | ZFCP_LOG_NORMAL | ||
1234 | ("bug: Wrong status qualifier 0x%x arrived.\n", | ||
1235 | new_fsf_req->qtcb->header.fsf_status_qual.word[0]); | ||
1236 | break; | 958 | break; |
1237 | } | 959 | } |
1238 | break; | 960 | break; |
1239 | |||
1240 | case FSF_GOOD: | 961 | case FSF_GOOD: |
1241 | retval = 0; | 962 | req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED; |
1242 | new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED; | ||
1243 | break; | ||
1244 | |||
1245 | default: | ||
1246 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
1247 | "(debug info 0x%x)\n", | ||
1248 | new_fsf_req->qtcb->header.fsf_status); | ||
1249 | break; | 963 | break; |
1250 | } | 964 | } |
1251 | skip_fsfstatus: | ||
1252 | return retval; | ||
1253 | } | 965 | } |
1254 | 966 | ||
1255 | /** | 967 | /** |
1256 | * zfcp_use_one_sbal - checks whether req buffer and resp bother each fit into | 968 | * zfcp_fsf_abort_fcp_command - abort running SCSI command |
1257 | * one SBALE | 969 | * @old_req_id: unsigned long |
1258 | * Two scatter-gather lists are passed, one for the reqeust and one for the | 970 | * @adapter: pointer to struct zfcp_adapter |
1259 | * response. | 971 | * @unit: pointer to struct zfcp_unit |
972 | * @req_flags: integer specifying the request flags | ||
973 | * Returns: pointer to struct zfcp_fsf_req | ||
974 | * | ||
975 | * FIXME(design): should be watched by a timeout !!! | ||
1260 | */ | 976 | */ |
1261 | static inline int | ||
1262 | zfcp_use_one_sbal(struct scatterlist *req, int req_count, | ||
1263 | struct scatterlist *resp, int resp_count) | ||
1264 | { | ||
1265 | return ((req_count == 1) && | ||
1266 | (resp_count == 1) && | ||
1267 | (((unsigned long) zfcp_sg_to_address(&req[0]) & | ||
1268 | PAGE_MASK) == | ||
1269 | ((unsigned long) (zfcp_sg_to_address(&req[0]) + | ||
1270 | req[0].length - 1) & PAGE_MASK)) && | ||
1271 | (((unsigned long) zfcp_sg_to_address(&resp[0]) & | ||
1272 | PAGE_MASK) == | ||
1273 | ((unsigned long) (zfcp_sg_to_address(&resp[0]) + | ||
1274 | resp[0].length - 1) & PAGE_MASK))); | ||
1275 | } | ||
1276 | 977 | ||
1277 | /** | 978 | struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, |
1278 | * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS) | 979 | struct zfcp_adapter *adapter, |
1279 | * @ct: pointer to struct zfcp_send_ct which conatins all needed data for | 980 | struct zfcp_unit *unit, |
1280 | * the request | 981 | int req_flags) |
1281 | * @pool: pointer to memory pool, if non-null this pool is used to allocate | ||
1282 | * a struct zfcp_fsf_req | ||
1283 | * @erp_action: pointer to erp_action, if non-null the Generic Service request | ||
1284 | * is sent within error recovery | ||
1285 | */ | ||
1286 | int | ||
1287 | zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, | ||
1288 | struct zfcp_erp_action *erp_action) | ||
1289 | { | 982 | { |
1290 | volatile struct qdio_buffer_element *sbale; | 983 | volatile struct qdio_buffer_element *sbale; |
1291 | struct zfcp_port *port; | 984 | struct zfcp_fsf_req *req = NULL; |
1292 | struct zfcp_adapter *adapter; | ||
1293 | struct zfcp_fsf_req *fsf_req; | ||
1294 | unsigned long lock_flags; | ||
1295 | int bytes; | ||
1296 | int ret = 0; | ||
1297 | |||
1298 | port = ct->port; | ||
1299 | adapter = port->adapter; | ||
1300 | |||
1301 | ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC, | ||
1302 | ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | ||
1303 | pool, &lock_flags, &fsf_req); | ||
1304 | if (ret < 0) { | ||
1305 | ZFCP_LOG_INFO("error: Could not create CT request (FC-GS) for " | ||
1306 | "adapter: %s\n", | ||
1307 | zfcp_get_busid_by_adapter(adapter)); | ||
1308 | goto failed_req; | ||
1309 | } | ||
1310 | 985 | ||
1311 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 986 | spin_lock(&adapter->req_q.lock); |
1312 | if (zfcp_use_one_sbal(ct->req, ct->req_count, | 987 | if (!atomic_read(&adapter->req_q.count)) |
1313 | ct->resp, ct->resp_count)){ | 988 | goto out; |
1314 | /* both request buffer and response buffer | 989 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, |
1315 | fit into one sbale each */ | 990 | req_flags, adapter->pool.fsf_req_abort); |
1316 | sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; | 991 | if (unlikely(IS_ERR(req))) |
1317 | sbale[2].addr = zfcp_sg_to_address(&ct->req[0]); | 992 | goto out; |
1318 | sbale[2].length = ct->req[0].length; | ||
1319 | sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]); | ||
1320 | sbale[3].length = ct->resp[0].length; | ||
1321 | sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
1322 | } else if (adapter->adapter_features & | ||
1323 | FSF_FEATURE_ELS_CT_CHAINED_SBALS) { | ||
1324 | /* try to use chained SBALs */ | ||
1325 | bytes = zfcp_qdio_sbals_from_sg(fsf_req, | ||
1326 | SBAL_FLAGS0_TYPE_WRITE_READ, | ||
1327 | ct->req, ct->req_count, | ||
1328 | ZFCP_MAX_SBALS_PER_CT_REQ); | ||
1329 | if (bytes <= 0) { | ||
1330 | ZFCP_LOG_INFO("error: creation of CT request failed " | ||
1331 | "on adapter %s\n", | ||
1332 | zfcp_get_busid_by_adapter(adapter)); | ||
1333 | if (bytes == 0) | ||
1334 | ret = -ENOMEM; | ||
1335 | else | ||
1336 | ret = bytes; | ||
1337 | |||
1338 | goto failed_send; | ||
1339 | } | ||
1340 | fsf_req->qtcb->bottom.support.req_buf_length = bytes; | ||
1341 | fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; | ||
1342 | bytes = zfcp_qdio_sbals_from_sg(fsf_req, | ||
1343 | SBAL_FLAGS0_TYPE_WRITE_READ, | ||
1344 | ct->resp, ct->resp_count, | ||
1345 | ZFCP_MAX_SBALS_PER_CT_REQ); | ||
1346 | if (bytes <= 0) { | ||
1347 | ZFCP_LOG_INFO("error: creation of CT request failed " | ||
1348 | "on adapter %s\n", | ||
1349 | zfcp_get_busid_by_adapter(adapter)); | ||
1350 | if (bytes == 0) | ||
1351 | ret = -ENOMEM; | ||
1352 | else | ||
1353 | ret = bytes; | ||
1354 | |||
1355 | goto failed_send; | ||
1356 | } | ||
1357 | fsf_req->qtcb->bottom.support.resp_buf_length = bytes; | ||
1358 | } else { | ||
1359 | /* reject send generic request */ | ||
1360 | ZFCP_LOG_INFO( | ||
1361 | "error: microcode does not support chained SBALs," | ||
1362 | "CT request too big (adapter %s)\n", | ||
1363 | zfcp_get_busid_by_adapter(adapter)); | ||
1364 | ret = -EOPNOTSUPP; | ||
1365 | goto failed_send; | ||
1366 | } | ||
1367 | |||
1368 | /* settings in QTCB */ | ||
1369 | fsf_req->qtcb->header.port_handle = port->handle; | ||
1370 | fsf_req->qtcb->bottom.support.service_class = | ||
1371 | ZFCP_FC_SERVICE_CLASS_DEFAULT; | ||
1372 | fsf_req->qtcb->bottom.support.timeout = ct->timeout; | ||
1373 | fsf_req->data = (unsigned long) ct; | ||
1374 | |||
1375 | zfcp_san_dbf_event_ct_request(fsf_req); | ||
1376 | 993 | ||
1377 | if (erp_action) { | 994 | if (unlikely(!(atomic_read(&unit->status) & |
1378 | erp_action->fsf_req = fsf_req; | 995 | ZFCP_STATUS_COMMON_UNBLOCKED))) |
1379 | fsf_req->erp_action = erp_action; | 996 | goto out_error_free; |
1380 | zfcp_erp_start_timer(fsf_req); | ||
1381 | } else | ||
1382 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | ||
1383 | 997 | ||
1384 | ret = zfcp_fsf_req_send(fsf_req); | 998 | sbale = zfcp_qdio_sbale_req(req); |
1385 | if (ret) { | 999 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
1386 | ZFCP_LOG_DEBUG("error: initiation of CT request failed " | 1000 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
1387 | "(adapter %s, port 0x%016Lx)\n", | ||
1388 | zfcp_get_busid_by_adapter(adapter), port->wwpn); | ||
1389 | goto failed_send; | ||
1390 | } | ||
1391 | 1001 | ||
1392 | ZFCP_LOG_DEBUG("CT request initiated (adapter %s, port 0x%016Lx)\n", | 1002 | req->data = unit; |
1393 | zfcp_get_busid_by_adapter(adapter), port->wwpn); | 1003 | req->handler = zfcp_fsf_abort_fcp_command_handler; |
1394 | goto out; | 1004 | req->qtcb->header.lun_handle = unit->handle; |
1005 | req->qtcb->header.port_handle = unit->port->handle; | ||
1006 | req->qtcb->bottom.support.req_handle = (u64) old_req_id; | ||
1395 | 1007 | ||
1396 | failed_send: | 1008 | zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); |
1397 | zfcp_fsf_req_free(fsf_req); | 1009 | if (!zfcp_fsf_req_send(req)) |
1398 | if (erp_action != NULL) { | 1010 | goto out; |
1399 | erp_action->fsf_req = NULL; | 1011 | |
1400 | } | 1012 | out_error_free: |
1401 | failed_req: | 1013 | zfcp_fsf_req_free(req); |
1402 | out: | 1014 | req = NULL; |
1403 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 1015 | out: |
1404 | lock_flags); | 1016 | spin_unlock(&adapter->req_q.lock); |
1405 | return ret; | 1017 | return req; |
1406 | } | 1018 | } |
1407 | 1019 | ||
1408 | /** | 1020 | static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) |
1409 | * zfcp_fsf_send_ct_handler - handler for Generic Service requests | ||
1410 | * @fsf_req: pointer to struct zfcp_fsf_req | ||
1411 | * | ||
1412 | * Data specific for the Generic Service request is passed using | ||
1413 | * fsf_req->data. There we find the pointer to struct zfcp_send_ct. | ||
1414 | * Usually a specific handler for the CT request is called which is | ||
1415 | * found in this structure. | ||
1416 | */ | ||
1417 | static int | ||
1418 | zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) | ||
1419 | { | 1021 | { |
1420 | struct zfcp_port *port; | 1022 | struct zfcp_adapter *adapter = req->adapter; |
1421 | struct zfcp_adapter *adapter; | 1023 | struct zfcp_send_ct *send_ct = req->data; |
1422 | struct zfcp_send_ct *send_ct; | 1024 | struct zfcp_port *port = send_ct->port; |
1423 | struct fsf_qtcb_header *header; | 1025 | struct fsf_qtcb_header *header = &req->qtcb->header; |
1424 | struct fsf_qtcb_bottom_support *bottom; | ||
1425 | int retval = -EINVAL; | ||
1426 | u16 subtable, rule, counter; | ||
1427 | 1026 | ||
1428 | adapter = fsf_req->adapter; | 1027 | send_ct->status = -EINVAL; |
1429 | send_ct = (struct zfcp_send_ct *) fsf_req->data; | ||
1430 | port = send_ct->port; | ||
1431 | header = &fsf_req->qtcb->header; | ||
1432 | bottom = &fsf_req->qtcb->bottom.support; | ||
1433 | 1028 | ||
1434 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) | 1029 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
1435 | goto skip_fsfstatus; | 1030 | goto skip_fsfstatus; |
1436 | 1031 | ||
1437 | /* evaluate FSF status in QTCB */ | ||
1438 | switch (header->fsf_status) { | 1032 | switch (header->fsf_status) { |
1439 | |||
1440 | case FSF_GOOD: | 1033 | case FSF_GOOD: |
1441 | zfcp_san_dbf_event_ct_response(fsf_req); | 1034 | zfcp_san_dbf_event_ct_response(req); |
1442 | retval = 0; | 1035 | send_ct->status = 0; |
1443 | break; | 1036 | break; |
1444 | |||
1445 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: | 1037 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: |
1446 | ZFCP_LOG_INFO("error: adapter %s does not support fc " | 1038 | zfcp_fsf_class_not_supp(req); |
1447 | "class %d.\n", | ||
1448 | zfcp_get_busid_by_port(port), | ||
1449 | ZFCP_FC_SERVICE_CLASS_DEFAULT); | ||
1450 | /* stop operation for this adapter */ | ||
1451 | zfcp_erp_adapter_shutdown(adapter, 0, 123, fsf_req); | ||
1452 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1453 | break; | 1039 | break; |
1454 | |||
1455 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1040 | case FSF_ADAPTER_STATUS_AVAILABLE: |
1456 | switch (header->fsf_status_qual.word[0]){ | 1041 | switch (header->fsf_status_qual.word[0]){ |
1457 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 1042 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
1458 | /* reopening link to port */ | ||
1459 | zfcp_test_link(port); | 1043 | zfcp_test_link(port); |
1460 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1461 | break; | ||
1462 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1044 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
1463 | /* ERP strategy will escalate */ | 1045 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1464 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1465 | break; | ||
1466 | default: | ||
1467 | ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x " | ||
1468 | "arrived.\n", | ||
1469 | header->fsf_status_qual.word[0]); | ||
1470 | break; | 1046 | break; |
1471 | } | 1047 | } |
1472 | break; | 1048 | break; |
1473 | |||
1474 | case FSF_ACCESS_DENIED: | 1049 | case FSF_ACCESS_DENIED: |
1475 | ZFCP_LOG_NORMAL("access denied, cannot send generic service " | 1050 | zfcp_fsf_access_denied_port(req, port); |
1476 | "command (adapter %s, port d_id=0x%06x)\n", | ||
1477 | zfcp_get_busid_by_port(port), port->d_id); | ||
1478 | for (counter = 0; counter < 2; counter++) { | ||
1479 | subtable = header->fsf_status_qual.halfword[counter * 2]; | ||
1480 | rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | ||
1481 | switch (subtable) { | ||
1482 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
1483 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
1484 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
1485 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
1486 | ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | ||
1487 | zfcp_act_subtable_type[subtable], rule); | ||
1488 | break; | ||
1489 | } | ||
1490 | } | ||
1491 | zfcp_erp_port_access_denied(port, 55, fsf_req); | ||
1492 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1493 | break; | ||
1494 | |||
1495 | case FSF_GENERIC_COMMAND_REJECTED: | ||
1496 | ZFCP_LOG_INFO("generic service command rejected " | ||
1497 | "(adapter %s, port d_id=0x%06x)\n", | ||
1498 | zfcp_get_busid_by_port(port), port->d_id); | ||
1499 | ZFCP_LOG_INFO("status qualifier:\n"); | ||
1500 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, | ||
1501 | (char *) &header->fsf_status_qual, | ||
1502 | sizeof (union fsf_status_qual)); | ||
1503 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1504 | break; | ||
1505 | |||
1506 | case FSF_PORT_HANDLE_NOT_VALID: | ||
1507 | ZFCP_LOG_DEBUG("Temporary port identifier 0x%x for port " | ||
1508 | "0x%016Lx on adapter %s invalid. This may " | ||
1509 | "happen occasionally.\n", port->handle, | ||
1510 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
1511 | ZFCP_LOG_INFO("status qualifier:\n"); | ||
1512 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, | ||
1513 | (char *) &header->fsf_status_qual, | ||
1514 | sizeof (union fsf_status_qual)); | ||
1515 | zfcp_erp_adapter_reopen(adapter, 0, 106, fsf_req); | ||
1516 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1517 | break; | 1051 | break; |
1518 | |||
1519 | case FSF_PORT_BOXED: | 1052 | case FSF_PORT_BOXED: |
1520 | ZFCP_LOG_INFO("port needs to be reopened " | 1053 | zfcp_erp_port_boxed(port, 49, req); |
1521 | "(adapter %s, port d_id=0x%06x)\n", | 1054 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
1522 | zfcp_get_busid_by_port(port), port->d_id); | 1055 | ZFCP_STATUS_FSFREQ_RETRY; |
1523 | zfcp_erp_port_boxed(port, 49, fsf_req); | ||
1524 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ||
1525 | | ZFCP_STATUS_FSFREQ_RETRY; | ||
1526 | break; | 1056 | break; |
1527 | 1057 | case FSF_PORT_HANDLE_NOT_VALID: | |
1528 | /* following states should never occure, all cases avoided | 1058 | zfcp_erp_adapter_reopen(adapter, 0, 106, req); |
1529 | in zfcp_fsf_send_ct - but who knows ... */ | 1059 | case FSF_GENERIC_COMMAND_REJECTED: |
1530 | case FSF_PAYLOAD_SIZE_MISMATCH: | 1060 | case FSF_PAYLOAD_SIZE_MISMATCH: |
1531 | ZFCP_LOG_INFO("payload size mismatch (adapter: %s, " | ||
1532 | "req_buf_length=%d, resp_buf_length=%d)\n", | ||
1533 | zfcp_get_busid_by_adapter(adapter), | ||
1534 | bottom->req_buf_length, bottom->resp_buf_length); | ||
1535 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1536 | break; | ||
1537 | case FSF_REQUEST_SIZE_TOO_LARGE: | 1061 | case FSF_REQUEST_SIZE_TOO_LARGE: |
1538 | ZFCP_LOG_INFO("request size too large (adapter: %s, " | ||
1539 | "req_buf_length=%d)\n", | ||
1540 | zfcp_get_busid_by_adapter(adapter), | ||
1541 | bottom->req_buf_length); | ||
1542 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1543 | break; | ||
1544 | case FSF_RESPONSE_SIZE_TOO_LARGE: | 1062 | case FSF_RESPONSE_SIZE_TOO_LARGE: |
1545 | ZFCP_LOG_INFO("response size too large (adapter: %s, " | ||
1546 | "resp_buf_length=%d)\n", | ||
1547 | zfcp_get_busid_by_adapter(adapter), | ||
1548 | bottom->resp_buf_length); | ||
1549 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1550 | break; | ||
1551 | case FSF_SBAL_MISMATCH: | 1063 | case FSF_SBAL_MISMATCH: |
1552 | ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, " | 1064 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1553 | "resp_buf_length=%d)\n", | ||
1554 | zfcp_get_busid_by_adapter(adapter), | ||
1555 | bottom->req_buf_length, bottom->resp_buf_length); | ||
1556 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1557 | break; | ||
1558 | |||
1559 | default: | ||
1560 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
1561 | "(debug info 0x%x)\n", header->fsf_status); | ||
1562 | break; | 1065 | break; |
1563 | } | 1066 | } |
1564 | 1067 | ||
1565 | skip_fsfstatus: | 1068 | skip_fsfstatus: |
1566 | send_ct->status = retval; | 1069 | if (send_ct->handler) |
1567 | |||
1568 | if (send_ct->handler != NULL) | ||
1569 | send_ct->handler(send_ct->handler_data); | 1070 | send_ct->handler(send_ct->handler_data); |
1071 | } | ||
1570 | 1072 | ||
1571 | return retval; | 1073 | static int zfcp_fsf_setup_sbals(struct zfcp_fsf_req *req, |
1074 | struct scatterlist *sg_req, | ||
1075 | struct scatterlist *sg_resp, int max_sbals) | ||
1076 | { | ||
1077 | int bytes; | ||
1078 | |||
1079 | bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, | ||
1080 | sg_req, max_sbals); | ||
1081 | if (bytes <= 0) | ||
1082 | return -ENOMEM; | ||
1083 | req->qtcb->bottom.support.req_buf_length = bytes; | ||
1084 | req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; | ||
1085 | |||
1086 | bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, | ||
1087 | sg_resp, max_sbals); | ||
1088 | if (bytes <= 0) | ||
1089 | return -ENOMEM; | ||
1090 | req->qtcb->bottom.support.resp_buf_length = bytes; | ||
1091 | |||
1092 | return 0; | ||
1572 | } | 1093 | } |
1573 | 1094 | ||
1574 | /** | 1095 | /** |
1575 | * zfcp_fsf_send_els - initiate an ELS command (FC-FS) | 1096 | * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS) |
1576 | * @els: pointer to struct zfcp_send_els which contains all needed data for | 1097 | * @ct: pointer to struct zfcp_send_ct with data for request |
1577 | * the command. | 1098 | * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req |
1099 | * @erp_action: if non-null the Generic Service request sent within ERP | ||
1578 | */ | 1100 | */ |
1579 | int | 1101 | int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, |
1580 | zfcp_fsf_send_els(struct zfcp_send_els *els) | 1102 | struct zfcp_erp_action *erp_action) |
1581 | { | 1103 | { |
1582 | volatile struct qdio_buffer_element *sbale; | 1104 | struct zfcp_port *port = ct->port; |
1583 | struct zfcp_fsf_req *fsf_req; | 1105 | struct zfcp_adapter *adapter = port->adapter; |
1584 | u32 d_id; | 1106 | struct zfcp_fsf_req *req; |
1585 | struct zfcp_adapter *adapter; | 1107 | int ret = -EIO; |
1586 | unsigned long lock_flags; | ||
1587 | int bytes; | ||
1588 | int ret = 0; | ||
1589 | |||
1590 | d_id = els->d_id; | ||
1591 | adapter = els->adapter; | ||
1592 | 1108 | ||
1593 | ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, | 1109 | spin_lock(&adapter->req_q.lock); |
1594 | ZFCP_REQ_AUTO_CLEANUP, | 1110 | if (zfcp_fsf_req_sbal_get(adapter)) |
1595 | NULL, &lock_flags, &fsf_req); | 1111 | goto out; |
1596 | if (ret < 0) { | ||
1597 | ZFCP_LOG_INFO("error: creation of ELS request failed " | ||
1598 | "(adapter %s, port d_id: 0x%06x)\n", | ||
1599 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1600 | goto failed_req; | ||
1601 | } | ||
1602 | 1112 | ||
1603 | if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | 1113 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC, |
1604 | &els->port->status))) { | 1114 | ZFCP_REQ_AUTO_CLEANUP, pool); |
1605 | ret = -EBUSY; | 1115 | if (unlikely(IS_ERR(req))) { |
1606 | goto port_blocked; | 1116 | ret = PTR_ERR(req); |
1117 | goto out; | ||
1607 | } | 1118 | } |
1608 | 1119 | ||
1609 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1120 | ret = zfcp_fsf_setup_sbals(req, ct->req, ct->resp, |
1610 | if (zfcp_use_one_sbal(els->req, els->req_count, | 1121 | FSF_MAX_SBALS_PER_REQ); |
1611 | els->resp, els->resp_count)){ | 1122 | if (ret) |
1612 | /* both request buffer and response buffer | ||
1613 | fit into one sbale each */ | ||
1614 | sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; | ||
1615 | sbale[2].addr = zfcp_sg_to_address(&els->req[0]); | ||
1616 | sbale[2].length = els->req[0].length; | ||
1617 | sbale[3].addr = zfcp_sg_to_address(&els->resp[0]); | ||
1618 | sbale[3].length = els->resp[0].length; | ||
1619 | sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
1620 | } else if (adapter->adapter_features & | ||
1621 | FSF_FEATURE_ELS_CT_CHAINED_SBALS) { | ||
1622 | /* try to use chained SBALs */ | ||
1623 | bytes = zfcp_qdio_sbals_from_sg(fsf_req, | ||
1624 | SBAL_FLAGS0_TYPE_WRITE_READ, | ||
1625 | els->req, els->req_count, | ||
1626 | ZFCP_MAX_SBALS_PER_ELS_REQ); | ||
1627 | if (bytes <= 0) { | ||
1628 | ZFCP_LOG_INFO("error: creation of ELS request failed " | ||
1629 | "(adapter %s, port d_id: 0x%06x)\n", | ||
1630 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1631 | if (bytes == 0) { | ||
1632 | ret = -ENOMEM; | ||
1633 | } else { | ||
1634 | ret = bytes; | ||
1635 | } | ||
1636 | goto failed_send; | ||
1637 | } | ||
1638 | fsf_req->qtcb->bottom.support.req_buf_length = bytes; | ||
1639 | fsf_req->sbale_curr = ZFCP_LAST_SBALE_PER_SBAL; | ||
1640 | bytes = zfcp_qdio_sbals_from_sg(fsf_req, | ||
1641 | SBAL_FLAGS0_TYPE_WRITE_READ, | ||
1642 | els->resp, els->resp_count, | ||
1643 | ZFCP_MAX_SBALS_PER_ELS_REQ); | ||
1644 | if (bytes <= 0) { | ||
1645 | ZFCP_LOG_INFO("error: creation of ELS request failed " | ||
1646 | "(adapter %s, port d_id: 0x%06x)\n", | ||
1647 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1648 | if (bytes == 0) { | ||
1649 | ret = -ENOMEM; | ||
1650 | } else { | ||
1651 | ret = bytes; | ||
1652 | } | ||
1653 | goto failed_send; | ||
1654 | } | ||
1655 | fsf_req->qtcb->bottom.support.resp_buf_length = bytes; | ||
1656 | } else { | ||
1657 | /* reject request */ | ||
1658 | ZFCP_LOG_INFO("error: microcode does not support chained SBALs" | ||
1659 | ", ELS request too big (adapter %s, " | ||
1660 | "port d_id: 0x%06x)\n", | ||
1661 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1662 | ret = -EOPNOTSUPP; | ||
1663 | goto failed_send; | ||
1664 | } | ||
1665 | |||
1666 | /* settings in QTCB */ | ||
1667 | fsf_req->qtcb->bottom.support.d_id = d_id; | ||
1668 | fsf_req->qtcb->bottom.support.service_class = | ||
1669 | ZFCP_FC_SERVICE_CLASS_DEFAULT; | ||
1670 | fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT; | ||
1671 | fsf_req->data = (unsigned long) els; | ||
1672 | |||
1673 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | ||
1674 | |||
1675 | zfcp_san_dbf_event_els_request(fsf_req); | ||
1676 | |||
1677 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | ||
1678 | ret = zfcp_fsf_req_send(fsf_req); | ||
1679 | if (ret) { | ||
1680 | ZFCP_LOG_DEBUG("error: initiation of ELS request failed " | ||
1681 | "(adapter %s, port d_id: 0x%06x)\n", | ||
1682 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1683 | goto failed_send; | 1123 | goto failed_send; |
1684 | } | ||
1685 | 1124 | ||
1686 | ZFCP_LOG_DEBUG("ELS request initiated (adapter %s, port d_id: " | 1125 | req->handler = zfcp_fsf_send_ct_handler; |
1687 | "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); | 1126 | req->qtcb->header.port_handle = port->handle; |
1688 | goto out; | 1127 | req->qtcb->bottom.support.service_class = FSF_CLASS_3; |
1128 | req->qtcb->bottom.support.timeout = ct->timeout; | ||
1129 | req->data = ct; | ||
1689 | 1130 | ||
1690 | port_blocked: | 1131 | zfcp_san_dbf_event_ct_request(req); |
1691 | failed_send: | ||
1692 | zfcp_fsf_req_free(fsf_req); | ||
1693 | 1132 | ||
1694 | failed_req: | 1133 | if (erp_action) { |
1695 | out: | 1134 | erp_action->fsf_req = req; |
1696 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 1135 | req->erp_action = erp_action; |
1697 | lock_flags); | 1136 | zfcp_fsf_start_erp_timer(req); |
1137 | } else | ||
1138 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); | ||
1139 | |||
1140 | ret = zfcp_fsf_req_send(req); | ||
1141 | if (ret) | ||
1142 | goto failed_send; | ||
1143 | |||
1144 | goto out; | ||
1698 | 1145 | ||
1699 | return ret; | 1146 | failed_send: |
1147 | zfcp_fsf_req_free(req); | ||
1148 | if (erp_action) | ||
1149 | erp_action->fsf_req = NULL; | ||
1150 | out: | ||
1151 | spin_unlock(&adapter->req_q.lock); | ||
1152 | return ret; | ||
1700 | } | 1153 | } |
1701 | 1154 | ||
1702 | /** | 1155 | static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) |
1703 | * zfcp_fsf_send_els_handler - handler for ELS commands | ||
1704 | * @fsf_req: pointer to struct zfcp_fsf_req | ||
1705 | * | ||
1706 | * Data specific for the ELS command is passed using | ||
1707 | * fsf_req->data. There we find the pointer to struct zfcp_send_els. | ||
1708 | * Usually a specific handler for the ELS command is called which is | ||
1709 | * found in this structure. | ||
1710 | */ | ||
1711 | static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) | ||
1712 | { | 1156 | { |
1713 | struct zfcp_adapter *adapter; | 1157 | struct zfcp_send_els *send_els = req->data; |
1714 | struct zfcp_port *port; | 1158 | struct zfcp_port *port = send_els->port; |
1715 | u32 d_id; | 1159 | struct fsf_qtcb_header *header = &req->qtcb->header; |
1716 | struct fsf_qtcb_header *header; | 1160 | |
1717 | struct fsf_qtcb_bottom_support *bottom; | 1161 | send_els->status = -EINVAL; |
1718 | struct zfcp_send_els *send_els; | 1162 | |
1719 | int retval = -EINVAL; | 1163 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
1720 | u16 subtable, rule, counter; | ||
1721 | |||
1722 | send_els = (struct zfcp_send_els *) fsf_req->data; | ||
1723 | adapter = send_els->adapter; | ||
1724 | port = send_els->port; | ||
1725 | d_id = send_els->d_id; | ||
1726 | header = &fsf_req->qtcb->header; | ||
1727 | bottom = &fsf_req->qtcb->bottom.support; | ||
1728 | |||
1729 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) | ||
1730 | goto skip_fsfstatus; | 1164 | goto skip_fsfstatus; |
1731 | 1165 | ||
1732 | switch (header->fsf_status) { | 1166 | switch (header->fsf_status) { |
1733 | |||
1734 | case FSF_GOOD: | 1167 | case FSF_GOOD: |
1735 | zfcp_san_dbf_event_els_response(fsf_req); | 1168 | zfcp_san_dbf_event_els_response(req); |
1736 | retval = 0; | 1169 | send_els->status = 0; |
1737 | break; | 1170 | break; |
1738 | |||
1739 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: | 1171 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: |
1740 | ZFCP_LOG_INFO("error: adapter %s does not support fc " | 1172 | zfcp_fsf_class_not_supp(req); |
1741 | "class %d.\n", | ||
1742 | zfcp_get_busid_by_adapter(adapter), | ||
1743 | ZFCP_FC_SERVICE_CLASS_DEFAULT); | ||
1744 | /* stop operation for this adapter */ | ||
1745 | zfcp_erp_adapter_shutdown(adapter, 0, 124, fsf_req); | ||
1746 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1747 | break; | 1173 | break; |
1748 | |||
1749 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1174 | case FSF_ADAPTER_STATUS_AVAILABLE: |
1750 | switch (header->fsf_status_qual.word[0]){ | 1175 | switch (header->fsf_status_qual.word[0]){ |
1751 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 1176 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
1752 | if (port && (send_els->ls_code != ZFCP_LS_ADISC)) | 1177 | if (port && (send_els->ls_code != ZFCP_LS_ADISC)) |
1753 | zfcp_test_link(port); | 1178 | zfcp_test_link(port); |
1754 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1179 | /*fall through */ |
1755 | break; | ||
1756 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1180 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
1757 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1758 | retval = | ||
1759 | zfcp_handle_els_rjt(header->fsf_status_qual.word[1], | ||
1760 | (struct zfcp_ls_rjt_par *) | ||
1761 | &header->fsf_status_qual.word[2]); | ||
1762 | break; | ||
1763 | case FSF_SQ_RETRY_IF_POSSIBLE: | 1181 | case FSF_SQ_RETRY_IF_POSSIBLE: |
1764 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1182 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1765 | break; | 1183 | break; |
1766 | default: | ||
1767 | ZFCP_LOG_INFO("bug: Wrong status qualifier 0x%x\n", | ||
1768 | header->fsf_status_qual.word[0]); | ||
1769 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, | ||
1770 | (char*)header->fsf_status_qual.word, 16); | ||
1771 | } | 1184 | } |
1772 | break; | 1185 | break; |
1773 | |||
1774 | case FSF_ELS_COMMAND_REJECTED: | 1186 | case FSF_ELS_COMMAND_REJECTED: |
1775 | ZFCP_LOG_INFO("ELS has been rejected because command filter " | ||
1776 | "prohibited sending " | ||
1777 | "(adapter: %s, port d_id: 0x%06x)\n", | ||
1778 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1779 | |||
1780 | break; | ||
1781 | |||
1782 | case FSF_PAYLOAD_SIZE_MISMATCH: | 1187 | case FSF_PAYLOAD_SIZE_MISMATCH: |
1783 | ZFCP_LOG_INFO( | ||
1784 | "ELS request size and ELS response size must be either " | ||
1785 | "both 0, or both greater than 0 " | ||
1786 | "(adapter: %s, req_buf_length=%d resp_buf_length=%d)\n", | ||
1787 | zfcp_get_busid_by_adapter(adapter), | ||
1788 | bottom->req_buf_length, | ||
1789 | bottom->resp_buf_length); | ||
1790 | break; | ||
1791 | |||
1792 | case FSF_REQUEST_SIZE_TOO_LARGE: | 1188 | case FSF_REQUEST_SIZE_TOO_LARGE: |
1793 | ZFCP_LOG_INFO( | ||
1794 | "Length of the ELS request buffer, " | ||
1795 | "specified in QTCB bottom, " | ||
1796 | "exceeds the size of the buffers " | ||
1797 | "that have been allocated for ELS request data " | ||
1798 | "(adapter: %s, req_buf_length=%d)\n", | ||
1799 | zfcp_get_busid_by_adapter(adapter), | ||
1800 | bottom->req_buf_length); | ||
1801 | break; | ||
1802 | |||
1803 | case FSF_RESPONSE_SIZE_TOO_LARGE: | 1189 | case FSF_RESPONSE_SIZE_TOO_LARGE: |
1804 | ZFCP_LOG_INFO( | ||
1805 | "Length of the ELS response buffer, " | ||
1806 | "specified in QTCB bottom, " | ||
1807 | "exceeds the size of the buffers " | ||
1808 | "that have been allocated for ELS response data " | ||
1809 | "(adapter: %s, resp_buf_length=%d)\n", | ||
1810 | zfcp_get_busid_by_adapter(adapter), | ||
1811 | bottom->resp_buf_length); | ||
1812 | break; | ||
1813 | |||
1814 | case FSF_SBAL_MISMATCH: | ||
1815 | /* should never occure, avoided in zfcp_fsf_send_els */ | ||
1816 | ZFCP_LOG_INFO("SBAL mismatch (adapter: %s, req_buf_length=%d, " | ||
1817 | "resp_buf_length=%d)\n", | ||
1818 | zfcp_get_busid_by_adapter(adapter), | ||
1819 | bottom->req_buf_length, bottom->resp_buf_length); | ||
1820 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1821 | break; | 1190 | break; |
1822 | |||
1823 | case FSF_ACCESS_DENIED: | 1191 | case FSF_ACCESS_DENIED: |
1824 | ZFCP_LOG_NORMAL("access denied, cannot send ELS command " | 1192 | zfcp_fsf_access_denied_port(req, port); |
1825 | "(adapter %s, port d_id=0x%06x)\n", | ||
1826 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
1827 | for (counter = 0; counter < 2; counter++) { | ||
1828 | subtable = header->fsf_status_qual.halfword[counter * 2]; | ||
1829 | rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | ||
1830 | switch (subtable) { | ||
1831 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
1832 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
1833 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
1834 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
1835 | ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | ||
1836 | zfcp_act_subtable_type[subtable], rule); | ||
1837 | break; | ||
1838 | } | ||
1839 | } | ||
1840 | if (port != NULL) | ||
1841 | zfcp_erp_port_access_denied(port, 56, fsf_req); | ||
1842 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1843 | break; | 1193 | break; |
1844 | 1194 | case FSF_SBAL_MISMATCH: | |
1195 | /* should never occure, avoided in zfcp_fsf_send_els */ | ||
1196 | /* fall through */ | ||
1845 | default: | 1197 | default: |
1846 | ZFCP_LOG_NORMAL( | 1198 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1847 | "bug: An unknown FSF Status was presented " | ||
1848 | "(adapter: %s, fsf_status=0x%08x)\n", | ||
1849 | zfcp_get_busid_by_adapter(adapter), | ||
1850 | header->fsf_status); | ||
1851 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1852 | break; | 1199 | break; |
1853 | } | 1200 | } |
1854 | |||
1855 | skip_fsfstatus: | 1201 | skip_fsfstatus: |
1856 | send_els->status = retval; | ||
1857 | |||
1858 | if (send_els->handler) | 1202 | if (send_els->handler) |
1859 | send_els->handler(send_els->handler_data); | 1203 | send_els->handler(send_els->handler_data); |
1204 | } | ||
1860 | 1205 | ||
1861 | return retval; | 1206 | /** |
1207 | * zfcp_fsf_send_els - initiate an ELS command (FC-FS) | ||
1208 | * @els: pointer to struct zfcp_send_els with data for the command | ||
1209 | */ | ||
1210 | int zfcp_fsf_send_els(struct zfcp_send_els *els) | ||
1211 | { | ||
1212 | struct zfcp_fsf_req *req; | ||
1213 | struct zfcp_adapter *adapter = els->adapter; | ||
1214 | struct fsf_qtcb_bottom_support *bottom; | ||
1215 | int ret = -EIO; | ||
1216 | |||
1217 | if (unlikely(!(atomic_read(&els->port->status) & | ||
1218 | ZFCP_STATUS_COMMON_UNBLOCKED))) | ||
1219 | return -EBUSY; | ||
1220 | |||
1221 | spin_lock(&adapter->req_q.lock); | ||
1222 | if (!atomic_read(&adapter->req_q.count)) | ||
1223 | goto out; | ||
1224 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, | ||
1225 | ZFCP_REQ_AUTO_CLEANUP, NULL); | ||
1226 | if (unlikely(IS_ERR(req))) { | ||
1227 | ret = PTR_ERR(req); | ||
1228 | goto out; | ||
1229 | } | ||
1230 | |||
1231 | ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, | ||
1232 | FSF_MAX_SBALS_PER_ELS_REQ); | ||
1233 | if (ret) | ||
1234 | goto failed_send; | ||
1235 | |||
1236 | bottom = &req->qtcb->bottom.support; | ||
1237 | req->handler = zfcp_fsf_send_els_handler; | ||
1238 | bottom->d_id = els->d_id; | ||
1239 | bottom->service_class = FSF_CLASS_3; | ||
1240 | bottom->timeout = 2 * R_A_TOV; | ||
1241 | req->data = els; | ||
1242 | |||
1243 | zfcp_san_dbf_event_els_request(req); | ||
1244 | |||
1245 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); | ||
1246 | ret = zfcp_fsf_req_send(req); | ||
1247 | if (ret) | ||
1248 | goto failed_send; | ||
1249 | |||
1250 | goto out; | ||
1251 | |||
1252 | failed_send: | ||
1253 | zfcp_fsf_req_free(req); | ||
1254 | out: | ||
1255 | spin_unlock(&adapter->req_q.lock); | ||
1256 | return ret; | ||
1862 | } | 1257 | } |
1863 | 1258 | ||
1864 | int | 1259 | int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) |
1865 | zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) | ||
1866 | { | 1260 | { |
1867 | volatile struct qdio_buffer_element *sbale; | 1261 | volatile struct qdio_buffer_element *sbale; |
1868 | struct zfcp_fsf_req *fsf_req; | 1262 | struct zfcp_fsf_req *req; |
1869 | struct zfcp_adapter *adapter = erp_action->adapter; | 1263 | struct zfcp_adapter *adapter = erp_action->adapter; |
1870 | unsigned long lock_flags; | 1264 | int retval = -EIO; |
1871 | int retval; | 1265 | |
1872 | 1266 | spin_lock(&adapter->req_q.lock); | |
1873 | /* setup new FSF request */ | 1267 | if (!atomic_read(&adapter->req_q.count)) |
1874 | retval = zfcp_fsf_req_create(adapter, | 1268 | goto out; |
1875 | FSF_QTCB_EXCHANGE_CONFIG_DATA, | 1269 | req = zfcp_fsf_req_create(adapter, |
1876 | ZFCP_REQ_AUTO_CLEANUP, | 1270 | FSF_QTCB_EXCHANGE_CONFIG_DATA, |
1877 | adapter->pool.fsf_req_erp, | 1271 | ZFCP_REQ_AUTO_CLEANUP, |
1878 | &lock_flags, &fsf_req); | 1272 | adapter->pool.fsf_req_erp); |
1879 | if (retval) { | 1273 | if (unlikely(IS_ERR(req))) { |
1880 | ZFCP_LOG_INFO("error: Could not create exchange configuration " | 1274 | retval = PTR_ERR(req); |
1881 | "data request for adapter %s.\n", | 1275 | goto out; |
1882 | zfcp_get_busid_by_adapter(adapter)); | ||
1883 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | ||
1884 | lock_flags); | ||
1885 | return retval; | ||
1886 | } | 1276 | } |
1887 | 1277 | ||
1888 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1278 | sbale = zfcp_qdio_sbale_req(req); |
1889 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1279 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
1890 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1280 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
1891 | 1281 | ||
1892 | fsf_req->qtcb->bottom.config.feature_selection = | 1282 | req->qtcb->bottom.config.feature_selection = |
1893 | FSF_FEATURE_CFDC | | 1283 | FSF_FEATURE_CFDC | |
1894 | FSF_FEATURE_LUN_SHARING | | 1284 | FSF_FEATURE_LUN_SHARING | |
1895 | FSF_FEATURE_NOTIFICATION_LOST | | 1285 | FSF_FEATURE_NOTIFICATION_LOST | |
1896 | FSF_FEATURE_UPDATE_ALERT; | 1286 | FSF_FEATURE_UPDATE_ALERT; |
1897 | fsf_req->erp_action = erp_action; | 1287 | req->erp_action = erp_action; |
1898 | erp_action->fsf_req = fsf_req; | 1288 | req->handler = zfcp_fsf_exchange_config_data_handler; |
1289 | erp_action->fsf_req = req; | ||
1899 | 1290 | ||
1900 | zfcp_erp_start_timer(fsf_req); | 1291 | zfcp_fsf_start_erp_timer(req); |
1901 | retval = zfcp_fsf_req_send(fsf_req); | 1292 | retval = zfcp_fsf_req_send(req); |
1902 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | ||
1903 | lock_flags); | ||
1904 | if (retval) { | 1293 | if (retval) { |
1905 | ZFCP_LOG_INFO("error: Could not send exchange configuration " | 1294 | zfcp_fsf_req_free(req); |
1906 | "data command on the adapter %s\n", | ||
1907 | zfcp_get_busid_by_adapter(adapter)); | ||
1908 | zfcp_fsf_req_free(fsf_req); | ||
1909 | erp_action->fsf_req = NULL; | 1295 | erp_action->fsf_req = NULL; |
1910 | } | 1296 | } |
1911 | else | 1297 | out: |
1912 | ZFCP_LOG_DEBUG("exchange configuration data request initiated " | 1298 | spin_unlock(&adapter->req_q.lock); |
1913 | "(adapter %s)\n", | ||
1914 | zfcp_get_busid_by_adapter(adapter)); | ||
1915 | |||
1916 | return retval; | 1299 | return retval; |
1917 | } | 1300 | } |
1918 | 1301 | ||
1919 | int | 1302 | int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, |
1920 | zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, | 1303 | struct fsf_qtcb_bottom_config *data) |
1921 | struct fsf_qtcb_bottom_config *data) | ||
1922 | { | 1304 | { |
1923 | volatile struct qdio_buffer_element *sbale; | 1305 | volatile struct qdio_buffer_element *sbale; |
1924 | struct zfcp_fsf_req *fsf_req; | 1306 | struct zfcp_fsf_req *req = NULL; |
1925 | unsigned long lock_flags; | 1307 | int retval = -EIO; |
1926 | int retval; | 1308 | |
1927 | 1309 | spin_lock(&adapter->req_q.lock); | |
1928 | /* setup new FSF request */ | 1310 | if (zfcp_fsf_req_sbal_get(adapter)) |
1929 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, | 1311 | goto out; |
1930 | ZFCP_WAIT_FOR_SBAL, NULL, &lock_flags, | 1312 | |
1931 | &fsf_req); | 1313 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, |
1932 | if (retval) { | 1314 | 0, NULL); |
1933 | ZFCP_LOG_INFO("error: Could not create exchange configuration " | 1315 | if (unlikely(IS_ERR(req))) { |
1934 | "data request for adapter %s.\n", | 1316 | retval = PTR_ERR(req); |
1935 | zfcp_get_busid_by_adapter(adapter)); | 1317 | goto out; |
1936 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | ||
1937 | lock_flags); | ||
1938 | return retval; | ||
1939 | } | 1318 | } |
1940 | 1319 | ||
1941 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1320 | sbale = zfcp_qdio_sbale_req(req); |
1942 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1321 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
1943 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1322 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
1323 | req->handler = zfcp_fsf_exchange_config_data_handler; | ||
1944 | 1324 | ||
1945 | fsf_req->qtcb->bottom.config.feature_selection = | 1325 | req->qtcb->bottom.config.feature_selection = |
1946 | FSF_FEATURE_CFDC | | 1326 | FSF_FEATURE_CFDC | |
1947 | FSF_FEATURE_LUN_SHARING | | 1327 | FSF_FEATURE_LUN_SHARING | |
1948 | FSF_FEATURE_NOTIFICATION_LOST | | 1328 | FSF_FEATURE_NOTIFICATION_LOST | |
1949 | FSF_FEATURE_UPDATE_ALERT; | 1329 | FSF_FEATURE_UPDATE_ALERT; |
1950 | 1330 | ||
1951 | if (data) | 1331 | if (data) |
1952 | fsf_req->data = (unsigned long) data; | 1332 | req->data = data; |
1953 | 1333 | ||
1954 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 1334 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); |
1955 | retval = zfcp_fsf_req_send(fsf_req); | 1335 | retval = zfcp_fsf_req_send(req); |
1956 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 1336 | out: |
1957 | lock_flags); | 1337 | spin_unlock(&adapter->req_q.lock); |
1958 | if (retval) | 1338 | if (!retval) |
1959 | ZFCP_LOG_INFO("error: Could not send exchange configuration " | 1339 | wait_event(req->completion_wq, |
1960 | "data command on the adapter %s\n", | 1340 | req->status & ZFCP_STATUS_FSFREQ_COMPLETED); |
1961 | zfcp_get_busid_by_adapter(adapter)); | ||
1962 | else | ||
1963 | wait_event(fsf_req->completion_wq, | ||
1964 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | ||
1965 | 1341 | ||
1966 | zfcp_fsf_req_free(fsf_req); | 1342 | zfcp_fsf_req_free(req); |
1967 | 1343 | ||
1968 | return retval; | 1344 | return retval; |
1969 | } | 1345 | } |
1970 | 1346 | ||
1971 | /** | 1347 | /** |
1972 | * zfcp_fsf_exchange_config_evaluate | ||
1973 | * @fsf_req: fsf_req which belongs to xchg config data request | ||
1974 | * @xchg_ok: specifies if xchg config data was incomplete or complete (0/1) | ||
1975 | * | ||
1976 | * returns: -EIO on error, 0 otherwise | ||
1977 | */ | ||
1978 | static int | ||
1979 | zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) | ||
1980 | { | ||
1981 | struct fsf_qtcb_bottom_config *bottom; | ||
1982 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
1983 | struct Scsi_Host *shost = adapter->scsi_host; | ||
1984 | |||
1985 | bottom = &fsf_req->qtcb->bottom.config; | ||
1986 | ZFCP_LOG_DEBUG("low/high QTCB version 0x%x/0x%x of FSF\n", | ||
1987 | bottom->low_qtcb_version, bottom->high_qtcb_version); | ||
1988 | adapter->fsf_lic_version = bottom->lic_version; | ||
1989 | adapter->adapter_features = bottom->adapter_features; | ||
1990 | adapter->connection_features = bottom->connection_features; | ||
1991 | adapter->peer_wwpn = 0; | ||
1992 | adapter->peer_wwnn = 0; | ||
1993 | adapter->peer_d_id = 0; | ||
1994 | |||
1995 | if (xchg_ok) { | ||
1996 | |||
1997 | if (fsf_req->data) | ||
1998 | memcpy((struct fsf_qtcb_bottom_config *) fsf_req->data, | ||
1999 | bottom, sizeof (struct fsf_qtcb_bottom_config)); | ||
2000 | |||
2001 | fc_host_node_name(shost) = bottom->nport_serv_param.wwnn; | ||
2002 | fc_host_port_name(shost) = bottom->nport_serv_param.wwpn; | ||
2003 | fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK; | ||
2004 | fc_host_speed(shost) = bottom->fc_link_speed; | ||
2005 | fc_host_supported_classes(shost) = | ||
2006 | FC_COS_CLASS2 | FC_COS_CLASS3; | ||
2007 | adapter->hydra_version = bottom->adapter_type; | ||
2008 | if (fc_host_permanent_port_name(shost) == -1) | ||
2009 | fc_host_permanent_port_name(shost) = | ||
2010 | fc_host_port_name(shost); | ||
2011 | if (bottom->fc_topology == FSF_TOPO_P2P) { | ||
2012 | adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK; | ||
2013 | adapter->peer_wwpn = bottom->plogi_payload.wwpn; | ||
2014 | adapter->peer_wwnn = bottom->plogi_payload.wwnn; | ||
2015 | fc_host_port_type(shost) = FC_PORTTYPE_PTP; | ||
2016 | } else if (bottom->fc_topology == FSF_TOPO_FABRIC) | ||
2017 | fc_host_port_type(shost) = FC_PORTTYPE_NPORT; | ||
2018 | else if (bottom->fc_topology == FSF_TOPO_AL) | ||
2019 | fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; | ||
2020 | else | ||
2021 | fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; | ||
2022 | } else { | ||
2023 | fc_host_node_name(shost) = 0; | ||
2024 | fc_host_port_name(shost) = 0; | ||
2025 | fc_host_port_id(shost) = 0; | ||
2026 | fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; | ||
2027 | fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; | ||
2028 | adapter->hydra_version = 0; | ||
2029 | } | ||
2030 | |||
2031 | if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { | ||
2032 | adapter->hardware_version = bottom->hardware_version; | ||
2033 | memcpy(fc_host_serial_number(shost), bottom->serial_number, | ||
2034 | min(FC_SERIAL_NUMBER_SIZE, 17)); | ||
2035 | EBCASC(fc_host_serial_number(shost), | ||
2036 | min(FC_SERIAL_NUMBER_SIZE, 17)); | ||
2037 | } | ||
2038 | |||
2039 | if (fsf_req->erp_action) | ||
2040 | ZFCP_LOG_NORMAL("The adapter %s reported the following " | ||
2041 | "characteristics:\n" | ||
2042 | "WWNN 0x%016Lx, WWPN 0x%016Lx, " | ||
2043 | "S_ID 0x%06x,\n" | ||
2044 | "adapter version 0x%x, " | ||
2045 | "LIC version 0x%x, " | ||
2046 | "FC link speed %d Gb/s\n", | ||
2047 | zfcp_get_busid_by_adapter(adapter), | ||
2048 | (wwn_t) fc_host_node_name(shost), | ||
2049 | (wwn_t) fc_host_port_name(shost), | ||
2050 | fc_host_port_id(shost), | ||
2051 | adapter->hydra_version, | ||
2052 | adapter->fsf_lic_version, | ||
2053 | fc_host_speed(shost)); | ||
2054 | if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) { | ||
2055 | ZFCP_LOG_NORMAL("error: the adapter %s " | ||
2056 | "only supports newer control block " | ||
2057 | "versions in comparison to this device " | ||
2058 | "driver (try updated device driver)\n", | ||
2059 | zfcp_get_busid_by_adapter(adapter)); | ||
2060 | zfcp_erp_adapter_shutdown(adapter, 0, 125, fsf_req); | ||
2061 | return -EIO; | ||
2062 | } | ||
2063 | if (ZFCP_QTCB_VERSION > bottom->high_qtcb_version) { | ||
2064 | ZFCP_LOG_NORMAL("error: the adapter %s " | ||
2065 | "only supports older control block " | ||
2066 | "versions than this device driver uses" | ||
2067 | "(consider a microcode upgrade)\n", | ||
2068 | zfcp_get_busid_by_adapter(adapter)); | ||
2069 | zfcp_erp_adapter_shutdown(adapter, 0, 126, fsf_req); | ||
2070 | return -EIO; | ||
2071 | } | ||
2072 | return 0; | ||
2073 | } | ||
2074 | |||
2075 | /** | ||
2076 | * function: zfcp_fsf_exchange_config_data_handler | ||
2077 | * | ||
2078 | * purpose: is called for finished Exchange Configuration Data command | ||
2079 | * | ||
2080 | * returns: | ||
2081 | */ | ||
2082 | static int | ||
2083 | zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) | ||
2084 | { | ||
2085 | struct fsf_qtcb_bottom_config *bottom; | ||
2086 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
2087 | struct fsf_qtcb *qtcb = fsf_req->qtcb; | ||
2088 | |||
2089 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) | ||
2090 | return -EIO; | ||
2091 | |||
2092 | switch (qtcb->header.fsf_status) { | ||
2093 | |||
2094 | case FSF_GOOD: | ||
2095 | if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1)) | ||
2096 | return -EIO; | ||
2097 | |||
2098 | switch (fc_host_port_type(adapter->scsi_host)) { | ||
2099 | case FC_PORTTYPE_PTP: | ||
2100 | ZFCP_LOG_NORMAL("Point-to-Point fibrechannel " | ||
2101 | "configuration detected at adapter %s\n" | ||
2102 | "Peer WWNN 0x%016llx, " | ||
2103 | "peer WWPN 0x%016llx, " | ||
2104 | "peer d_id 0x%06x\n", | ||
2105 | zfcp_get_busid_by_adapter(adapter), | ||
2106 | adapter->peer_wwnn, | ||
2107 | adapter->peer_wwpn, | ||
2108 | adapter->peer_d_id); | ||
2109 | break; | ||
2110 | case FC_PORTTYPE_NLPORT: | ||
2111 | ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel " | ||
2112 | "topology detected at adapter %s " | ||
2113 | "unsupported, shutting down adapter\n", | ||
2114 | zfcp_get_busid_by_adapter(adapter)); | ||
2115 | zfcp_erp_adapter_shutdown(adapter, 0, 127, fsf_req); | ||
2116 | return -EIO; | ||
2117 | case FC_PORTTYPE_NPORT: | ||
2118 | if (fsf_req->erp_action) | ||
2119 | ZFCP_LOG_NORMAL("Switched fabric fibrechannel " | ||
2120 | "network detected at adapter " | ||
2121 | "%s.\n", | ||
2122 | zfcp_get_busid_by_adapter(adapter)); | ||
2123 | break; | ||
2124 | default: | ||
2125 | ZFCP_LOG_NORMAL("bug: The fibrechannel topology " | ||
2126 | "reported by the exchange " | ||
2127 | "configuration command for " | ||
2128 | "the adapter %s is not " | ||
2129 | "of a type known to the zfcp " | ||
2130 | "driver, shutting down adapter\n", | ||
2131 | zfcp_get_busid_by_adapter(adapter)); | ||
2132 | zfcp_erp_adapter_shutdown(adapter, 0, 128, fsf_req); | ||
2133 | return -EIO; | ||
2134 | } | ||
2135 | bottom = &qtcb->bottom.config; | ||
2136 | if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) { | ||
2137 | ZFCP_LOG_NORMAL("bug: Maximum QTCB size (%d bytes) " | ||
2138 | "allowed by the adapter %s " | ||
2139 | "is lower than the minimum " | ||
2140 | "required by the driver (%ld bytes).\n", | ||
2141 | bottom->max_qtcb_size, | ||
2142 | zfcp_get_busid_by_adapter(adapter), | ||
2143 | sizeof(struct fsf_qtcb)); | ||
2144 | zfcp_erp_adapter_shutdown(adapter, 0, 129, fsf_req); | ||
2145 | return -EIO; | ||
2146 | } | ||
2147 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | ||
2148 | &adapter->status); | ||
2149 | break; | ||
2150 | case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: | ||
2151 | if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0)) | ||
2152 | return -EIO; | ||
2153 | |||
2154 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | ||
2155 | &adapter->status); | ||
2156 | |||
2157 | zfcp_fsf_link_down_info_eval(fsf_req, 42, | ||
2158 | &qtcb->header.fsf_status_qual.link_down_info); | ||
2159 | break; | ||
2160 | default: | ||
2161 | zfcp_erp_adapter_shutdown(adapter, 0, 130, fsf_req); | ||
2162 | return -EIO; | ||
2163 | } | ||
2164 | return 0; | ||
2165 | } | ||
2166 | |||
2167 | /** | ||
2168 | * zfcp_fsf_exchange_port_data - request information about local port | 1348 | * zfcp_fsf_exchange_port_data - request information about local port |
2169 | * @erp_action: ERP action for the adapter for which port data is requested | 1349 | * @erp_action: ERP action for the adapter for which port data is requested |
1350 | * Returns: 0 on success, error otherwise | ||
2170 | */ | 1351 | */ |
2171 | int | 1352 | int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) |
2172 | zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) | ||
2173 | { | 1353 | { |
2174 | volatile struct qdio_buffer_element *sbale; | 1354 | volatile struct qdio_buffer_element *sbale; |
2175 | struct zfcp_fsf_req *fsf_req; | 1355 | struct zfcp_fsf_req *req; |
2176 | struct zfcp_adapter *adapter = erp_action->adapter; | 1356 | struct zfcp_adapter *adapter = erp_action->adapter; |
2177 | unsigned long lock_flags; | 1357 | int retval = -EIO; |
2178 | int retval; | ||
2179 | 1358 | ||
2180 | if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { | 1359 | if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) |
2181 | ZFCP_LOG_INFO("error: exchange port data " | ||
2182 | "command not supported by adapter %s\n", | ||
2183 | zfcp_get_busid_by_adapter(adapter)); | ||
2184 | return -EOPNOTSUPP; | 1360 | return -EOPNOTSUPP; |
2185 | } | ||
2186 | 1361 | ||
2187 | /* setup new FSF request */ | 1362 | spin_lock(&adapter->req_q.lock); |
2188 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, | 1363 | if (!atomic_read(&adapter->req_q.count)) |
2189 | ZFCP_REQ_AUTO_CLEANUP, | 1364 | goto out; |
2190 | adapter->pool.fsf_req_erp, | 1365 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, |
2191 | &lock_flags, &fsf_req); | 1366 | ZFCP_REQ_AUTO_CLEANUP, |
2192 | if (retval) { | 1367 | adapter->pool.fsf_req_erp); |
2193 | ZFCP_LOG_INFO("error: Out of resources. Could not create an " | 1368 | if (unlikely(IS_ERR(req))) { |
2194 | "exchange port data request for " | 1369 | retval = PTR_ERR(req); |
2195 | "the adapter %s.\n", | 1370 | goto out; |
2196 | zfcp_get_busid_by_adapter(adapter)); | ||
2197 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | ||
2198 | lock_flags); | ||
2199 | return retval; | ||
2200 | } | 1371 | } |
2201 | 1372 | ||
2202 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1373 | sbale = zfcp_qdio_sbale_req(req); |
2203 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1374 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
2204 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1375 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
2205 | 1376 | ||
2206 | erp_action->fsf_req = fsf_req; | 1377 | req->handler = zfcp_fsf_exchange_port_data_handler; |
2207 | fsf_req->erp_action = erp_action; | 1378 | req->erp_action = erp_action; |
2208 | zfcp_erp_start_timer(fsf_req); | 1379 | erp_action->fsf_req = req; |
2209 | |||
2210 | retval = zfcp_fsf_req_send(fsf_req); | ||
2211 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | ||
2212 | 1380 | ||
1381 | zfcp_fsf_start_erp_timer(req); | ||
1382 | retval = zfcp_fsf_req_send(req); | ||
2213 | if (retval) { | 1383 | if (retval) { |
2214 | ZFCP_LOG_INFO("error: Could not send an exchange port data " | 1384 | zfcp_fsf_req_free(req); |
2215 | "command on the adapter %s\n", | ||
2216 | zfcp_get_busid_by_adapter(adapter)); | ||
2217 | zfcp_fsf_req_free(fsf_req); | ||
2218 | erp_action->fsf_req = NULL; | 1385 | erp_action->fsf_req = NULL; |
2219 | } | 1386 | } |
2220 | else | 1387 | out: |
2221 | ZFCP_LOG_DEBUG("exchange port data request initiated " | 1388 | spin_unlock(&adapter->req_q.lock); |
2222 | "(adapter %s)\n", | ||
2223 | zfcp_get_busid_by_adapter(adapter)); | ||
2224 | return retval; | 1389 | return retval; |
2225 | } | 1390 | } |
2226 | 1391 | ||
2227 | |||
2228 | /** | 1392 | /** |
2229 | * zfcp_fsf_exchange_port_data_sync - request information about local port | 1393 | * zfcp_fsf_exchange_port_data_sync - request information about local port |
2230 | * and wait until information is ready | 1394 | * @adapter: pointer to struct zfcp_adapter |
1395 | * @data: pointer to struct fsf_qtcb_bottom_port | ||
1396 | * Returns: 0 on success, error otherwise | ||
2231 | */ | 1397 | */ |
2232 | int | 1398 | int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, |
2233 | zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, | 1399 | struct fsf_qtcb_bottom_port *data) |
2234 | struct fsf_qtcb_bottom_port *data) | ||
2235 | { | 1400 | { |
2236 | volatile struct qdio_buffer_element *sbale; | 1401 | volatile struct qdio_buffer_element *sbale; |
2237 | struct zfcp_fsf_req *fsf_req; | 1402 | struct zfcp_fsf_req *req = NULL; |
2238 | unsigned long lock_flags; | 1403 | int retval = -EIO; |
2239 | int retval; | 1404 | |
2240 | 1405 | if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) | |
2241 | if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { | ||
2242 | ZFCP_LOG_INFO("error: exchange port data " | ||
2243 | "command not supported by adapter %s\n", | ||
2244 | zfcp_get_busid_by_adapter(adapter)); | ||
2245 | return -EOPNOTSUPP; | 1406 | return -EOPNOTSUPP; |
2246 | } | ||
2247 | 1407 | ||
2248 | /* setup new FSF request */ | 1408 | spin_lock(&adapter->req_q.lock); |
2249 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, | 1409 | if (!atomic_read(&adapter->req_q.count)) |
2250 | 0, NULL, &lock_flags, &fsf_req); | 1410 | goto out; |
2251 | if (retval) { | 1411 | |
2252 | ZFCP_LOG_INFO("error: Out of resources. Could not create an " | 1412 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0, |
2253 | "exchange port data request for " | 1413 | NULL); |
2254 | "the adapter %s.\n", | 1414 | if (unlikely(IS_ERR(req))) { |
2255 | zfcp_get_busid_by_adapter(adapter)); | 1415 | retval = PTR_ERR(req); |
2256 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, | 1416 | goto out; |
2257 | lock_flags); | ||
2258 | return retval; | ||
2259 | } | 1417 | } |
2260 | 1418 | ||
2261 | if (data) | 1419 | if (data) |
2262 | fsf_req->data = (unsigned long) data; | 1420 | req->data = data; |
2263 | 1421 | ||
2264 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1422 | sbale = zfcp_qdio_sbale_req(req); |
2265 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1423 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
2266 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1424 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
2267 | 1425 | ||
2268 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 1426 | req->handler = zfcp_fsf_exchange_port_data_handler; |
2269 | retval = zfcp_fsf_req_send(fsf_req); | 1427 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); |
2270 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | 1428 | retval = zfcp_fsf_req_send(req); |
2271 | 1429 | out: | |
2272 | if (retval) | 1430 | spin_unlock(&adapter->req_q.lock); |
2273 | ZFCP_LOG_INFO("error: Could not send an exchange port data " | 1431 | if (!retval) |
2274 | "command on the adapter %s\n", | 1432 | wait_event(req->completion_wq, |
2275 | zfcp_get_busid_by_adapter(adapter)); | 1433 | req->status & ZFCP_STATUS_FSFREQ_COMPLETED); |
2276 | else | 1434 | zfcp_fsf_req_free(req); |
2277 | wait_event(fsf_req->completion_wq, | ||
2278 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | ||
2279 | |||
2280 | zfcp_fsf_req_free(fsf_req); | ||
2281 | |||
2282 | return retval; | ||
2283 | } | ||
2284 | |||
2285 | /** | ||
2286 | * zfcp_fsf_exchange_port_evaluate | ||
2287 | * @fsf_req: fsf_req which belongs to xchg port data request | ||
2288 | * @xchg_ok: specifies if xchg port data was incomplete or complete (0/1) | ||
2289 | */ | ||
2290 | static void | ||
2291 | zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) | ||
2292 | { | ||
2293 | struct zfcp_adapter *adapter; | ||
2294 | struct fsf_qtcb_bottom_port *bottom; | ||
2295 | struct Scsi_Host *shost; | ||
2296 | |||
2297 | adapter = fsf_req->adapter; | ||
2298 | bottom = &fsf_req->qtcb->bottom.port; | ||
2299 | shost = adapter->scsi_host; | ||
2300 | |||
2301 | if (fsf_req->data) | ||
2302 | memcpy((struct fsf_qtcb_bottom_port*) fsf_req->data, bottom, | ||
2303 | sizeof(struct fsf_qtcb_bottom_port)); | ||
2304 | |||
2305 | if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) | ||
2306 | fc_host_permanent_port_name(shost) = bottom->wwpn; | ||
2307 | else | ||
2308 | fc_host_permanent_port_name(shost) = fc_host_port_name(shost); | ||
2309 | fc_host_maxframe_size(shost) = bottom->maximum_frame_size; | ||
2310 | fc_host_supported_speeds(shost) = bottom->supported_speed; | ||
2311 | } | ||
2312 | |||
2313 | /** | ||
2314 | * zfcp_fsf_exchange_port_data_handler - handler for exchange_port_data request | ||
2315 | * @fsf_req: pointer to struct zfcp_fsf_req | ||
2316 | */ | ||
2317 | static void | ||
2318 | zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req) | ||
2319 | { | ||
2320 | struct zfcp_adapter *adapter; | ||
2321 | struct fsf_qtcb *qtcb; | ||
2322 | |||
2323 | adapter = fsf_req->adapter; | ||
2324 | qtcb = fsf_req->qtcb; | ||
2325 | |||
2326 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) | ||
2327 | return; | ||
2328 | |||
2329 | switch (qtcb->header.fsf_status) { | ||
2330 | case FSF_GOOD: | ||
2331 | zfcp_fsf_exchange_port_evaluate(fsf_req, 1); | ||
2332 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); | ||
2333 | break; | ||
2334 | case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: | ||
2335 | zfcp_fsf_exchange_port_evaluate(fsf_req, 0); | ||
2336 | atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); | ||
2337 | zfcp_fsf_link_down_info_eval(fsf_req, 43, | ||
2338 | &qtcb->header.fsf_status_qual.link_down_info); | ||
2339 | break; | ||
2340 | } | ||
2341 | } | ||
2342 | |||
2343 | |||
2344 | /* | ||
2345 | * function: zfcp_fsf_open_port | ||
2346 | * | ||
2347 | * purpose: | ||
2348 | * | ||
2349 | * returns: address of initiated FSF request | ||
2350 | * NULL - request could not be initiated | ||
2351 | */ | ||
2352 | int | ||
2353 | zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) | ||
2354 | { | ||
2355 | volatile struct qdio_buffer_element *sbale; | ||
2356 | struct zfcp_fsf_req *fsf_req; | ||
2357 | unsigned long lock_flags; | ||
2358 | int retval = 0; | ||
2359 | |||
2360 | /* setup new FSF request */ | ||
2361 | retval = zfcp_fsf_req_create(erp_action->adapter, | ||
2362 | FSF_QTCB_OPEN_PORT_WITH_DID, | ||
2363 | ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | ||
2364 | erp_action->adapter->pool.fsf_req_erp, | ||
2365 | &lock_flags, &fsf_req); | ||
2366 | if (retval < 0) { | ||
2367 | ZFCP_LOG_INFO("error: Could not create open port request " | ||
2368 | "for port 0x%016Lx on adapter %s.\n", | ||
2369 | erp_action->port->wwpn, | ||
2370 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
2371 | goto out; | ||
2372 | } | ||
2373 | |||
2374 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | ||
2375 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | ||
2376 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
2377 | |||
2378 | fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id; | ||
2379 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status); | ||
2380 | fsf_req->data = (unsigned long) erp_action->port; | ||
2381 | fsf_req->erp_action = erp_action; | ||
2382 | erp_action->fsf_req = fsf_req; | ||
2383 | |||
2384 | zfcp_erp_start_timer(fsf_req); | ||
2385 | retval = zfcp_fsf_req_send(fsf_req); | ||
2386 | if (retval) { | ||
2387 | ZFCP_LOG_INFO("error: Could not send open port request for " | ||
2388 | "port 0x%016Lx on adapter %s.\n", | ||
2389 | erp_action->port->wwpn, | ||
2390 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
2391 | zfcp_fsf_req_free(fsf_req); | ||
2392 | erp_action->fsf_req = NULL; | ||
2393 | goto out; | ||
2394 | } | ||
2395 | 1435 | ||
2396 | ZFCP_LOG_DEBUG("open port request initiated " | ||
2397 | "(adapter %s, port 0x%016Lx)\n", | ||
2398 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2399 | erp_action->port->wwpn); | ||
2400 | out: | ||
2401 | write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | ||
2402 | lock_flags); | ||
2403 | return retval; | 1436 | return retval; |
2404 | } | 1437 | } |
2405 | 1438 | ||
2406 | /* | 1439 | static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) |
2407 | * function: zfcp_fsf_open_port_handler | ||
2408 | * | ||
2409 | * purpose: is called for finished Open Port command | ||
2410 | * | ||
2411 | * returns: | ||
2412 | */ | ||
2413 | static int | ||
2414 | zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) | ||
2415 | { | 1440 | { |
2416 | int retval = -EINVAL; | 1441 | struct zfcp_port *port = req->data; |
2417 | struct zfcp_port *port; | 1442 | struct fsf_qtcb_header *header = &req->qtcb->header; |
2418 | struct fsf_plogi *plogi; | 1443 | struct fsf_plogi *plogi; |
2419 | struct fsf_qtcb_header *header; | ||
2420 | u16 subtable, rule, counter; | ||
2421 | 1444 | ||
2422 | port = (struct zfcp_port *) fsf_req->data; | 1445 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
2423 | header = &fsf_req->qtcb->header; | ||
2424 | |||
2425 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
2426 | /* don't change port status in our bookkeeping */ | ||
2427 | goto skip_fsfstatus; | 1446 | goto skip_fsfstatus; |
2428 | } | ||
2429 | 1447 | ||
2430 | /* evaluate FSF status in QTCB */ | ||
2431 | switch (header->fsf_status) { | 1448 | switch (header->fsf_status) { |
2432 | |||
2433 | case FSF_PORT_ALREADY_OPEN: | 1449 | case FSF_PORT_ALREADY_OPEN: |
2434 | ZFCP_LOG_NORMAL("bug: remote port 0x%016Lx on adapter %s " | ||
2435 | "is already open.\n", | ||
2436 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
2437 | /* | ||
2438 | * This is a bug, however operation should continue normally | ||
2439 | * if it is simply ignored | ||
2440 | */ | ||
2441 | break; | 1450 | break; |
2442 | |||
2443 | case FSF_ACCESS_DENIED: | 1451 | case FSF_ACCESS_DENIED: |
2444 | ZFCP_LOG_NORMAL("Access denied, cannot open port 0x%016Lx " | 1452 | zfcp_fsf_access_denied_port(req, port); |
2445 | "on adapter %s\n", | ||
2446 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
2447 | for (counter = 0; counter < 2; counter++) { | ||
2448 | subtable = header->fsf_status_qual.halfword[counter * 2]; | ||
2449 | rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | ||
2450 | switch (subtable) { | ||
2451 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
2452 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
2453 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
2454 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
2455 | ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | ||
2456 | zfcp_act_subtable_type[subtable], rule); | ||
2457 | break; | ||
2458 | } | ||
2459 | } | ||
2460 | zfcp_erp_port_access_denied(port, 57, fsf_req); | ||
2461 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2462 | break; | 1453 | break; |
2463 | |||
2464 | case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: | 1454 | case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: |
2465 | ZFCP_LOG_INFO("error: The FSF adapter is out of resources. " | 1455 | dev_warn(&req->adapter->ccw_device->dev, |
2466 | "The remote port 0x%016Lx on adapter %s " | 1456 | "The adapter is out of resources. The remote port " |
2467 | "could not be opened. Disabling it.\n", | 1457 | "0x%016Lx could not be opened, disabling it.\n", |
2468 | port->wwpn, zfcp_get_busid_by_port(port)); | 1458 | port->wwpn); |
2469 | zfcp_erp_port_failed(port, 31, fsf_req); | 1459 | zfcp_erp_port_failed(port, 31, req); |
2470 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1460 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2471 | break; | 1461 | break; |
2472 | |||
2473 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1462 | case FSF_ADAPTER_STATUS_AVAILABLE: |
2474 | switch (header->fsf_status_qual.word[0]) { | 1463 | switch (header->fsf_status_qual.word[0]) { |
2475 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 1464 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
2476 | /* ERP strategy will escalate */ | ||
2477 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2478 | break; | ||
2479 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1465 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
2480 | /* ERP strategy will escalate */ | 1466 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2481 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2482 | break; | 1467 | break; |
2483 | case FSF_SQ_NO_RETRY_POSSIBLE: | 1468 | case FSF_SQ_NO_RETRY_POSSIBLE: |
2484 | ZFCP_LOG_NORMAL("The remote port 0x%016Lx on " | 1469 | dev_warn(&req->adapter->ccw_device->dev, |
2485 | "adapter %s could not be opened. " | 1470 | "The remote port 0x%016Lx could not be " |
2486 | "Disabling it.\n", | 1471 | "opened. Disabling it.\n", port->wwpn); |
2487 | port->wwpn, | 1472 | zfcp_erp_port_failed(port, 32, req); |
2488 | zfcp_get_busid_by_port(port)); | 1473 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2489 | zfcp_erp_port_failed(port, 32, fsf_req); | ||
2490 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2491 | break; | ||
2492 | default: | ||
2493 | ZFCP_LOG_NORMAL | ||
2494 | ("bug: Wrong status qualifier 0x%x arrived.\n", | ||
2495 | header->fsf_status_qual.word[0]); | ||
2496 | break; | 1474 | break; |
2497 | } | 1475 | } |
2498 | break; | 1476 | break; |
2499 | |||
2500 | case FSF_GOOD: | 1477 | case FSF_GOOD: |
2501 | /* save port handle assigned by FSF */ | ||
2502 | port->handle = header->port_handle; | 1478 | port->handle = header->port_handle; |
2503 | ZFCP_LOG_INFO("The remote port 0x%016Lx via adapter %s " | ||
2504 | "was opened, it's port handle is 0x%x\n", | ||
2505 | port->wwpn, zfcp_get_busid_by_port(port), | ||
2506 | port->handle); | ||
2507 | /* mark port as open */ | ||
2508 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN | | 1479 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN | |
2509 | ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); | 1480 | ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); |
2510 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | | 1481 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | |
2511 | ZFCP_STATUS_COMMON_ACCESS_BOXED, | 1482 | ZFCP_STATUS_COMMON_ACCESS_BOXED, |
2512 | &port->status); | 1483 | &port->status); |
2513 | retval = 0; | ||
2514 | /* check whether D_ID has changed during open */ | 1484 | /* check whether D_ID has changed during open */ |
2515 | /* | 1485 | /* |
2516 | * FIXME: This check is not airtight, as the FCP channel does | 1486 | * FIXME: This check is not airtight, as the FCP channel does |
@@ -2526,320 +1496,168 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) | |||
2526 | * another GID_PN straight after a port has been opened. | 1496 | * another GID_PN straight after a port has been opened. |
2527 | * Alternately, an ADISC/PDISC ELS should suffice, as well. | 1497 | * Alternately, an ADISC/PDISC ELS should suffice, as well. |
2528 | */ | 1498 | */ |
2529 | plogi = (struct fsf_plogi *) fsf_req->qtcb->bottom.support.els; | 1499 | if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN) |
2530 | if (!atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, &port->status)) | 1500 | break; |
2531 | { | 1501 | |
2532 | if (fsf_req->qtcb->bottom.support.els1_length < | 1502 | plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els; |
2533 | sizeof (struct fsf_plogi)) { | 1503 | if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) { |
2534 | ZFCP_LOG_INFO( | 1504 | if (plogi->serv_param.wwpn != port->wwpn) |
2535 | "warning: insufficient length of " | 1505 | atomic_clear_mask(ZFCP_STATUS_PORT_DID_DID, |
2536 | "PLOGI payload (%i)\n", | 1506 | &port->status); |
2537 | fsf_req->qtcb->bottom.support.els1_length); | 1507 | else { |
2538 | /* skip sanity check and assume wwpn is ok */ | 1508 | port->wwnn = plogi->serv_param.wwnn; |
2539 | } else { | 1509 | zfcp_fc_plogi_evaluate(port, plogi); |
2540 | if (plogi->serv_param.wwpn != port->wwpn) { | ||
2541 | ZFCP_LOG_INFO("warning: d_id of port " | ||
2542 | "0x%016Lx changed during " | ||
2543 | "open\n", port->wwpn); | ||
2544 | atomic_clear_mask( | ||
2545 | ZFCP_STATUS_PORT_DID_DID, | ||
2546 | &port->status); | ||
2547 | } else { | ||
2548 | port->wwnn = plogi->serv_param.wwnn; | ||
2549 | zfcp_plogi_evaluate(port, plogi); | ||
2550 | } | ||
2551 | } | 1510 | } |
2552 | } | 1511 | } |
2553 | break; | 1512 | break; |
2554 | |||
2555 | case FSF_UNKNOWN_OP_SUBTYPE: | 1513 | case FSF_UNKNOWN_OP_SUBTYPE: |
2556 | /* should never occure, subtype not set in zfcp_fsf_open_port */ | 1514 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2557 | ZFCP_LOG_INFO("unknown operation subtype (adapter: %s, " | ||
2558 | "op_subtype=0x%x)\n", | ||
2559 | zfcp_get_busid_by_port(port), | ||
2560 | fsf_req->qtcb->bottom.support.operation_subtype); | ||
2561 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2562 | break; | ||
2563 | |||
2564 | default: | ||
2565 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
2566 | "(debug info 0x%x)\n", | ||
2567 | header->fsf_status); | ||
2568 | break; | 1515 | break; |
2569 | } | 1516 | } |
2570 | 1517 | ||
2571 | skip_fsfstatus: | 1518 | skip_fsfstatus: |
2572 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status); | 1519 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status); |
2573 | return retval; | ||
2574 | } | 1520 | } |
2575 | 1521 | ||
2576 | /* | 1522 | /** |
2577 | * function: zfcp_fsf_close_port | 1523 | * zfcp_fsf_open_port - create and send open port request |
2578 | * | 1524 | * @erp_action: pointer to struct zfcp_erp_action |
2579 | * purpose: submit FSF command "close port" | 1525 | * Returns: 0 on success, error otherwise |
2580 | * | ||
2581 | * returns: address of initiated FSF request | ||
2582 | * NULL - request could not be initiated | ||
2583 | */ | 1526 | */ |
2584 | int | 1527 | int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) |
2585 | zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) | ||
2586 | { | 1528 | { |
2587 | volatile struct qdio_buffer_element *sbale; | 1529 | volatile struct qdio_buffer_element *sbale; |
2588 | struct zfcp_fsf_req *fsf_req; | 1530 | struct zfcp_adapter *adapter = erp_action->adapter; |
2589 | unsigned long lock_flags; | 1531 | struct zfcp_fsf_req *req; |
2590 | int retval = 0; | 1532 | int retval = -EIO; |
2591 | 1533 | ||
2592 | /* setup new FSF request */ | 1534 | spin_lock(&adapter->req_q.lock); |
2593 | retval = zfcp_fsf_req_create(erp_action->adapter, | 1535 | if (zfcp_fsf_req_sbal_get(adapter)) |
2594 | FSF_QTCB_CLOSE_PORT, | 1536 | goto out; |
2595 | ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | 1537 | |
2596 | erp_action->adapter->pool.fsf_req_erp, | 1538 | req = zfcp_fsf_req_create(adapter, |
2597 | &lock_flags, &fsf_req); | 1539 | FSF_QTCB_OPEN_PORT_WITH_DID, |
2598 | if (retval < 0) { | 1540 | ZFCP_REQ_AUTO_CLEANUP, |
2599 | ZFCP_LOG_INFO("error: Could not create a close port request " | 1541 | adapter->pool.fsf_req_erp); |
2600 | "for port 0x%016Lx on adapter %s.\n", | 1542 | if (unlikely(IS_ERR(req))) { |
2601 | erp_action->port->wwpn, | 1543 | retval = PTR_ERR(req); |
2602 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
2603 | goto out; | 1544 | goto out; |
2604 | } | 1545 | } |
2605 | 1546 | ||
2606 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1547 | sbale = zfcp_qdio_sbale_req(req); |
2607 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1548 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
2608 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1549 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
2609 | 1550 | ||
2610 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status); | 1551 | req->handler = zfcp_fsf_open_port_handler; |
2611 | fsf_req->data = (unsigned long) erp_action->port; | 1552 | req->qtcb->bottom.support.d_id = erp_action->port->d_id; |
2612 | fsf_req->erp_action = erp_action; | 1553 | req->data = erp_action->port; |
2613 | fsf_req->qtcb->header.port_handle = erp_action->port->handle; | 1554 | req->erp_action = erp_action; |
2614 | fsf_req->erp_action = erp_action; | 1555 | erp_action->fsf_req = req; |
2615 | erp_action->fsf_req = fsf_req; | 1556 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status); |
2616 | 1557 | ||
2617 | zfcp_erp_start_timer(fsf_req); | 1558 | zfcp_fsf_start_erp_timer(req); |
2618 | retval = zfcp_fsf_req_send(fsf_req); | 1559 | retval = zfcp_fsf_req_send(req); |
2619 | if (retval) { | 1560 | if (retval) { |
2620 | ZFCP_LOG_INFO("error: Could not send a close port request for " | 1561 | zfcp_fsf_req_free(req); |
2621 | "port 0x%016Lx on adapter %s.\n", | ||
2622 | erp_action->port->wwpn, | ||
2623 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
2624 | zfcp_fsf_req_free(fsf_req); | ||
2625 | erp_action->fsf_req = NULL; | 1562 | erp_action->fsf_req = NULL; |
2626 | goto out; | ||
2627 | } | 1563 | } |
2628 | 1564 | out: | |
2629 | ZFCP_LOG_TRACE("close port request initiated " | 1565 | spin_unlock(&adapter->req_q.lock); |
2630 | "(adapter %s, port 0x%016Lx)\n", | ||
2631 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2632 | erp_action->port->wwpn); | ||
2633 | out: | ||
2634 | write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | ||
2635 | lock_flags); | ||
2636 | return retval; | 1566 | return retval; |
2637 | } | 1567 | } |
2638 | 1568 | ||
2639 | /* | 1569 | static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req) |
2640 | * function: zfcp_fsf_close_port_handler | ||
2641 | * | ||
2642 | * purpose: is called for finished Close Port FSF command | ||
2643 | * | ||
2644 | * returns: | ||
2645 | */ | ||
2646 | static int | ||
2647 | zfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req) | ||
2648 | { | 1570 | { |
2649 | int retval = -EINVAL; | 1571 | struct zfcp_port *port = req->data; |
2650 | struct zfcp_port *port; | ||
2651 | 1572 | ||
2652 | port = (struct zfcp_port *) fsf_req->data; | 1573 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
2653 | |||
2654 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
2655 | /* don't change port status in our bookkeeping */ | ||
2656 | goto skip_fsfstatus; | 1574 | goto skip_fsfstatus; |
2657 | } | ||
2658 | |||
2659 | /* evaluate FSF status in QTCB */ | ||
2660 | switch (fsf_req->qtcb->header.fsf_status) { | ||
2661 | 1575 | ||
1576 | switch (req->qtcb->header.fsf_status) { | ||
2662 | case FSF_PORT_HANDLE_NOT_VALID: | 1577 | case FSF_PORT_HANDLE_NOT_VALID: |
2663 | ZFCP_LOG_INFO("Temporary port identifier 0x%x for port " | 1578 | zfcp_erp_adapter_reopen(port->adapter, 0, 107, req); |
2664 | "0x%016Lx on adapter %s invalid. This may happen " | 1579 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2665 | "occasionally.\n", port->handle, | ||
2666 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
2667 | ZFCP_LOG_DEBUG("status qualifier:\n"); | ||
2668 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
2669 | (char *) &fsf_req->qtcb->header.fsf_status_qual, | ||
2670 | sizeof (union fsf_status_qual)); | ||
2671 | zfcp_erp_adapter_reopen(port->adapter, 0, 107, fsf_req); | ||
2672 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2673 | break; | 1580 | break; |
2674 | |||
2675 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1581 | case FSF_ADAPTER_STATUS_AVAILABLE: |
2676 | /* Note: FSF has actually closed the port in this case. | ||
2677 | * The status code is just daft. Fingers crossed for a change | ||
2678 | */ | ||
2679 | retval = 0; | ||
2680 | break; | 1582 | break; |
2681 | |||
2682 | case FSF_GOOD: | 1583 | case FSF_GOOD: |
2683 | ZFCP_LOG_TRACE("remote port 0x016%Lx on adapter %s closed, " | 1584 | zfcp_erp_modify_port_status(port, 33, req, |
2684 | "port handle 0x%x\n", port->wwpn, | ||
2685 | zfcp_get_busid_by_port(port), port->handle); | ||
2686 | zfcp_erp_modify_port_status(port, 33, fsf_req, | ||
2687 | ZFCP_STATUS_COMMON_OPEN, | 1585 | ZFCP_STATUS_COMMON_OPEN, |
2688 | ZFCP_CLEAR); | 1586 | ZFCP_CLEAR); |
2689 | retval = 0; | ||
2690 | break; | ||
2691 | |||
2692 | default: | ||
2693 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
2694 | "(debug info 0x%x)\n", | ||
2695 | fsf_req->qtcb->header.fsf_status); | ||
2696 | break; | 1587 | break; |
2697 | } | 1588 | } |
2698 | 1589 | ||
2699 | skip_fsfstatus: | 1590 | skip_fsfstatus: |
2700 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status); | 1591 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status); |
2701 | return retval; | ||
2702 | } | 1592 | } |
2703 | 1593 | ||
2704 | /* | 1594 | /** |
2705 | * function: zfcp_fsf_close_physical_port | 1595 | * zfcp_fsf_close_port - create and send close port request |
2706 | * | 1596 | * @erp_action: pointer to struct zfcp_erp_action |
2707 | * purpose: submit FSF command "close physical port" | 1597 | * Returns: 0 on success, error otherwise |
2708 | * | ||
2709 | * returns: address of initiated FSF request | ||
2710 | * NULL - request could not be initiated | ||
2711 | */ | 1598 | */ |
2712 | int | 1599 | int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) |
2713 | zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) | ||
2714 | { | 1600 | { |
2715 | volatile struct qdio_buffer_element *sbale; | 1601 | volatile struct qdio_buffer_element *sbale; |
2716 | struct zfcp_fsf_req *fsf_req; | 1602 | struct zfcp_adapter *adapter = erp_action->adapter; |
2717 | unsigned long lock_flags; | 1603 | struct zfcp_fsf_req *req; |
2718 | int retval = 0; | 1604 | int retval = -EIO; |
2719 | |||
2720 | /* setup new FSF request */ | ||
2721 | retval = zfcp_fsf_req_create(erp_action->adapter, | ||
2722 | FSF_QTCB_CLOSE_PHYSICAL_PORT, | ||
2723 | ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | ||
2724 | erp_action->adapter->pool.fsf_req_erp, | ||
2725 | &lock_flags, &fsf_req); | ||
2726 | if (retval < 0) { | ||
2727 | ZFCP_LOG_INFO("error: Could not create close physical port " | ||
2728 | "request (adapter %s, port 0x%016Lx)\n", | ||
2729 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2730 | erp_action->port->wwpn); | ||
2731 | 1605 | ||
1606 | spin_lock(&adapter->req_q.lock); | ||
1607 | if (zfcp_fsf_req_sbal_get(adapter)) | ||
1608 | goto out; | ||
1609 | |||
1610 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT, | ||
1611 | ZFCP_REQ_AUTO_CLEANUP, | ||
1612 | adapter->pool.fsf_req_erp); | ||
1613 | if (unlikely(IS_ERR(req))) { | ||
1614 | retval = PTR_ERR(req); | ||
2732 | goto out; | 1615 | goto out; |
2733 | } | 1616 | } |
2734 | 1617 | ||
2735 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1618 | sbale = zfcp_qdio_sbale_req(req); |
2736 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1619 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
2737 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1620 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
2738 | 1621 | ||
2739 | /* mark port as being closed */ | 1622 | req->handler = zfcp_fsf_close_port_handler; |
2740 | atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, | 1623 | req->data = erp_action->port; |
2741 | &erp_action->port->status); | 1624 | req->erp_action = erp_action; |
2742 | /* save a pointer to this port */ | 1625 | req->qtcb->header.port_handle = erp_action->port->handle; |
2743 | fsf_req->data = (unsigned long) erp_action->port; | 1626 | erp_action->fsf_req = req; |
2744 | fsf_req->qtcb->header.port_handle = erp_action->port->handle; | 1627 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status); |
2745 | fsf_req->erp_action = erp_action; | 1628 | |
2746 | erp_action->fsf_req = fsf_req; | 1629 | zfcp_fsf_start_erp_timer(req); |
2747 | 1630 | retval = zfcp_fsf_req_send(req); | |
2748 | zfcp_erp_start_timer(fsf_req); | ||
2749 | retval = zfcp_fsf_req_send(fsf_req); | ||
2750 | if (retval) { | 1631 | if (retval) { |
2751 | ZFCP_LOG_INFO("error: Could not send close physical port " | 1632 | zfcp_fsf_req_free(req); |
2752 | "request (adapter %s, port 0x%016Lx)\n", | ||
2753 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2754 | erp_action->port->wwpn); | ||
2755 | zfcp_fsf_req_free(fsf_req); | ||
2756 | erp_action->fsf_req = NULL; | 1633 | erp_action->fsf_req = NULL; |
2757 | goto out; | ||
2758 | } | 1634 | } |
2759 | 1635 | out: | |
2760 | ZFCP_LOG_TRACE("close physical port request initiated " | 1636 | spin_unlock(&adapter->req_q.lock); |
2761 | "(adapter %s, port 0x%016Lx)\n", | ||
2762 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2763 | erp_action->port->wwpn); | ||
2764 | out: | ||
2765 | write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | ||
2766 | lock_flags); | ||
2767 | return retval; | 1637 | return retval; |
2768 | } | 1638 | } |
2769 | 1639 | ||
2770 | /* | 1640 | static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) |
2771 | * function: zfcp_fsf_close_physical_port_handler | ||
2772 | * | ||
2773 | * purpose: is called for finished Close Physical Port FSF command | ||
2774 | * | ||
2775 | * returns: | ||
2776 | */ | ||
2777 | static int | ||
2778 | zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) | ||
2779 | { | 1641 | { |
2780 | int retval = -EINVAL; | 1642 | struct zfcp_port *port = req->data; |
2781 | struct zfcp_port *port; | 1643 | struct fsf_qtcb_header *header = &req->qtcb->header; |
2782 | struct zfcp_unit *unit; | 1644 | struct zfcp_unit *unit; |
2783 | struct fsf_qtcb_header *header; | ||
2784 | u16 subtable, rule, counter; | ||
2785 | 1645 | ||
2786 | port = (struct zfcp_port *) fsf_req->data; | 1646 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
2787 | header = &fsf_req->qtcb->header; | ||
2788 | |||
2789 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
2790 | /* don't change port status in our bookkeeping */ | ||
2791 | goto skip_fsfstatus; | 1647 | goto skip_fsfstatus; |
2792 | } | ||
2793 | 1648 | ||
2794 | /* evaluate FSF status in QTCB */ | ||
2795 | switch (header->fsf_status) { | 1649 | switch (header->fsf_status) { |
2796 | |||
2797 | case FSF_PORT_HANDLE_NOT_VALID: | 1650 | case FSF_PORT_HANDLE_NOT_VALID: |
2798 | ZFCP_LOG_INFO("Temporary port identifier 0x%x invalid" | 1651 | zfcp_erp_adapter_reopen(port->adapter, 0, 108, req); |
2799 | "(adapter %s, port 0x%016Lx). " | 1652 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2800 | "This may happen occasionally.\n", | ||
2801 | port->handle, | ||
2802 | zfcp_get_busid_by_port(port), | ||
2803 | port->wwpn); | ||
2804 | ZFCP_LOG_DEBUG("status qualifier:\n"); | ||
2805 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
2806 | (char *) &header->fsf_status_qual, | ||
2807 | sizeof (union fsf_status_qual)); | ||
2808 | zfcp_erp_adapter_reopen(port->adapter, 0, 108, fsf_req); | ||
2809 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2810 | break; | 1653 | break; |
2811 | |||
2812 | case FSF_ACCESS_DENIED: | 1654 | case FSF_ACCESS_DENIED: |
2813 | ZFCP_LOG_NORMAL("Access denied, cannot close " | 1655 | zfcp_fsf_access_denied_port(req, port); |
2814 | "physical port 0x%016Lx on adapter %s\n", | ||
2815 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
2816 | for (counter = 0; counter < 2; counter++) { | ||
2817 | subtable = header->fsf_status_qual.halfword[counter * 2]; | ||
2818 | rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | ||
2819 | switch (subtable) { | ||
2820 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
2821 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
2822 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
2823 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
2824 | ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | ||
2825 | zfcp_act_subtable_type[subtable], rule); | ||
2826 | break; | ||
2827 | } | ||
2828 | } | ||
2829 | zfcp_erp_port_access_denied(port, 58, fsf_req); | ||
2830 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2831 | break; | 1656 | break; |
2832 | |||
2833 | case FSF_PORT_BOXED: | 1657 | case FSF_PORT_BOXED: |
2834 | ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter " | 1658 | zfcp_erp_port_boxed(port, 50, req); |
2835 | "%s needs to be reopened but it was attempted " | 1659 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
2836 | "to close it physically.\n", | 1660 | ZFCP_STATUS_FSFREQ_RETRY; |
2837 | port->wwpn, | ||
2838 | zfcp_get_busid_by_port(port)); | ||
2839 | zfcp_erp_port_boxed(port, 50, fsf_req); | ||
2840 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | ||
2841 | ZFCP_STATUS_FSFREQ_RETRY; | ||
2842 | |||
2843 | /* can't use generic zfcp_erp_modify_port_status because | 1661 | /* can't use generic zfcp_erp_modify_port_status because |
2844 | * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ | 1662 | * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ |
2845 | atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); | 1663 | atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); |
@@ -2847,154 +1665,88 @@ zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) | |||
2847 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, | 1665 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, |
2848 | &unit->status); | 1666 | &unit->status); |
2849 | break; | 1667 | break; |
2850 | |||
2851 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1668 | case FSF_ADAPTER_STATUS_AVAILABLE: |
2852 | switch (header->fsf_status_qual.word[0]) { | 1669 | switch (header->fsf_status_qual.word[0]) { |
2853 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 1670 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
2854 | /* This will now be escalated by ERP */ | 1671 | /* fall through */ |
2855 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2856 | break; | ||
2857 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1672 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
2858 | /* ERP strategy will escalate */ | 1673 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
2859 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
2860 | break; | ||
2861 | default: | ||
2862 | ZFCP_LOG_NORMAL | ||
2863 | ("bug: Wrong status qualifier 0x%x arrived.\n", | ||
2864 | header->fsf_status_qual.word[0]); | ||
2865 | break; | 1674 | break; |
2866 | } | 1675 | } |
2867 | break; | 1676 | break; |
2868 | |||
2869 | case FSF_GOOD: | 1677 | case FSF_GOOD: |
2870 | ZFCP_LOG_DEBUG("Remote port 0x%016Lx via adapter %s " | ||
2871 | "physically closed, port handle 0x%x\n", | ||
2872 | port->wwpn, | ||
2873 | zfcp_get_busid_by_port(port), port->handle); | ||
2874 | /* can't use generic zfcp_erp_modify_port_status because | 1678 | /* can't use generic zfcp_erp_modify_port_status because |
2875 | * ZFCP_STATUS_COMMON_OPEN must not be reset for the port | 1679 | * ZFCP_STATUS_COMMON_OPEN must not be reset for the port |
2876 | */ | 1680 | */ |
2877 | atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); | 1681 | atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); |
2878 | list_for_each_entry(unit, &port->unit_list_head, list) | 1682 | list_for_each_entry(unit, &port->unit_list_head, list) |
2879 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); | 1683 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, |
2880 | retval = 0; | 1684 | &unit->status); |
2881 | break; | ||
2882 | |||
2883 | default: | ||
2884 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
2885 | "(debug info 0x%x)\n", | ||
2886 | header->fsf_status); | ||
2887 | break; | 1685 | break; |
2888 | } | 1686 | } |
2889 | 1687 | skip_fsfstatus: | |
2890 | skip_fsfstatus: | ||
2891 | atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status); | 1688 | atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &port->status); |
2892 | return retval; | ||
2893 | } | 1689 | } |
2894 | 1690 | ||
2895 | /* | 1691 | /** |
2896 | * function: zfcp_fsf_open_unit | 1692 | * zfcp_fsf_close_physical_port - close physical port |
2897 | * | 1693 | * @erp_action: pointer to struct zfcp_erp_action |
2898 | * purpose: | 1694 | * Returns: 0 on success |
2899 | * | ||
2900 | * returns: | ||
2901 | * | ||
2902 | * assumptions: This routine does not check whether the associated | ||
2903 | * remote port has already been opened. This should be | ||
2904 | * done by calling routines. Otherwise some status | ||
2905 | * may be presented by FSF | ||
2906 | */ | 1695 | */ |
2907 | int | 1696 | int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) |
2908 | zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) | ||
2909 | { | 1697 | { |
2910 | volatile struct qdio_buffer_element *sbale; | 1698 | volatile struct qdio_buffer_element *sbale; |
2911 | struct zfcp_fsf_req *fsf_req; | 1699 | struct zfcp_adapter *adapter = erp_action->adapter; |
2912 | unsigned long lock_flags; | 1700 | struct zfcp_fsf_req *req; |
2913 | int retval = 0; | 1701 | int retval = -EIO; |
2914 | 1702 | ||
2915 | /* setup new FSF request */ | 1703 | spin_lock(&adapter->req_q.lock); |
2916 | retval = zfcp_fsf_req_create(erp_action->adapter, | 1704 | if (zfcp_fsf_req_sbal_get(adapter)) |
2917 | FSF_QTCB_OPEN_LUN, | 1705 | goto out; |
2918 | ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | 1706 | |
2919 | erp_action->adapter->pool.fsf_req_erp, | 1707 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PHYSICAL_PORT, |
2920 | &lock_flags, &fsf_req); | 1708 | ZFCP_REQ_AUTO_CLEANUP, |
2921 | if (retval < 0) { | 1709 | adapter->pool.fsf_req_erp); |
2922 | ZFCP_LOG_INFO("error: Could not create open unit request for " | 1710 | if (unlikely(IS_ERR(req))) { |
2923 | "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n", | 1711 | retval = PTR_ERR(req); |
2924 | erp_action->unit->fcp_lun, | ||
2925 | erp_action->unit->port->wwpn, | ||
2926 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
2927 | goto out; | 1712 | goto out; |
2928 | } | 1713 | } |
2929 | 1714 | ||
2930 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1715 | sbale = zfcp_qdio_sbale_req(req); |
2931 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1716 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
2932 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1717 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
2933 | 1718 | ||
2934 | fsf_req->qtcb->header.port_handle = erp_action->port->handle; | 1719 | req->data = erp_action->port; |
2935 | fsf_req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun; | 1720 | req->qtcb->header.port_handle = erp_action->port->handle; |
2936 | if (!(erp_action->adapter->connection_features & FSF_FEATURE_NPIV_MODE)) | 1721 | req->erp_action = erp_action; |
2937 | fsf_req->qtcb->bottom.support.option = | 1722 | req->handler = zfcp_fsf_close_physical_port_handler; |
2938 | FSF_OPEN_LUN_SUPPRESS_BOXING; | 1723 | erp_action->fsf_req = req; |
2939 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); | 1724 | atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, |
2940 | fsf_req->data = (unsigned long) erp_action->unit; | 1725 | &erp_action->port->status); |
2941 | fsf_req->erp_action = erp_action; | ||
2942 | erp_action->fsf_req = fsf_req; | ||
2943 | 1726 | ||
2944 | zfcp_erp_start_timer(fsf_req); | 1727 | zfcp_fsf_start_erp_timer(req); |
2945 | retval = zfcp_fsf_req_send(erp_action->fsf_req); | 1728 | retval = zfcp_fsf_req_send(req); |
2946 | if (retval) { | 1729 | if (retval) { |
2947 | ZFCP_LOG_INFO("error: Could not send an open unit request " | 1730 | zfcp_fsf_req_free(req); |
2948 | "on the adapter %s, port 0x%016Lx for " | ||
2949 | "unit 0x%016Lx\n", | ||
2950 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2951 | erp_action->port->wwpn, | ||
2952 | erp_action->unit->fcp_lun); | ||
2953 | zfcp_fsf_req_free(fsf_req); | ||
2954 | erp_action->fsf_req = NULL; | 1731 | erp_action->fsf_req = NULL; |
2955 | goto out; | ||
2956 | } | 1732 | } |
2957 | 1733 | out: | |
2958 | ZFCP_LOG_TRACE("Open LUN request initiated (adapter %s, " | 1734 | spin_unlock(&adapter->req_q.lock); |
2959 | "port 0x%016Lx, unit 0x%016Lx)\n", | ||
2960 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
2961 | erp_action->port->wwpn, erp_action->unit->fcp_lun); | ||
2962 | out: | ||
2963 | write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | ||
2964 | lock_flags); | ||
2965 | return retval; | 1735 | return retval; |
2966 | } | 1736 | } |
2967 | 1737 | ||
2968 | /* | 1738 | static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) |
2969 | * function: zfcp_fsf_open_unit_handler | ||
2970 | * | ||
2971 | * purpose: is called for finished Open LUN command | ||
2972 | * | ||
2973 | * returns: | ||
2974 | */ | ||
2975 | static int | ||
2976 | zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) | ||
2977 | { | 1739 | { |
2978 | int retval = -EINVAL; | 1740 | struct zfcp_adapter *adapter = req->adapter; |
2979 | struct zfcp_adapter *adapter; | 1741 | struct zfcp_unit *unit = req->data; |
2980 | struct zfcp_unit *unit; | 1742 | struct fsf_qtcb_header *header = &req->qtcb->header; |
2981 | struct fsf_qtcb_header *header; | 1743 | struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; |
2982 | struct fsf_qtcb_bottom_support *bottom; | 1744 | struct fsf_queue_designator *queue_designator = |
2983 | struct fsf_queue_designator *queue_designator; | 1745 | &header->fsf_status_qual.fsf_queue_designator; |
2984 | u16 subtable, rule, counter; | ||
2985 | int exclusive, readwrite; | 1746 | int exclusive, readwrite; |
2986 | 1747 | ||
2987 | unit = (struct zfcp_unit *) fsf_req->data; | 1748 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
2988 | |||
2989 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
2990 | /* don't change unit status in our bookkeeping */ | ||
2991 | goto skip_fsfstatus; | 1749 | goto skip_fsfstatus; |
2992 | } | ||
2993 | |||
2994 | adapter = fsf_req->adapter; | ||
2995 | header = &fsf_req->qtcb->header; | ||
2996 | bottom = &fsf_req->qtcb->bottom.support; | ||
2997 | queue_designator = &header->fsf_status_qual.fsf_queue_designator; | ||
2998 | 1750 | ||
2999 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | | 1751 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | |
3000 | ZFCP_STATUS_COMMON_ACCESS_BOXED | | 1752 | ZFCP_STATUS_COMMON_ACCESS_BOXED | |
@@ -3002,155 +1754,65 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) | |||
3002 | ZFCP_STATUS_UNIT_READONLY, | 1754 | ZFCP_STATUS_UNIT_READONLY, |
3003 | &unit->status); | 1755 | &unit->status); |
3004 | 1756 | ||
3005 | /* evaluate FSF status in QTCB */ | ||
3006 | switch (header->fsf_status) { | 1757 | switch (header->fsf_status) { |
3007 | 1758 | ||
3008 | case FSF_PORT_HANDLE_NOT_VALID: | 1759 | case FSF_PORT_HANDLE_NOT_VALID: |
3009 | ZFCP_LOG_INFO("Temporary port identifier 0x%x " | 1760 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 109, req); |
3010 | "for port 0x%016Lx on adapter %s invalid " | 1761 | /* fall through */ |
3011 | "This may happen occasionally\n", | ||
3012 | unit->port->handle, | ||
3013 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | ||
3014 | ZFCP_LOG_DEBUG("status qualifier:\n"); | ||
3015 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3016 | (char *) &header->fsf_status_qual, | ||
3017 | sizeof (union fsf_status_qual)); | ||
3018 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 109, fsf_req); | ||
3019 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3020 | break; | ||
3021 | |||
3022 | case FSF_LUN_ALREADY_OPEN: | 1762 | case FSF_LUN_ALREADY_OPEN: |
3023 | ZFCP_LOG_NORMAL("bug: Attempted to open unit 0x%016Lx on " | ||
3024 | "remote port 0x%016Lx on adapter %s twice.\n", | ||
3025 | unit->fcp_lun, | ||
3026 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | ||
3027 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3028 | break; | 1763 | break; |
3029 | |||
3030 | case FSF_ACCESS_DENIED: | 1764 | case FSF_ACCESS_DENIED: |
3031 | ZFCP_LOG_NORMAL("Access denied, cannot open unit 0x%016Lx on " | 1765 | zfcp_fsf_access_denied_unit(req, unit); |
3032 | "remote port 0x%016Lx on adapter %s\n", | ||
3033 | unit->fcp_lun, unit->port->wwpn, | ||
3034 | zfcp_get_busid_by_unit(unit)); | ||
3035 | for (counter = 0; counter < 2; counter++) { | ||
3036 | subtable = header->fsf_status_qual.halfword[counter * 2]; | ||
3037 | rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | ||
3038 | switch (subtable) { | ||
3039 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
3040 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
3041 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
3042 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
3043 | ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | ||
3044 | zfcp_act_subtable_type[subtable], rule); | ||
3045 | break; | ||
3046 | } | ||
3047 | } | ||
3048 | zfcp_erp_unit_access_denied(unit, 59, fsf_req); | ||
3049 | atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); | 1766 | atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); |
3050 | atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); | 1767 | atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); |
3051 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3052 | break; | 1768 | break; |
3053 | |||
3054 | case FSF_PORT_BOXED: | 1769 | case FSF_PORT_BOXED: |
3055 | ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s " | 1770 | zfcp_erp_port_boxed(unit->port, 51, req); |
3056 | "needs to be reopened\n", | 1771 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
3057 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | 1772 | ZFCP_STATUS_FSFREQ_RETRY; |
3058 | zfcp_erp_port_boxed(unit->port, 51, fsf_req); | ||
3059 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | ||
3060 | ZFCP_STATUS_FSFREQ_RETRY; | ||
3061 | break; | 1773 | break; |
3062 | |||
3063 | case FSF_LUN_SHARING_VIOLATION: | 1774 | case FSF_LUN_SHARING_VIOLATION: |
3064 | if (header->fsf_status_qual.word[0] != 0) { | 1775 | if (header->fsf_status_qual.word[0]) |
3065 | ZFCP_LOG_NORMAL("FCP-LUN 0x%Lx at the remote port " | 1776 | dev_warn(&adapter->ccw_device->dev, |
3066 | "with WWPN 0x%Lx " | 1777 | "FCP-LUN 0x%Lx at the remote port " |
3067 | "connected to the adapter %s " | 1778 | "with WWPN 0x%Lx " |
3068 | "is already in use in LPAR%d, CSS%d\n", | 1779 | "connected to the adapter " |
3069 | unit->fcp_lun, | 1780 | "is already in use in LPAR%d, CSS%d.\n", |
3070 | unit->port->wwpn, | 1781 | unit->fcp_lun, |
3071 | zfcp_get_busid_by_unit(unit), | 1782 | unit->port->wwpn, |
3072 | queue_designator->hla, | 1783 | queue_designator->hla, |
3073 | queue_designator->cssid); | 1784 | queue_designator->cssid); |
3074 | } else { | 1785 | else |
3075 | subtable = header->fsf_status_qual.halfword[4]; | 1786 | zfcp_act_eval_err(adapter, |
3076 | rule = header->fsf_status_qual.halfword[5]; | 1787 | header->fsf_status_qual.word[2]); |
3077 | switch (subtable) { | 1788 | zfcp_erp_unit_access_denied(unit, 60, req); |
3078 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
3079 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
3080 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
3081 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
3082 | ZFCP_LOG_NORMAL("Access to FCP-LUN 0x%Lx at the " | ||
3083 | "remote port with WWPN 0x%Lx " | ||
3084 | "connected to the adapter %s " | ||
3085 | "is denied (%s rule %d)\n", | ||
3086 | unit->fcp_lun, | ||
3087 | unit->port->wwpn, | ||
3088 | zfcp_get_busid_by_unit(unit), | ||
3089 | zfcp_act_subtable_type[subtable], | ||
3090 | rule); | ||
3091 | break; | ||
3092 | } | ||
3093 | } | ||
3094 | ZFCP_LOG_DEBUG("status qualifier:\n"); | ||
3095 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3096 | (char *) &header->fsf_status_qual, | ||
3097 | sizeof (union fsf_status_qual)); | ||
3098 | zfcp_erp_unit_access_denied(unit, 60, fsf_req); | ||
3099 | atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); | 1789 | atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); |
3100 | atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); | 1790 | atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); |
3101 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1791 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
3102 | break; | 1792 | break; |
3103 | |||
3104 | case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED: | 1793 | case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED: |
3105 | ZFCP_LOG_INFO("error: The adapter ran out of resources. " | 1794 | dev_warn(&adapter->ccw_device->dev, |
3106 | "There is no handle (temporary port identifier) " | 1795 | "The adapter ran out of resources. There is no " |
3107 | "available for unit 0x%016Lx on port 0x%016Lx " | 1796 | "handle available for unit 0x%016Lx on port 0x%016Lx.", |
3108 | "on adapter %s\n", | 1797 | unit->fcp_lun, unit->port->wwpn); |
3109 | unit->fcp_lun, | 1798 | zfcp_erp_unit_failed(unit, 34, req); |
3110 | unit->port->wwpn, | 1799 | /* fall through */ |
3111 | zfcp_get_busid_by_unit(unit)); | 1800 | case FSF_INVALID_COMMAND_OPTION: |
3112 | zfcp_erp_unit_failed(unit, 34, fsf_req); | 1801 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
3113 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3114 | break; | 1802 | break; |
3115 | |||
3116 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1803 | case FSF_ADAPTER_STATUS_AVAILABLE: |
3117 | switch (header->fsf_status_qual.word[0]) { | 1804 | switch (header->fsf_status_qual.word[0]) { |
3118 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 1805 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
3119 | /* Re-establish link to port */ | ||
3120 | zfcp_test_link(unit->port); | 1806 | zfcp_test_link(unit->port); |
3121 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1807 | /* fall through */ |
3122 | break; | ||
3123 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1808 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
3124 | /* ERP strategy will escalate */ | 1809 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
3125 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3126 | break; | 1810 | break; |
3127 | default: | ||
3128 | ZFCP_LOG_NORMAL | ||
3129 | ("bug: Wrong status qualifier 0x%x arrived.\n", | ||
3130 | header->fsf_status_qual.word[0]); | ||
3131 | } | 1811 | } |
3132 | break; | 1812 | break; |
3133 | 1813 | ||
3134 | case FSF_INVALID_COMMAND_OPTION: | ||
3135 | ZFCP_LOG_NORMAL( | ||
3136 | "Invalid option 0x%x has been specified " | ||
3137 | "in QTCB bottom sent to the adapter %s\n", | ||
3138 | bottom->option, | ||
3139 | zfcp_get_busid_by_adapter(adapter)); | ||
3140 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3141 | retval = -EINVAL; | ||
3142 | break; | ||
3143 | |||
3144 | case FSF_GOOD: | 1814 | case FSF_GOOD: |
3145 | /* save LUN handle assigned by FSF */ | ||
3146 | unit->handle = header->lun_handle; | 1815 | unit->handle = header->lun_handle; |
3147 | ZFCP_LOG_TRACE("unit 0x%016Lx on remote port 0x%016Lx on " | ||
3148 | "adapter %s opened, port handle 0x%x\n", | ||
3149 | unit->fcp_lun, | ||
3150 | unit->port->wwpn, | ||
3151 | zfcp_get_busid_by_unit(unit), | ||
3152 | unit->handle); | ||
3153 | /* mark unit as open */ | ||
3154 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); | 1816 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); |
3155 | 1817 | ||
3156 | if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && | 1818 | if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && |
@@ -3168,1528 +1830,629 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) | |||
3168 | if (!readwrite) { | 1830 | if (!readwrite) { |
3169 | atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, | 1831 | atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, |
3170 | &unit->status); | 1832 | &unit->status); |
3171 | ZFCP_LOG_NORMAL("read-only access for unit " | 1833 | dev_info(&adapter->ccw_device->dev, |
3172 | "(adapter %s, wwpn=0x%016Lx, " | 1834 | "Read-only access for unit 0x%016Lx " |
3173 | "fcp_lun=0x%016Lx)\n", | 1835 | "on port 0x%016Lx.\n", |
3174 | zfcp_get_busid_by_unit(unit), | 1836 | unit->fcp_lun, unit->port->wwpn); |
3175 | unit->port->wwpn, | ||
3176 | unit->fcp_lun); | ||
3177 | } | 1837 | } |
3178 | 1838 | ||
3179 | if (exclusive && !readwrite) { | 1839 | if (exclusive && !readwrite) { |
3180 | ZFCP_LOG_NORMAL("exclusive access of read-only " | 1840 | dev_err(&adapter->ccw_device->dev, |
3181 | "unit not supported\n"); | 1841 | "Exclusive access of read-only unit " |
3182 | zfcp_erp_unit_failed(unit, 35, fsf_req); | 1842 | "0x%016Lx on port 0x%016Lx not " |
3183 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1843 | "supported, disabling unit.\n", |
3184 | zfcp_erp_unit_shutdown(unit, 0, 80, fsf_req); | 1844 | unit->fcp_lun, unit->port->wwpn); |
1845 | zfcp_erp_unit_failed(unit, 35, req); | ||
1846 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1847 | zfcp_erp_unit_shutdown(unit, 0, 80, req); | ||
3185 | } else if (!exclusive && readwrite) { | 1848 | } else if (!exclusive && readwrite) { |
3186 | ZFCP_LOG_NORMAL("shared access of read-write " | 1849 | dev_err(&adapter->ccw_device->dev, |
3187 | "unit not supported\n"); | 1850 | "Shared access of read-write unit " |
3188 | zfcp_erp_unit_failed(unit, 36, fsf_req); | 1851 | "0x%016Lx on port 0x%016Lx not " |
3189 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1852 | "supported, disabling unit.\n", |
3190 | zfcp_erp_unit_shutdown(unit, 0, 81, fsf_req); | 1853 | unit->fcp_lun, unit->port->wwpn); |
1854 | zfcp_erp_unit_failed(unit, 36, req); | ||
1855 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
1856 | zfcp_erp_unit_shutdown(unit, 0, 81, req); | ||
3191 | } | 1857 | } |
3192 | } | 1858 | } |
3193 | |||
3194 | retval = 0; | ||
3195 | break; | ||
3196 | |||
3197 | default: | ||
3198 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
3199 | "(debug info 0x%x)\n", | ||
3200 | header->fsf_status); | ||
3201 | break; | 1859 | break; |
3202 | } | 1860 | } |
3203 | 1861 | ||
3204 | skip_fsfstatus: | 1862 | skip_fsfstatus: |
3205 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status); | 1863 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status); |
3206 | return retval; | ||
3207 | } | 1864 | } |
3208 | 1865 | ||
3209 | /* | 1866 | /** |
3210 | * function: zfcp_fsf_close_unit | 1867 | * zfcp_fsf_open_unit - open unit |
3211 | * | 1868 | * @erp_action: pointer to struct zfcp_erp_action |
3212 | * purpose: | 1869 | * Returns: 0 on success, error otherwise |
3213 | * | ||
3214 | * returns: address of fsf_req - request successfully initiated | ||
3215 | * NULL - | ||
3216 | * | ||
3217 | * assumptions: This routine does not check whether the associated | ||
3218 | * remote port/lun has already been opened. This should be | ||
3219 | * done by calling routines. Otherwise some status | ||
3220 | * may be presented by FSF | ||
3221 | */ | 1870 | */ |
3222 | int | 1871 | int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) |
3223 | zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) | ||
3224 | { | 1872 | { |
3225 | volatile struct qdio_buffer_element *sbale; | 1873 | volatile struct qdio_buffer_element *sbale; |
3226 | struct zfcp_fsf_req *fsf_req; | 1874 | struct zfcp_adapter *adapter = erp_action->adapter; |
3227 | unsigned long lock_flags; | 1875 | struct zfcp_fsf_req *req; |
3228 | int retval = 0; | 1876 | int retval = -EIO; |
3229 | 1877 | ||
3230 | /* setup new FSF request */ | 1878 | spin_lock(&adapter->req_q.lock); |
3231 | retval = zfcp_fsf_req_create(erp_action->adapter, | 1879 | if (zfcp_fsf_req_sbal_get(adapter)) |
3232 | FSF_QTCB_CLOSE_LUN, | 1880 | goto out; |
3233 | ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP, | 1881 | |
3234 | erp_action->adapter->pool.fsf_req_erp, | 1882 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_LUN, |
3235 | &lock_flags, &fsf_req); | 1883 | ZFCP_REQ_AUTO_CLEANUP, |
3236 | if (retval < 0) { | 1884 | adapter->pool.fsf_req_erp); |
3237 | ZFCP_LOG_INFO("error: Could not create close unit request for " | 1885 | if (unlikely(IS_ERR(req))) { |
3238 | "unit 0x%016Lx on port 0x%016Lx on adapter %s.\n", | 1886 | retval = PTR_ERR(req); |
3239 | erp_action->unit->fcp_lun, | ||
3240 | erp_action->port->wwpn, | ||
3241 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
3242 | goto out; | 1887 | goto out; |
3243 | } | 1888 | } |
3244 | 1889 | ||
3245 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 1890 | sbale = zfcp_qdio_sbale_req(req); |
3246 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; | 1891 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
3247 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1892 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
3248 | 1893 | ||
3249 | fsf_req->qtcb->header.port_handle = erp_action->port->handle; | 1894 | req->qtcb->header.port_handle = erp_action->port->handle; |
3250 | fsf_req->qtcb->header.lun_handle = erp_action->unit->handle; | 1895 | req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun; |
3251 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status); | 1896 | req->handler = zfcp_fsf_open_unit_handler; |
3252 | fsf_req->data = (unsigned long) erp_action->unit; | 1897 | req->data = erp_action->unit; |
3253 | fsf_req->erp_action = erp_action; | 1898 | req->erp_action = erp_action; |
3254 | erp_action->fsf_req = fsf_req; | 1899 | erp_action->fsf_req = req; |
3255 | 1900 | ||
3256 | zfcp_erp_start_timer(fsf_req); | 1901 | if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) |
3257 | retval = zfcp_fsf_req_send(erp_action->fsf_req); | 1902 | req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING; |
1903 | |||
1904 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); | ||
1905 | |||
1906 | zfcp_fsf_start_erp_timer(req); | ||
1907 | retval = zfcp_fsf_req_send(req); | ||
3258 | if (retval) { | 1908 | if (retval) { |
3259 | ZFCP_LOG_INFO("error: Could not send a close unit request for " | 1909 | zfcp_fsf_req_free(req); |
3260 | "unit 0x%016Lx on port 0x%016Lx onadapter %s.\n", | ||
3261 | erp_action->unit->fcp_lun, | ||
3262 | erp_action->port->wwpn, | ||
3263 | zfcp_get_busid_by_adapter(erp_action->adapter)); | ||
3264 | zfcp_fsf_req_free(fsf_req); | ||
3265 | erp_action->fsf_req = NULL; | 1910 | erp_action->fsf_req = NULL; |
3266 | goto out; | ||
3267 | } | 1911 | } |
3268 | 1912 | out: | |
3269 | ZFCP_LOG_TRACE("Close LUN request initiated (adapter %s, " | 1913 | spin_unlock(&adapter->req_q.lock); |
3270 | "port 0x%016Lx, unit 0x%016Lx)\n", | ||
3271 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
3272 | erp_action->port->wwpn, erp_action->unit->fcp_lun); | ||
3273 | out: | ||
3274 | write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock, | ||
3275 | lock_flags); | ||
3276 | return retval; | 1914 | return retval; |
3277 | } | 1915 | } |
3278 | 1916 | ||
3279 | /* | 1917 | static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req) |
3280 | * function: zfcp_fsf_close_unit_handler | ||
3281 | * | ||
3282 | * purpose: is called for finished Close LUN FSF command | ||
3283 | * | ||
3284 | * returns: | ||
3285 | */ | ||
3286 | static int | ||
3287 | zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req) | ||
3288 | { | 1918 | { |
3289 | int retval = -EINVAL; | 1919 | struct zfcp_unit *unit = req->data; |
3290 | struct zfcp_unit *unit; | ||
3291 | |||
3292 | unit = (struct zfcp_unit *) fsf_req->data; | ||
3293 | 1920 | ||
3294 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | 1921 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
3295 | /* don't change unit status in our bookkeeping */ | ||
3296 | goto skip_fsfstatus; | 1922 | goto skip_fsfstatus; |
3297 | } | ||
3298 | |||
3299 | /* evaluate FSF status in QTCB */ | ||
3300 | switch (fsf_req->qtcb->header.fsf_status) { | ||
3301 | 1923 | ||
1924 | switch (req->qtcb->header.fsf_status) { | ||
3302 | case FSF_PORT_HANDLE_NOT_VALID: | 1925 | case FSF_PORT_HANDLE_NOT_VALID: |
3303 | ZFCP_LOG_INFO("Temporary port identifier 0x%x for port " | 1926 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 110, req); |
3304 | "0x%016Lx on adapter %s invalid. This may " | 1927 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
3305 | "happen in rare circumstances\n", | ||
3306 | unit->port->handle, | ||
3307 | unit->port->wwpn, | ||
3308 | zfcp_get_busid_by_unit(unit)); | ||
3309 | ZFCP_LOG_DEBUG("status qualifier:\n"); | ||
3310 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3311 | (char *) &fsf_req->qtcb->header.fsf_status_qual, | ||
3312 | sizeof (union fsf_status_qual)); | ||
3313 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 110, fsf_req); | ||
3314 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3315 | break; | 1928 | break; |
3316 | |||
3317 | case FSF_LUN_HANDLE_NOT_VALID: | 1929 | case FSF_LUN_HANDLE_NOT_VALID: |
3318 | ZFCP_LOG_INFO("Temporary LUN identifier 0x%x of unit " | 1930 | zfcp_erp_port_reopen(unit->port, 0, 111, req); |
3319 | "0x%016Lx on port 0x%016Lx on adapter %s is " | 1931 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
3320 | "invalid. This may happen occasionally.\n", | ||
3321 | unit->handle, | ||
3322 | unit->fcp_lun, | ||
3323 | unit->port->wwpn, | ||
3324 | zfcp_get_busid_by_unit(unit)); | ||
3325 | ZFCP_LOG_DEBUG("Status qualifier data:\n"); | ||
3326 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3327 | (char *) &fsf_req->qtcb->header.fsf_status_qual, | ||
3328 | sizeof (union fsf_status_qual)); | ||
3329 | zfcp_erp_port_reopen(unit->port, 0, 111, fsf_req); | ||
3330 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3331 | break; | 1932 | break; |
3332 | |||
3333 | case FSF_PORT_BOXED: | 1933 | case FSF_PORT_BOXED: |
3334 | ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s " | 1934 | zfcp_erp_port_boxed(unit->port, 52, req); |
3335 | "needs to be reopened\n", | 1935 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
3336 | unit->port->wwpn, | 1936 | ZFCP_STATUS_FSFREQ_RETRY; |
3337 | zfcp_get_busid_by_unit(unit)); | ||
3338 | zfcp_erp_port_boxed(unit->port, 52, fsf_req); | ||
3339 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | ||
3340 | ZFCP_STATUS_FSFREQ_RETRY; | ||
3341 | break; | 1937 | break; |
3342 | |||
3343 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1938 | case FSF_ADAPTER_STATUS_AVAILABLE: |
3344 | switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) { | 1939 | switch (req->qtcb->header.fsf_status_qual.word[0]) { |
3345 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 1940 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
3346 | /* re-establish link to port */ | ||
3347 | zfcp_test_link(unit->port); | 1941 | zfcp_test_link(unit->port); |
3348 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1942 | /* fall through */ |
3349 | break; | ||
3350 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 1943 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
3351 | /* ERP strategy will escalate */ | 1944 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
3352 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3353 | break; | ||
3354 | default: | ||
3355 | ZFCP_LOG_NORMAL | ||
3356 | ("bug: Wrong status qualifier 0x%x arrived.\n", | ||
3357 | fsf_req->qtcb->header.fsf_status_qual.word[0]); | ||
3358 | break; | 1945 | break; |
3359 | } | 1946 | } |
3360 | break; | 1947 | break; |
3361 | |||
3362 | case FSF_GOOD: | 1948 | case FSF_GOOD: |
3363 | ZFCP_LOG_TRACE("unit 0x%016Lx on port 0x%016Lx on adapter %s " | ||
3364 | "closed, port handle 0x%x\n", | ||
3365 | unit->fcp_lun, | ||
3366 | unit->port->wwpn, | ||
3367 | zfcp_get_busid_by_unit(unit), | ||
3368 | unit->handle); | ||
3369 | /* mark unit as closed */ | ||
3370 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); | 1949 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); |
3371 | retval = 0; | ||
3372 | break; | ||
3373 | |||
3374 | default: | ||
3375 | ZFCP_LOG_NORMAL("bug: An unknown FSF Status was presented " | ||
3376 | "(debug info 0x%x)\n", | ||
3377 | fsf_req->qtcb->header.fsf_status); | ||
3378 | break; | 1950 | break; |
3379 | } | 1951 | } |
3380 | 1952 | skip_fsfstatus: | |
3381 | skip_fsfstatus: | ||
3382 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status); | 1953 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status); |
3383 | return retval; | ||
3384 | } | 1954 | } |
3385 | 1955 | ||
3386 | /** | 1956 | /** |
3387 | * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) | 1957 | * zfcp_fsf_close_unit - close zfcp unit |
3388 | * @adapter: adapter where scsi command is issued | 1958 | * @erp_action: pointer to struct zfcp_unit |
3389 | * @unit: unit where command is sent to | 1959 | * Returns: 0 on success, error otherwise |
3390 | * @scsi_cmnd: scsi command to be sent | ||
3391 | * @timer: timer to be started when request is initiated | ||
3392 | * @req_flags: flags for fsf_request | ||
3393 | */ | 1960 | */ |
3394 | int | 1961 | int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) |
3395 | zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, | ||
3396 | struct zfcp_unit *unit, | ||
3397 | struct scsi_cmnd * scsi_cmnd, | ||
3398 | int use_timer, int req_flags) | ||
3399 | { | 1962 | { |
3400 | struct zfcp_fsf_req *fsf_req = NULL; | 1963 | volatile struct qdio_buffer_element *sbale; |
3401 | struct fcp_cmnd_iu *fcp_cmnd_iu; | 1964 | struct zfcp_adapter *adapter = erp_action->adapter; |
3402 | unsigned int sbtype; | 1965 | struct zfcp_fsf_req *req; |
3403 | unsigned long lock_flags; | 1966 | int retval = -EIO; |
3404 | int real_bytes = 0; | ||
3405 | int retval = 0; | ||
3406 | int mask; | ||
3407 | |||
3408 | /* setup new FSF request */ | ||
3409 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, | ||
3410 | adapter->pool.fsf_req_scsi, | ||
3411 | &lock_flags, &fsf_req); | ||
3412 | if (unlikely(retval < 0)) { | ||
3413 | ZFCP_LOG_DEBUG("error: Could not create FCP command request " | ||
3414 | "for unit 0x%016Lx on port 0x%016Lx on " | ||
3415 | "adapter %s\n", | ||
3416 | unit->fcp_lun, | ||
3417 | unit->port->wwpn, | ||
3418 | zfcp_get_busid_by_adapter(adapter)); | ||
3419 | goto failed_req_create; | ||
3420 | } | ||
3421 | |||
3422 | if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
3423 | &unit->status))) { | ||
3424 | retval = -EBUSY; | ||
3425 | goto unit_blocked; | ||
3426 | } | ||
3427 | |||
3428 | zfcp_unit_get(unit); | ||
3429 | fsf_req->unit = unit; | ||
3430 | |||
3431 | /* associate FSF request with SCSI request (for look up on abort) */ | ||
3432 | scsi_cmnd->host_scribble = (unsigned char *) fsf_req->req_id; | ||
3433 | |||
3434 | /* associate SCSI command with FSF request */ | ||
3435 | fsf_req->data = (unsigned long) scsi_cmnd; | ||
3436 | |||
3437 | /* set handles of unit and its parent port in QTCB */ | ||
3438 | fsf_req->qtcb->header.lun_handle = unit->handle; | ||
3439 | fsf_req->qtcb->header.port_handle = unit->port->handle; | ||
3440 | |||
3441 | /* FSF does not define the structure of the FCP_CMND IU */ | ||
3442 | fcp_cmnd_iu = (struct fcp_cmnd_iu *) | ||
3443 | &(fsf_req->qtcb->bottom.io.fcp_cmnd); | ||
3444 | |||
3445 | /* | ||
3446 | * set depending on data direction: | ||
3447 | * data direction bits in SBALE (SB Type) | ||
3448 | * data direction bits in QTCB | ||
3449 | * data direction bits in FCP_CMND IU | ||
3450 | */ | ||
3451 | switch (scsi_cmnd->sc_data_direction) { | ||
3452 | case DMA_NONE: | ||
3453 | fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; | ||
3454 | /* | ||
3455 | * FIXME(qdio): | ||
3456 | * what is the correct type for commands | ||
3457 | * without 'real' data buffers? | ||
3458 | */ | ||
3459 | sbtype = SBAL_FLAGS0_TYPE_READ; | ||
3460 | break; | ||
3461 | case DMA_FROM_DEVICE: | ||
3462 | fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; | ||
3463 | sbtype = SBAL_FLAGS0_TYPE_READ; | ||
3464 | fcp_cmnd_iu->rddata = 1; | ||
3465 | break; | ||
3466 | case DMA_TO_DEVICE: | ||
3467 | fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE; | ||
3468 | sbtype = SBAL_FLAGS0_TYPE_WRITE; | ||
3469 | fcp_cmnd_iu->wddata = 1; | ||
3470 | break; | ||
3471 | case DMA_BIDIRECTIONAL: | ||
3472 | default: | ||
3473 | /* | ||
3474 | * dummy, catch this condition earlier | ||
3475 | * in zfcp_scsi_queuecommand | ||
3476 | */ | ||
3477 | goto failed_scsi_cmnd; | ||
3478 | } | ||
3479 | |||
3480 | /* set FC service class in QTCB (3 per default) */ | ||
3481 | fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT; | ||
3482 | |||
3483 | /* set FCP_LUN in FCP_CMND IU in QTCB */ | ||
3484 | fcp_cmnd_iu->fcp_lun = unit->fcp_lun; | ||
3485 | |||
3486 | mask = ZFCP_STATUS_UNIT_READONLY | ZFCP_STATUS_UNIT_SHARED; | ||
3487 | |||
3488 | /* set task attributes in FCP_CMND IU in QTCB */ | ||
3489 | if (likely((scsi_cmnd->device->simple_tags) || | ||
3490 | (atomic_test_mask(mask, &unit->status)))) | ||
3491 | fcp_cmnd_iu->task_attribute = SIMPLE_Q; | ||
3492 | else | ||
3493 | fcp_cmnd_iu->task_attribute = UNTAGGED; | ||
3494 | |||
3495 | /* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */ | ||
3496 | if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) { | ||
3497 | fcp_cmnd_iu->add_fcp_cdb_length | ||
3498 | = (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2; | ||
3499 | ZFCP_LOG_TRACE("SCSI CDB length is 0x%x, " | ||
3500 | "additional FCP_CDB length is 0x%x " | ||
3501 | "(shifted right 2 bits)\n", | ||
3502 | scsi_cmnd->cmd_len, | ||
3503 | fcp_cmnd_iu->add_fcp_cdb_length); | ||
3504 | } | ||
3505 | /* | ||
3506 | * copy SCSI CDB (including additional length, if any) to | ||
3507 | * FCP_CDB in FCP_CMND IU in QTCB | ||
3508 | */ | ||
3509 | memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); | ||
3510 | |||
3511 | /* FCP CMND IU length in QTCB */ | ||
3512 | fsf_req->qtcb->bottom.io.fcp_cmnd_length = | ||
3513 | sizeof (struct fcp_cmnd_iu) + | ||
3514 | fcp_cmnd_iu->add_fcp_cdb_length + sizeof (fcp_dl_t); | ||
3515 | 1967 | ||
3516 | /* generate SBALEs from data buffer */ | 1968 | spin_lock(&adapter->req_q.lock); |
3517 | real_bytes = zfcp_qdio_sbals_from_scsicmnd(fsf_req, sbtype, scsi_cmnd); | 1969 | if (zfcp_fsf_req_sbal_get(adapter)) |
3518 | if (unlikely(real_bytes < 0)) { | 1970 | goto out; |
3519 | if (fsf_req->sbal_number < ZFCP_MAX_SBALS_PER_REQ) { | 1971 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN, |
3520 | ZFCP_LOG_DEBUG( | 1972 | ZFCP_REQ_AUTO_CLEANUP, |
3521 | "Data did not fit into available buffer(s), " | 1973 | adapter->pool.fsf_req_erp); |
3522 | "waiting for more...\n"); | 1974 | if (unlikely(IS_ERR(req))) { |
3523 | retval = -EIO; | 1975 | retval = PTR_ERR(req); |
3524 | } else { | 1976 | goto out; |
3525 | ZFCP_LOG_NORMAL("error: No truncation implemented but " | ||
3526 | "required. Shutting down unit " | ||
3527 | "(adapter %s, port 0x%016Lx, " | ||
3528 | "unit 0x%016Lx)\n", | ||
3529 | zfcp_get_busid_by_unit(unit), | ||
3530 | unit->port->wwpn, | ||
3531 | unit->fcp_lun); | ||
3532 | zfcp_erp_unit_shutdown(unit, 0, 131, fsf_req); | ||
3533 | retval = -EINVAL; | ||
3534 | } | ||
3535 | goto no_fit; | ||
3536 | } | 1977 | } |
3537 | 1978 | ||
3538 | /* set length of FCP data length in FCP_CMND IU in QTCB */ | 1979 | sbale = zfcp_qdio_sbale_req(req); |
3539 | zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes); | 1980 | sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; |
1981 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
3540 | 1982 | ||
3541 | ZFCP_LOG_DEBUG("Sending SCSI command:\n"); | 1983 | req->qtcb->header.port_handle = erp_action->port->handle; |
3542 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | 1984 | req->qtcb->header.lun_handle = erp_action->unit->handle; |
3543 | (char *) scsi_cmnd->cmnd, scsi_cmnd->cmd_len); | 1985 | req->handler = zfcp_fsf_close_unit_handler; |
1986 | req->data = erp_action->unit; | ||
1987 | req->erp_action = erp_action; | ||
1988 | erp_action->fsf_req = req; | ||
1989 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status); | ||
3544 | 1990 | ||
3545 | if (use_timer) | 1991 | zfcp_fsf_start_erp_timer(req); |
3546 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | 1992 | retval = zfcp_fsf_req_send(req); |
3547 | 1993 | if (retval) { | |
3548 | retval = zfcp_fsf_req_send(fsf_req); | 1994 | zfcp_fsf_req_free(req); |
3549 | if (unlikely(retval < 0)) { | 1995 | erp_action->fsf_req = NULL; |
3550 | ZFCP_LOG_INFO("error: Could not send FCP command request " | ||
3551 | "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n", | ||
3552 | zfcp_get_busid_by_adapter(adapter), | ||
3553 | unit->port->wwpn, | ||
3554 | unit->fcp_lun); | ||
3555 | goto send_failed; | ||
3556 | } | 1996 | } |
3557 | 1997 | out: | |
3558 | ZFCP_LOG_TRACE("Send FCP Command initiated (adapter %s, " | 1998 | spin_unlock(&adapter->req_q.lock); |
3559 | "port 0x%016Lx, unit 0x%016Lx)\n", | ||
3560 | zfcp_get_busid_by_adapter(adapter), | ||
3561 | unit->port->wwpn, | ||
3562 | unit->fcp_lun); | ||
3563 | goto success; | ||
3564 | |||
3565 | send_failed: | ||
3566 | no_fit: | ||
3567 | failed_scsi_cmnd: | ||
3568 | zfcp_unit_put(unit); | ||
3569 | unit_blocked: | ||
3570 | zfcp_fsf_req_free(fsf_req); | ||
3571 | fsf_req = NULL; | ||
3572 | scsi_cmnd->host_scribble = NULL; | ||
3573 | success: | ||
3574 | failed_req_create: | ||
3575 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | ||
3576 | return retval; | 1999 | return retval; |
3577 | } | 2000 | } |
3578 | 2001 | ||
3579 | struct zfcp_fsf_req * | 2002 | static void zfcp_fsf_update_lat(struct fsf_latency_record *lat_rec, u32 lat) |
3580 | zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, | ||
3581 | struct zfcp_unit *unit, | ||
3582 | u8 tm_flags, int req_flags) | ||
3583 | { | 2003 | { |
3584 | struct zfcp_fsf_req *fsf_req = NULL; | 2004 | lat_rec->sum += lat; |
3585 | int retval = 0; | 2005 | lat_rec->min = min(lat_rec->min, lat); |
3586 | struct fcp_cmnd_iu *fcp_cmnd_iu; | 2006 | lat_rec->max = max(lat_rec->max, lat); |
3587 | unsigned long lock_flags; | ||
3588 | volatile struct qdio_buffer_element *sbale; | ||
3589 | |||
3590 | /* setup new FSF request */ | ||
3591 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, | ||
3592 | adapter->pool.fsf_req_scsi, | ||
3593 | &lock_flags, &fsf_req); | ||
3594 | if (retval < 0) { | ||
3595 | ZFCP_LOG_INFO("error: Could not create FCP command (task " | ||
3596 | "management) request for adapter %s, port " | ||
3597 | " 0x%016Lx, unit 0x%016Lx.\n", | ||
3598 | zfcp_get_busid_by_adapter(adapter), | ||
3599 | unit->port->wwpn, unit->fcp_lun); | ||
3600 | goto out; | ||
3601 | } | ||
3602 | |||
3603 | if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
3604 | &unit->status))) | ||
3605 | goto unit_blocked; | ||
3606 | |||
3607 | /* | ||
3608 | * Used to decide on proper handler in the return path, | ||
3609 | * could be either zfcp_fsf_send_fcp_command_task_handler or | ||
3610 | * zfcp_fsf_send_fcp_command_task_management_handler */ | ||
3611 | |||
3612 | fsf_req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT; | ||
3613 | |||
3614 | /* | ||
3615 | * hold a pointer to the unit being target of this | ||
3616 | * task management request | ||
3617 | */ | ||
3618 | fsf_req->data = (unsigned long) unit; | ||
3619 | |||
3620 | /* set FSF related fields in QTCB */ | ||
3621 | fsf_req->qtcb->header.lun_handle = unit->handle; | ||
3622 | fsf_req->qtcb->header.port_handle = unit->port->handle; | ||
3623 | fsf_req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; | ||
3624 | fsf_req->qtcb->bottom.io.service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT; | ||
3625 | fsf_req->qtcb->bottom.io.fcp_cmnd_length = | ||
3626 | sizeof (struct fcp_cmnd_iu) + sizeof (fcp_dl_t); | ||
3627 | |||
3628 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | ||
3629 | sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; | ||
3630 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
3631 | |||
3632 | /* set FCP related fields in FCP_CMND IU in QTCB */ | ||
3633 | fcp_cmnd_iu = (struct fcp_cmnd_iu *) | ||
3634 | &(fsf_req->qtcb->bottom.io.fcp_cmnd); | ||
3635 | fcp_cmnd_iu->fcp_lun = unit->fcp_lun; | ||
3636 | fcp_cmnd_iu->task_management_flags = tm_flags; | ||
3637 | |||
3638 | zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT); | ||
3639 | retval = zfcp_fsf_req_send(fsf_req); | ||
3640 | if (!retval) | ||
3641 | goto out; | ||
3642 | |||
3643 | unit_blocked: | ||
3644 | zfcp_fsf_req_free(fsf_req); | ||
3645 | fsf_req = NULL; | ||
3646 | |||
3647 | out: | ||
3648 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | ||
3649 | return fsf_req; | ||
3650 | } | 2007 | } |
3651 | 2008 | ||
3652 | /* | 2009 | static void zfcp_fsf_req_latency(struct zfcp_fsf_req *req) |
3653 | * function: zfcp_fsf_send_fcp_command_handler | ||
3654 | * | ||
3655 | * purpose: is called for finished Send FCP Command | ||
3656 | * | ||
3657 | * returns: | ||
3658 | */ | ||
3659 | static int | ||
3660 | zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) | ||
3661 | { | 2010 | { |
3662 | int retval = -EINVAL; | 2011 | struct fsf_qual_latency_info *lat_inf; |
3663 | struct zfcp_unit *unit; | 2012 | struct latency_cont *lat; |
3664 | struct fsf_qtcb_header *header; | 2013 | struct zfcp_unit *unit = req->unit; |
3665 | u16 subtable, rule, counter; | 2014 | unsigned long flags; |
3666 | |||
3667 | header = &fsf_req->qtcb->header; | ||
3668 | |||
3669 | if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)) | ||
3670 | unit = (struct zfcp_unit *) fsf_req->data; | ||
3671 | else | ||
3672 | unit = fsf_req->unit; | ||
3673 | |||
3674 | if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { | ||
3675 | /* go directly to calls of special handlers */ | ||
3676 | goto skip_fsfstatus; | ||
3677 | } | ||
3678 | |||
3679 | /* evaluate FSF status in QTCB */ | ||
3680 | switch (header->fsf_status) { | ||
3681 | |||
3682 | case FSF_PORT_HANDLE_NOT_VALID: | ||
3683 | ZFCP_LOG_INFO("Temporary port identifier 0x%x for port " | ||
3684 | "0x%016Lx on adapter %s invalid\n", | ||
3685 | unit->port->handle, | ||
3686 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | ||
3687 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3688 | (char *) &header->fsf_status_qual, | ||
3689 | sizeof (union fsf_status_qual)); | ||
3690 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 112, fsf_req); | ||
3691 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3692 | break; | ||
3693 | |||
3694 | case FSF_LUN_HANDLE_NOT_VALID: | ||
3695 | ZFCP_LOG_INFO("Temporary LUN identifier 0x%x for unit " | ||
3696 | "0x%016Lx on port 0x%016Lx on adapter %s is " | ||
3697 | "invalid. This may happen occasionally.\n", | ||
3698 | unit->handle, | ||
3699 | unit->fcp_lun, | ||
3700 | unit->port->wwpn, | ||
3701 | zfcp_get_busid_by_unit(unit)); | ||
3702 | ZFCP_LOG_NORMAL("Status qualifier data:\n"); | ||
3703 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, | ||
3704 | (char *) &header->fsf_status_qual, | ||
3705 | sizeof (union fsf_status_qual)); | ||
3706 | zfcp_erp_port_reopen(unit->port, 0, 113, fsf_req); | ||
3707 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3708 | break; | ||
3709 | |||
3710 | case FSF_HANDLE_MISMATCH: | ||
3711 | ZFCP_LOG_NORMAL("bug: The port handle 0x%x has changed " | ||
3712 | "unexpectedly. (adapter %s, port 0x%016Lx, " | ||
3713 | "unit 0x%016Lx)\n", | ||
3714 | unit->port->handle, | ||
3715 | zfcp_get_busid_by_unit(unit), | ||
3716 | unit->port->wwpn, | ||
3717 | unit->fcp_lun); | ||
3718 | ZFCP_LOG_NORMAL("status qualifier:\n"); | ||
3719 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, | ||
3720 | (char *) &header->fsf_status_qual, | ||
3721 | sizeof (union fsf_status_qual)); | ||
3722 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 114, fsf_req); | ||
3723 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3724 | break; | ||
3725 | |||
3726 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: | ||
3727 | ZFCP_LOG_INFO("error: adapter %s does not support fc " | ||
3728 | "class %d.\n", | ||
3729 | zfcp_get_busid_by_unit(unit), | ||
3730 | ZFCP_FC_SERVICE_CLASS_DEFAULT); | ||
3731 | /* stop operation for this adapter */ | ||
3732 | zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 132, fsf_req); | ||
3733 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3734 | break; | ||
3735 | |||
3736 | case FSF_FCPLUN_NOT_VALID: | ||
3737 | ZFCP_LOG_NORMAL("bug: unit 0x%016Lx on port 0x%016Lx on " | ||
3738 | "adapter %s does not have correct unit " | ||
3739 | "handle 0x%x\n", | ||
3740 | unit->fcp_lun, | ||
3741 | unit->port->wwpn, | ||
3742 | zfcp_get_busid_by_unit(unit), | ||
3743 | unit->handle); | ||
3744 | ZFCP_LOG_DEBUG("status qualifier:\n"); | ||
3745 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3746 | (char *) &header->fsf_status_qual, | ||
3747 | sizeof (union fsf_status_qual)); | ||
3748 | zfcp_erp_port_reopen(unit->port, 0, 115, fsf_req); | ||
3749 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3750 | break; | ||
3751 | |||
3752 | case FSF_ACCESS_DENIED: | ||
3753 | ZFCP_LOG_NORMAL("Access denied, cannot send FCP command to " | ||
3754 | "unit 0x%016Lx on port 0x%016Lx on " | ||
3755 | "adapter %s\n", unit->fcp_lun, unit->port->wwpn, | ||
3756 | zfcp_get_busid_by_unit(unit)); | ||
3757 | for (counter = 0; counter < 2; counter++) { | ||
3758 | subtable = header->fsf_status_qual.halfword[counter * 2]; | ||
3759 | rule = header->fsf_status_qual.halfword[counter * 2 + 1]; | ||
3760 | switch (subtable) { | ||
3761 | case FSF_SQ_CFDC_SUBTABLE_OS: | ||
3762 | case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN: | ||
3763 | case FSF_SQ_CFDC_SUBTABLE_PORT_DID: | ||
3764 | case FSF_SQ_CFDC_SUBTABLE_LUN: | ||
3765 | ZFCP_LOG_INFO("Access denied (%s rule %d)\n", | ||
3766 | zfcp_act_subtable_type[subtable], rule); | ||
3767 | break; | ||
3768 | } | ||
3769 | } | ||
3770 | zfcp_erp_unit_access_denied(unit, 61, fsf_req); | ||
3771 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3772 | break; | ||
3773 | |||
3774 | case FSF_DIRECTION_INDICATOR_NOT_VALID: | ||
3775 | ZFCP_LOG_INFO("bug: Invalid data direction given for unit " | ||
3776 | "0x%016Lx on port 0x%016Lx on adapter %s " | ||
3777 | "(debug info %d)\n", | ||
3778 | unit->fcp_lun, | ||
3779 | unit->port->wwpn, | ||
3780 | zfcp_get_busid_by_unit(unit), | ||
3781 | fsf_req->qtcb->bottom.io.data_direction); | ||
3782 | /* stop operation for this adapter */ | ||
3783 | zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, fsf_req); | ||
3784 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3785 | break; | ||
3786 | |||
3787 | case FSF_CMND_LENGTH_NOT_VALID: | ||
3788 | ZFCP_LOG_NORMAL | ||
3789 | ("bug: An invalid control-data-block length field " | ||
3790 | "was found in a command for unit 0x%016Lx on port " | ||
3791 | "0x%016Lx on adapter %s " "(debug info %d)\n", | ||
3792 | unit->fcp_lun, unit->port->wwpn, | ||
3793 | zfcp_get_busid_by_unit(unit), | ||
3794 | fsf_req->qtcb->bottom.io.fcp_cmnd_length); | ||
3795 | /* stop operation for this adapter */ | ||
3796 | zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, fsf_req); | ||
3797 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3798 | break; | ||
3799 | 2015 | ||
3800 | case FSF_PORT_BOXED: | 2016 | lat_inf = &req->qtcb->prefix.prot_status_qual.latency_info; |
3801 | ZFCP_LOG_DEBUG("The remote port 0x%016Lx on adapter %s " | ||
3802 | "needs to be reopened\n", | ||
3803 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | ||
3804 | zfcp_erp_port_boxed(unit->port, 53, fsf_req); | ||
3805 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | | ||
3806 | ZFCP_STATUS_FSFREQ_RETRY; | ||
3807 | break; | ||
3808 | 2017 | ||
3809 | case FSF_LUN_BOXED: | 2018 | switch (req->qtcb->bottom.io.data_direction) { |
3810 | ZFCP_LOG_NORMAL("unit needs to be reopened (adapter %s, " | 2019 | case FSF_DATADIR_READ: |
3811 | "wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n", | 2020 | lat = &unit->latencies.read; |
3812 | zfcp_get_busid_by_unit(unit), | ||
3813 | unit->port->wwpn, unit->fcp_lun); | ||
3814 | zfcp_erp_unit_boxed(unit, 54, fsf_req); | ||
3815 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ||
3816 | | ZFCP_STATUS_FSFREQ_RETRY; | ||
3817 | break; | ||
3818 | |||
3819 | case FSF_ADAPTER_STATUS_AVAILABLE: | ||
3820 | switch (header->fsf_status_qual.word[0]) { | ||
3821 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | ||
3822 | /* re-establish link to port */ | ||
3823 | zfcp_test_link(unit->port); | ||
3824 | break; | ||
3825 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | ||
3826 | /* FIXME(hw) need proper specs for proper action */ | ||
3827 | /* let scsi stack deal with retries and escalation */ | ||
3828 | break; | ||
3829 | default: | ||
3830 | ZFCP_LOG_NORMAL | ||
3831 | ("Unknown status qualifier 0x%x arrived.\n", | ||
3832 | header->fsf_status_qual.word[0]); | ||
3833 | break; | ||
3834 | } | ||
3835 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
3836 | break; | 2021 | break; |
3837 | 2022 | case FSF_DATADIR_WRITE: | |
3838 | case FSF_GOOD: | 2023 | lat = &unit->latencies.write; |
3839 | break; | 2024 | break; |
3840 | 2025 | case FSF_DATADIR_CMND: | |
3841 | case FSF_FCP_RSP_AVAILABLE: | 2026 | lat = &unit->latencies.cmd; |
3842 | break; | 2027 | break; |
2028 | default: | ||
2029 | return; | ||
3843 | } | 2030 | } |
3844 | 2031 | ||
3845 | skip_fsfstatus: | 2032 | spin_lock_irqsave(&unit->latencies.lock, flags); |
3846 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) { | 2033 | zfcp_fsf_update_lat(&lat->channel, lat_inf->channel_lat); |
3847 | retval = | 2034 | zfcp_fsf_update_lat(&lat->fabric, lat_inf->fabric_lat); |
3848 | zfcp_fsf_send_fcp_command_task_management_handler(fsf_req); | 2035 | lat->counter++; |
3849 | } else { | 2036 | spin_unlock_irqrestore(&unit->latencies.lock, flags); |
3850 | retval = zfcp_fsf_send_fcp_command_task_handler(fsf_req); | ||
3851 | fsf_req->unit = NULL; | ||
3852 | zfcp_unit_put(unit); | ||
3853 | } | ||
3854 | return retval; | ||
3855 | } | 2037 | } |
3856 | 2038 | ||
3857 | /* | 2039 | static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) |
3858 | * function: zfcp_fsf_send_fcp_command_task_handler | ||
3859 | * | ||
3860 | * purpose: evaluates FCP_RSP IU | ||
3861 | * | ||
3862 | * returns: | ||
3863 | */ | ||
3864 | static int | ||
3865 | zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) | ||
3866 | { | 2040 | { |
3867 | int retval = 0; | 2041 | struct scsi_cmnd *scpnt = req->data; |
3868 | struct scsi_cmnd *scpnt; | ||
3869 | struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) | 2042 | struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) |
3870 | &(fsf_req->qtcb->bottom.io.fcp_rsp); | 2043 | &(req->qtcb->bottom.io.fcp_rsp); |
3871 | struct fcp_cmnd_iu *fcp_cmnd_iu = (struct fcp_cmnd_iu *) | ||
3872 | &(fsf_req->qtcb->bottom.io.fcp_cmnd); | ||
3873 | u32 sns_len; | 2044 | u32 sns_len; |
3874 | char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); | 2045 | char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; |
3875 | unsigned long flags; | 2046 | unsigned long flags; |
3876 | struct zfcp_unit *unit = fsf_req->unit; | 2047 | |
3877 | 2048 | if (unlikely(!scpnt)) | |
3878 | read_lock_irqsave(&fsf_req->adapter->abort_lock, flags); | 2049 | return; |
3879 | scpnt = (struct scsi_cmnd *) fsf_req->data; | 2050 | |
3880 | if (unlikely(!scpnt)) { | 2051 | read_lock_irqsave(&req->adapter->abort_lock, flags); |
3881 | ZFCP_LOG_DEBUG | 2052 | |
3882 | ("Command with fsf_req %p is not associated to " | 2053 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { |
3883 | "a scsi command anymore. Aborted?\n", fsf_req); | 2054 | set_host_byte(scpnt, DID_SOFT_ERROR); |
3884 | goto out; | 2055 | set_driver_byte(scpnt, SUGGEST_RETRY); |
3885 | } | ||
3886 | if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { | ||
3887 | /* FIXME: (design) mid-layer should handle DID_ABORT like | ||
3888 | * DID_SOFT_ERROR by retrying the request for devices | ||
3889 | * that allow retries. | ||
3890 | */ | ||
3891 | ZFCP_LOG_DEBUG("Setting DID_SOFT_ERROR and SUGGEST_RETRY\n"); | ||
3892 | set_host_byte(&scpnt->result, DID_SOFT_ERROR); | ||
3893 | set_driver_byte(&scpnt->result, SUGGEST_RETRY); | ||
3894 | goto skip_fsfstatus; | 2056 | goto skip_fsfstatus; |
3895 | } | 2057 | } |
3896 | 2058 | ||
3897 | if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { | 2059 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { |
3898 | ZFCP_LOG_DEBUG("Setting DID_ERROR\n"); | 2060 | set_host_byte(scpnt, DID_ERROR); |
3899 | set_host_byte(&scpnt->result, DID_ERROR); | ||
3900 | goto skip_fsfstatus; | 2061 | goto skip_fsfstatus; |
3901 | } | 2062 | } |
3902 | 2063 | ||
3903 | /* set message byte of result in SCSI command */ | 2064 | set_msg_byte(scpnt, COMMAND_COMPLETE); |
3904 | scpnt->result |= COMMAND_COMPLETE << 8; | ||
3905 | 2065 | ||
3906 | /* | ||
3907 | * copy SCSI status code of FCP_STATUS of FCP_RSP IU to status byte | ||
3908 | * of result in SCSI command | ||
3909 | */ | ||
3910 | scpnt->result |= fcp_rsp_iu->scsi_status; | 2066 | scpnt->result |= fcp_rsp_iu->scsi_status; |
3911 | if (unlikely(fcp_rsp_iu->scsi_status)) { | ||
3912 | /* DEBUG */ | ||
3913 | ZFCP_LOG_DEBUG("status for SCSI Command:\n"); | ||
3914 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3915 | scpnt->cmnd, scpnt->cmd_len); | ||
3916 | ZFCP_LOG_DEBUG("SCSI status code 0x%x\n", | ||
3917 | fcp_rsp_iu->scsi_status); | ||
3918 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3919 | (void *) fcp_rsp_iu, sizeof (struct fcp_rsp_iu)); | ||
3920 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3921 | zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), | ||
3922 | fcp_rsp_iu->fcp_sns_len); | ||
3923 | } | ||
3924 | 2067 | ||
3925 | /* check FCP_RSP_INFO */ | 2068 | if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) |
2069 | zfcp_fsf_req_latency(req); | ||
2070 | |||
3926 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { | 2071 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { |
3927 | ZFCP_LOG_DEBUG("rsp_len is valid\n"); | 2072 | if (fcp_rsp_info[3] == RSP_CODE_GOOD) |
3928 | switch (fcp_rsp_info[3]) { | 2073 | set_host_byte(scpnt, DID_OK); |
3929 | case RSP_CODE_GOOD: | 2074 | else { |
3930 | /* ok, continue */ | 2075 | set_host_byte(scpnt, DID_ERROR); |
3931 | ZFCP_LOG_TRACE("no failure or Task Management " | ||
3932 | "Function complete\n"); | ||
3933 | set_host_byte(&scpnt->result, DID_OK); | ||
3934 | break; | ||
3935 | case RSP_CODE_LENGTH_MISMATCH: | ||
3936 | /* hardware bug */ | ||
3937 | ZFCP_LOG_NORMAL("bug: FCP response code indictates " | ||
3938 | "that the fibrechannel protocol data " | ||
3939 | "length differs from the burst length. " | ||
3940 | "The problem occured on unit 0x%016Lx " | ||
3941 | "on port 0x%016Lx on adapter %s", | ||
3942 | unit->fcp_lun, | ||
3943 | unit->port->wwpn, | ||
3944 | zfcp_get_busid_by_unit(unit)); | ||
3945 | /* dump SCSI CDB as prepared by zfcp */ | ||
3946 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3947 | (char *) &fsf_req->qtcb-> | ||
3948 | bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); | ||
3949 | set_host_byte(&scpnt->result, DID_ERROR); | ||
3950 | goto skip_fsfstatus; | ||
3951 | case RSP_CODE_FIELD_INVALID: | ||
3952 | /* driver or hardware bug */ | ||
3953 | ZFCP_LOG_NORMAL("bug: FCP response code indictates " | ||
3954 | "that the fibrechannel protocol data " | ||
3955 | "fields were incorrectly set up. " | ||
3956 | "The problem occured on the unit " | ||
3957 | "0x%016Lx on port 0x%016Lx on " | ||
3958 | "adapter %s", | ||
3959 | unit->fcp_lun, | ||
3960 | unit->port->wwpn, | ||
3961 | zfcp_get_busid_by_unit(unit)); | ||
3962 | /* dump SCSI CDB as prepared by zfcp */ | ||
3963 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3964 | (char *) &fsf_req->qtcb-> | ||
3965 | bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); | ||
3966 | set_host_byte(&scpnt->result, DID_ERROR); | ||
3967 | goto skip_fsfstatus; | ||
3968 | case RSP_CODE_RO_MISMATCH: | ||
3969 | /* hardware bug */ | ||
3970 | ZFCP_LOG_NORMAL("bug: The FCP response code indicates " | ||
3971 | "that conflicting values for the " | ||
3972 | "fibrechannel payload offset from the " | ||
3973 | "header were found. " | ||
3974 | "The problem occured on unit 0x%016Lx " | ||
3975 | "on port 0x%016Lx on adapter %s.\n", | ||
3976 | unit->fcp_lun, | ||
3977 | unit->port->wwpn, | ||
3978 | zfcp_get_busid_by_unit(unit)); | ||
3979 | /* dump SCSI CDB as prepared by zfcp */ | ||
3980 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3981 | (char *) &fsf_req->qtcb-> | ||
3982 | bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); | ||
3983 | set_host_byte(&scpnt->result, DID_ERROR); | ||
3984 | goto skip_fsfstatus; | ||
3985 | default: | ||
3986 | ZFCP_LOG_NORMAL("bug: An invalid FCP response " | ||
3987 | "code was detected for a command. " | ||
3988 | "The problem occured on the unit " | ||
3989 | "0x%016Lx on port 0x%016Lx on " | ||
3990 | "adapter %s (debug info 0x%x)\n", | ||
3991 | unit->fcp_lun, | ||
3992 | unit->port->wwpn, | ||
3993 | zfcp_get_busid_by_unit(unit), | ||
3994 | fcp_rsp_info[3]); | ||
3995 | /* dump SCSI CDB as prepared by zfcp */ | ||
3996 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, | ||
3997 | (char *) &fsf_req->qtcb-> | ||
3998 | bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); | ||
3999 | set_host_byte(&scpnt->result, DID_ERROR); | ||
4000 | goto skip_fsfstatus; | 2076 | goto skip_fsfstatus; |
4001 | } | 2077 | } |
4002 | } | 2078 | } |
4003 | 2079 | ||
4004 | /* check for sense data */ | ||
4005 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) { | 2080 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_sns_len_valid)) { |
4006 | sns_len = FSF_FCP_RSP_SIZE - | 2081 | sns_len = FSF_FCP_RSP_SIZE - sizeof(struct fcp_rsp_iu) + |
4007 | sizeof (struct fcp_rsp_iu) + fcp_rsp_iu->fcp_rsp_len; | 2082 | fcp_rsp_iu->fcp_rsp_len; |
4008 | ZFCP_LOG_TRACE("room for %i bytes sense data in QTCB\n", | ||
4009 | sns_len); | ||
4010 | sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE); | 2083 | sns_len = min(sns_len, (u32) SCSI_SENSE_BUFFERSIZE); |
4011 | ZFCP_LOG_TRACE("room for %i bytes sense data in SCSI command\n", | ||
4012 | SCSI_SENSE_BUFFERSIZE); | ||
4013 | sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len); | 2084 | sns_len = min(sns_len, fcp_rsp_iu->fcp_sns_len); |
4014 | ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n", | ||
4015 | scpnt->result); | ||
4016 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, | ||
4017 | scpnt->cmnd, scpnt->cmd_len); | ||
4018 | 2085 | ||
4019 | ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n", | ||
4020 | fcp_rsp_iu->fcp_sns_len); | ||
4021 | memcpy(scpnt->sense_buffer, | 2086 | memcpy(scpnt->sense_buffer, |
4022 | zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len); | 2087 | zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len); |
4023 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, | ||
4024 | (void *)scpnt->sense_buffer, sns_len); | ||
4025 | } | ||
4026 | |||
4027 | /* check for overrun */ | ||
4028 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_over)) { | ||
4029 | ZFCP_LOG_INFO("A data overrun was detected for a command. " | ||
4030 | "unit 0x%016Lx, port 0x%016Lx, adapter %s. " | ||
4031 | "The response data length is " | ||
4032 | "%d, the original length was %d.\n", | ||
4033 | unit->fcp_lun, | ||
4034 | unit->port->wwpn, | ||
4035 | zfcp_get_busid_by_unit(unit), | ||
4036 | fcp_rsp_iu->fcp_resid, | ||
4037 | (int) zfcp_get_fcp_dl(fcp_cmnd_iu)); | ||
4038 | } | 2088 | } |
4039 | 2089 | ||
4040 | /* check for underrun */ | ||
4041 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) { | 2090 | if (unlikely(fcp_rsp_iu->validity.bits.fcp_resid_under)) { |
4042 | ZFCP_LOG_INFO("A data underrun was detected for a command. " | ||
4043 | "unit 0x%016Lx, port 0x%016Lx, adapter %s. " | ||
4044 | "The response data length is " | ||
4045 | "%d, the original length was %d.\n", | ||
4046 | unit->fcp_lun, | ||
4047 | unit->port->wwpn, | ||
4048 | zfcp_get_busid_by_unit(unit), | ||
4049 | fcp_rsp_iu->fcp_resid, | ||
4050 | (int) zfcp_get_fcp_dl(fcp_cmnd_iu)); | ||
4051 | |||
4052 | scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid); | 2091 | scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid); |
4053 | if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) < | 2092 | if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) < |
4054 | scpnt->underflow) | 2093 | scpnt->underflow) |
4055 | set_host_byte(&scpnt->result, DID_ERROR); | 2094 | set_host_byte(scpnt, DID_ERROR); |
4056 | } | 2095 | } |
4057 | 2096 | skip_fsfstatus: | |
4058 | skip_fsfstatus: | ||
4059 | ZFCP_LOG_DEBUG("scpnt->result =0x%x\n", scpnt->result); | ||
4060 | |||
4061 | if (scpnt->result != 0) | 2097 | if (scpnt->result != 0) |
4062 | zfcp_scsi_dbf_event_result("erro", 3, fsf_req->adapter, scpnt, fsf_req); | 2098 | zfcp_scsi_dbf_event_result("erro", 3, req->adapter, scpnt, req); |
4063 | else if (scpnt->retries > 0) | 2099 | else if (scpnt->retries > 0) |
4064 | zfcp_scsi_dbf_event_result("retr", 4, fsf_req->adapter, scpnt, fsf_req); | 2100 | zfcp_scsi_dbf_event_result("retr", 4, req->adapter, scpnt, req); |
4065 | else | 2101 | else |
4066 | zfcp_scsi_dbf_event_result("norm", 6, fsf_req->adapter, scpnt, fsf_req); | 2102 | zfcp_scsi_dbf_event_result("norm", 6, req->adapter, scpnt, req); |
4067 | 2103 | ||
4068 | /* cleanup pointer (need this especially for abort) */ | ||
4069 | scpnt->host_scribble = NULL; | 2104 | scpnt->host_scribble = NULL; |
4070 | |||
4071 | /* always call back */ | ||
4072 | (scpnt->scsi_done) (scpnt); | 2105 | (scpnt->scsi_done) (scpnt); |
4073 | |||
4074 | /* | 2106 | /* |
4075 | * We must hold this lock until scsi_done has been called. | 2107 | * We must hold this lock until scsi_done has been called. |
4076 | * Otherwise we may call scsi_done after abort regarding this | 2108 | * Otherwise we may call scsi_done after abort regarding this |
4077 | * command has completed. | 2109 | * command has completed. |
4078 | * Note: scsi_done must not block! | 2110 | * Note: scsi_done must not block! |
4079 | */ | 2111 | */ |
4080 | out: | 2112 | read_unlock_irqrestore(&req->adapter->abort_lock, flags); |
4081 | read_unlock_irqrestore(&fsf_req->adapter->abort_lock, flags); | ||
4082 | return retval; | ||
4083 | } | 2113 | } |
4084 | 2114 | ||
4085 | /* | 2115 | static void zfcp_fsf_send_fcp_ctm_handler(struct zfcp_fsf_req *req) |
4086 | * function: zfcp_fsf_send_fcp_command_task_management_handler | ||
4087 | * | ||
4088 | * purpose: evaluates FCP_RSP IU | ||
4089 | * | ||
4090 | * returns: | ||
4091 | */ | ||
4092 | static int | ||
4093 | zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) | ||
4094 | { | 2116 | { |
4095 | int retval = 0; | ||
4096 | struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) | 2117 | struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) |
4097 | &(fsf_req->qtcb->bottom.io.fcp_rsp); | 2118 | &(req->qtcb->bottom.io.fcp_rsp); |
4098 | char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); | 2119 | char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; |
4099 | struct zfcp_unit *unit = (struct zfcp_unit *) fsf_req->data; | ||
4100 | |||
4101 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | ||
4102 | fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; | ||
4103 | goto skip_fsfstatus; | ||
4104 | } | ||
4105 | 2120 | ||
4106 | /* check FCP_RSP_INFO */ | 2121 | if ((fcp_rsp_info[3] != RSP_CODE_GOOD) || |
4107 | switch (fcp_rsp_info[3]) { | 2122 | (req->status & ZFCP_STATUS_FSFREQ_ERROR)) |
4108 | case RSP_CODE_GOOD: | 2123 | req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; |
4109 | /* ok, continue */ | ||
4110 | ZFCP_LOG_DEBUG("no failure or Task Management " | ||
4111 | "Function complete\n"); | ||
4112 | break; | ||
4113 | case RSP_CODE_TASKMAN_UNSUPP: | ||
4114 | ZFCP_LOG_NORMAL("bug: A reuested task management function " | ||
4115 | "is not supported on the target device " | ||
4116 | "unit 0x%016Lx, port 0x%016Lx, adapter %s\n ", | ||
4117 | unit->fcp_lun, | ||
4118 | unit->port->wwpn, | ||
4119 | zfcp_get_busid_by_unit(unit)); | ||
4120 | fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP; | ||
4121 | break; | ||
4122 | case RSP_CODE_TASKMAN_FAILED: | ||
4123 | ZFCP_LOG_NORMAL("bug: A reuested task management function " | ||
4124 | "failed to complete successfully. " | ||
4125 | "unit 0x%016Lx, port 0x%016Lx, adapter %s.\n", | ||
4126 | unit->fcp_lun, | ||
4127 | unit->port->wwpn, | ||
4128 | zfcp_get_busid_by_unit(unit)); | ||
4129 | fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; | ||
4130 | break; | ||
4131 | default: | ||
4132 | ZFCP_LOG_NORMAL("bug: An invalid FCP response " | ||
4133 | "code was detected for a command. " | ||
4134 | "unit 0x%016Lx, port 0x%016Lx, adapter %s " | ||
4135 | "(debug info 0x%x)\n", | ||
4136 | unit->fcp_lun, | ||
4137 | unit->port->wwpn, | ||
4138 | zfcp_get_busid_by_unit(unit), | ||
4139 | fcp_rsp_info[3]); | ||
4140 | fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED; | ||
4141 | } | ||
4142 | |||
4143 | skip_fsfstatus: | ||
4144 | return retval; | ||
4145 | } | 2124 | } |
4146 | 2125 | ||
4147 | 2126 | ||
4148 | /* | 2127 | static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req) |
4149 | * function: zfcp_fsf_control_file | ||
4150 | * | ||
4151 | * purpose: Initiator of the control file upload/download FSF requests | ||
4152 | * | ||
4153 | * returns: 0 - FSF request is successfuly created and queued | ||
4154 | * -EOPNOTSUPP - The FCP adapter does not have Control File support | ||
4155 | * -EINVAL - Invalid direction specified | ||
4156 | * -ENOMEM - Insufficient memory | ||
4157 | * -EPERM - Cannot create FSF request or place it in QDIO queue | ||
4158 | */ | ||
4159 | int | ||
4160 | zfcp_fsf_control_file(struct zfcp_adapter *adapter, | ||
4161 | struct zfcp_fsf_req **fsf_req_ptr, | ||
4162 | u32 fsf_command, | ||
4163 | u32 option, | ||
4164 | struct zfcp_sg_list *sg_list) | ||
4165 | { | 2128 | { |
4166 | struct zfcp_fsf_req *fsf_req; | 2129 | struct zfcp_unit *unit; |
4167 | struct fsf_qtcb_bottom_support *bottom; | 2130 | struct fsf_qtcb_header *header = &req->qtcb->header; |
4168 | volatile struct qdio_buffer_element *sbale; | ||
4169 | unsigned long lock_flags; | ||
4170 | int req_flags = 0; | ||
4171 | int direction; | ||
4172 | int retval = 0; | ||
4173 | |||
4174 | if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) { | ||
4175 | ZFCP_LOG_INFO("cfdc not supported (adapter %s)\n", | ||
4176 | zfcp_get_busid_by_adapter(adapter)); | ||
4177 | retval = -EOPNOTSUPP; | ||
4178 | goto out; | ||
4179 | } | ||
4180 | |||
4181 | switch (fsf_command) { | ||
4182 | |||
4183 | case FSF_QTCB_DOWNLOAD_CONTROL_FILE: | ||
4184 | direction = SBAL_FLAGS0_TYPE_WRITE; | ||
4185 | if ((option != FSF_CFDC_OPTION_FULL_ACCESS) && | ||
4186 | (option != FSF_CFDC_OPTION_RESTRICTED_ACCESS)) | ||
4187 | req_flags = ZFCP_WAIT_FOR_SBAL; | ||
4188 | break; | ||
4189 | |||
4190 | case FSF_QTCB_UPLOAD_CONTROL_FILE: | ||
4191 | direction = SBAL_FLAGS0_TYPE_READ; | ||
4192 | break; | ||
4193 | |||
4194 | default: | ||
4195 | ZFCP_LOG_INFO("Invalid FSF command code 0x%08x\n", fsf_command); | ||
4196 | retval = -EINVAL; | ||
4197 | goto out; | ||
4198 | } | ||
4199 | |||
4200 | retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags, | ||
4201 | NULL, &lock_flags, &fsf_req); | ||
4202 | if (retval < 0) { | ||
4203 | ZFCP_LOG_INFO("error: Could not create FSF request for the " | ||
4204 | "adapter %s\n", | ||
4205 | zfcp_get_busid_by_adapter(adapter)); | ||
4206 | retval = -EPERM; | ||
4207 | goto unlock_queue_lock; | ||
4208 | } | ||
4209 | |||
4210 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | ||
4211 | sbale[0].flags |= direction; | ||
4212 | |||
4213 | bottom = &fsf_req->qtcb->bottom.support; | ||
4214 | bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; | ||
4215 | bottom->option = option; | ||
4216 | |||
4217 | if (sg_list->count > 0) { | ||
4218 | int bytes; | ||
4219 | |||
4220 | bytes = zfcp_qdio_sbals_from_sg(fsf_req, direction, | ||
4221 | sg_list->sg, sg_list->count, | ||
4222 | ZFCP_MAX_SBALS_PER_REQ); | ||
4223 | if (bytes != ZFCP_CFDC_MAX_CONTROL_FILE_SIZE) { | ||
4224 | ZFCP_LOG_INFO( | ||
4225 | "error: Could not create sufficient number of " | ||
4226 | "SBALS for an FSF request to the adapter %s\n", | ||
4227 | zfcp_get_busid_by_adapter(adapter)); | ||
4228 | retval = -ENOMEM; | ||
4229 | goto free_fsf_req; | ||
4230 | } | ||
4231 | } else | ||
4232 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
4233 | |||
4234 | zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT); | ||
4235 | retval = zfcp_fsf_req_send(fsf_req); | ||
4236 | if (retval < 0) { | ||
4237 | ZFCP_LOG_INFO("initiation of cfdc up/download failed" | ||
4238 | "(adapter %s)\n", | ||
4239 | zfcp_get_busid_by_adapter(adapter)); | ||
4240 | retval = -EPERM; | ||
4241 | goto free_fsf_req; | ||
4242 | } | ||
4243 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | ||
4244 | |||
4245 | ZFCP_LOG_NORMAL("Control file %s FSF request has been sent to the " | ||
4246 | "adapter %s\n", | ||
4247 | fsf_command == FSF_QTCB_DOWNLOAD_CONTROL_FILE ? | ||
4248 | "download" : "upload", | ||
4249 | zfcp_get_busid_by_adapter(adapter)); | ||
4250 | |||
4251 | wait_event(fsf_req->completion_wq, | ||
4252 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | ||
4253 | |||
4254 | *fsf_req_ptr = fsf_req; | ||
4255 | goto out; | ||
4256 | |||
4257 | free_fsf_req: | ||
4258 | zfcp_fsf_req_free(fsf_req); | ||
4259 | unlock_queue_lock: | ||
4260 | write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); | ||
4261 | out: | ||
4262 | return retval; | ||
4263 | } | ||
4264 | |||
4265 | 2131 | ||
4266 | /* | 2132 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)) |
4267 | * function: zfcp_fsf_control_file_handler | 2133 | unit = req->data; |
4268 | * | 2134 | else |
4269 | * purpose: Handler of the control file upload/download FSF requests | 2135 | unit = req->unit; |
4270 | * | ||
4271 | * returns: 0 - FSF request successfuly processed | ||
4272 | * -EAGAIN - Operation has to be repeated because of a temporary problem | ||
4273 | * -EACCES - There is no permission to execute an operation | ||
4274 | * -EPERM - The control file is not in a right format | ||
4275 | * -EIO - There is a problem with the FCP adapter | ||
4276 | * -EINVAL - Invalid operation | ||
4277 | * -EFAULT - User space memory I/O operation fault | ||
4278 | */ | ||
4279 | static int | ||
4280 | zfcp_fsf_control_file_handler(struct zfcp_fsf_req *fsf_req) | ||
4281 | { | ||
4282 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
4283 | struct fsf_qtcb_header *header = &fsf_req->qtcb->header; | ||
4284 | struct fsf_qtcb_bottom_support *bottom = &fsf_req->qtcb->bottom.support; | ||
4285 | int retval = 0; | ||
4286 | 2136 | ||
4287 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { | 2137 | if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ERROR)) |
4288 | retval = -EINVAL; | ||
4289 | goto skip_fsfstatus; | 2138 | goto skip_fsfstatus; |
4290 | } | ||
4291 | 2139 | ||
4292 | switch (header->fsf_status) { | 2140 | switch (header->fsf_status) { |
4293 | 2141 | case FSF_HANDLE_MISMATCH: | |
4294 | case FSF_GOOD: | 2142 | case FSF_PORT_HANDLE_NOT_VALID: |
4295 | ZFCP_LOG_NORMAL( | 2143 | zfcp_erp_adapter_reopen(unit->port->adapter, 0, 112, req); |
4296 | "The FSF request has been successfully completed " | 2144 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4297 | "on the adapter %s\n", | ||
4298 | zfcp_get_busid_by_adapter(adapter)); | ||
4299 | break; | ||
4300 | |||
4301 | case FSF_OPERATION_PARTIALLY_SUCCESSFUL: | ||
4302 | if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) { | ||
4303 | switch (header->fsf_status_qual.word[0]) { | ||
4304 | |||
4305 | case FSF_SQ_CFDC_HARDENED_ON_SE: | ||
4306 | ZFCP_LOG_NORMAL( | ||
4307 | "CFDC on the adapter %s has being " | ||
4308 | "hardened on primary and secondary SE\n", | ||
4309 | zfcp_get_busid_by_adapter(adapter)); | ||
4310 | break; | ||
4311 | |||
4312 | case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE: | ||
4313 | ZFCP_LOG_NORMAL( | ||
4314 | "CFDC of the adapter %s could not " | ||
4315 | "be saved on the SE\n", | ||
4316 | zfcp_get_busid_by_adapter(adapter)); | ||
4317 | break; | ||
4318 | |||
4319 | case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2: | ||
4320 | ZFCP_LOG_NORMAL( | ||
4321 | "CFDC of the adapter %s could not " | ||
4322 | "be copied to the secondary SE\n", | ||
4323 | zfcp_get_busid_by_adapter(adapter)); | ||
4324 | break; | ||
4325 | |||
4326 | default: | ||
4327 | ZFCP_LOG_NORMAL( | ||
4328 | "CFDC could not be hardened " | ||
4329 | "on the adapter %s\n", | ||
4330 | zfcp_get_busid_by_adapter(adapter)); | ||
4331 | } | ||
4332 | } | ||
4333 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4334 | retval = -EAGAIN; | ||
4335 | break; | ||
4336 | |||
4337 | case FSF_AUTHORIZATION_FAILURE: | ||
4338 | ZFCP_LOG_NORMAL( | ||
4339 | "Adapter %s does not accept privileged commands\n", | ||
4340 | zfcp_get_busid_by_adapter(adapter)); | ||
4341 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4342 | retval = -EACCES; | ||
4343 | break; | 2145 | break; |
4344 | 2146 | case FSF_FCPLUN_NOT_VALID: | |
4345 | case FSF_CFDC_ERROR_DETECTED: | 2147 | case FSF_LUN_HANDLE_NOT_VALID: |
4346 | ZFCP_LOG_NORMAL( | 2148 | zfcp_erp_port_reopen(unit->port, 0, 113, req); |
4347 | "Error at position %d in the CFDC, " | 2149 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4348 | "CFDC is discarded by the adapter %s\n", | ||
4349 | header->fsf_status_qual.word[0], | ||
4350 | zfcp_get_busid_by_adapter(adapter)); | ||
4351 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4352 | retval = -EPERM; | ||
4353 | break; | 2150 | break; |
4354 | 2151 | case FSF_SERVICE_CLASS_NOT_SUPPORTED: | |
4355 | case FSF_CONTROL_FILE_UPDATE_ERROR: | 2152 | zfcp_fsf_class_not_supp(req); |
4356 | ZFCP_LOG_NORMAL( | ||
4357 | "Adapter %s cannot harden the control file, " | ||
4358 | "file is discarded\n", | ||
4359 | zfcp_get_busid_by_adapter(adapter)); | ||
4360 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4361 | retval = -EIO; | ||
4362 | break; | 2153 | break; |
4363 | 2154 | case FSF_ACCESS_DENIED: | |
4364 | case FSF_CONTROL_FILE_TOO_LARGE: | 2155 | zfcp_fsf_access_denied_unit(req, unit); |
4365 | ZFCP_LOG_NORMAL( | ||
4366 | "Control file is too large, file is discarded " | ||
4367 | "by the adapter %s\n", | ||
4368 | zfcp_get_busid_by_adapter(adapter)); | ||
4369 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4370 | retval = -EIO; | ||
4371 | break; | 2156 | break; |
4372 | 2157 | case FSF_DIRECTION_INDICATOR_NOT_VALID: | |
4373 | case FSF_ACCESS_CONFLICT_DETECTED: | 2158 | dev_err(&req->adapter->ccw_device->dev, |
4374 | if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) | 2159 | "Invalid data direction (%d) given for unit " |
4375 | ZFCP_LOG_NORMAL( | 2160 | "0x%016Lx on port 0x%016Lx, shutting down " |
4376 | "CFDC has been discarded by the adapter %s, " | 2161 | "adapter.\n", |
4377 | "because activation would impact " | 2162 | req->qtcb->bottom.io.data_direction, |
4378 | "%d active connection(s)\n", | 2163 | unit->fcp_lun, unit->port->wwpn); |
4379 | zfcp_get_busid_by_adapter(adapter), | 2164 | zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, req); |
4380 | header->fsf_status_qual.word[0]); | 2165 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4381 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4382 | retval = -EIO; | ||
4383 | break; | 2166 | break; |
4384 | 2167 | case FSF_CMND_LENGTH_NOT_VALID: | |
4385 | case FSF_CONFLICTS_OVERRULED: | 2168 | dev_err(&req->adapter->ccw_device->dev, |
4386 | if (bottom->operation_subtype == FSF_CFDC_OPERATION_SUBTYPE) | 2169 | "An invalid control-data-block length field (%d) " |
4387 | ZFCP_LOG_NORMAL( | 2170 | "was found in a command for unit 0x%016Lx on port " |
4388 | "CFDC has been activated on the adapter %s, " | 2171 | "0x%016Lx. Shutting down adapter.\n", |
4389 | "but activation has impacted " | 2172 | req->qtcb->bottom.io.fcp_cmnd_length, |
4390 | "%d active connection(s)\n", | 2173 | unit->fcp_lun, unit->port->wwpn); |
4391 | zfcp_get_busid_by_adapter(adapter), | 2174 | zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, req); |
4392 | header->fsf_status_qual.word[0]); | 2175 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4393 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4394 | retval = -EIO; | ||
4395 | break; | 2176 | break; |
4396 | 2177 | case FSF_PORT_BOXED: | |
4397 | case FSF_UNKNOWN_OP_SUBTYPE: | 2178 | zfcp_erp_port_boxed(unit->port, 53, req); |
4398 | ZFCP_LOG_NORMAL("unknown operation subtype (adapter: %s, " | 2179 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
4399 | "op_subtype=0x%x)\n", | 2180 | ZFCP_STATUS_FSFREQ_RETRY; |
4400 | zfcp_get_busid_by_adapter(adapter), | ||
4401 | bottom->operation_subtype); | ||
4402 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4403 | retval = -EINVAL; | ||
4404 | break; | 2181 | break; |
4405 | 2182 | case FSF_LUN_BOXED: | |
4406 | case FSF_INVALID_COMMAND_OPTION: | 2183 | zfcp_erp_unit_boxed(unit, 54, req); |
4407 | ZFCP_LOG_NORMAL( | 2184 | req->status |= ZFCP_STATUS_FSFREQ_ERROR | |
4408 | "Invalid option 0x%x has been specified " | 2185 | ZFCP_STATUS_FSFREQ_RETRY; |
4409 | "in QTCB bottom sent to the adapter %s\n", | ||
4410 | bottom->option, | ||
4411 | zfcp_get_busid_by_adapter(adapter)); | ||
4412 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4413 | retval = -EINVAL; | ||
4414 | break; | 2186 | break; |
4415 | 2187 | case FSF_ADAPTER_STATUS_AVAILABLE: | |
4416 | default: | 2188 | if (header->fsf_status_qual.word[0] == |
4417 | ZFCP_LOG_NORMAL( | 2189 | FSF_SQ_INVOKE_LINK_TEST_PROCEDURE) |
4418 | "bug: An unknown/unexpected FSF status 0x%08x " | 2190 | zfcp_test_link(unit->port); |
4419 | "was presented on the adapter %s\n", | 2191 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4420 | header->fsf_status, | ||
4421 | zfcp_get_busid_by_adapter(adapter)); | ||
4422 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; | ||
4423 | retval = -EINVAL; | ||
4424 | break; | 2192 | break; |
4425 | } | 2193 | } |
4426 | |||
4427 | skip_fsfstatus: | 2194 | skip_fsfstatus: |
4428 | return retval; | 2195 | if (req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) |
4429 | } | 2196 | zfcp_fsf_send_fcp_ctm_handler(req); |
4430 | 2197 | else { | |
4431 | static inline int | 2198 | zfcp_fsf_send_fcp_command_task_handler(req); |
4432 | zfcp_fsf_req_sbal_check(unsigned long *flags, | 2199 | req->unit = NULL; |
4433 | struct zfcp_qdio_queue *queue, int needed) | 2200 | zfcp_unit_put(unit); |
4434 | { | ||
4435 | write_lock_irqsave(&queue->queue_lock, *flags); | ||
4436 | if (likely(atomic_read(&queue->free_count) >= needed)) | ||
4437 | return 1; | ||
4438 | write_unlock_irqrestore(&queue->queue_lock, *flags); | ||
4439 | return 0; | ||
4440 | } | ||
4441 | |||
4442 | /* | ||
4443 | * set qtcb pointer in fsf_req and initialize QTCB | ||
4444 | */ | ||
4445 | static void | ||
4446 | zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req) | ||
4447 | { | ||
4448 | if (likely(fsf_req->qtcb != NULL)) { | ||
4449 | fsf_req->qtcb->prefix.req_seq_no = | ||
4450 | fsf_req->adapter->fsf_req_seq_no; | ||
4451 | fsf_req->qtcb->prefix.req_id = fsf_req->req_id; | ||
4452 | fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION; | ||
4453 | fsf_req->qtcb->prefix.qtcb_type = | ||
4454 | fsf_qtcb_type[fsf_req->fsf_command]; | ||
4455 | fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION; | ||
4456 | fsf_req->qtcb->header.req_handle = fsf_req->req_id; | ||
4457 | fsf_req->qtcb->header.fsf_command = fsf_req->fsf_command; | ||
4458 | } | 2201 | } |
4459 | } | 2202 | } |
4460 | 2203 | ||
4461 | /** | 2204 | /** |
4462 | * zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue | 2205 | * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) |
4463 | * @adapter: adapter for which request queue is examined | 2206 | * @adapter: adapter where scsi command is issued |
4464 | * @req_flags: flags indicating whether to wait for needed SBAL or not | 2207 | * @unit: unit where command is sent to |
4465 | * @lock_flags: lock_flags if queue_lock is taken | 2208 | * @scsi_cmnd: scsi command to be sent |
4466 | * Return: 0 on success, otherwise -EIO, or -ERESTARTSYS | 2209 | * @timer: timer to be started when request is initiated |
4467 | * Locks: lock adapter->request_queue->queue_lock on success | 2210 | * @req_flags: flags for fsf_request |
4468 | */ | ||
4469 | static int | ||
4470 | zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags, | ||
4471 | unsigned long *lock_flags) | ||
4472 | { | ||
4473 | long ret; | ||
4474 | struct zfcp_qdio_queue *req_queue = &adapter->request_queue; | ||
4475 | |||
4476 | if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) { | ||
4477 | ret = wait_event_interruptible_timeout(adapter->request_wq, | ||
4478 | zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1), | ||
4479 | ZFCP_SBAL_TIMEOUT); | ||
4480 | if (ret < 0) | ||
4481 | return ret; | ||
4482 | if (!ret) | ||
4483 | return -EIO; | ||
4484 | } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1)) | ||
4485 | return -EIO; | ||
4486 | |||
4487 | return 0; | ||
4488 | } | ||
4489 | |||
4490 | /* | ||
4491 | * function: zfcp_fsf_req_create | ||
4492 | * | ||
4493 | * purpose: create an FSF request at the specified adapter and | ||
4494 | * setup common fields | ||
4495 | * | ||
4496 | * returns: -ENOMEM if there was insufficient memory for a request | ||
4497 | * -EIO if no qdio buffers could be allocate to the request | ||
4498 | * -EINVAL/-EPERM on bug conditions in req_dequeue | ||
4499 | * 0 in success | ||
4500 | * | ||
4501 | * note: The created request is returned by reference. | ||
4502 | * | ||
4503 | * locks: lock of concerned request queue must not be held, | ||
4504 | * but is held on completion (write, irqsave) | ||
4505 | */ | 2211 | */ |
4506 | int | 2212 | int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, |
4507 | zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, | 2213 | struct zfcp_unit *unit, |
4508 | mempool_t *pool, unsigned long *lock_flags, | 2214 | struct scsi_cmnd *scsi_cmnd, |
4509 | struct zfcp_fsf_req **fsf_req_p) | 2215 | int use_timer, int req_flags) |
4510 | { | 2216 | { |
4511 | volatile struct qdio_buffer_element *sbale; | 2217 | struct zfcp_fsf_req *req; |
4512 | struct zfcp_fsf_req *fsf_req = NULL; | 2218 | struct fcp_cmnd_iu *fcp_cmnd_iu; |
4513 | int ret = 0; | 2219 | unsigned int sbtype; |
4514 | struct zfcp_qdio_queue *req_queue = &adapter->request_queue; | 2220 | int real_bytes, retval = -EIO; |
4515 | |||
4516 | /* allocate new FSF request */ | ||
4517 | fsf_req = zfcp_fsf_req_alloc(pool, req_flags); | ||
4518 | if (unlikely(NULL == fsf_req)) { | ||
4519 | ZFCP_LOG_DEBUG("error: Could not put an FSF request into " | ||
4520 | "the outbound (send) queue.\n"); | ||
4521 | ret = -ENOMEM; | ||
4522 | goto failed_fsf_req; | ||
4523 | } | ||
4524 | |||
4525 | fsf_req->adapter = adapter; | ||
4526 | fsf_req->fsf_command = fsf_cmd; | ||
4527 | INIT_LIST_HEAD(&fsf_req->list); | ||
4528 | init_timer(&fsf_req->timer); | ||
4529 | 2221 | ||
4530 | /* initialize waitqueue which may be used to wait on | 2222 | if (unlikely(!(atomic_read(&unit->status) & |
4531 | this request completion */ | 2223 | ZFCP_STATUS_COMMON_UNBLOCKED))) |
4532 | init_waitqueue_head(&fsf_req->completion_wq); | 2224 | return -EBUSY; |
4533 | 2225 | ||
4534 | ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags); | 2226 | spin_lock(&adapter->req_q.lock); |
4535 | if (ret < 0) | 2227 | if (!atomic_read(&adapter->req_q.count)) |
4536 | goto failed_sbals; | 2228 | goto out; |
2229 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, | ||
2230 | adapter->pool.fsf_req_scsi); | ||
2231 | if (unlikely(IS_ERR(req))) { | ||
2232 | retval = PTR_ERR(req); | ||
2233 | goto out; | ||
2234 | } | ||
4537 | 2235 | ||
4538 | /* this is serialized (we are holding req_queue-lock of adapter) */ | 2236 | zfcp_unit_get(unit); |
4539 | if (adapter->req_no == 0) | 2237 | req->unit = unit; |
4540 | adapter->req_no++; | 2238 | req->data = scsi_cmnd; |
4541 | fsf_req->req_id = adapter->req_no++; | 2239 | req->handler = zfcp_fsf_send_fcp_command_handler; |
2240 | req->qtcb->header.lun_handle = unit->handle; | ||
2241 | req->qtcb->header.port_handle = unit->port->handle; | ||
2242 | req->qtcb->bottom.io.service_class = FSF_CLASS_3; | ||
4542 | 2243 | ||
4543 | zfcp_fsf_req_qtcb_init(fsf_req); | 2244 | scsi_cmnd->host_scribble = (unsigned char *) req->req_id; |
4544 | 2245 | ||
2246 | fcp_cmnd_iu = (struct fcp_cmnd_iu *) &(req->qtcb->bottom.io.fcp_cmnd); | ||
2247 | fcp_cmnd_iu->fcp_lun = unit->fcp_lun; | ||
4545 | /* | 2248 | /* |
4546 | * We hold queue_lock here. Check if QDIOUP is set and let request fail | 2249 | * set depending on data direction: |
4547 | * if it is not set (see also *_open_qdio and *_close_qdio). | 2250 | * data direction bits in SBALE (SB Type) |
2251 | * data direction bits in QTCB | ||
2252 | * data direction bits in FCP_CMND IU | ||
4548 | */ | 2253 | */ |
4549 | 2254 | switch (scsi_cmnd->sc_data_direction) { | |
4550 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) { | 2255 | case DMA_NONE: |
4551 | write_unlock_irqrestore(&req_queue->queue_lock, *lock_flags); | 2256 | req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; |
4552 | ret = -EIO; | 2257 | sbtype = SBAL_FLAGS0_TYPE_READ; |
4553 | goto failed_sbals; | 2258 | break; |
2259 | case DMA_FROM_DEVICE: | ||
2260 | req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; | ||
2261 | sbtype = SBAL_FLAGS0_TYPE_READ; | ||
2262 | fcp_cmnd_iu->rddata = 1; | ||
2263 | break; | ||
2264 | case DMA_TO_DEVICE: | ||
2265 | req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE; | ||
2266 | sbtype = SBAL_FLAGS0_TYPE_WRITE; | ||
2267 | fcp_cmnd_iu->wddata = 1; | ||
2268 | break; | ||
2269 | case DMA_BIDIRECTIONAL: | ||
2270 | default: | ||
2271 | retval = -EIO; | ||
2272 | goto failed_scsi_cmnd; | ||
4554 | } | 2273 | } |
4555 | 2274 | ||
4556 | if (fsf_req->qtcb) { | 2275 | if (likely((scsi_cmnd->device->simple_tags) || |
4557 | fsf_req->seq_no = adapter->fsf_req_seq_no; | 2276 | ((atomic_read(&unit->status) & ZFCP_STATUS_UNIT_READONLY) && |
4558 | fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; | 2277 | (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_SHARED)))) |
4559 | } | 2278 | fcp_cmnd_iu->task_attribute = SIMPLE_Q; |
4560 | fsf_req->sbal_number = 1; | 2279 | else |
4561 | fsf_req->sbal_first = req_queue->free_index; | 2280 | fcp_cmnd_iu->task_attribute = UNTAGGED; |
4562 | fsf_req->sbal_curr = req_queue->free_index; | ||
4563 | fsf_req->sbale_curr = 1; | ||
4564 | 2281 | ||
4565 | if (likely(req_flags & ZFCP_REQ_AUTO_CLEANUP)) { | 2282 | if (unlikely(scsi_cmnd->cmd_len > FCP_CDB_LENGTH)) |
4566 | fsf_req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; | 2283 | fcp_cmnd_iu->add_fcp_cdb_length = |
4567 | } | 2284 | (scsi_cmnd->cmd_len - FCP_CDB_LENGTH) >> 2; |
4568 | 2285 | ||
4569 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 2286 | memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); |
4570 | 2287 | ||
4571 | /* setup common SBALE fields */ | 2288 | req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + |
4572 | sbale[0].addr = (void *) fsf_req->req_id; | 2289 | fcp_cmnd_iu->add_fcp_cdb_length + sizeof(fcp_dl_t); |
4573 | sbale[0].flags |= SBAL_FLAGS0_COMMAND; | 2290 | |
4574 | if (likely(fsf_req->qtcb != NULL)) { | 2291 | real_bytes = zfcp_qdio_sbals_from_sg(req, sbtype, |
4575 | sbale[1].addr = (void *) fsf_req->qtcb; | 2292 | scsi_sglist(scsi_cmnd), |
4576 | sbale[1].length = sizeof(struct fsf_qtcb); | 2293 | FSF_MAX_SBALS_PER_REQ); |
2294 | if (unlikely(real_bytes < 0)) { | ||
2295 | if (req->sbal_number < FSF_MAX_SBALS_PER_REQ) | ||
2296 | retval = -EIO; | ||
2297 | else { | ||
2298 | dev_err(&adapter->ccw_device->dev, | ||
2299 | "SCSI request too large. " | ||
2300 | "Shutting down unit 0x%016Lx on port " | ||
2301 | "0x%016Lx.\n", unit->fcp_lun, | ||
2302 | unit->port->wwpn); | ||
2303 | zfcp_erp_unit_shutdown(unit, 0, 131, req); | ||
2304 | retval = -EINVAL; | ||
2305 | } | ||
2306 | goto failed_scsi_cmnd; | ||
4577 | } | 2307 | } |
4578 | 2308 | ||
4579 | ZFCP_LOG_TRACE("got %i free BUFFERs starting at index %i\n", | 2309 | zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes); |
4580 | fsf_req->sbal_number, fsf_req->sbal_first); | ||
4581 | 2310 | ||
4582 | goto success; | 2311 | if (use_timer) |
2312 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); | ||
4583 | 2313 | ||
4584 | failed_sbals: | 2314 | retval = zfcp_fsf_req_send(req); |
4585 | /* dequeue new FSF request previously enqueued */ | 2315 | if (unlikely(retval)) |
4586 | zfcp_fsf_req_free(fsf_req); | 2316 | goto failed_scsi_cmnd; |
4587 | fsf_req = NULL; | ||
4588 | 2317 | ||
4589 | failed_fsf_req: | 2318 | goto out; |
4590 | write_lock_irqsave(&req_queue->queue_lock, *lock_flags); | 2319 | |
4591 | success: | 2320 | failed_scsi_cmnd: |
4592 | *fsf_req_p = fsf_req; | 2321 | zfcp_unit_put(unit); |
4593 | return ret; | 2322 | zfcp_fsf_req_free(req); |
2323 | scsi_cmnd->host_scribble = NULL; | ||
2324 | out: | ||
2325 | spin_unlock(&adapter->req_q.lock); | ||
2326 | return retval; | ||
4594 | } | 2327 | } |
4595 | 2328 | ||
4596 | /* | 2329 | /** |
4597 | * function: zfcp_fsf_req_send | 2330 | * zfcp_fsf_send_fcp_ctm - send SCSI task management command |
4598 | * | 2331 | * @adapter: pointer to struct zfcp-adapter |
4599 | * purpose: start transfer of FSF request via QDIO | 2332 | * @unit: pointer to struct zfcp_unit |
4600 | * | 2333 | * @tm_flags: unsigned byte for task management flags |
4601 | * returns: 0 - request transfer succesfully started | 2334 | * @req_flags: int request flags |
4602 | * !0 - start of request transfer failed | 2335 | * Returns: on success pointer to struct fsf_req, NULL otherwise |
4603 | */ | 2336 | */ |
4604 | static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req) | 2337 | struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter, |
2338 | struct zfcp_unit *unit, | ||
2339 | u8 tm_flags, int req_flags) | ||
4605 | { | 2340 | { |
4606 | struct zfcp_adapter *adapter; | ||
4607 | struct zfcp_qdio_queue *req_queue; | ||
4608 | volatile struct qdio_buffer_element *sbale; | 2341 | volatile struct qdio_buffer_element *sbale; |
4609 | int inc_seq_no; | 2342 | struct zfcp_fsf_req *req = NULL; |
4610 | int new_distance_from_int; | 2343 | struct fcp_cmnd_iu *fcp_cmnd_iu; |
4611 | int retval = 0; | ||
4612 | 2344 | ||
4613 | adapter = fsf_req->adapter; | 2345 | if (unlikely(!(atomic_read(&unit->status) & |
4614 | req_queue = &adapter->request_queue, | 2346 | ZFCP_STATUS_COMMON_UNBLOCKED))) |
2347 | return NULL; | ||
4615 | 2348 | ||
2349 | spin_lock(&adapter->req_q.lock); | ||
2350 | if (!atomic_read(&adapter->req_q.count)) | ||
2351 | goto out; | ||
2352 | req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, | ||
2353 | adapter->pool.fsf_req_scsi); | ||
2354 | if (unlikely(IS_ERR(req))) | ||
2355 | goto out; | ||
4616 | 2356 | ||
4617 | /* FIXME(debug): remove it later */ | 2357 | req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT; |
4618 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_first, 0); | 2358 | req->data = unit; |
4619 | ZFCP_LOG_DEBUG("SBALE0 flags=0x%x\n", sbale[0].flags); | 2359 | req->handler = zfcp_fsf_send_fcp_command_handler; |
4620 | ZFCP_LOG_TRACE("HEX DUMP OF SBALE1 PAYLOAD:\n"); | 2360 | req->qtcb->header.lun_handle = unit->handle; |
4621 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr, | 2361 | req->qtcb->header.port_handle = unit->port->handle; |
4622 | sbale[1].length); | 2362 | req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; |
2363 | req->qtcb->bottom.io.service_class = FSF_CLASS_3; | ||
2364 | req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + | ||
2365 | sizeof(fcp_dl_t); | ||
2366 | |||
2367 | sbale = zfcp_qdio_sbale_req(req); | ||
2368 | sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; | ||
2369 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | ||
4623 | 2370 | ||
4624 | /* put allocated FSF request into hash table */ | 2371 | fcp_cmnd_iu = (struct fcp_cmnd_iu *) &req->qtcb->bottom.io.fcp_cmnd; |
4625 | spin_lock(&adapter->req_list_lock); | 2372 | fcp_cmnd_iu->fcp_lun = unit->fcp_lun; |
4626 | zfcp_reqlist_add(adapter, fsf_req); | 2373 | fcp_cmnd_iu->task_management_flags = tm_flags; |
4627 | spin_unlock(&adapter->req_list_lock); | ||
4628 | 2374 | ||
4629 | inc_seq_no = (fsf_req->qtcb != NULL); | 2375 | zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT); |
2376 | if (!zfcp_fsf_req_send(req)) | ||
2377 | goto out; | ||
4630 | 2378 | ||
4631 | ZFCP_LOG_TRACE("request queue of adapter %s: " | 2379 | zfcp_fsf_req_free(req); |
4632 | "next free SBAL is %i, %i free SBALs\n", | 2380 | req = NULL; |
4633 | zfcp_get_busid_by_adapter(adapter), | 2381 | out: |
4634 | req_queue->free_index, | 2382 | spin_unlock(&adapter->req_q.lock); |
4635 | atomic_read(&req_queue->free_count)); | 2383 | return req; |
2384 | } | ||
4636 | 2385 | ||
4637 | ZFCP_LOG_DEBUG("calling do_QDIO adapter %s, flags=0x%x, queue_no=%i, " | 2386 | static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req) |
4638 | "index_in_queue=%i, count=%i, buffers=%p\n", | 2387 | { |
4639 | zfcp_get_busid_by_adapter(adapter), | 2388 | if (req->qtcb->header.fsf_status != FSF_GOOD) |
4640 | QDIO_FLAG_SYNC_OUTPUT, | 2389 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
4641 | 0, fsf_req->sbal_first, fsf_req->sbal_number, | 2390 | } |
4642 | &req_queue->buffer[fsf_req->sbal_first]); | ||
4643 | 2391 | ||
4644 | /* | 2392 | /** |
4645 | * adjust the number of free SBALs in request queue as well as | 2393 | * zfcp_fsf_control_file - control file upload/download |
4646 | * position of first one | 2394 | * @adapter: pointer to struct zfcp_adapter |
4647 | */ | 2395 | * @fsf_cfdc: pointer to struct zfcp_fsf_cfdc |
4648 | atomic_sub(fsf_req->sbal_number, &req_queue->free_count); | 2396 | * Returns: on success pointer to struct zfcp_fsf_req, NULL otherwise |
4649 | ZFCP_LOG_TRACE("free_count=%d\n", atomic_read(&req_queue->free_count)); | 2397 | */ |
4650 | req_queue->free_index += fsf_req->sbal_number; /* increase */ | 2398 | struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, |
4651 | req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap if needed */ | 2399 | struct zfcp_fsf_cfdc *fsf_cfdc) |
4652 | new_distance_from_int = zfcp_qdio_determine_pci(req_queue, fsf_req); | 2400 | { |
2401 | volatile struct qdio_buffer_element *sbale; | ||
2402 | struct zfcp_fsf_req *req = NULL; | ||
2403 | struct fsf_qtcb_bottom_support *bottom; | ||
2404 | int direction, retval = -EIO, bytes; | ||
2405 | |||
2406 | if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) | ||
2407 | return ERR_PTR(-EOPNOTSUPP); | ||
2408 | |||
2409 | switch (fsf_cfdc->command) { | ||
2410 | case FSF_QTCB_DOWNLOAD_CONTROL_FILE: | ||
2411 | direction = SBAL_FLAGS0_TYPE_WRITE; | ||
2412 | break; | ||
2413 | case FSF_QTCB_UPLOAD_CONTROL_FILE: | ||
2414 | direction = SBAL_FLAGS0_TYPE_READ; | ||
2415 | break; | ||
2416 | default: | ||
2417 | return ERR_PTR(-EINVAL); | ||
2418 | } | ||
4653 | 2419 | ||
4654 | fsf_req->issued = get_clock(); | 2420 | spin_lock(&adapter->req_q.lock); |
2421 | if (zfcp_fsf_req_sbal_get(adapter)) | ||
2422 | goto out; | ||
4655 | 2423 | ||
4656 | retval = do_QDIO(adapter->ccw_device, | 2424 | req = zfcp_fsf_req_create(adapter, fsf_cfdc->command, 0, NULL); |
4657 | QDIO_FLAG_SYNC_OUTPUT, | 2425 | if (unlikely(IS_ERR(req))) { |
4658 | 0, fsf_req->sbal_first, fsf_req->sbal_number, NULL); | 2426 | retval = -EPERM; |
2427 | goto out; | ||
2428 | } | ||
4659 | 2429 | ||
4660 | if (unlikely(retval)) { | 2430 | req->handler = zfcp_fsf_control_file_handler; |
4661 | /* Queues are down..... */ | 2431 | |
4662 | retval = -EIO; | 2432 | sbale = zfcp_qdio_sbale_req(req); |
4663 | del_timer(&fsf_req->timer); | 2433 | sbale[0].flags |= direction; |
4664 | spin_lock(&adapter->req_list_lock); | ||
4665 | zfcp_reqlist_remove(adapter, fsf_req); | ||
4666 | spin_unlock(&adapter->req_list_lock); | ||
4667 | /* undo changes in request queue made for this request */ | ||
4668 | zfcp_qdio_zero_sbals(req_queue->buffer, | ||
4669 | fsf_req->sbal_first, fsf_req->sbal_number); | ||
4670 | atomic_add(fsf_req->sbal_number, &req_queue->free_count); | ||
4671 | req_queue->free_index -= fsf_req->sbal_number; | ||
4672 | req_queue->free_index += QDIO_MAX_BUFFERS_PER_Q; | ||
4673 | req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */ | ||
4674 | zfcp_erp_adapter_reopen(adapter, 0, 116, fsf_req); | ||
4675 | } else { | ||
4676 | req_queue->distance_from_int = new_distance_from_int; | ||
4677 | /* | ||
4678 | * increase FSF sequence counter - | ||
4679 | * this must only be done for request successfully enqueued to | ||
4680 | * QDIO this rejected requests may be cleaned up by calling | ||
4681 | * routines resulting in missing sequence counter values | ||
4682 | * otherwise, | ||
4683 | */ | ||
4684 | 2434 | ||
4685 | /* Don't increase for unsolicited status */ | 2435 | bottom = &req->qtcb->bottom.support; |
4686 | if (inc_seq_no) | 2436 | bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; |
4687 | adapter->fsf_req_seq_no++; | 2437 | bottom->option = fsf_cfdc->option; |
4688 | 2438 | ||
4689 | /* count FSF requests pending */ | 2439 | bytes = zfcp_qdio_sbals_from_sg(req, direction, fsf_cfdc->sg, |
4690 | atomic_inc(&adapter->reqs_active); | 2440 | FSF_MAX_SBALS_PER_REQ); |
2441 | if (bytes != ZFCP_CFDC_MAX_SIZE) { | ||
2442 | retval = -ENOMEM; | ||
2443 | zfcp_fsf_req_free(req); | ||
2444 | goto out; | ||
4691 | } | 2445 | } |
4692 | return retval; | ||
4693 | } | ||
4694 | 2446 | ||
4695 | #undef ZFCP_LOG_AREA | 2447 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); |
2448 | retval = zfcp_fsf_req_send(req); | ||
2449 | out: | ||
2450 | spin_unlock(&adapter->req_q.lock); | ||
2451 | |||
2452 | if (!retval) { | ||
2453 | wait_event(req->completion_wq, | ||
2454 | req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | ||
2455 | return req; | ||
2456 | } | ||
2457 | return ERR_PTR(retval); | ||
2458 | } | ||
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 099970b27001..bf94b4da0763 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h | |||
@@ -1,27 +1,16 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Interface to the FSF support functions. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #ifndef FSF_H | 9 | #ifndef FSF_H |
23 | #define FSF_H | 10 | #define FSF_H |
24 | 11 | ||
12 | #include <linux/pfn.h> | ||
13 | |||
25 | #define FSF_QTCB_CURRENT_VERSION 0x00000001 | 14 | #define FSF_QTCB_CURRENT_VERSION 0x00000001 |
26 | 15 | ||
27 | /* FSF commands */ | 16 | /* FSF commands */ |
@@ -258,6 +247,16 @@ | |||
258 | #define FSF_UNIT_ACCESS_EXCLUSIVE 0x02000000 | 247 | #define FSF_UNIT_ACCESS_EXCLUSIVE 0x02000000 |
259 | #define FSF_UNIT_ACCESS_OUTBOUND_TRANSFER 0x10000000 | 248 | #define FSF_UNIT_ACCESS_OUTBOUND_TRANSFER 0x10000000 |
260 | 249 | ||
250 | /* FSF interface for CFDC */ | ||
251 | #define ZFCP_CFDC_MAX_SIZE 127 * 1024 | ||
252 | #define ZFCP_CFDC_PAGES PFN_UP(ZFCP_CFDC_MAX_SIZE) | ||
253 | |||
254 | struct zfcp_fsf_cfdc { | ||
255 | struct scatterlist sg[ZFCP_CFDC_PAGES]; | ||
256 | u32 command; | ||
257 | u32 option; | ||
258 | }; | ||
259 | |||
261 | struct fsf_queue_designator { | 260 | struct fsf_queue_designator { |
262 | u8 cssid; | 261 | u8 cssid; |
263 | u8 chpid; | 262 | u8 chpid; |
@@ -288,6 +287,18 @@ struct fsf_bit_error_payload { | |||
288 | u32 current_transmit_b2b_credit; | 287 | u32 current_transmit_b2b_credit; |
289 | } __attribute__ ((packed)); | 288 | } __attribute__ ((packed)); |
290 | 289 | ||
290 | struct fsf_link_down_info { | ||
291 | u32 error_code; | ||
292 | u32 res1; | ||
293 | u8 res2[2]; | ||
294 | u8 primary_status; | ||
295 | u8 ioerr_code; | ||
296 | u8 action_code; | ||
297 | u8 reason_code; | ||
298 | u8 explanation_code; | ||
299 | u8 vendor_specific_code; | ||
300 | } __attribute__ ((packed)); | ||
301 | |||
291 | struct fsf_status_read_buffer { | 302 | struct fsf_status_read_buffer { |
292 | u32 status_type; | 303 | u32 status_type; |
293 | u32 status_subtype; | 304 | u32 status_subtype; |
@@ -298,7 +309,12 @@ struct fsf_status_read_buffer { | |||
298 | u32 class; | 309 | u32 class; |
299 | u64 fcp_lun; | 310 | u64 fcp_lun; |
300 | u8 res3[24]; | 311 | u8 res3[24]; |
301 | u8 payload[FSF_STATUS_READ_PAYLOAD_SIZE]; | 312 | union { |
313 | u8 data[FSF_STATUS_READ_PAYLOAD_SIZE]; | ||
314 | u32 word[FSF_STATUS_READ_PAYLOAD_SIZE/sizeof(u32)]; | ||
315 | struct fsf_link_down_info link_down_info; | ||
316 | struct fsf_bit_error_payload bit_error; | ||
317 | } payload; | ||
302 | } __attribute__ ((packed)); | 318 | } __attribute__ ((packed)); |
303 | 319 | ||
304 | struct fsf_qual_version_error { | 320 | struct fsf_qual_version_error { |
@@ -311,23 +327,19 @@ struct fsf_qual_sequence_error { | |||
311 | u32 res1[3]; | 327 | u32 res1[3]; |
312 | } __attribute__ ((packed)); | 328 | } __attribute__ ((packed)); |
313 | 329 | ||
314 | struct fsf_link_down_info { | 330 | struct fsf_qual_latency_info { |
315 | u32 error_code; | 331 | u32 channel_lat; |
316 | u32 res1; | 332 | u32 fabric_lat; |
317 | u8 res2[2]; | 333 | u8 res1[8]; |
318 | u8 primary_status; | ||
319 | u8 ioerr_code; | ||
320 | u8 action_code; | ||
321 | u8 reason_code; | ||
322 | u8 explanation_code; | ||
323 | u8 vendor_specific_code; | ||
324 | } __attribute__ ((packed)); | 334 | } __attribute__ ((packed)); |
325 | 335 | ||
326 | union fsf_prot_status_qual { | 336 | union fsf_prot_status_qual { |
337 | u32 word[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u32)]; | ||
327 | u64 doubleword[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u64)]; | 338 | u64 doubleword[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u64)]; |
328 | struct fsf_qual_version_error version_error; | 339 | struct fsf_qual_version_error version_error; |
329 | struct fsf_qual_sequence_error sequence_error; | 340 | struct fsf_qual_sequence_error sequence_error; |
330 | struct fsf_link_down_info link_down_info; | 341 | struct fsf_link_down_info link_down_info; |
342 | struct fsf_qual_latency_info latency_info; | ||
331 | } __attribute__ ((packed)); | 343 | } __attribute__ ((packed)); |
332 | 344 | ||
333 | struct fsf_qtcb_prefix { | 345 | struct fsf_qtcb_prefix { |
@@ -437,7 +449,9 @@ struct fsf_qtcb_bottom_config { | |||
437 | u32 fc_link_speed; | 449 | u32 fc_link_speed; |
438 | u32 adapter_type; | 450 | u32 adapter_type; |
439 | u32 peer_d_id; | 451 | u32 peer_d_id; |
440 | u8 res2[12]; | 452 | u8 res1[2]; |
453 | u16 timer_interval; | ||
454 | u8 res2[8]; | ||
441 | u32 s_id; | 455 | u32 s_id; |
442 | struct fsf_nport_serv_param nport_serv_param; | 456 | struct fsf_nport_serv_param nport_serv_param; |
443 | u8 reserved_nport_serv_param[16]; | 457 | u8 reserved_nport_serv_param[16]; |
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 8ca5f074c687..72e3094796d4 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c | |||
@@ -1,241 +1,103 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Setup and helper functions to access QDIO. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #include "zfcp_ext.h" | 9 | #include "zfcp_ext.h" |
23 | 10 | ||
24 | static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int); | 11 | /* FIXME(tune): free space should be one max. SBAL chain plus what? */ |
25 | static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get | 12 | #define ZFCP_QDIO_PCI_INTERVAL (QDIO_MAX_BUFFERS_PER_Q \ |
26 | (struct zfcp_qdio_queue *, int, int); | 13 | - (FSF_MAX_SBALS_PER_REQ + 4)) |
27 | static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp | 14 | #define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) |
28 | (struct zfcp_fsf_req *, int, int); | ||
29 | static volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain | ||
30 | (struct zfcp_fsf_req *, unsigned long); | ||
31 | static volatile struct qdio_buffer_element *zfcp_qdio_sbale_next | ||
32 | (struct zfcp_fsf_req *, unsigned long); | ||
33 | static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int); | ||
34 | static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *); | ||
35 | static void zfcp_qdio_sbale_fill | ||
36 | (struct zfcp_fsf_req *, unsigned long, void *, int); | ||
37 | static int zfcp_qdio_sbals_from_segment | ||
38 | (struct zfcp_fsf_req *, unsigned long, void *, unsigned long); | ||
39 | |||
40 | static qdio_handler_t zfcp_qdio_request_handler; | ||
41 | static qdio_handler_t zfcp_qdio_response_handler; | ||
42 | static int zfcp_qdio_handler_error_check(struct zfcp_adapter *, | ||
43 | unsigned int, unsigned int, unsigned int, int, int); | ||
44 | |||
45 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_QDIO | ||
46 | |||
47 | /* | ||
48 | * Frees BUFFER memory for each of the pointers of the struct qdio_buffer array | ||
49 | * in the adapter struct sbuf is the pointer array. | ||
50 | * | ||
51 | * locks: must only be called with zfcp_data.config_sema taken | ||
52 | */ | ||
53 | static void | ||
54 | zfcp_qdio_buffers_dequeue(struct qdio_buffer **sbuf) | ||
55 | { | ||
56 | int pos; | ||
57 | |||
58 | for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) | ||
59 | free_page((unsigned long) sbuf[pos]); | ||
60 | } | ||
61 | 15 | ||
62 | /* | 16 | static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal) |
63 | * Allocates BUFFER memory to each of the pointers of the qdio_buffer_t | ||
64 | * array in the adapter struct. | ||
65 | * Cur_buf is the pointer array | ||
66 | * | ||
67 | * returns: zero on success else -ENOMEM | ||
68 | * locks: must only be called with zfcp_data.config_sema taken | ||
69 | */ | ||
70 | static int | ||
71 | zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbuf) | ||
72 | { | 17 | { |
73 | int pos; | 18 | int pos; |
74 | 19 | ||
75 | for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) { | 20 | for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) { |
76 | sbuf[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL); | 21 | sbal[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL); |
77 | if (!sbuf[pos]) { | 22 | if (!sbal[pos]) |
78 | zfcp_qdio_buffers_dequeue(sbuf); | ||
79 | return -ENOMEM; | 23 | return -ENOMEM; |
80 | } | ||
81 | } | 24 | } |
82 | for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos++) | 25 | for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos++) |
83 | if (pos % QBUFF_PER_PAGE) | 26 | if (pos % QBUFF_PER_PAGE) |
84 | sbuf[pos] = sbuf[pos - 1] + 1; | 27 | sbal[pos] = sbal[pos - 1] + 1; |
85 | return 0; | 28 | return 0; |
86 | } | 29 | } |
87 | 30 | ||
88 | /* locks: must only be called with zfcp_data.config_sema taken */ | 31 | static volatile struct qdio_buffer_element * |
89 | int | 32 | zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx) |
90 | zfcp_qdio_allocate_queues(struct zfcp_adapter *adapter) | ||
91 | { | 33 | { |
92 | int ret; | 34 | return &q->sbal[sbal_idx]->element[sbale_idx]; |
93 | |||
94 | ret = zfcp_qdio_buffers_enqueue(adapter->request_queue.buffer); | ||
95 | if (ret) | ||
96 | return ret; | ||
97 | return zfcp_qdio_buffers_enqueue(adapter->response_queue.buffer); | ||
98 | } | 35 | } |
99 | 36 | ||
100 | /* locks: must only be called with zfcp_data.config_sema taken */ | 37 | /** |
101 | void | 38 | * zfcp_qdio_free - free memory used by request- and resposne queue |
102 | zfcp_qdio_free_queues(struct zfcp_adapter *adapter) | 39 | * @adapter: pointer to the zfcp_adapter structure |
40 | */ | ||
41 | void zfcp_qdio_free(struct zfcp_adapter *adapter) | ||
103 | { | 42 | { |
104 | ZFCP_LOG_TRACE("freeing request_queue buffers\n"); | 43 | struct qdio_buffer **sbal_req, **sbal_resp; |
105 | zfcp_qdio_buffers_dequeue(adapter->request_queue.buffer); | 44 | int p; |
106 | 45 | ||
107 | ZFCP_LOG_TRACE("freeing response_queue buffers\n"); | 46 | if (adapter->ccw_device) |
108 | zfcp_qdio_buffers_dequeue(adapter->response_queue.buffer); | 47 | qdio_free(adapter->ccw_device); |
109 | } | ||
110 | 48 | ||
111 | int | 49 | sbal_req = adapter->req_q.sbal; |
112 | zfcp_qdio_allocate(struct zfcp_adapter *adapter) | 50 | sbal_resp = adapter->resp_q.sbal; |
113 | { | ||
114 | struct qdio_initialize *init_data; | ||
115 | 51 | ||
116 | init_data = &adapter->qdio_init_data; | 52 | for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) { |
53 | free_page((unsigned long) sbal_req[p]); | ||
54 | free_page((unsigned long) sbal_resp[p]); | ||
55 | } | ||
56 | } | ||
117 | 57 | ||
118 | init_data->cdev = adapter->ccw_device; | 58 | static void zfcp_qdio_handler_error(struct zfcp_adapter *adapter, u8 id) |
119 | init_data->q_format = QDIO_SCSI_QFMT; | 59 | { |
120 | memcpy(init_data->adapter_name, zfcp_get_busid_by_adapter(adapter), 8); | 60 | dev_warn(&adapter->ccw_device->dev, "QDIO problem occurred.\n"); |
121 | ASCEBC(init_data->adapter_name, 8); | ||
122 | init_data->qib_param_field_format = 0; | ||
123 | init_data->qib_param_field = NULL; | ||
124 | init_data->input_slib_elements = NULL; | ||
125 | init_data->output_slib_elements = NULL; | ||
126 | init_data->min_input_threshold = ZFCP_MIN_INPUT_THRESHOLD; | ||
127 | init_data->max_input_threshold = ZFCP_MAX_INPUT_THRESHOLD; | ||
128 | init_data->min_output_threshold = ZFCP_MIN_OUTPUT_THRESHOLD; | ||
129 | init_data->max_output_threshold = ZFCP_MAX_OUTPUT_THRESHOLD; | ||
130 | init_data->no_input_qs = 1; | ||
131 | init_data->no_output_qs = 1; | ||
132 | init_data->input_handler = zfcp_qdio_response_handler; | ||
133 | init_data->output_handler = zfcp_qdio_request_handler; | ||
134 | init_data->int_parm = (unsigned long) adapter; | ||
135 | init_data->flags = QDIO_INBOUND_0COPY_SBALS | | ||
136 | QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS; | ||
137 | init_data->input_sbal_addr_array = | ||
138 | (void **) (adapter->response_queue.buffer); | ||
139 | init_data->output_sbal_addr_array = | ||
140 | (void **) (adapter->request_queue.buffer); | ||
141 | 61 | ||
142 | return qdio_allocate(init_data); | 62 | zfcp_erp_adapter_reopen(adapter, |
63 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | ||
64 | ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL); | ||
143 | } | 65 | } |
144 | 66 | ||
145 | /* | 67 | static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt) |
146 | * function: zfcp_qdio_handler_error_check | ||
147 | * | ||
148 | * purpose: called by the response handler to determine error condition | ||
149 | * | ||
150 | * returns: error flag | ||
151 | * | ||
152 | */ | ||
153 | static int | ||
154 | zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status, | ||
155 | unsigned int qdio_error, unsigned int siga_error, | ||
156 | int first_element, int elements_processed) | ||
157 | { | 68 | { |
158 | int retval = 0; | 69 | int i, sbal_idx; |
159 | 70 | ||
160 | if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) { | 71 | for (i = first; i < first + cnt; i++) { |
161 | retval = -EIO; | 72 | sbal_idx = i % QDIO_MAX_BUFFERS_PER_Q; |
162 | 73 | memset(sbal[sbal_idx], 0, sizeof(struct qdio_buffer)); | |
163 | ZFCP_LOG_INFO("QDIO problem occurred (status=0x%x, " | ||
164 | "qdio_error=0x%x, siga_error=0x%x)\n", | ||
165 | status, qdio_error, siga_error); | ||
166 | |||
167 | zfcp_hba_dbf_event_qdio(adapter, status, qdio_error, siga_error, | ||
168 | first_element, elements_processed); | ||
169 | /* | ||
170 | * Restarting IO on the failed adapter from scratch. | ||
171 | * Since we have been using this adapter, it is save to assume | ||
172 | * that it is not failed but recoverable. The card seems to | ||
173 | * report link-up events by self-initiated queue shutdown. | ||
174 | * That is why we need to clear the link-down flag | ||
175 | * which is set again in case we have missed by a mile. | ||
176 | */ | ||
177 | zfcp_erp_adapter_reopen(adapter, | ||
178 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | ||
179 | ZFCP_STATUS_COMMON_ERP_FAILED, 140, | ||
180 | NULL); | ||
181 | } | 74 | } |
182 | return retval; | ||
183 | } | 75 | } |
184 | 76 | ||
185 | /* | 77 | static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int status, |
186 | * function: zfcp_qdio_request_handler | 78 | unsigned int qdio_err, unsigned int siga_err, |
187 | * | 79 | unsigned int queue_no, int first, int count, |
188 | * purpose: is called by QDIO layer for completed SBALs in request queue | 80 | unsigned long parm) |
189 | * | ||
190 | * returns: (void) | ||
191 | */ | ||
192 | static void | ||
193 | zfcp_qdio_request_handler(struct ccw_device *ccw_device, | ||
194 | unsigned int status, | ||
195 | unsigned int qdio_error, | ||
196 | unsigned int siga_error, | ||
197 | unsigned int queue_number, | ||
198 | int first_element, | ||
199 | int elements_processed, | ||
200 | unsigned long int_parm) | ||
201 | { | 81 | { |
202 | struct zfcp_adapter *adapter; | 82 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm; |
203 | struct zfcp_qdio_queue *queue; | 83 | struct zfcp_qdio_queue *queue = &adapter->req_q; |
204 | |||
205 | adapter = (struct zfcp_adapter *) int_parm; | ||
206 | queue = &adapter->request_queue; | ||
207 | |||
208 | ZFCP_LOG_DEBUG("adapter %s, first=%d, elements_processed=%d\n", | ||
209 | zfcp_get_busid_by_adapter(adapter), | ||
210 | first_element, elements_processed); | ||
211 | 84 | ||
212 | if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error, | 85 | if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) { |
213 | siga_error, first_element, | 86 | zfcp_hba_dbf_event_qdio(adapter, status, qdio_err, siga_err, |
214 | elements_processed))) | 87 | first, count); |
215 | goto out; | 88 | zfcp_qdio_handler_error(adapter, 140); |
216 | /* | 89 | return; |
217 | * we stored address of struct zfcp_adapter data structure | 90 | } |
218 | * associated with irq in int_parm | ||
219 | */ | ||
220 | 91 | ||
221 | /* cleanup all SBALs being program-owned now */ | 92 | /* cleanup all SBALs being program-owned now */ |
222 | zfcp_qdio_zero_sbals(queue->buffer, first_element, elements_processed); | 93 | zfcp_qdio_zero_sbals(queue->sbal, first, count); |
223 | 94 | ||
224 | /* increase free space in outbound queue */ | 95 | atomic_add(count, &queue->count); |
225 | atomic_add(elements_processed, &queue->free_count); | ||
226 | ZFCP_LOG_DEBUG("free_count=%d\n", atomic_read(&queue->free_count)); | ||
227 | wake_up(&adapter->request_wq); | 96 | wake_up(&adapter->request_wq); |
228 | ZFCP_LOG_DEBUG("elements_processed=%d, free count=%d\n", | ||
229 | elements_processed, atomic_read(&queue->free_count)); | ||
230 | out: | ||
231 | return; | ||
232 | } | 97 | } |
233 | 98 | ||
234 | /** | ||
235 | * zfcp_qdio_reqid_check - checks for valid reqids. | ||
236 | */ | ||
237 | static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, | 99 | static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, |
238 | unsigned long req_id) | 100 | unsigned long req_id, int sbal_idx) |
239 | { | 101 | { |
240 | struct zfcp_fsf_req *fsf_req; | 102 | struct zfcp_fsf_req *fsf_req; |
241 | unsigned long flags; | 103 | unsigned long flags; |
@@ -248,203 +110,117 @@ static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, | |||
248 | * Unknown request means that we have potentially memory | 110 | * Unknown request means that we have potentially memory |
249 | * corruption and must stop the machine immediatly. | 111 | * corruption and must stop the machine immediatly. |
250 | */ | 112 | */ |
251 | panic("error: unknown request id (%ld) on adapter %s.\n", | 113 | panic("error: unknown request id (%lx) on adapter %s.\n", |
252 | req_id, zfcp_get_busid_by_adapter(adapter)); | 114 | req_id, zfcp_get_busid_by_adapter(adapter)); |
253 | 115 | ||
254 | zfcp_reqlist_remove(adapter, fsf_req); | 116 | zfcp_reqlist_remove(adapter, fsf_req); |
255 | atomic_dec(&adapter->reqs_active); | ||
256 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); | 117 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); |
257 | 118 | ||
258 | /* finish the FSF request */ | 119 | fsf_req->sbal_response = sbal_idx; |
259 | zfcp_fsf_req_complete(fsf_req); | 120 | zfcp_fsf_req_complete(fsf_req); |
260 | } | 121 | } |
261 | 122 | ||
262 | /* | 123 | static void zfcp_qdio_resp_put_back(struct zfcp_adapter *adapter, int processed) |
263 | * function: zfcp_qdio_response_handler | ||
264 | * | ||
265 | * purpose: is called by QDIO layer for completed SBALs in response queue | ||
266 | * | ||
267 | * returns: (void) | ||
268 | */ | ||
269 | static void | ||
270 | zfcp_qdio_response_handler(struct ccw_device *ccw_device, | ||
271 | unsigned int status, | ||
272 | unsigned int qdio_error, | ||
273 | unsigned int siga_error, | ||
274 | unsigned int queue_number, | ||
275 | int first_element, | ||
276 | int elements_processed, | ||
277 | unsigned long int_parm) | ||
278 | { | 124 | { |
279 | struct zfcp_adapter *adapter; | 125 | struct zfcp_qdio_queue *queue = &adapter->resp_q; |
280 | struct zfcp_qdio_queue *queue; | 126 | struct ccw_device *cdev = adapter->ccw_device; |
281 | int buffer_index; | 127 | u8 count, start = queue->first; |
282 | int i; | 128 | unsigned int retval; |
283 | struct qdio_buffer *buffer; | ||
284 | int retval = 0; | ||
285 | u8 count; | ||
286 | u8 start; | ||
287 | volatile struct qdio_buffer_element *buffere = NULL; | ||
288 | int buffere_index; | ||
289 | |||
290 | adapter = (struct zfcp_adapter *) int_parm; | ||
291 | queue = &adapter->response_queue; | ||
292 | |||
293 | if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error, | ||
294 | siga_error, first_element, | ||
295 | elements_processed))) | ||
296 | goto out; | ||
297 | 129 | ||
298 | /* | 130 | count = atomic_read(&queue->count) + processed; |
299 | * we stored address of struct zfcp_adapter data structure | 131 | |
300 | * associated with irq in int_parm | 132 | retval = do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, |
301 | */ | 133 | 0, start, count, NULL); |
134 | |||
135 | if (unlikely(retval)) { | ||
136 | atomic_set(&queue->count, count); | ||
137 | /* FIXME: Recover this with an adapter reopen? */ | ||
138 | } else { | ||
139 | queue->first += count; | ||
140 | queue->first %= QDIO_MAX_BUFFERS_PER_Q; | ||
141 | atomic_set(&queue->count, 0); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int status, | ||
146 | unsigned int qdio_err, unsigned int siga_err, | ||
147 | unsigned int queue_no, int first, int count, | ||
148 | unsigned long parm) | ||
149 | { | ||
150 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm; | ||
151 | struct zfcp_qdio_queue *queue = &adapter->resp_q; | ||
152 | volatile struct qdio_buffer_element *sbale; | ||
153 | int sbal_idx, sbale_idx, sbal_no; | ||
154 | |||
155 | if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) { | ||
156 | zfcp_hba_dbf_event_qdio(adapter, status, qdio_err, siga_err, | ||
157 | first, count); | ||
158 | zfcp_qdio_handler_error(adapter, 147); | ||
159 | return; | ||
160 | } | ||
302 | 161 | ||
303 | buffere = &(queue->buffer[first_element]->element[0]); | ||
304 | ZFCP_LOG_DEBUG("first BUFFERE flags=0x%x\n", buffere->flags); | ||
305 | /* | 162 | /* |
306 | * go through all SBALs from input queue currently | 163 | * go through all SBALs from input queue currently |
307 | * returned by QDIO layer | 164 | * returned by QDIO layer |
308 | */ | 165 | */ |
309 | 166 | for (sbal_no = 0; sbal_no < count; sbal_no++) { | |
310 | for (i = 0; i < elements_processed; i++) { | 167 | sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q; |
311 | |||
312 | buffer_index = first_element + i; | ||
313 | buffer_index %= QDIO_MAX_BUFFERS_PER_Q; | ||
314 | buffer = queue->buffer[buffer_index]; | ||
315 | 168 | ||
316 | /* go through all SBALEs of SBAL */ | 169 | /* go through all SBALEs of SBAL */ |
317 | for (buffere_index = 0; | 170 | for (sbale_idx = 0; sbale_idx < QDIO_MAX_ELEMENTS_PER_BUFFER; |
318 | buffere_index < QDIO_MAX_ELEMENTS_PER_BUFFER; | 171 | sbale_idx++) { |
319 | buffere_index++) { | 172 | sbale = zfcp_qdio_sbale(queue, sbal_idx, sbale_idx); |
320 | |||
321 | /* look for QDIO request identifiers in SB */ | ||
322 | buffere = &buffer->element[buffere_index]; | ||
323 | zfcp_qdio_reqid_check(adapter, | 173 | zfcp_qdio_reqid_check(adapter, |
324 | (unsigned long) buffere->addr); | 174 | (unsigned long) sbale->addr, |
325 | 175 | sbal_idx); | |
326 | /* | 176 | if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY)) |
327 | * A single used SBALE per inbound SBALE has been | ||
328 | * implemented by QDIO so far. Hope they will | ||
329 | * do some optimisation. Will need to change to | ||
330 | * unlikely() then. | ||
331 | */ | ||
332 | if (likely(buffere->flags & SBAL_FLAGS_LAST_ENTRY)) | ||
333 | break; | 177 | break; |
334 | }; | 178 | }; |
335 | 179 | ||
336 | if (unlikely(!(buffere->flags & SBAL_FLAGS_LAST_ENTRY))) { | 180 | if (unlikely(!(sbale->flags & SBAL_FLAGS_LAST_ENTRY))) |
337 | ZFCP_LOG_NORMAL("bug: End of inbound data " | 181 | dev_warn(&adapter->ccw_device->dev, |
338 | "not marked!\n"); | 182 | "Protocol violation by adapter. " |
339 | } | 183 | "Continuing operations.\n"); |
340 | } | 184 | } |
341 | 185 | ||
342 | /* | 186 | /* |
343 | * put range of SBALs back to response queue | 187 | * put range of SBALs back to response queue |
344 | * (including SBALs which have already been free before) | 188 | * (including SBALs which have already been free before) |
345 | */ | 189 | */ |
346 | count = atomic_read(&queue->free_count) + elements_processed; | 190 | zfcp_qdio_resp_put_back(adapter, count); |
347 | start = queue->free_index; | ||
348 | |||
349 | ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, " | ||
350 | "queue_no=%i, index_in_queue=%i, count=%i, " | ||
351 | "buffers=0x%lx\n", | ||
352 | zfcp_get_busid_by_adapter(adapter), | ||
353 | QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, | ||
354 | 0, start, count, (unsigned long) &queue->buffer[start]); | ||
355 | |||
356 | retval = do_QDIO(ccw_device, | ||
357 | QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, | ||
358 | 0, start, count, NULL); | ||
359 | |||
360 | if (unlikely(retval)) { | ||
361 | atomic_set(&queue->free_count, count); | ||
362 | ZFCP_LOG_DEBUG("clearing of inbound data regions failed, " | ||
363 | "queues may be down " | ||
364 | "(count=%d, start=%d, retval=%d)\n", | ||
365 | count, start, retval); | ||
366 | } else { | ||
367 | queue->free_index += count; | ||
368 | queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; | ||
369 | atomic_set(&queue->free_count, 0); | ||
370 | ZFCP_LOG_TRACE("%i buffers enqueued to response " | ||
371 | "queue at position %i\n", count, start); | ||
372 | } | ||
373 | out: | ||
374 | return; | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * zfcp_qdio_sbale_get - return pointer to SBALE of qdio_queue | ||
379 | * @queue: queue from which SBALE should be returned | ||
380 | * @sbal: specifies number of SBAL in queue | ||
381 | * @sbale: specifes number of SBALE in SBAL | ||
382 | */ | ||
383 | static inline volatile struct qdio_buffer_element * | ||
384 | zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale) | ||
385 | { | ||
386 | return &queue->buffer[sbal]->element[sbale]; | ||
387 | } | 191 | } |
388 | 192 | ||
389 | /** | 193 | /** |
390 | * zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for | 194 | * zfcp_qdio_sbale_req - return ptr to SBALE of req_q for a struct zfcp_fsf_req |
391 | * a struct zfcp_fsf_req | 195 | * @fsf_req: pointer to struct fsf_req |
196 | * Returns: pointer to qdio_buffer_element (SBALE) structure | ||
392 | */ | 197 | */ |
393 | volatile struct qdio_buffer_element * | 198 | volatile struct qdio_buffer_element * |
394 | zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale) | 199 | zfcp_qdio_sbale_req(struct zfcp_fsf_req *req) |
395 | { | 200 | { |
396 | return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue, | 201 | return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, 0); |
397 | sbal, sbale); | ||
398 | } | 202 | } |
399 | 203 | ||
400 | /** | 204 | /** |
401 | * zfcp_qdio_sbale_resp - return pointer to SBALE of response_queue for | 205 | * zfcp_qdio_sbale_curr - return curr SBALE on req_q for a struct zfcp_fsf_req |
402 | * a struct zfcp_fsf_req | 206 | * @fsf_req: pointer to struct fsf_req |
403 | */ | 207 | * Returns: pointer to qdio_buffer_element (SBALE) structure |
404 | static inline volatile struct qdio_buffer_element * | ||
405 | zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale) | ||
406 | { | ||
407 | return zfcp_qdio_sbale_get(&fsf_req->adapter->response_queue, | ||
408 | sbal, sbale); | ||
409 | } | ||
410 | |||
411 | /** | ||
412 | * zfcp_qdio_sbale_curr - return current SBALE on request_queue for | ||
413 | * a struct zfcp_fsf_req | ||
414 | */ | 208 | */ |
415 | volatile struct qdio_buffer_element * | 209 | volatile struct qdio_buffer_element * |
416 | zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req) | 210 | zfcp_qdio_sbale_curr(struct zfcp_fsf_req *req) |
417 | { | 211 | { |
418 | return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, | 212 | return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, |
419 | fsf_req->sbale_curr); | 213 | req->sbale_curr); |
420 | } | 214 | } |
421 | 215 | ||
422 | /** | 216 | static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) |
423 | * zfcp_qdio_sbal_limit - determine maximum number of SBALs that can be used | ||
424 | * on the request_queue for a struct zfcp_fsf_req | ||
425 | * @fsf_req: the number of the last SBAL that can be used is stored herein | ||
426 | * @max_sbals: used to pass an upper limit for the number of SBALs | ||
427 | * | ||
428 | * Note: We can assume at least one free SBAL in the request_queue when called. | ||
429 | */ | ||
430 | static void | ||
431 | zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) | ||
432 | { | 217 | { |
433 | int count = atomic_read(&fsf_req->adapter->request_queue.free_count); | 218 | int count = atomic_read(&fsf_req->adapter->req_q.count); |
434 | count = min(count, max_sbals); | 219 | count = min(count, max_sbals); |
435 | fsf_req->sbal_last = fsf_req->sbal_first; | 220 | fsf_req->sbal_limit = (fsf_req->sbal_first + count - 1) |
436 | fsf_req->sbal_last += (count - 1); | 221 | % QDIO_MAX_BUFFERS_PER_Q; |
437 | fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q; | ||
438 | } | 222 | } |
439 | 223 | ||
440 | /** | ||
441 | * zfcp_qdio_sbal_chain - chain SBALs if more than one SBAL is needed for a | ||
442 | * request | ||
443 | * @fsf_req: zfcp_fsf_req to be processed | ||
444 | * @sbtype: SBAL flags which have to be set in first SBALE of new SBAL | ||
445 | * | ||
446 | * This function changes sbal_curr, sbale_curr, sbal_number of fsf_req. | ||
447 | */ | ||
448 | static volatile struct qdio_buffer_element * | 224 | static volatile struct qdio_buffer_element * |
449 | zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) | 225 | zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) |
450 | { | 226 | { |
@@ -455,16 +231,16 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) | |||
455 | sbale->flags |= SBAL_FLAGS_LAST_ENTRY; | 231 | sbale->flags |= SBAL_FLAGS_LAST_ENTRY; |
456 | 232 | ||
457 | /* don't exceed last allowed SBAL */ | 233 | /* don't exceed last allowed SBAL */ |
458 | if (fsf_req->sbal_curr == fsf_req->sbal_last) | 234 | if (fsf_req->sbal_last == fsf_req->sbal_limit) |
459 | return NULL; | 235 | return NULL; |
460 | 236 | ||
461 | /* set chaining flag in first SBALE of current SBAL */ | 237 | /* set chaining flag in first SBALE of current SBAL */ |
462 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 238 | sbale = zfcp_qdio_sbale_req(fsf_req); |
463 | sbale->flags |= SBAL_FLAGS0_MORE_SBALS; | 239 | sbale->flags |= SBAL_FLAGS0_MORE_SBALS; |
464 | 240 | ||
465 | /* calculate index of next SBAL */ | 241 | /* calculate index of next SBAL */ |
466 | fsf_req->sbal_curr++; | 242 | fsf_req->sbal_last++; |
467 | fsf_req->sbal_curr %= QDIO_MAX_BUFFERS_PER_Q; | 243 | fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q; |
468 | 244 | ||
469 | /* keep this requests number of SBALs up-to-date */ | 245 | /* keep this requests number of SBALs up-to-date */ |
470 | fsf_req->sbal_number++; | 246 | fsf_req->sbal_number++; |
@@ -479,214 +255,255 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) | |||
479 | return sbale; | 255 | return sbale; |
480 | } | 256 | } |
481 | 257 | ||
482 | /** | ||
483 | * zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed | ||
484 | */ | ||
485 | static volatile struct qdio_buffer_element * | 258 | static volatile struct qdio_buffer_element * |
486 | zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) | 259 | zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) |
487 | { | 260 | { |
488 | if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) | 261 | if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) |
489 | return zfcp_qdio_sbal_chain(fsf_req, sbtype); | 262 | return zfcp_qdio_sbal_chain(fsf_req, sbtype); |
490 | |||
491 | fsf_req->sbale_curr++; | 263 | fsf_req->sbale_curr++; |
492 | |||
493 | return zfcp_qdio_sbale_curr(fsf_req); | 264 | return zfcp_qdio_sbale_curr(fsf_req); |
494 | } | 265 | } |
495 | 266 | ||
496 | /** | 267 | static void zfcp_qdio_undo_sbals(struct zfcp_fsf_req *fsf_req) |
497 | * zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue | ||
498 | * with zero from | ||
499 | */ | ||
500 | static int | ||
501 | zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last) | ||
502 | { | ||
503 | struct qdio_buffer **buf = queue->buffer; | ||
504 | int curr = first; | ||
505 | int count = 0; | ||
506 | |||
507 | for(;;) { | ||
508 | curr %= QDIO_MAX_BUFFERS_PER_Q; | ||
509 | count++; | ||
510 | memset(buf[curr], 0, sizeof(struct qdio_buffer)); | ||
511 | if (curr == last) | ||
512 | break; | ||
513 | curr++; | ||
514 | } | ||
515 | return count; | ||
516 | } | ||
517 | |||
518 | |||
519 | /** | ||
520 | * zfcp_qdio_sbals_wipe - reset all changes in SBALs for an fsf_req | ||
521 | */ | ||
522 | static inline int | ||
523 | zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req) | ||
524 | { | 268 | { |
525 | return zfcp_qdio_sbals_zero(&fsf_req->adapter->request_queue, | 269 | struct qdio_buffer **sbal = fsf_req->adapter->req_q.sbal; |
526 | fsf_req->sbal_first, fsf_req->sbal_curr); | 270 | int first = fsf_req->sbal_first; |
271 | int last = fsf_req->sbal_last; | ||
272 | int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) % | ||
273 | QDIO_MAX_BUFFERS_PER_Q + 1; | ||
274 | zfcp_qdio_zero_sbals(sbal, first, count); | ||
527 | } | 275 | } |
528 | 276 | ||
529 | 277 | static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req, | |
530 | /** | 278 | unsigned int sbtype, void *start_addr, |
531 | * zfcp_qdio_sbale_fill - set address and length in current SBALE | 279 | unsigned int total_length) |
532 | * on request_queue | ||
533 | */ | ||
534 | static void | ||
535 | zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, | ||
536 | void *addr, int length) | ||
537 | { | 280 | { |
538 | volatile struct qdio_buffer_element *sbale; | 281 | volatile struct qdio_buffer_element *sbale; |
539 | |||
540 | sbale = zfcp_qdio_sbale_curr(fsf_req); | ||
541 | sbale->addr = addr; | ||
542 | sbale->length = length; | ||
543 | } | ||
544 | |||
545 | /** | ||
546 | * zfcp_qdio_sbals_from_segment - map memory segment to SBALE(s) | ||
547 | * @fsf_req: request to be processed | ||
548 | * @sbtype: SBALE flags | ||
549 | * @start_addr: address of memory segment | ||
550 | * @total_length: length of memory segment | ||
551 | * | ||
552 | * Alignment and length of the segment determine how many SBALEs are needed | ||
553 | * for the memory segment. | ||
554 | */ | ||
555 | static int | ||
556 | zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, | ||
557 | void *start_addr, unsigned long total_length) | ||
558 | { | ||
559 | unsigned long remaining, length; | 282 | unsigned long remaining, length; |
560 | void *addr; | 283 | void *addr; |
561 | 284 | ||
562 | /* split segment up heeding page boundaries */ | 285 | /* split segment up */ |
563 | for (addr = start_addr, remaining = total_length; remaining > 0; | 286 | for (addr = start_addr, remaining = total_length; remaining > 0; |
564 | addr += length, remaining -= length) { | 287 | addr += length, remaining -= length) { |
565 | /* get next free SBALE for new piece */ | 288 | sbale = zfcp_qdio_sbale_next(fsf_req, sbtype); |
566 | if (NULL == zfcp_qdio_sbale_next(fsf_req, sbtype)) { | 289 | if (!sbale) { |
567 | /* no SBALE left, clean up and leave */ | 290 | zfcp_qdio_undo_sbals(fsf_req); |
568 | zfcp_qdio_sbals_wipe(fsf_req); | ||
569 | return -EINVAL; | 291 | return -EINVAL; |
570 | } | 292 | } |
571 | /* calculate length of new piece */ | 293 | |
294 | /* new piece must not exceed next page boundary */ | ||
572 | length = min(remaining, | 295 | length = min(remaining, |
573 | (PAGE_SIZE - ((unsigned long) addr & | 296 | (PAGE_SIZE - ((unsigned long)addr & |
574 | (PAGE_SIZE - 1)))); | 297 | (PAGE_SIZE - 1)))); |
575 | /* fill current SBALE with calculated piece */ | 298 | sbale->addr = addr; |
576 | zfcp_qdio_sbale_fill(fsf_req, sbtype, addr, length); | 299 | sbale->length = length; |
577 | } | 300 | } |
578 | return total_length; | 301 | return 0; |
579 | } | 302 | } |
580 | 303 | ||
581 | |||
582 | /** | 304 | /** |
583 | * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list | 305 | * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list |
584 | * @fsf_req: request to be processed | 306 | * @fsf_req: request to be processed |
585 | * @sbtype: SBALE flags | 307 | * @sbtype: SBALE flags |
586 | * @sg: scatter-gather list | 308 | * @sg: scatter-gather list |
587 | * @sg_count: number of elements in scatter-gather list | ||
588 | * @max_sbals: upper bound for number of SBALs to be used | 309 | * @max_sbals: upper bound for number of SBALs to be used |
310 | * Returns: number of bytes, or error (negativ) | ||
589 | */ | 311 | */ |
590 | int | 312 | int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, |
591 | zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, | 313 | struct scatterlist *sg, int max_sbals) |
592 | struct scatterlist *sgl, int sg_count, int max_sbals) | ||
593 | { | 314 | { |
594 | int sg_index; | ||
595 | struct scatterlist *sg_segment; | ||
596 | int retval; | ||
597 | volatile struct qdio_buffer_element *sbale; | 315 | volatile struct qdio_buffer_element *sbale; |
598 | int bytes = 0; | 316 | int retval, bytes = 0; |
599 | 317 | ||
600 | /* figure out last allowed SBAL */ | 318 | /* figure out last allowed SBAL */ |
601 | zfcp_qdio_sbal_limit(fsf_req, max_sbals); | 319 | zfcp_qdio_sbal_limit(fsf_req, max_sbals); |
602 | 320 | ||
603 | /* set storage-block type for current SBAL */ | 321 | /* set storage-block type for this request */ |
604 | sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); | 322 | sbale = zfcp_qdio_sbale_req(fsf_req); |
605 | sbale->flags |= sbtype; | 323 | sbale->flags |= sbtype; |
606 | 324 | ||
607 | /* process all segements of scatter-gather list */ | 325 | for (; sg; sg = sg_next(sg)) { |
608 | for_each_sg(sgl, sg_segment, sg_count, sg_index) { | 326 | retval = zfcp_qdio_fill_sbals(fsf_req, sbtype, sg_virt(sg), |
609 | retval = zfcp_qdio_sbals_from_segment( | 327 | sg->length); |
610 | fsf_req, | 328 | if (retval < 0) |
611 | sbtype, | 329 | return retval; |
612 | zfcp_sg_to_address(sg_segment), | 330 | bytes += sg->length; |
613 | sg_segment->length); | ||
614 | if (retval < 0) { | ||
615 | bytes = retval; | ||
616 | goto out; | ||
617 | } else | ||
618 | bytes += retval; | ||
619 | } | 331 | } |
332 | |||
620 | /* assume that no other SBALEs are to follow in the same SBAL */ | 333 | /* assume that no other SBALEs are to follow in the same SBAL */ |
621 | sbale = zfcp_qdio_sbale_curr(fsf_req); | 334 | sbale = zfcp_qdio_sbale_curr(fsf_req); |
622 | sbale->flags |= SBAL_FLAGS_LAST_ENTRY; | 335 | sbale->flags |= SBAL_FLAGS_LAST_ENTRY; |
623 | out: | 336 | |
624 | return bytes; | 337 | return bytes; |
625 | } | 338 | } |
626 | 339 | ||
627 | |||
628 | /** | 340 | /** |
629 | * zfcp_qdio_sbals_from_scsicmnd - fill SBALs from scsi command | 341 | * zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO |
630 | * @fsf_req: request to be processed | 342 | * @fsf_req: pointer to struct zfcp_fsf_req |
631 | * @sbtype: SBALE flags | 343 | * Returns: 0 on success, error otherwise |
632 | * @scsi_cmnd: either scatter-gather list or buffer contained herein is used | ||
633 | * to fill SBALs | ||
634 | */ | 344 | */ |
635 | int | 345 | int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req) |
636 | zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req, | ||
637 | unsigned long sbtype, struct scsi_cmnd *scsi_cmnd) | ||
638 | { | 346 | { |
639 | return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, scsi_sglist(scsi_cmnd), | 347 | struct zfcp_adapter *adapter = fsf_req->adapter; |
640 | scsi_sg_count(scsi_cmnd), | 348 | struct zfcp_qdio_queue *req_q = &adapter->req_q; |
641 | ZFCP_MAX_SBALS_PER_REQ); | 349 | int first = fsf_req->sbal_first; |
350 | int count = fsf_req->sbal_number; | ||
351 | int retval, pci, pci_batch; | ||
352 | volatile struct qdio_buffer_element *sbale; | ||
353 | |||
354 | /* acknowledgements for transferred buffers */ | ||
355 | pci_batch = req_q->pci_batch + count; | ||
356 | if (unlikely(pci_batch >= ZFCP_QDIO_PCI_INTERVAL)) { | ||
357 | pci_batch %= ZFCP_QDIO_PCI_INTERVAL; | ||
358 | pci = first + count - (pci_batch + 1); | ||
359 | pci %= QDIO_MAX_BUFFERS_PER_Q; | ||
360 | sbale = zfcp_qdio_sbale(req_q, pci, 0); | ||
361 | sbale->flags |= SBAL_FLAGS0_PCI; | ||
362 | } | ||
363 | |||
364 | retval = do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0, first, | ||
365 | count, NULL); | ||
366 | if (unlikely(retval)) { | ||
367 | zfcp_qdio_zero_sbals(req_q->sbal, first, count); | ||
368 | return retval; | ||
369 | } | ||
370 | |||
371 | /* account for transferred buffers */ | ||
372 | atomic_sub(count, &req_q->count); | ||
373 | req_q->first += count; | ||
374 | req_q->first %= QDIO_MAX_BUFFERS_PER_Q; | ||
375 | req_q->pci_batch = pci_batch; | ||
376 | return 0; | ||
642 | } | 377 | } |
643 | 378 | ||
644 | /** | 379 | /** |
645 | * zfcp_qdio_determine_pci - set PCI flag in first SBALE on qdio queue if needed | 380 | * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data |
381 | * @adapter: pointer to struct zfcp_adapter | ||
382 | * Returns: -ENOMEM on memory allocation error or return value from | ||
383 | * qdio_allocate | ||
646 | */ | 384 | */ |
647 | int | 385 | int zfcp_qdio_allocate(struct zfcp_adapter *adapter) |
648 | zfcp_qdio_determine_pci(struct zfcp_qdio_queue *req_queue, | ||
649 | struct zfcp_fsf_req *fsf_req) | ||
650 | { | 386 | { |
651 | int new_distance_from_int; | 387 | struct qdio_initialize *init_data; |
652 | int pci_pos; | ||
653 | volatile struct qdio_buffer_element *sbale; | ||
654 | 388 | ||
655 | new_distance_from_int = req_queue->distance_from_int + | 389 | if (zfcp_qdio_buffers_enqueue(adapter->req_q.sbal) || |
656 | fsf_req->sbal_number; | 390 | zfcp_qdio_buffers_enqueue(adapter->resp_q.sbal)) |
657 | 391 | return -ENOMEM; | |
658 | if (unlikely(new_distance_from_int >= ZFCP_QDIO_PCI_INTERVAL)) { | 392 | |
659 | new_distance_from_int %= ZFCP_QDIO_PCI_INTERVAL; | 393 | init_data = &adapter->qdio_init_data; |
660 | pci_pos = fsf_req->sbal_first; | 394 | |
661 | pci_pos += fsf_req->sbal_number; | 395 | init_data->cdev = adapter->ccw_device; |
662 | pci_pos -= new_distance_from_int; | 396 | init_data->q_format = QDIO_ZFCP_QFMT; |
663 | pci_pos -= 1; | 397 | memcpy(init_data->adapter_name, zfcp_get_busid_by_adapter(adapter), 8); |
664 | pci_pos %= QDIO_MAX_BUFFERS_PER_Q; | 398 | ASCEBC(init_data->adapter_name, 8); |
665 | sbale = zfcp_qdio_sbale_req(fsf_req, pci_pos, 0); | 399 | init_data->qib_param_field_format = 0; |
666 | sbale->flags |= SBAL_FLAGS0_PCI; | 400 | init_data->qib_param_field = NULL; |
667 | } | 401 | init_data->input_slib_elements = NULL; |
668 | return new_distance_from_int; | 402 | init_data->output_slib_elements = NULL; |
403 | init_data->min_input_threshold = 1; | ||
404 | init_data->max_input_threshold = 5000; | ||
405 | init_data->min_output_threshold = 1; | ||
406 | init_data->max_output_threshold = 1000; | ||
407 | init_data->no_input_qs = 1; | ||
408 | init_data->no_output_qs = 1; | ||
409 | init_data->input_handler = zfcp_qdio_int_resp; | ||
410 | init_data->output_handler = zfcp_qdio_int_req; | ||
411 | init_data->int_parm = (unsigned long) adapter; | ||
412 | init_data->flags = QDIO_INBOUND_0COPY_SBALS | | ||
413 | QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS; | ||
414 | init_data->input_sbal_addr_array = | ||
415 | (void **) (adapter->resp_q.sbal); | ||
416 | init_data->output_sbal_addr_array = | ||
417 | (void **) (adapter->req_q.sbal); | ||
418 | |||
419 | return qdio_allocate(init_data); | ||
669 | } | 420 | } |
670 | 421 | ||
671 | /* | 422 | /** |
672 | * function: zfcp_zero_sbals | 423 | * zfcp_close_qdio - close qdio queues for an adapter |
673 | * | ||
674 | * purpose: zeros specified range of SBALs | ||
675 | * | ||
676 | * returns: | ||
677 | */ | 424 | */ |
678 | void | 425 | void zfcp_qdio_close(struct zfcp_adapter *adapter) |
679 | zfcp_qdio_zero_sbals(struct qdio_buffer *buf[], int first, int clean_count) | ||
680 | { | 426 | { |
681 | int cur_pos; | 427 | struct zfcp_qdio_queue *req_q; |
682 | int index; | 428 | int first, count; |
683 | 429 | ||
684 | for (cur_pos = first; cur_pos < (first + clean_count); cur_pos++) { | 430 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) |
685 | index = cur_pos % QDIO_MAX_BUFFERS_PER_Q; | 431 | return; |
686 | memset(buf[index], 0, sizeof (struct qdio_buffer)); | 432 | |
687 | ZFCP_LOG_TRACE("zeroing BUFFER %d at address %p\n", | 433 | /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ |
688 | index, buf[index]); | 434 | req_q = &adapter->req_q; |
435 | spin_lock(&req_q->lock); | ||
436 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); | ||
437 | spin_unlock(&req_q->lock); | ||
438 | |||
439 | while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) | ||
440 | == -EINPROGRESS) | ||
441 | ssleep(1); | ||
442 | |||
443 | /* cleanup used outbound sbals */ | ||
444 | count = atomic_read(&req_q->count); | ||
445 | if (count < QDIO_MAX_BUFFERS_PER_Q) { | ||
446 | first = (req_q->first + count) % QDIO_MAX_BUFFERS_PER_Q; | ||
447 | count = QDIO_MAX_BUFFERS_PER_Q - count; | ||
448 | zfcp_qdio_zero_sbals(req_q->sbal, first, count); | ||
689 | } | 449 | } |
450 | req_q->first = 0; | ||
451 | atomic_set(&req_q->count, 0); | ||
452 | req_q->pci_batch = 0; | ||
453 | adapter->resp_q.first = 0; | ||
454 | atomic_set(&adapter->resp_q.count, 0); | ||
690 | } | 455 | } |
691 | 456 | ||
692 | #undef ZFCP_LOG_AREA | 457 | /** |
458 | * zfcp_qdio_open - prepare and initialize response queue | ||
459 | * @adapter: pointer to struct zfcp_adapter | ||
460 | * Returns: 0 on success, otherwise -EIO | ||
461 | */ | ||
462 | int zfcp_qdio_open(struct zfcp_adapter *adapter) | ||
463 | { | ||
464 | volatile struct qdio_buffer_element *sbale; | ||
465 | int cc; | ||
466 | |||
467 | if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) | ||
468 | return -EIO; | ||
469 | |||
470 | if (qdio_establish(&adapter->qdio_init_data)) { | ||
471 | dev_err(&adapter->ccw_device->dev, | ||
472 | "Establish of QDIO queues failed.\n"); | ||
473 | return -EIO; | ||
474 | } | ||
475 | |||
476 | if (qdio_activate(adapter->ccw_device, 0)) { | ||
477 | dev_err(&adapter->ccw_device->dev, | ||
478 | "Activate of QDIO queues failed.\n"); | ||
479 | goto failed_qdio; | ||
480 | } | ||
481 | |||
482 | for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) { | ||
483 | sbale = &(adapter->resp_q.sbal[cc]->element[0]); | ||
484 | sbale->length = 0; | ||
485 | sbale->flags = SBAL_FLAGS_LAST_ENTRY; | ||
486 | sbale->addr = NULL; | ||
487 | } | ||
488 | |||
489 | if (do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_INPUT, 0, 0, | ||
490 | QDIO_MAX_BUFFERS_PER_Q, NULL)) { | ||
491 | dev_err(&adapter->ccw_device->dev, | ||
492 | "Init of QDIO response queue failed.\n"); | ||
493 | goto failed_qdio; | ||
494 | } | ||
495 | |||
496 | /* set index of first avalable SBALS / number of available SBALS */ | ||
497 | adapter->req_q.first = 0; | ||
498 | atomic_set(&adapter->req_q.count, QDIO_MAX_BUFFERS_PER_Q); | ||
499 | adapter->req_q.pci_batch = 0; | ||
500 | |||
501 | return 0; | ||
502 | |||
503 | failed_qdio: | ||
504 | while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) | ||
505 | == -EINPROGRESS) | ||
506 | ssleep(1); | ||
507 | |||
508 | return -EIO; | ||
509 | } | ||
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 01687559dc06..aeae56b00b45 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -1,220 +1,65 @@ | |||
1 | /* | 1 | /* |
2 | * This file is part of the zfcp device driver for | 2 | * zfcp device driver |
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | 3 | * |
5 | * (C) Copyright IBM Corp. 2002, 2006 | 4 | * Interface to Linux SCSI midlayer. |
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify | 6 | * Copyright IBM Corporation 2002, 2008 |
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | 7 | */ |
21 | 8 | ||
22 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI | ||
23 | |||
24 | #include "zfcp_ext.h" | 9 | #include "zfcp_ext.h" |
25 | #include <asm/atomic.h> | 10 | #include <asm/atomic.h> |
26 | 11 | ||
27 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdp); | ||
28 | static int zfcp_scsi_slave_alloc(struct scsi_device *sdp); | ||
29 | static int zfcp_scsi_slave_configure(struct scsi_device *sdp); | ||
30 | static int zfcp_scsi_queuecommand(struct scsi_cmnd *, | ||
31 | void (*done) (struct scsi_cmnd *)); | ||
32 | static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *); | ||
33 | static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *); | ||
34 | static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *); | ||
35 | static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *); | ||
36 | static int zfcp_task_management_function(struct zfcp_unit *, u8, | ||
37 | struct scsi_cmnd *); | ||
38 | |||
39 | static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, | ||
40 | unsigned int, unsigned int); | ||
41 | |||
42 | static struct device_attribute *zfcp_sysfs_sdev_attrs[]; | ||
43 | static struct device_attribute *zfcp_a_stats_attrs[]; | ||
44 | |||
45 | struct zfcp_data zfcp_data = { | ||
46 | .scsi_host_template = { | ||
47 | .name = ZFCP_NAME, | ||
48 | .module = THIS_MODULE, | ||
49 | .proc_name = "zfcp", | ||
50 | .slave_alloc = zfcp_scsi_slave_alloc, | ||
51 | .slave_configure = zfcp_scsi_slave_configure, | ||
52 | .slave_destroy = zfcp_scsi_slave_destroy, | ||
53 | .queuecommand = zfcp_scsi_queuecommand, | ||
54 | .eh_abort_handler = zfcp_scsi_eh_abort_handler, | ||
55 | .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler, | ||
56 | .eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler, | ||
57 | .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler, | ||
58 | .can_queue = 4096, | ||
59 | .this_id = -1, | ||
60 | .sg_tablesize = ZFCP_MAX_SBALES_PER_REQ, | ||
61 | .cmd_per_lun = 1, | ||
62 | .use_clustering = 1, | ||
63 | .sdev_attrs = zfcp_sysfs_sdev_attrs, | ||
64 | .max_sectors = ZFCP_MAX_SECTORS, | ||
65 | .shost_attrs = zfcp_a_stats_attrs, | ||
66 | }, | ||
67 | .driver_version = ZFCP_VERSION, | ||
68 | }; | ||
69 | |||
70 | /* Find start of Response Information in FCP response unit*/ | ||
71 | char * | ||
72 | zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) | ||
73 | { | ||
74 | char *fcp_rsp_info_ptr; | ||
75 | |||
76 | fcp_rsp_info_ptr = | ||
77 | (unsigned char *) fcp_rsp_iu + (sizeof (struct fcp_rsp_iu)); | ||
78 | |||
79 | return fcp_rsp_info_ptr; | ||
80 | } | ||
81 | |||
82 | /* Find start of Sense Information in FCP response unit*/ | 12 | /* Find start of Sense Information in FCP response unit*/ |
83 | char * | 13 | char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) |
84 | zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) | ||
85 | { | 14 | { |
86 | char *fcp_sns_info_ptr; | 15 | char *fcp_sns_info_ptr; |
87 | 16 | ||
88 | fcp_sns_info_ptr = | 17 | fcp_sns_info_ptr = (unsigned char *) &fcp_rsp_iu[1]; |
89 | (unsigned char *) fcp_rsp_iu + (sizeof (struct fcp_rsp_iu)); | ||
90 | if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid) | 18 | if (fcp_rsp_iu->validity.bits.fcp_rsp_len_valid) |
91 | fcp_sns_info_ptr = (char *) fcp_sns_info_ptr + | 19 | fcp_sns_info_ptr += fcp_rsp_iu->fcp_rsp_len; |
92 | fcp_rsp_iu->fcp_rsp_len; | ||
93 | 20 | ||
94 | return fcp_sns_info_ptr; | 21 | return fcp_sns_info_ptr; |
95 | } | 22 | } |
96 | 23 | ||
97 | static fcp_dl_t * | 24 | void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl) |
98 | zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd) | ||
99 | { | 25 | { |
100 | int additional_length = fcp_cmd->add_fcp_cdb_length << 2; | 26 | fcp_dl_t *fcp_dl_ptr; |
101 | fcp_dl_t *fcp_dl_addr; | ||
102 | 27 | ||
103 | fcp_dl_addr = (fcp_dl_t *) | ||
104 | ((unsigned char *) fcp_cmd + | ||
105 | sizeof (struct fcp_cmnd_iu) + additional_length); | ||
106 | /* | 28 | /* |
107 | * fcp_dl_addr = start address of fcp_cmnd structure + | 29 | * fcp_dl_addr = start address of fcp_cmnd structure + |
108 | * size of fixed part + size of dynamically sized add_dcp_cdb field | 30 | * size of fixed part + size of dynamically sized add_dcp_cdb field |
109 | * SEE FCP-2 documentation | 31 | * SEE FCP-2 documentation |
110 | */ | 32 | */ |
111 | return fcp_dl_addr; | 33 | fcp_dl_ptr = (fcp_dl_t *) ((unsigned char *) &fcp_cmd[1] + |
34 | (fcp_cmd->add_fcp_cdb_length << 2)); | ||
35 | *fcp_dl_ptr = fcp_dl; | ||
112 | } | 36 | } |
113 | 37 | ||
114 | fcp_dl_t | ||
115 | zfcp_get_fcp_dl(struct fcp_cmnd_iu * fcp_cmd) | ||
116 | { | ||
117 | return *zfcp_get_fcp_dl_ptr(fcp_cmd); | ||
118 | } | ||
119 | |||
120 | void | ||
121 | zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl) | ||
122 | { | ||
123 | *zfcp_get_fcp_dl_ptr(fcp_cmd) = fcp_dl; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * note: it's a bit-or operation not an assignment | ||
128 | * regarding the specified byte | ||
129 | */ | ||
130 | static inline void | ||
131 | set_byte(int *result, char status, char pos) | ||
132 | { | ||
133 | *result |= status << (pos * 8); | ||
134 | } | ||
135 | |||
136 | void | ||
137 | set_host_byte(int *result, char status) | ||
138 | { | ||
139 | set_byte(result, status, 2); | ||
140 | } | ||
141 | |||
142 | void | ||
143 | set_driver_byte(int *result, char status) | ||
144 | { | ||
145 | set_byte(result, status, 3); | ||
146 | } | ||
147 | |||
148 | static int | ||
149 | zfcp_scsi_slave_alloc(struct scsi_device *sdp) | ||
150 | { | ||
151 | struct zfcp_adapter *adapter; | ||
152 | struct zfcp_unit *unit; | ||
153 | unsigned long flags; | ||
154 | int retval = -ENXIO; | ||
155 | |||
156 | adapter = (struct zfcp_adapter *) sdp->host->hostdata[0]; | ||
157 | if (!adapter) | ||
158 | goto out; | ||
159 | |||
160 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
161 | unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun); | ||
162 | if (unit && atomic_test_mask(ZFCP_STATUS_UNIT_REGISTERED, | ||
163 | &unit->status)) { | ||
164 | sdp->hostdata = unit; | ||
165 | unit->device = sdp; | ||
166 | zfcp_unit_get(unit); | ||
167 | retval = 0; | ||
168 | } | ||
169 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
170 | out: | ||
171 | return retval; | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * zfcp_scsi_slave_destroy - called when scsi device is removed | ||
176 | * | ||
177 | * Remove reference to associated scsi device for an zfcp_unit. | ||
178 | * Mark zfcp_unit as failed. The scsi device might be deleted via sysfs | ||
179 | * or a scan for this device might have failed. | ||
180 | */ | ||
181 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) | 38 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) |
182 | { | 39 | { |
183 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; | 40 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; |
184 | 41 | WARN_ON(!unit); | |
185 | if (unit) { | 42 | if (unit) { |
186 | atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); | 43 | atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); |
187 | sdpnt->hostdata = NULL; | 44 | sdpnt->hostdata = NULL; |
188 | unit->device = NULL; | 45 | unit->device = NULL; |
189 | zfcp_erp_unit_failed(unit, 12, NULL); | 46 | zfcp_erp_unit_failed(unit, 12, NULL); |
190 | zfcp_unit_put(unit); | 47 | zfcp_unit_put(unit); |
191 | } else | 48 | } |
192 | ZFCP_LOG_NORMAL("bug: no unit associated with SCSI device at " | ||
193 | "address %p\n", sdpnt); | ||
194 | } | 49 | } |
195 | 50 | ||
196 | /* | 51 | static int zfcp_scsi_slave_configure(struct scsi_device *sdp) |
197 | * called from scsi midlayer to allow finetuning of a device. | ||
198 | */ | ||
199 | static int | ||
200 | zfcp_scsi_slave_configure(struct scsi_device *sdp) | ||
201 | { | 52 | { |
202 | if (sdp->tagged_supported) | 53 | if (sdp->tagged_supported) |
203 | scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, ZFCP_CMND_PER_LUN); | 54 | scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, 32); |
204 | else | 55 | else |
205 | scsi_adjust_queue_depth(sdp, 0, 1); | 56 | scsi_adjust_queue_depth(sdp, 0, 1); |
206 | return 0; | 57 | return 0; |
207 | } | 58 | } |
208 | 59 | ||
209 | /** | 60 | static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) |
210 | * zfcp_scsi_command_fail - set result in scsi_cmnd and call scsi_done function | ||
211 | * @scpnt: pointer to struct scsi_cmnd where result is set | ||
212 | * @result: result to be set in scpnt (e.g. DID_ERROR) | ||
213 | */ | ||
214 | static void | ||
215 | zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) | ||
216 | { | 61 | { |
217 | set_host_byte(&scpnt->result, result); | 62 | set_host_byte(scpnt, result); |
218 | if ((scpnt->device != NULL) && (scpnt->device->host != NULL)) | 63 | if ((scpnt->device != NULL) && (scpnt->device->host != NULL)) |
219 | zfcp_scsi_dbf_event_result("fail", 4, | 64 | zfcp_scsi_dbf_event_result("fail", 4, |
220 | (struct zfcp_adapter*) scpnt->device->host->hostdata[0], | 65 | (struct zfcp_adapter*) scpnt->device->host->hostdata[0], |
@@ -223,114 +68,13 @@ zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) | |||
223 | scpnt->scsi_done(scpnt); | 68 | scpnt->scsi_done(scpnt); |
224 | } | 69 | } |
225 | 70 | ||
226 | /** | 71 | static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, |
227 | * zfcp_scsi_command_async - worker for zfcp_scsi_queuecommand and | 72 | void (*done) (struct scsi_cmnd *)) |
228 | * zfcp_scsi_command_sync | ||
229 | * @adapter: adapter where scsi command is issued | ||
230 | * @unit: unit to which scsi command is sent | ||
231 | * @scpnt: scsi command to be sent | ||
232 | * @timer: timer to be started if request is successfully initiated | ||
233 | * | ||
234 | * Note: In scsi_done function must be set in scpnt. | ||
235 | */ | ||
236 | int | ||
237 | zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit, | ||
238 | struct scsi_cmnd *scpnt, int use_timer) | ||
239 | { | ||
240 | int tmp; | ||
241 | int retval; | ||
242 | |||
243 | retval = 0; | ||
244 | |||
245 | BUG_ON((adapter == NULL) || (adapter != unit->port->adapter)); | ||
246 | BUG_ON(scpnt->scsi_done == NULL); | ||
247 | |||
248 | if (unlikely(NULL == unit)) { | ||
249 | zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); | ||
250 | goto out; | ||
251 | } | ||
252 | |||
253 | if (unlikely( | ||
254 | atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status) || | ||
255 | !atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status))) { | ||
256 | ZFCP_LOG_DEBUG("stopping SCSI I/O on unit 0x%016Lx on port " | ||
257 | "0x%016Lx on adapter %s\n", | ||
258 | unit->fcp_lun, unit->port->wwpn, | ||
259 | zfcp_get_busid_by_adapter(adapter)); | ||
260 | zfcp_scsi_command_fail(scpnt, DID_ERROR); | ||
261 | goto out; | ||
262 | } | ||
263 | |||
264 | tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer, | ||
265 | ZFCP_REQ_AUTO_CLEANUP); | ||
266 | if (unlikely(tmp == -EBUSY)) { | ||
267 | ZFCP_LOG_DEBUG("adapter %s not ready or unit 0x%016Lx " | ||
268 | "on port 0x%016Lx in recovery\n", | ||
269 | zfcp_get_busid_by_unit(unit), | ||
270 | unit->fcp_lun, unit->port->wwpn); | ||
271 | zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); | ||
272 | goto out; | ||
273 | } | ||
274 | |||
275 | if (unlikely(tmp < 0)) { | ||
276 | ZFCP_LOG_DEBUG("error: initiation of Send FCP Cmnd failed\n"); | ||
277 | retval = SCSI_MLQUEUE_HOST_BUSY; | ||
278 | } | ||
279 | |||
280 | out: | ||
281 | return retval; | ||
282 | } | ||
283 | |||
284 | static void | ||
285 | zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt) | ||
286 | { | ||
287 | struct completion *wait = (struct completion *) scpnt->SCp.ptr; | ||
288 | complete(wait); | ||
289 | } | ||
290 | |||
291 | |||
292 | /** | ||
293 | * zfcp_scsi_command_sync - send a SCSI command and wait for completion | ||
294 | * @unit: unit where command is sent to | ||
295 | * @scpnt: scsi command to be sent | ||
296 | * @use_timer: indicates whether timer should be setup or not | ||
297 | * Return: 0 | ||
298 | * | ||
299 | * Errors are indicated in scpnt->result | ||
300 | */ | ||
301 | int | ||
302 | zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt, | ||
303 | int use_timer) | ||
304 | { | ||
305 | int ret; | ||
306 | DECLARE_COMPLETION_ONSTACK(wait); | ||
307 | |||
308 | scpnt->SCp.ptr = (void *) &wait; /* silent re-use */ | ||
309 | scpnt->scsi_done = zfcp_scsi_command_sync_handler; | ||
310 | ret = zfcp_scsi_command_async(unit->port->adapter, unit, scpnt, | ||
311 | use_timer); | ||
312 | if (ret == 0) | ||
313 | wait_for_completion(&wait); | ||
314 | |||
315 | scpnt->SCp.ptr = NULL; | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | /* | ||
321 | * function: zfcp_scsi_queuecommand | ||
322 | * | ||
323 | * purpose: enqueues a SCSI command to the specified target device | ||
324 | * | ||
325 | * returns: 0 - success, SCSI command enqueued | ||
326 | * !0 - failure | ||
327 | */ | ||
328 | static int | ||
329 | zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, | ||
330 | void (*done) (struct scsi_cmnd *)) | ||
331 | { | 73 | { |
332 | struct zfcp_unit *unit; | 74 | struct zfcp_unit *unit; |
333 | struct zfcp_adapter *adapter; | 75 | struct zfcp_adapter *adapter; |
76 | int status; | ||
77 | int ret; | ||
334 | 78 | ||
335 | /* reset the status for this request */ | 79 | /* reset the status for this request */ |
336 | scpnt->result = 0; | 80 | scpnt->result = 0; |
@@ -342,44 +86,76 @@ zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, | |||
342 | * (stored there by zfcp_scsi_slave_alloc) | 86 | * (stored there by zfcp_scsi_slave_alloc) |
343 | */ | 87 | */ |
344 | adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; | 88 | adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; |
345 | unit = (struct zfcp_unit *) scpnt->device->hostdata; | 89 | unit = scpnt->device->hostdata; |
90 | |||
91 | BUG_ON(!adapter || (adapter != unit->port->adapter)); | ||
92 | BUG_ON(!scpnt->scsi_done); | ||
346 | 93 | ||
347 | return zfcp_scsi_command_async(adapter, unit, scpnt, 0); | 94 | if (unlikely(!unit)) { |
95 | zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | status = atomic_read(&unit->status); | ||
100 | if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) || | ||
101 | !(status & ZFCP_STATUS_COMMON_RUNNING))) { | ||
102 | zfcp_scsi_command_fail(scpnt, DID_ERROR); | ||
103 | return 0;; | ||
104 | } | ||
105 | |||
106 | ret = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, 0, | ||
107 | ZFCP_REQ_AUTO_CLEANUP); | ||
108 | if (unlikely(ret == -EBUSY)) | ||
109 | zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); | ||
110 | else if (unlikely(ret < 0)) | ||
111 | return SCSI_MLQUEUE_HOST_BUSY; | ||
112 | |||
113 | return ret; | ||
348 | } | 114 | } |
349 | 115 | ||
350 | static struct zfcp_unit * | 116 | static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter, |
351 | zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id, | 117 | int channel, unsigned int id, |
352 | unsigned int lun) | 118 | unsigned int lun) |
353 | { | 119 | { |
354 | struct zfcp_port *port; | 120 | struct zfcp_port *port; |
355 | struct zfcp_unit *unit, *retval = NULL; | 121 | struct zfcp_unit *unit; |
356 | 122 | ||
357 | list_for_each_entry(port, &adapter->port_list_head, list) { | 123 | list_for_each_entry(port, &adapter->port_list_head, list) { |
358 | if (!port->rport || (id != port->rport->scsi_target_id)) | 124 | if (!port->rport || (id != port->rport->scsi_target_id)) |
359 | continue; | 125 | continue; |
360 | list_for_each_entry(unit, &port->unit_list_head, list) | 126 | list_for_each_entry(unit, &port->unit_list_head, list) |
361 | if (lun == unit->scsi_lun) { | 127 | if (lun == unit->scsi_lun) |
362 | retval = unit; | 128 | return unit; |
363 | goto out; | ||
364 | } | ||
365 | } | 129 | } |
366 | out: | 130 | |
131 | return NULL; | ||
132 | } | ||
133 | |||
134 | static int zfcp_scsi_slave_alloc(struct scsi_device *sdp) | ||
135 | { | ||
136 | struct zfcp_adapter *adapter; | ||
137 | struct zfcp_unit *unit; | ||
138 | unsigned long flags; | ||
139 | int retval = -ENXIO; | ||
140 | |||
141 | adapter = (struct zfcp_adapter *) sdp->host->hostdata[0]; | ||
142 | if (!adapter) | ||
143 | goto out; | ||
144 | |||
145 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
146 | unit = zfcp_unit_lookup(adapter, sdp->channel, sdp->id, sdp->lun); | ||
147 | if (unit && | ||
148 | (atomic_read(&unit->status) & ZFCP_STATUS_UNIT_REGISTERED)) { | ||
149 | sdp->hostdata = unit; | ||
150 | unit->device = sdp; | ||
151 | zfcp_unit_get(unit); | ||
152 | retval = 0; | ||
153 | } | ||
154 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
155 | out: | ||
367 | return retval; | 156 | return retval; |
368 | } | 157 | } |
369 | 158 | ||
370 | /** | ||
371 | * zfcp_scsi_eh_abort_handler - abort the specified SCSI command | ||
372 | * @scpnt: pointer to scsi_cmnd to be aborted | ||
373 | * Return: SUCCESS - command has been aborted and cleaned up in internal | ||
374 | * bookkeeping, SCSI stack won't be called for aborted command | ||
375 | * FAILED - otherwise | ||
376 | * | ||
377 | * We do not need to care for a SCSI command which completes normally | ||
378 | * but late during this abort routine runs. We are allowed to return | ||
379 | * late commands to the SCSI stack. It tracks the state of commands and | ||
380 | * will handle late commands. (Usually, the normal completion of late | ||
381 | * commands is ignored with respect to the running abort operation.) | ||
382 | */ | ||
383 | static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) | 159 | static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) |
384 | { | 160 | { |
385 | struct Scsi_Host *scsi_host; | 161 | struct Scsi_Host *scsi_host; |
@@ -387,44 +163,37 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) | |||
387 | struct zfcp_unit *unit; | 163 | struct zfcp_unit *unit; |
388 | struct zfcp_fsf_req *fsf_req; | 164 | struct zfcp_fsf_req *fsf_req; |
389 | unsigned long flags; | 165 | unsigned long flags; |
390 | unsigned long old_req_id; | 166 | unsigned long old_req_id = (unsigned long) scpnt->host_scribble; |
391 | int retval = SUCCESS; | 167 | int retval = SUCCESS; |
392 | 168 | ||
393 | scsi_host = scpnt->device->host; | 169 | scsi_host = scpnt->device->host; |
394 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | 170 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; |
395 | unit = (struct zfcp_unit *) scpnt->device->hostdata; | 171 | unit = scpnt->device->hostdata; |
396 | |||
397 | ZFCP_LOG_INFO("aborting scsi_cmnd=%p on adapter %s\n", | ||
398 | scpnt, zfcp_get_busid_by_adapter(adapter)); | ||
399 | 172 | ||
400 | /* avoid race condition between late normal completion and abort */ | 173 | /* avoid race condition between late normal completion and abort */ |
401 | write_lock_irqsave(&adapter->abort_lock, flags); | 174 | write_lock_irqsave(&adapter->abort_lock, flags); |
402 | 175 | ||
403 | /* Check whether corresponding fsf_req is still pending */ | 176 | /* Check whether corresponding fsf_req is still pending */ |
404 | spin_lock(&adapter->req_list_lock); | 177 | spin_lock(&adapter->req_list_lock); |
405 | fsf_req = zfcp_reqlist_find(adapter, | 178 | fsf_req = zfcp_reqlist_find(adapter, old_req_id); |
406 | (unsigned long) scpnt->host_scribble); | ||
407 | spin_unlock(&adapter->req_list_lock); | 179 | spin_unlock(&adapter->req_list_lock); |
408 | if (!fsf_req) { | 180 | if (!fsf_req) { |
409 | write_unlock_irqrestore(&adapter->abort_lock, flags); | 181 | write_unlock_irqrestore(&adapter->abort_lock, flags); |
410 | zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0); | 182 | zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0); |
411 | retval = SUCCESS; | 183 | return retval; |
412 | goto out; | ||
413 | } | 184 | } |
414 | fsf_req->data = 0; | 185 | fsf_req->data = NULL; |
415 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING; | 186 | fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING; |
416 | old_req_id = fsf_req->req_id; | ||
417 | 187 | ||
418 | /* don't access old fsf_req after releasing the abort_lock */ | 188 | /* don't access old fsf_req after releasing the abort_lock */ |
419 | write_unlock_irqrestore(&adapter->abort_lock, flags); | 189 | write_unlock_irqrestore(&adapter->abort_lock, flags); |
420 | 190 | ||
421 | fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0); | 191 | fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0); |
422 | if (!fsf_req) { | 192 | if (!fsf_req) { |
423 | ZFCP_LOG_INFO("error: initiation of Abort FCP Cmnd failed\n"); | ||
424 | zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, | 193 | zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, |
425 | old_req_id); | 194 | old_req_id); |
426 | retval = FAILED; | 195 | retval = FAILED; |
427 | goto out; | 196 | return retval; |
428 | } | 197 | } |
429 | 198 | ||
430 | __wait_event(fsf_req->completion_wq, | 199 | __wait_event(fsf_req->completion_wq, |
@@ -432,66 +201,29 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) | |||
432 | 201 | ||
433 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { | 202 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { |
434 | zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0); | 203 | zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0); |
435 | retval = SUCCESS; | ||
436 | } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { | 204 | } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { |
437 | zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0); | 205 | zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0); |
438 | retval = SUCCESS; | ||
439 | } else { | 206 | } else { |
440 | zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0); | 207 | zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0); |
441 | retval = FAILED; | 208 | retval = FAILED; |
442 | } | 209 | } |
443 | zfcp_fsf_req_free(fsf_req); | 210 | zfcp_fsf_req_free(fsf_req); |
444 | out: | ||
445 | return retval; | ||
446 | } | ||
447 | |||
448 | static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) | ||
449 | { | ||
450 | int retval; | ||
451 | struct zfcp_unit *unit = scpnt->device->hostdata; | ||
452 | 211 | ||
453 | if (!unit) { | 212 | return retval; |
454 | WARN_ON(1); | ||
455 | return SUCCESS; | ||
456 | } | ||
457 | retval = zfcp_task_management_function(unit, | ||
458 | FCP_LOGICAL_UNIT_RESET, | ||
459 | scpnt); | ||
460 | return retval ? FAILED : SUCCESS; | ||
461 | } | ||
462 | |||
463 | static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) | ||
464 | { | ||
465 | int retval; | ||
466 | struct zfcp_unit *unit = scpnt->device->hostdata; | ||
467 | |||
468 | if (!unit) { | ||
469 | WARN_ON(1); | ||
470 | return SUCCESS; | ||
471 | } | ||
472 | retval = zfcp_task_management_function(unit, FCP_TARGET_RESET, scpnt); | ||
473 | return retval ? FAILED : SUCCESS; | ||
474 | } | 213 | } |
475 | 214 | ||
476 | static int | 215 | static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags, |
477 | zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags, | 216 | struct scsi_cmnd *scpnt) |
478 | struct scsi_cmnd *scpnt) | ||
479 | { | 217 | { |
480 | struct zfcp_adapter *adapter = unit->port->adapter; | 218 | struct zfcp_adapter *adapter = unit->port->adapter; |
481 | struct zfcp_fsf_req *fsf_req; | 219 | struct zfcp_fsf_req *fsf_req; |
482 | int retval = 0; | 220 | int retval = SUCCESS; |
483 | 221 | ||
484 | /* issue task management function */ | 222 | /* issue task management function */ |
485 | fsf_req = zfcp_fsf_send_fcp_command_task_management | 223 | fsf_req = zfcp_fsf_send_fcp_ctm(adapter, unit, tm_flags, 0); |
486 | (adapter, unit, tm_flags, 0); | ||
487 | if (!fsf_req) { | 224 | if (!fsf_req) { |
488 | ZFCP_LOG_INFO("error: creation of task management request " | ||
489 | "failed for unit 0x%016Lx on port 0x%016Lx on " | ||
490 | "adapter %s\n", unit->fcp_lun, unit->port->wwpn, | ||
491 | zfcp_get_busid_by_adapter(adapter)); | ||
492 | zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt); | 225 | zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt); |
493 | retval = -ENOMEM; | 226 | return FAILED; |
494 | goto out; | ||
495 | } | 227 | } |
496 | 228 | ||
497 | __wait_event(fsf_req->completion_wq, | 229 | __wait_event(fsf_req->completion_wq, |
@@ -502,87 +234,90 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags, | |||
502 | */ | 234 | */ |
503 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { | 235 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { |
504 | zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); | 236 | zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); |
505 | retval = -EIO; | 237 | retval = FAILED; |
506 | } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) { | 238 | } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) { |
507 | zfcp_scsi_dbf_event_devreset("nsup", tm_flags, unit, scpnt); | 239 | zfcp_scsi_dbf_event_devreset("nsup", tm_flags, unit, scpnt); |
508 | retval = -ENOTSUPP; | 240 | retval = FAILED; |
509 | } else | 241 | } else |
510 | zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); | 242 | zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); |
511 | 243 | ||
512 | zfcp_fsf_req_free(fsf_req); | 244 | zfcp_fsf_req_free(fsf_req); |
513 | out: | 245 | |
514 | return retval; | 246 | return retval; |
515 | } | 247 | } |
516 | 248 | ||
517 | /** | 249 | static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) |
518 | * zfcp_scsi_eh_host_reset_handler - handler for host reset | 250 | { |
519 | */ | 251 | struct zfcp_unit *unit = scpnt->device->hostdata; |
252 | |||
253 | if (!unit) { | ||
254 | WARN_ON(1); | ||
255 | return SUCCESS; | ||
256 | } | ||
257 | return zfcp_task_mgmt_function(unit, FCP_LOGICAL_UNIT_RESET, scpnt); | ||
258 | } | ||
259 | |||
260 | static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) | ||
261 | { | ||
262 | struct zfcp_unit *unit = scpnt->device->hostdata; | ||
263 | |||
264 | if (!unit) { | ||
265 | WARN_ON(1); | ||
266 | return SUCCESS; | ||
267 | } | ||
268 | return zfcp_task_mgmt_function(unit, FCP_TARGET_RESET, scpnt); | ||
269 | } | ||
270 | |||
520 | static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) | 271 | static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) |
521 | { | 272 | { |
522 | struct zfcp_unit *unit; | 273 | struct zfcp_unit *unit; |
523 | struct zfcp_adapter *adapter; | 274 | struct zfcp_adapter *adapter; |
524 | 275 | ||
525 | unit = (struct zfcp_unit*) scpnt->device->hostdata; | 276 | unit = scpnt->device->hostdata; |
526 | adapter = unit->port->adapter; | 277 | adapter = unit->port->adapter; |
527 | |||
528 | ZFCP_LOG_NORMAL("host reset because of problems with " | ||
529 | "unit 0x%016Lx on port 0x%016Lx, adapter %s\n", | ||
530 | unit->fcp_lun, unit->port->wwpn, | ||
531 | zfcp_get_busid_by_adapter(unit->port->adapter)); | ||
532 | |||
533 | zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt); | 278 | zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt); |
534 | zfcp_erp_wait(adapter); | 279 | zfcp_erp_wait(adapter); |
535 | 280 | ||
536 | return SUCCESS; | 281 | return SUCCESS; |
537 | } | 282 | } |
538 | 283 | ||
539 | int | 284 | int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) |
540 | zfcp_adapter_scsi_register(struct zfcp_adapter *adapter) | ||
541 | { | 285 | { |
542 | int retval = 0; | 286 | struct ccw_dev_id dev_id; |
543 | static unsigned int unique_id = 0; | ||
544 | 287 | ||
545 | if (adapter->scsi_host) | 288 | if (adapter->scsi_host) |
546 | goto out; | 289 | return 0; |
547 | 290 | ||
291 | ccw_device_get_id(adapter->ccw_device, &dev_id); | ||
548 | /* register adapter as SCSI host with mid layer of SCSI stack */ | 292 | /* register adapter as SCSI host with mid layer of SCSI stack */ |
549 | adapter->scsi_host = scsi_host_alloc(&zfcp_data.scsi_host_template, | 293 | adapter->scsi_host = scsi_host_alloc(&zfcp_data.scsi_host_template, |
550 | sizeof (struct zfcp_adapter *)); | 294 | sizeof (struct zfcp_adapter *)); |
551 | if (!adapter->scsi_host) { | 295 | if (!adapter->scsi_host) { |
552 | ZFCP_LOG_NORMAL("error: registration with SCSI stack failed " | 296 | dev_err(&adapter->ccw_device->dev, |
553 | "for adapter %s ", | 297 | "registration with SCSI stack failed."); |
554 | zfcp_get_busid_by_adapter(adapter)); | 298 | return -EIO; |
555 | retval = -EIO; | ||
556 | goto out; | ||
557 | } | 299 | } |
558 | ZFCP_LOG_DEBUG("host registered, scsi_host=%p\n", adapter->scsi_host); | ||
559 | 300 | ||
560 | /* tell the SCSI stack some characteristics of this adapter */ | 301 | /* tell the SCSI stack some characteristics of this adapter */ |
561 | adapter->scsi_host->max_id = 1; | 302 | adapter->scsi_host->max_id = 1; |
562 | adapter->scsi_host->max_lun = 1; | 303 | adapter->scsi_host->max_lun = 1; |
563 | adapter->scsi_host->max_channel = 0; | 304 | adapter->scsi_host->max_channel = 0; |
564 | adapter->scsi_host->unique_id = unique_id++; /* FIXME */ | 305 | adapter->scsi_host->unique_id = dev_id.devno; |
565 | adapter->scsi_host->max_cmd_len = ZFCP_MAX_SCSI_CMND_LENGTH; | 306 | adapter->scsi_host->max_cmd_len = 255; |
566 | adapter->scsi_host->transportt = zfcp_data.scsi_transport_template; | 307 | adapter->scsi_host->transportt = zfcp_data.scsi_transport_template; |
567 | 308 | ||
568 | /* | ||
569 | * save a pointer to our own adapter data structure within | ||
570 | * hostdata field of SCSI host data structure | ||
571 | */ | ||
572 | adapter->scsi_host->hostdata[0] = (unsigned long) adapter; | 309 | adapter->scsi_host->hostdata[0] = (unsigned long) adapter; |
573 | 310 | ||
574 | if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) { | 311 | if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) { |
575 | scsi_host_put(adapter->scsi_host); | 312 | scsi_host_put(adapter->scsi_host); |
576 | retval = -EIO; | 313 | return -EIO; |
577 | goto out; | ||
578 | } | 314 | } |
579 | atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status); | 315 | atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status); |
580 | out: | 316 | |
581 | return retval; | 317 | return 0; |
582 | } | 318 | } |
583 | 319 | ||
584 | void | 320 | void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) |
585 | zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) | ||
586 | { | 321 | { |
587 | struct Scsi_Host *shost; | 322 | struct Scsi_Host *shost; |
588 | struct zfcp_port *port; | 323 | struct zfcp_port *port; |
@@ -590,10 +325,12 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) | |||
590 | shost = adapter->scsi_host; | 325 | shost = adapter->scsi_host; |
591 | if (!shost) | 326 | if (!shost) |
592 | return; | 327 | return; |
328 | |||
593 | read_lock_irq(&zfcp_data.config_lock); | 329 | read_lock_irq(&zfcp_data.config_lock); |
594 | list_for_each_entry(port, &adapter->port_list_head, list) | 330 | list_for_each_entry(port, &adapter->port_list_head, list) |
595 | if (port->rport) | 331 | if (port->rport) |
596 | port->rport = NULL; | 332 | port->rport = NULL; |
333 | |||
597 | read_unlock_irq(&zfcp_data.config_lock); | 334 | read_unlock_irq(&zfcp_data.config_lock); |
598 | fc_remove_host(shost); | 335 | fc_remove_host(shost); |
599 | scsi_remove_host(shost); | 336 | scsi_remove_host(shost); |
@@ -604,9 +341,6 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) | |||
604 | return; | 341 | return; |
605 | } | 342 | } |
606 | 343 | ||
607 | /* | ||
608 | * Support functions for FC transport class | ||
609 | */ | ||
610 | static struct fc_host_statistics* | 344 | static struct fc_host_statistics* |
611 | zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) | 345 | zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) |
612 | { | 346 | { |
@@ -622,13 +356,12 @@ zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) | |||
622 | return adapter->fc_stats; | 356 | return adapter->fc_stats; |
623 | } | 357 | } |
624 | 358 | ||
625 | static void | 359 | static void zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, |
626 | zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, | 360 | struct fsf_qtcb_bottom_port *data, |
627 | struct fsf_qtcb_bottom_port *data, | 361 | struct fsf_qtcb_bottom_port *old) |
628 | struct fsf_qtcb_bottom_port *old) | ||
629 | { | 362 | { |
630 | fc_stats->seconds_since_last_reset = data->seconds_since_last_reset - | 363 | fc_stats->seconds_since_last_reset = |
631 | old->seconds_since_last_reset; | 364 | data->seconds_since_last_reset - old->seconds_since_last_reset; |
632 | fc_stats->tx_frames = data->tx_frames - old->tx_frames; | 365 | fc_stats->tx_frames = data->tx_frames - old->tx_frames; |
633 | fc_stats->tx_words = data->tx_words - old->tx_words; | 366 | fc_stats->tx_words = data->tx_words - old->tx_words; |
634 | fc_stats->rx_frames = data->rx_frames - old->rx_frames; | 367 | fc_stats->rx_frames = data->rx_frames - old->rx_frames; |
@@ -639,26 +372,25 @@ zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, | |||
639 | fc_stats->dumped_frames = data->dumped_frames - old->dumped_frames; | 372 | fc_stats->dumped_frames = data->dumped_frames - old->dumped_frames; |
640 | fc_stats->link_failure_count = data->link_failure - old->link_failure; | 373 | fc_stats->link_failure_count = data->link_failure - old->link_failure; |
641 | fc_stats->loss_of_sync_count = data->loss_of_sync - old->loss_of_sync; | 374 | fc_stats->loss_of_sync_count = data->loss_of_sync - old->loss_of_sync; |
642 | fc_stats->loss_of_signal_count = data->loss_of_signal - | 375 | fc_stats->loss_of_signal_count = |
643 | old->loss_of_signal; | 376 | data->loss_of_signal - old->loss_of_signal; |
644 | fc_stats->prim_seq_protocol_err_count = data->psp_error_counts - | 377 | fc_stats->prim_seq_protocol_err_count = |
645 | old->psp_error_counts; | 378 | data->psp_error_counts - old->psp_error_counts; |
646 | fc_stats->invalid_tx_word_count = data->invalid_tx_words - | 379 | fc_stats->invalid_tx_word_count = |
647 | old->invalid_tx_words; | 380 | data->invalid_tx_words - old->invalid_tx_words; |
648 | fc_stats->invalid_crc_count = data->invalid_crcs - old->invalid_crcs; | 381 | fc_stats->invalid_crc_count = data->invalid_crcs - old->invalid_crcs; |
649 | fc_stats->fcp_input_requests = data->input_requests - | 382 | fc_stats->fcp_input_requests = |
650 | old->input_requests; | 383 | data->input_requests - old->input_requests; |
651 | fc_stats->fcp_output_requests = data->output_requests - | 384 | fc_stats->fcp_output_requests = |
652 | old->output_requests; | 385 | data->output_requests - old->output_requests; |
653 | fc_stats->fcp_control_requests = data->control_requests - | 386 | fc_stats->fcp_control_requests = |
654 | old->control_requests; | 387 | data->control_requests - old->control_requests; |
655 | fc_stats->fcp_input_megabytes = data->input_mb - old->input_mb; | 388 | fc_stats->fcp_input_megabytes = data->input_mb - old->input_mb; |
656 | fc_stats->fcp_output_megabytes = data->output_mb - old->output_mb; | 389 | fc_stats->fcp_output_megabytes = data->output_mb - old->output_mb; |
657 | } | 390 | } |
658 | 391 | ||
659 | static void | 392 | static void zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats, |
660 | zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats, | 393 | struct fsf_qtcb_bottom_port *data) |
661 | struct fsf_qtcb_bottom_port *data) | ||
662 | { | 394 | { |
663 | fc_stats->seconds_since_last_reset = data->seconds_since_last_reset; | 395 | fc_stats->seconds_since_last_reset = data->seconds_since_last_reset; |
664 | fc_stats->tx_frames = data->tx_frames; | 396 | fc_stats->tx_frames = data->tx_frames; |
@@ -682,22 +414,14 @@ zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats, | |||
682 | fc_stats->fcp_output_megabytes = data->output_mb; | 414 | fc_stats->fcp_output_megabytes = data->output_mb; |
683 | } | 415 | } |
684 | 416 | ||
685 | /** | 417 | static struct fc_host_statistics *zfcp_get_fc_host_stats(struct Scsi_Host *host) |
686 | * zfcp_get_fc_host_stats - provide fc_host_statistics for scsi_transport_fc | ||
687 | * | ||
688 | * assumption: scsi_transport_fc synchronizes calls of | ||
689 | * get_fc_host_stats and reset_fc_host_stats | ||
690 | * (XXX to be checked otherwise introduce locking) | ||
691 | */ | ||
692 | static struct fc_host_statistics * | ||
693 | zfcp_get_fc_host_stats(struct Scsi_Host *shost) | ||
694 | { | 418 | { |
695 | struct zfcp_adapter *adapter; | 419 | struct zfcp_adapter *adapter; |
696 | struct fc_host_statistics *fc_stats; | 420 | struct fc_host_statistics *fc_stats; |
697 | struct fsf_qtcb_bottom_port *data; | 421 | struct fsf_qtcb_bottom_port *data; |
698 | int ret; | 422 | int ret; |
699 | 423 | ||
700 | adapter = (struct zfcp_adapter *)shost->hostdata[0]; | 424 | adapter = (struct zfcp_adapter *)host->hostdata[0]; |
701 | fc_stats = zfcp_init_fc_host_stats(adapter); | 425 | fc_stats = zfcp_init_fc_host_stats(adapter); |
702 | if (!fc_stats) | 426 | if (!fc_stats) |
703 | return NULL; | 427 | return NULL; |
@@ -709,26 +433,25 @@ zfcp_get_fc_host_stats(struct Scsi_Host *shost) | |||
709 | ret = zfcp_fsf_exchange_port_data_sync(adapter, data); | 433 | ret = zfcp_fsf_exchange_port_data_sync(adapter, data); |
710 | if (ret) { | 434 | if (ret) { |
711 | kfree(data); | 435 | kfree(data); |
712 | return NULL; /* XXX return zeroed fc_stats? */ | 436 | return NULL; |
713 | } | 437 | } |
714 | 438 | ||
715 | if (adapter->stats_reset && | 439 | if (adapter->stats_reset && |
716 | ((jiffies/HZ - adapter->stats_reset) < | 440 | ((jiffies/HZ - adapter->stats_reset) < |
717 | data->seconds_since_last_reset)) { | 441 | data->seconds_since_last_reset)) |
718 | zfcp_adjust_fc_host_stats(fc_stats, data, | 442 | zfcp_adjust_fc_host_stats(fc_stats, data, |
719 | adapter->stats_reset_data); | 443 | adapter->stats_reset_data); |
720 | } else | 444 | else |
721 | zfcp_set_fc_host_stats(fc_stats, data); | 445 | zfcp_set_fc_host_stats(fc_stats, data); |
722 | 446 | ||
723 | kfree(data); | 447 | kfree(data); |
724 | return fc_stats; | 448 | return fc_stats; |
725 | } | 449 | } |
726 | 450 | ||
727 | static void | 451 | static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost) |
728 | zfcp_reset_fc_host_stats(struct Scsi_Host *shost) | ||
729 | { | 452 | { |
730 | struct zfcp_adapter *adapter; | 453 | struct zfcp_adapter *adapter; |
731 | struct fsf_qtcb_bottom_port *data, *old_data; | 454 | struct fsf_qtcb_bottom_port *data; |
732 | int ret; | 455 | int ret; |
733 | 456 | ||
734 | adapter = (struct zfcp_adapter *)shost->hostdata[0]; | 457 | adapter = (struct zfcp_adapter *)shost->hostdata[0]; |
@@ -737,17 +460,33 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost) | |||
737 | return; | 460 | return; |
738 | 461 | ||
739 | ret = zfcp_fsf_exchange_port_data_sync(adapter, data); | 462 | ret = zfcp_fsf_exchange_port_data_sync(adapter, data); |
740 | if (ret) { | 463 | if (ret) |
741 | kfree(data); | 464 | kfree(data); |
742 | } else { | 465 | else { |
743 | adapter->stats_reset = jiffies/HZ; | 466 | adapter->stats_reset = jiffies/HZ; |
744 | old_data = adapter->stats_reset_data; | 467 | kfree(adapter->stats_reset_data); |
745 | adapter->stats_reset_data = data; /* finally freed in | 468 | adapter->stats_reset_data = data; /* finally freed in |
746 | adater_dequeue */ | 469 | adapter_dequeue */ |
747 | kfree(old_data); | ||
748 | } | 470 | } |
749 | } | 471 | } |
750 | 472 | ||
473 | static void zfcp_get_host_port_state(struct Scsi_Host *shost) | ||
474 | { | ||
475 | struct zfcp_adapter *adapter = | ||
476 | (struct zfcp_adapter *)shost->hostdata[0]; | ||
477 | int status = atomic_read(&adapter->status); | ||
478 | |||
479 | if ((status & ZFCP_STATUS_COMMON_RUNNING) && | ||
480 | !(status & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)) | ||
481 | fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; | ||
482 | else if (status & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) | ||
483 | fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; | ||
484 | else if (status & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
485 | fc_host_port_state(shost) = FC_PORTSTATE_ERROR; | ||
486 | else | ||
487 | fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; | ||
488 | } | ||
489 | |||
751 | static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) | 490 | static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) |
752 | { | 491 | { |
753 | rport->dev_loss_tmo = timeout; | 492 | rport->dev_loss_tmo = timeout; |
@@ -770,6 +509,8 @@ struct fc_function_template zfcp_transport_functions = { | |||
770 | .get_fc_host_stats = zfcp_get_fc_host_stats, | 509 | .get_fc_host_stats = zfcp_get_fc_host_stats, |
771 | .reset_fc_host_stats = zfcp_reset_fc_host_stats, | 510 | .reset_fc_host_stats = zfcp_reset_fc_host_stats, |
772 | .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, | 511 | .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, |
512 | .get_host_port_state = zfcp_get_host_port_state, | ||
513 | .show_host_port_state = 1, | ||
773 | /* no functions registered for following dynamic attributes but | 514 | /* no functions registered for following dynamic attributes but |
774 | directly set by LLDD */ | 515 | directly set by LLDD */ |
775 | .show_host_port_type = 1, | 516 | .show_host_port_type = 1, |
@@ -778,149 +519,26 @@ struct fc_function_template zfcp_transport_functions = { | |||
778 | .disable_target_scan = 1, | 519 | .disable_target_scan = 1, |
779 | }; | 520 | }; |
780 | 521 | ||
781 | /** | 522 | struct zfcp_data zfcp_data = { |
782 | * ZFCP_DEFINE_SCSI_ATTR | 523 | .scsi_host_template = { |
783 | * @_name: name of show attribute | 524 | .name = "zfcp", |
784 | * @_format: format string | 525 | .module = THIS_MODULE, |
785 | * @_value: value to print | 526 | .proc_name = "zfcp", |
786 | * | 527 | .slave_alloc = zfcp_scsi_slave_alloc, |
787 | * Generates attribute for a unit. | 528 | .slave_configure = zfcp_scsi_slave_configure, |
788 | */ | 529 | .slave_destroy = zfcp_scsi_slave_destroy, |
789 | #define ZFCP_DEFINE_SCSI_ATTR(_name, _format, _value) \ | 530 | .queuecommand = zfcp_scsi_queuecommand, |
790 | static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, struct device_attribute *attr, \ | 531 | .eh_abort_handler = zfcp_scsi_eh_abort_handler, |
791 | char *buf) \ | 532 | .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler, |
792 | { \ | 533 | .eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler, |
793 | struct scsi_device *sdev; \ | 534 | .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler, |
794 | struct zfcp_unit *unit; \ | 535 | .can_queue = 4096, |
795 | \ | 536 | .this_id = -1, |
796 | sdev = to_scsi_device(dev); \ | 537 | .sg_tablesize = ZFCP_MAX_SBALES_PER_REQ, |
797 | unit = sdev->hostdata; \ | 538 | .cmd_per_lun = 1, |
798 | return sprintf(buf, _format, _value); \ | 539 | .use_clustering = 1, |
799 | } \ | 540 | .sdev_attrs = zfcp_sysfs_sdev_attrs, |
800 | \ | 541 | .max_sectors = (ZFCP_MAX_SBALES_PER_REQ * 8), |
801 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL); | 542 | .shost_attrs = zfcp_sysfs_shost_attrs, |
802 | 543 | }, | |
803 | ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", zfcp_get_busid_by_unit(unit)); | ||
804 | ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", unit->port->wwpn); | ||
805 | ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", unit->fcp_lun); | ||
806 | |||
807 | static struct device_attribute *zfcp_sysfs_sdev_attrs[] = { | ||
808 | &dev_attr_fcp_lun, | ||
809 | &dev_attr_wwpn, | ||
810 | &dev_attr_hba_id, | ||
811 | NULL | ||
812 | }; | ||
813 | |||
814 | static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, | ||
815 | struct device_attribute *attr, | ||
816 | char *buf) | ||
817 | { | ||
818 | struct Scsi_Host *scsi_host = dev_to_shost(dev); | ||
819 | struct fsf_qtcb_bottom_port *qtcb_port; | ||
820 | int retval; | ||
821 | struct zfcp_adapter *adapter; | ||
822 | |||
823 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | ||
824 | if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) | ||
825 | return -EOPNOTSUPP; | ||
826 | |||
827 | qtcb_port = kzalloc(sizeof(struct fsf_qtcb_bottom_port), GFP_KERNEL); | ||
828 | if (!qtcb_port) | ||
829 | return -ENOMEM; | ||
830 | |||
831 | retval = zfcp_fsf_exchange_port_data_sync(adapter, qtcb_port); | ||
832 | if (!retval) | ||
833 | retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, | ||
834 | qtcb_port->cb_util, qtcb_port->a_util); | ||
835 | kfree(qtcb_port); | ||
836 | return retval; | ||
837 | } | ||
838 | |||
839 | static int zfcp_sysfs_adapter_ex_config(struct device *dev, | ||
840 | struct fsf_statistics_info *stat_inf) | ||
841 | { | ||
842 | int retval; | ||
843 | struct fsf_qtcb_bottom_config *qtcb_config; | ||
844 | struct Scsi_Host *scsi_host = dev_to_shost(dev); | ||
845 | struct zfcp_adapter *adapter; | ||
846 | |||
847 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | ||
848 | if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) | ||
849 | return -EOPNOTSUPP; | ||
850 | |||
851 | qtcb_config = kzalloc(sizeof(struct fsf_qtcb_bottom_config), | ||
852 | GFP_KERNEL); | ||
853 | if (!qtcb_config) | ||
854 | return -ENOMEM; | ||
855 | |||
856 | retval = zfcp_fsf_exchange_config_data_sync(adapter, qtcb_config); | ||
857 | if (!retval) | ||
858 | *stat_inf = qtcb_config->stat_info; | ||
859 | |||
860 | kfree(qtcb_config); | ||
861 | return retval; | ||
862 | } | ||
863 | |||
864 | static ssize_t zfcp_sysfs_adapter_request_show(struct device *dev, | ||
865 | struct device_attribute *attr, | ||
866 | char *buf) | ||
867 | { | ||
868 | struct fsf_statistics_info stat_info; | ||
869 | int retval; | ||
870 | |||
871 | retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); | ||
872 | if (retval) | ||
873 | return retval; | ||
874 | |||
875 | return sprintf(buf, "%llu %llu %llu\n", | ||
876 | (unsigned long long) stat_info.input_req, | ||
877 | (unsigned long long) stat_info.output_req, | ||
878 | (unsigned long long) stat_info.control_req); | ||
879 | } | ||
880 | |||
881 | static ssize_t zfcp_sysfs_adapter_mb_show(struct device *dev, | ||
882 | struct device_attribute *attr, | ||
883 | char *buf) | ||
884 | { | ||
885 | struct fsf_statistics_info stat_info; | ||
886 | int retval; | ||
887 | |||
888 | retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); | ||
889 | if (retval) | ||
890 | return retval; | ||
891 | |||
892 | return sprintf(buf, "%llu %llu\n", | ||
893 | (unsigned long long) stat_info.input_mb, | ||
894 | (unsigned long long) stat_info.output_mb); | ||
895 | } | ||
896 | |||
897 | static ssize_t zfcp_sysfs_adapter_sec_active_show(struct device *dev, | ||
898 | struct device_attribute *attr, | ||
899 | char *buf) | ||
900 | { | ||
901 | struct fsf_statistics_info stat_info; | ||
902 | int retval; | ||
903 | |||
904 | retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); | ||
905 | if (retval) | ||
906 | return retval; | ||
907 | |||
908 | return sprintf(buf, "%llu\n", | ||
909 | (unsigned long long) stat_info.seconds_act); | ||
910 | } | ||
911 | |||
912 | static DEVICE_ATTR(utilization, S_IRUGO, zfcp_sysfs_adapter_util_show, NULL); | ||
913 | static DEVICE_ATTR(requests, S_IRUGO, zfcp_sysfs_adapter_request_show, NULL); | ||
914 | static DEVICE_ATTR(megabytes, S_IRUGO, zfcp_sysfs_adapter_mb_show, NULL); | ||
915 | static DEVICE_ATTR(seconds_active, S_IRUGO, | ||
916 | zfcp_sysfs_adapter_sec_active_show, NULL); | ||
917 | |||
918 | static struct device_attribute *zfcp_a_stats_attrs[] = { | ||
919 | &dev_attr_utilization, | ||
920 | &dev_attr_requests, | ||
921 | &dev_attr_megabytes, | ||
922 | &dev_attr_seconds_active, | ||
923 | NULL | ||
924 | }; | 544 | }; |
925 | |||
926 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c new file mode 100644 index 000000000000..2e85c6c49e7d --- /dev/null +++ b/drivers/s390/scsi/zfcp_sysfs.c | |||
@@ -0,0 +1,496 @@ | |||
1 | /* | ||
2 | * zfcp device driver | ||
3 | * | ||
4 | * sysfs attributes. | ||
5 | * | ||
6 | * Copyright IBM Corporation 2008 | ||
7 | */ | ||
8 | |||
9 | #include "zfcp_ext.h" | ||
10 | |||
11 | #define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \ | ||
12 | struct device_attribute dev_attr_##_feat##_##_name = __ATTR(_name, _mode,\ | ||
13 | _show, _store) | ||
14 | #define ZFCP_DEFINE_ATTR(_feat_def, _feat, _name, _format, _value) \ | ||
15 | static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \ | ||
16 | struct device_attribute *at,\ | ||
17 | char *buf) \ | ||
18 | { \ | ||
19 | struct _feat_def *_feat = dev_get_drvdata(dev); \ | ||
20 | \ | ||
21 | return sprintf(buf, _format, _value); \ | ||
22 | } \ | ||
23 | static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \ | ||
24 | zfcp_sysfs_##_feat##_##_name##_show, NULL); | ||
25 | |||
26 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, status, "0x%08x\n", | ||
27 | atomic_read(&adapter->status)); | ||
28 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwnn, "0x%016llx\n", | ||
29 | adapter->peer_wwnn); | ||
30 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwpn, "0x%016llx\n", | ||
31 | adapter->peer_wwpn); | ||
32 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_d_id, "0x%06x\n", | ||
33 | adapter->peer_d_id); | ||
34 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, card_version, "0x%04x\n", | ||
35 | adapter->hydra_version); | ||
36 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, lic_version, "0x%08x\n", | ||
37 | adapter->fsf_lic_version); | ||
38 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, hardware_version, "0x%08x\n", | ||
39 | adapter->hardware_version); | ||
40 | ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, in_recovery, "%d\n", | ||
41 | (atomic_read(&adapter->status) & | ||
42 | ZFCP_STATUS_COMMON_ERP_INUSE) != 0); | ||
43 | |||
44 | ZFCP_DEFINE_ATTR(zfcp_port, port, status, "0x%08x\n", | ||
45 | atomic_read(&port->status)); | ||
46 | ZFCP_DEFINE_ATTR(zfcp_port, port, in_recovery, "%d\n", | ||
47 | (atomic_read(&port->status) & | ||
48 | ZFCP_STATUS_COMMON_ERP_INUSE) != 0); | ||
49 | ZFCP_DEFINE_ATTR(zfcp_port, port, access_denied, "%d\n", | ||
50 | (atomic_read(&port->status) & | ||
51 | ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0); | ||
52 | |||
53 | ZFCP_DEFINE_ATTR(zfcp_unit, unit, status, "0x%08x\n", | ||
54 | atomic_read(&unit->status)); | ||
55 | ZFCP_DEFINE_ATTR(zfcp_unit, unit, in_recovery, "%d\n", | ||
56 | (atomic_read(&unit->status) & | ||
57 | ZFCP_STATUS_COMMON_ERP_INUSE) != 0); | ||
58 | ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_denied, "%d\n", | ||
59 | (atomic_read(&unit->status) & | ||
60 | ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0); | ||
61 | ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_shared, "%d\n", | ||
62 | (atomic_read(&unit->status) & | ||
63 | ZFCP_STATUS_UNIT_SHARED) != 0); | ||
64 | ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_readonly, "%d\n", | ||
65 | (atomic_read(&unit->status) & | ||
66 | ZFCP_STATUS_UNIT_READONLY) != 0); | ||
67 | |||
68 | #define ZFCP_SYSFS_FAILED(_feat_def, _feat, _adapter, _mod_id, _reopen_id) \ | ||
69 | static ssize_t zfcp_sysfs_##_feat##_failed_show(struct device *dev, \ | ||
70 | struct device_attribute *attr, \ | ||
71 | char *buf) \ | ||
72 | { \ | ||
73 | struct _feat_def *_feat = dev_get_drvdata(dev); \ | ||
74 | \ | ||
75 | if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_ERP_FAILED) \ | ||
76 | return sprintf(buf, "1\n"); \ | ||
77 | else \ | ||
78 | return sprintf(buf, "0\n"); \ | ||
79 | } \ | ||
80 | static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ | ||
81 | struct device_attribute *attr,\ | ||
82 | const char *buf, size_t count)\ | ||
83 | { \ | ||
84 | struct _feat_def *_feat = dev_get_drvdata(dev); \ | ||
85 | unsigned long val; \ | ||
86 | int retval = 0; \ | ||
87 | \ | ||
88 | down(&zfcp_data.config_sema); \ | ||
89 | if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_REMOVE) { \ | ||
90 | retval = -EBUSY; \ | ||
91 | goto out; \ | ||
92 | } \ | ||
93 | \ | ||
94 | if (strict_strtoul(buf, 0, &val) || val != 0) { \ | ||
95 | retval = -EINVAL; \ | ||
96 | goto out; \ | ||
97 | } \ | ||
98 | \ | ||
99 | zfcp_erp_modify_##_feat##_status(_feat, _mod_id, NULL, \ | ||
100 | ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);\ | ||
101 | zfcp_erp_##_feat##_reopen(_feat, ZFCP_STATUS_COMMON_ERP_FAILED, \ | ||
102 | _reopen_id, NULL); \ | ||
103 | zfcp_erp_wait(_adapter); \ | ||
104 | out: \ | ||
105 | up(&zfcp_data.config_sema); \ | ||
106 | return retval ? retval : (ssize_t) count; \ | ||
107 | } \ | ||
108 | static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \ | ||
109 | zfcp_sysfs_##_feat##_failed_show, \ | ||
110 | zfcp_sysfs_##_feat##_failed_store); | ||
111 | |||
112 | ZFCP_SYSFS_FAILED(zfcp_adapter, adapter, adapter, 44, 93); | ||
113 | ZFCP_SYSFS_FAILED(zfcp_port, port, port->adapter, 45, 96); | ||
114 | ZFCP_SYSFS_FAILED(zfcp_unit, unit, unit->port->adapter, 46, 97); | ||
115 | |||
116 | static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, | ||
117 | struct device_attribute *attr, | ||
118 | const char *buf, size_t count) | ||
119 | { | ||
120 | struct zfcp_adapter *adapter = dev_get_drvdata(dev); | ||
121 | int ret; | ||
122 | |||
123 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) | ||
124 | return -EBUSY; | ||
125 | |||
126 | ret = zfcp_scan_ports(adapter); | ||
127 | return ret ? ret : (ssize_t) count; | ||
128 | } | ||
129 | static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, | ||
130 | zfcp_sysfs_port_rescan_store); | ||
131 | |||
132 | static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, | ||
133 | struct device_attribute *attr, | ||
134 | const char *buf, size_t count) | ||
135 | { | ||
136 | struct zfcp_adapter *adapter = dev_get_drvdata(dev); | ||
137 | struct zfcp_port *port; | ||
138 | wwn_t wwpn; | ||
139 | int retval = 0; | ||
140 | |||
141 | down(&zfcp_data.config_sema); | ||
142 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { | ||
143 | retval = -EBUSY; | ||
144 | goto out; | ||
145 | } | ||
146 | |||
147 | if (strict_strtoull(buf, 0, &wwpn)) { | ||
148 | retval = -EINVAL; | ||
149 | goto out; | ||
150 | } | ||
151 | |||
152 | write_lock_irq(&zfcp_data.config_lock); | ||
153 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | ||
154 | if (port && (atomic_read(&port->refcount) == 0)) { | ||
155 | zfcp_port_get(port); | ||
156 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | ||
157 | list_move(&port->list, &adapter->port_remove_lh); | ||
158 | } else | ||
159 | port = NULL; | ||
160 | write_unlock_irq(&zfcp_data.config_lock); | ||
161 | |||
162 | if (!port) { | ||
163 | retval = -ENXIO; | ||
164 | goto out; | ||
165 | } | ||
166 | |||
167 | zfcp_erp_port_shutdown(port, 0, 92, NULL); | ||
168 | zfcp_erp_wait(adapter); | ||
169 | zfcp_port_put(port); | ||
170 | zfcp_port_dequeue(port); | ||
171 | out: | ||
172 | up(&zfcp_data.config_sema); | ||
173 | return retval ? retval : (ssize_t) count; | ||
174 | } | ||
175 | static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL, | ||
176 | zfcp_sysfs_port_remove_store); | ||
177 | |||
178 | static struct attribute *zfcp_adapter_attrs[] = { | ||
179 | &dev_attr_adapter_failed.attr, | ||
180 | &dev_attr_adapter_in_recovery.attr, | ||
181 | &dev_attr_adapter_port_remove.attr, | ||
182 | &dev_attr_adapter_port_rescan.attr, | ||
183 | &dev_attr_adapter_peer_wwnn.attr, | ||
184 | &dev_attr_adapter_peer_wwpn.attr, | ||
185 | &dev_attr_adapter_peer_d_id.attr, | ||
186 | &dev_attr_adapter_card_version.attr, | ||
187 | &dev_attr_adapter_lic_version.attr, | ||
188 | &dev_attr_adapter_status.attr, | ||
189 | &dev_attr_adapter_hardware_version.attr, | ||
190 | NULL | ||
191 | }; | ||
192 | |||
193 | struct attribute_group zfcp_sysfs_adapter_attrs = { | ||
194 | .attrs = zfcp_adapter_attrs, | ||
195 | }; | ||
196 | |||
197 | static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, | ||
198 | struct device_attribute *attr, | ||
199 | const char *buf, size_t count) | ||
200 | { | ||
201 | struct zfcp_port *port = dev_get_drvdata(dev); | ||
202 | struct zfcp_unit *unit; | ||
203 | fcp_lun_t fcp_lun; | ||
204 | int retval = -EINVAL; | ||
205 | |||
206 | down(&zfcp_data.config_sema); | ||
207 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { | ||
208 | retval = -EBUSY; | ||
209 | goto out; | ||
210 | } | ||
211 | |||
212 | if (strict_strtoull(buf, 0, &fcp_lun)) | ||
213 | goto out; | ||
214 | |||
215 | unit = zfcp_unit_enqueue(port, fcp_lun); | ||
216 | if (IS_ERR(unit)) | ||
217 | goto out; | ||
218 | |||
219 | retval = 0; | ||
220 | |||
221 | zfcp_erp_unit_reopen(unit, 0, 94, NULL); | ||
222 | zfcp_erp_wait(unit->port->adapter); | ||
223 | zfcp_unit_put(unit); | ||
224 | out: | ||
225 | up(&zfcp_data.config_sema); | ||
226 | return retval ? retval : (ssize_t) count; | ||
227 | } | ||
228 | static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); | ||
229 | |||
230 | static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, | ||
231 | struct device_attribute *attr, | ||
232 | const char *buf, size_t count) | ||
233 | { | ||
234 | struct zfcp_port *port = dev_get_drvdata(dev); | ||
235 | struct zfcp_unit *unit; | ||
236 | fcp_lun_t fcp_lun; | ||
237 | int retval = 0; | ||
238 | |||
239 | down(&zfcp_data.config_sema); | ||
240 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { | ||
241 | retval = -EBUSY; | ||
242 | goto out; | ||
243 | } | ||
244 | |||
245 | if (strict_strtoull(buf, 0, &fcp_lun)) { | ||
246 | retval = -EINVAL; | ||
247 | goto out; | ||
248 | } | ||
249 | |||
250 | write_lock_irq(&zfcp_data.config_lock); | ||
251 | unit = zfcp_get_unit_by_lun(port, fcp_lun); | ||
252 | if (unit && (atomic_read(&unit->refcount) == 0)) { | ||
253 | zfcp_unit_get(unit); | ||
254 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | ||
255 | list_move(&unit->list, &port->unit_remove_lh); | ||
256 | } else | ||
257 | unit = NULL; | ||
258 | |||
259 | write_unlock_irq(&zfcp_data.config_lock); | ||
260 | |||
261 | if (!unit) { | ||
262 | retval = -ENXIO; | ||
263 | goto out; | ||
264 | } | ||
265 | |||
266 | zfcp_erp_unit_shutdown(unit, 0, 95, NULL); | ||
267 | zfcp_erp_wait(unit->port->adapter); | ||
268 | zfcp_unit_put(unit); | ||
269 | zfcp_unit_dequeue(unit); | ||
270 | out: | ||
271 | up(&zfcp_data.config_sema); | ||
272 | return retval ? retval : (ssize_t) count; | ||
273 | } | ||
274 | static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); | ||
275 | |||
276 | static struct attribute *zfcp_port_ns_attrs[] = { | ||
277 | &dev_attr_port_failed.attr, | ||
278 | &dev_attr_port_in_recovery.attr, | ||
279 | &dev_attr_port_status.attr, | ||
280 | &dev_attr_port_access_denied.attr, | ||
281 | NULL | ||
282 | }; | ||
283 | |||
284 | /** | ||
285 | * zfcp_sysfs_ns_port_attrs - sysfs attributes for nameserver | ||
286 | */ | ||
287 | struct attribute_group zfcp_sysfs_ns_port_attrs = { | ||
288 | .attrs = zfcp_port_ns_attrs, | ||
289 | }; | ||
290 | |||
291 | static struct attribute *zfcp_port_no_ns_attrs[] = { | ||
292 | &dev_attr_unit_add.attr, | ||
293 | &dev_attr_unit_remove.attr, | ||
294 | &dev_attr_port_failed.attr, | ||
295 | &dev_attr_port_in_recovery.attr, | ||
296 | &dev_attr_port_status.attr, | ||
297 | &dev_attr_port_access_denied.attr, | ||
298 | NULL | ||
299 | }; | ||
300 | |||
301 | /** | ||
302 | * zfcp_sysfs_port_attrs - sysfs attributes for all other ports | ||
303 | */ | ||
304 | struct attribute_group zfcp_sysfs_port_attrs = { | ||
305 | .attrs = zfcp_port_no_ns_attrs, | ||
306 | }; | ||
307 | |||
308 | static struct attribute *zfcp_unit_attrs[] = { | ||
309 | &dev_attr_unit_failed.attr, | ||
310 | &dev_attr_unit_in_recovery.attr, | ||
311 | &dev_attr_unit_status.attr, | ||
312 | &dev_attr_unit_access_denied.attr, | ||
313 | &dev_attr_unit_access_shared.attr, | ||
314 | &dev_attr_unit_access_readonly.attr, | ||
315 | NULL | ||
316 | }; | ||
317 | |||
318 | struct attribute_group zfcp_sysfs_unit_attrs = { | ||
319 | .attrs = zfcp_unit_attrs, | ||
320 | }; | ||
321 | |||
322 | #define ZFCP_DEFINE_LATENCY_ATTR(_name) \ | ||
323 | static ssize_t \ | ||
324 | zfcp_sysfs_unit_##_name##_latency_show(struct device *dev, \ | ||
325 | struct device_attribute *attr, \ | ||
326 | char *buf) { \ | ||
327 | struct scsi_device *sdev = to_scsi_device(dev); \ | ||
328 | struct zfcp_unit *unit = sdev->hostdata; \ | ||
329 | struct zfcp_latencies *lat = &unit->latencies; \ | ||
330 | struct zfcp_adapter *adapter = unit->port->adapter; \ | ||
331 | unsigned long flags; \ | ||
332 | unsigned long long fsum, fmin, fmax, csum, cmin, cmax, cc; \ | ||
333 | \ | ||
334 | spin_lock_irqsave(&lat->lock, flags); \ | ||
335 | fsum = lat->_name.fabric.sum * adapter->timer_ticks; \ | ||
336 | fmin = lat->_name.fabric.min * adapter->timer_ticks; \ | ||
337 | fmax = lat->_name.fabric.max * adapter->timer_ticks; \ | ||
338 | csum = lat->_name.channel.sum * adapter->timer_ticks; \ | ||
339 | cmin = lat->_name.channel.min * adapter->timer_ticks; \ | ||
340 | cmax = lat->_name.channel.max * adapter->timer_ticks; \ | ||
341 | cc = lat->_name.counter; \ | ||
342 | spin_unlock_irqrestore(&lat->lock, flags); \ | ||
343 | \ | ||
344 | do_div(fsum, 1000); \ | ||
345 | do_div(fmin, 1000); \ | ||
346 | do_div(fmax, 1000); \ | ||
347 | do_div(csum, 1000); \ | ||
348 | do_div(cmin, 1000); \ | ||
349 | do_div(cmax, 1000); \ | ||
350 | \ | ||
351 | return sprintf(buf, "%llu %llu %llu %llu %llu %llu %llu\n", \ | ||
352 | fmin, fmax, fsum, cmin, cmax, csum, cc); \ | ||
353 | } \ | ||
354 | static ssize_t \ | ||
355 | zfcp_sysfs_unit_##_name##_latency_store(struct device *dev, \ | ||
356 | struct device_attribute *attr, \ | ||
357 | const char *buf, size_t count) \ | ||
358 | { \ | ||
359 | struct scsi_device *sdev = to_scsi_device(dev); \ | ||
360 | struct zfcp_unit *unit = sdev->hostdata; \ | ||
361 | struct zfcp_latencies *lat = &unit->latencies; \ | ||
362 | unsigned long flags; \ | ||
363 | \ | ||
364 | spin_lock_irqsave(&lat->lock, flags); \ | ||
365 | lat->_name.fabric.sum = 0; \ | ||
366 | lat->_name.fabric.min = 0xFFFFFFFF; \ | ||
367 | lat->_name.fabric.max = 0; \ | ||
368 | lat->_name.channel.sum = 0; \ | ||
369 | lat->_name.channel.min = 0xFFFFFFFF; \ | ||
370 | lat->_name.channel.max = 0; \ | ||
371 | lat->_name.counter = 0; \ | ||
372 | spin_unlock_irqrestore(&lat->lock, flags); \ | ||
373 | \ | ||
374 | return (ssize_t) count; \ | ||
375 | } \ | ||
376 | static DEVICE_ATTR(_name##_latency, S_IWUSR | S_IRUGO, \ | ||
377 | zfcp_sysfs_unit_##_name##_latency_show, \ | ||
378 | zfcp_sysfs_unit_##_name##_latency_store); | ||
379 | |||
380 | ZFCP_DEFINE_LATENCY_ATTR(read); | ||
381 | ZFCP_DEFINE_LATENCY_ATTR(write); | ||
382 | ZFCP_DEFINE_LATENCY_ATTR(cmd); | ||
383 | |||
384 | #define ZFCP_DEFINE_SCSI_ATTR(_name, _format, _value) \ | ||
385 | static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, \ | ||
386 | struct device_attribute *attr,\ | ||
387 | char *buf) \ | ||
388 | { \ | ||
389 | struct scsi_device *sdev = to_scsi_device(dev); \ | ||
390 | struct zfcp_unit *unit = sdev->hostdata; \ | ||
391 | \ | ||
392 | return sprintf(buf, _format, _value); \ | ||
393 | } \ | ||
394 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL); | ||
395 | |||
396 | ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", | ||
397 | unit->port->adapter->ccw_device->dev.bus_id); | ||
398 | ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", unit->port->wwpn); | ||
399 | ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", unit->fcp_lun); | ||
400 | |||
401 | struct device_attribute *zfcp_sysfs_sdev_attrs[] = { | ||
402 | &dev_attr_fcp_lun, | ||
403 | &dev_attr_wwpn, | ||
404 | &dev_attr_hba_id, | ||
405 | &dev_attr_read_latency, | ||
406 | &dev_attr_write_latency, | ||
407 | &dev_attr_cmd_latency, | ||
408 | NULL | ||
409 | }; | ||
410 | |||
411 | static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, | ||
412 | struct device_attribute *attr, | ||
413 | char *buf) | ||
414 | { | ||
415 | struct Scsi_Host *scsi_host = dev_to_shost(dev); | ||
416 | struct fsf_qtcb_bottom_port *qtcb_port; | ||
417 | struct zfcp_adapter *adapter; | ||
418 | int retval; | ||
419 | |||
420 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | ||
421 | if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) | ||
422 | return -EOPNOTSUPP; | ||
423 | |||
424 | qtcb_port = kzalloc(sizeof(struct fsf_qtcb_bottom_port), GFP_KERNEL); | ||
425 | if (!qtcb_port) | ||
426 | return -ENOMEM; | ||
427 | |||
428 | retval = zfcp_fsf_exchange_port_data_sync(adapter, qtcb_port); | ||
429 | if (!retval) | ||
430 | retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, | ||
431 | qtcb_port->cb_util, qtcb_port->a_util); | ||
432 | kfree(qtcb_port); | ||
433 | return retval; | ||
434 | } | ||
435 | static DEVICE_ATTR(utilization, S_IRUGO, zfcp_sysfs_adapter_util_show, NULL); | ||
436 | |||
437 | static int zfcp_sysfs_adapter_ex_config(struct device *dev, | ||
438 | struct fsf_statistics_info *stat_inf) | ||
439 | { | ||
440 | struct Scsi_Host *scsi_host = dev_to_shost(dev); | ||
441 | struct fsf_qtcb_bottom_config *qtcb_config; | ||
442 | struct zfcp_adapter *adapter; | ||
443 | int retval; | ||
444 | |||
445 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | ||
446 | if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) | ||
447 | return -EOPNOTSUPP; | ||
448 | |||
449 | qtcb_config = kzalloc(sizeof(struct fsf_qtcb_bottom_config), | ||
450 | GFP_KERNEL); | ||
451 | if (!qtcb_config) | ||
452 | return -ENOMEM; | ||
453 | |||
454 | retval = zfcp_fsf_exchange_config_data_sync(adapter, qtcb_config); | ||
455 | if (!retval) | ||
456 | *stat_inf = qtcb_config->stat_info; | ||
457 | |||
458 | kfree(qtcb_config); | ||
459 | return retval; | ||
460 | } | ||
461 | |||
462 | #define ZFCP_SHOST_ATTR(_name, _format, _arg...) \ | ||
463 | static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, \ | ||
464 | struct device_attribute *attr,\ | ||
465 | char *buf) \ | ||
466 | { \ | ||
467 | struct fsf_statistics_info stat_info; \ | ||
468 | int retval; \ | ||
469 | \ | ||
470 | retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); \ | ||
471 | if (retval) \ | ||
472 | return retval; \ | ||
473 | \ | ||
474 | return sprintf(buf, _format, ## _arg); \ | ||
475 | } \ | ||
476 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL); | ||
477 | |||
478 | ZFCP_SHOST_ATTR(requests, "%llu %llu %llu\n", | ||
479 | (unsigned long long) stat_info.input_req, | ||
480 | (unsigned long long) stat_info.output_req, | ||
481 | (unsigned long long) stat_info.control_req); | ||
482 | |||
483 | ZFCP_SHOST_ATTR(megabytes, "%llu %llu\n", | ||
484 | (unsigned long long) stat_info.input_mb, | ||
485 | (unsigned long long) stat_info.output_mb); | ||
486 | |||
487 | ZFCP_SHOST_ATTR(seconds_active, "%llu\n", | ||
488 | (unsigned long long) stat_info.seconds_act); | ||
489 | |||
490 | struct device_attribute *zfcp_sysfs_shost_attrs[] = { | ||
491 | &dev_attr_utilization, | ||
492 | &dev_attr_requests, | ||
493 | &dev_attr_megabytes, | ||
494 | &dev_attr_seconds_active, | ||
495 | NULL | ||
496 | }; | ||
diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c deleted file mode 100644 index ccbba4dd3a77..000000000000 --- a/drivers/s390/scsi/zfcp_sysfs_adapter.c +++ /dev/null | |||
@@ -1,270 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of the zfcp device driver for | ||
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | ||
5 | * (C) Copyright IBM Corp. 2002, 2006 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "zfcp_ext.h" | ||
23 | |||
24 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | ||
25 | |||
26 | /** | ||
27 | * ZFCP_DEFINE_ADAPTER_ATTR | ||
28 | * @_name: name of show attribute | ||
29 | * @_format: format string | ||
30 | * @_value: value to print | ||
31 | * | ||
32 | * Generates attributes for an adapter. | ||
33 | */ | ||
34 | #define ZFCP_DEFINE_ADAPTER_ATTR(_name, _format, _value) \ | ||
35 | static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, struct device_attribute *attr, \ | ||
36 | char *buf) \ | ||
37 | { \ | ||
38 | struct zfcp_adapter *adapter; \ | ||
39 | \ | ||
40 | adapter = dev_get_drvdata(dev); \ | ||
41 | return sprintf(buf, _format, _value); \ | ||
42 | } \ | ||
43 | \ | ||
44 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL); | ||
45 | |||
46 | ZFCP_DEFINE_ADAPTER_ATTR(status, "0x%08x\n", atomic_read(&adapter->status)); | ||
47 | ZFCP_DEFINE_ADAPTER_ATTR(peer_wwnn, "0x%016llx\n", adapter->peer_wwnn); | ||
48 | ZFCP_DEFINE_ADAPTER_ATTR(peer_wwpn, "0x%016llx\n", adapter->peer_wwpn); | ||
49 | ZFCP_DEFINE_ADAPTER_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id); | ||
50 | ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version); | ||
51 | ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version); | ||
52 | ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n", | ||
53 | adapter->hardware_version); | ||
54 | ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask | ||
55 | (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)); | ||
56 | |||
57 | /** | ||
58 | * zfcp_sysfs_port_add_store - add a port to sysfs tree | ||
59 | * @dev: pointer to belonging device | ||
60 | * @buf: pointer to input buffer | ||
61 | * @count: number of bytes in buffer | ||
62 | * | ||
63 | * Store function of the "port_add" attribute of an adapter. | ||
64 | */ | ||
65 | static ssize_t | ||
66 | zfcp_sysfs_port_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
67 | { | ||
68 | wwn_t wwpn; | ||
69 | char *endp; | ||
70 | struct zfcp_adapter *adapter; | ||
71 | struct zfcp_port *port; | ||
72 | int retval = -EINVAL; | ||
73 | |||
74 | down(&zfcp_data.config_sema); | ||
75 | |||
76 | adapter = dev_get_drvdata(dev); | ||
77 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { | ||
78 | retval = -EBUSY; | ||
79 | goto out; | ||
80 | } | ||
81 | |||
82 | wwpn = simple_strtoull(buf, &endp, 0); | ||
83 | if ((endp + 1) < (buf + count)) | ||
84 | goto out; | ||
85 | |||
86 | port = zfcp_port_enqueue(adapter, wwpn, 0, 0); | ||
87 | if (!port) | ||
88 | goto out; | ||
89 | |||
90 | retval = 0; | ||
91 | |||
92 | zfcp_erp_port_reopen(port, 0, 91, NULL); | ||
93 | zfcp_erp_wait(port->adapter); | ||
94 | zfcp_port_put(port); | ||
95 | out: | ||
96 | up(&zfcp_data.config_sema); | ||
97 | return retval ? retval : (ssize_t) count; | ||
98 | } | ||
99 | |||
100 | static DEVICE_ATTR(port_add, S_IWUSR, NULL, zfcp_sysfs_port_add_store); | ||
101 | |||
102 | /** | ||
103 | * zfcp_sysfs_port_remove_store - remove a port from sysfs tree | ||
104 | * @dev: pointer to belonging device | ||
105 | * @buf: pointer to input buffer | ||
106 | * @count: number of bytes in buffer | ||
107 | * | ||
108 | * Store function of the "port_remove" attribute of an adapter. | ||
109 | */ | ||
110 | static ssize_t | ||
111 | zfcp_sysfs_port_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
112 | { | ||
113 | struct zfcp_adapter *adapter; | ||
114 | struct zfcp_port *port; | ||
115 | wwn_t wwpn; | ||
116 | char *endp; | ||
117 | int retval = 0; | ||
118 | |||
119 | down(&zfcp_data.config_sema); | ||
120 | |||
121 | adapter = dev_get_drvdata(dev); | ||
122 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { | ||
123 | retval = -EBUSY; | ||
124 | goto out; | ||
125 | } | ||
126 | |||
127 | wwpn = simple_strtoull(buf, &endp, 0); | ||
128 | if ((endp + 1) < (buf + count)) { | ||
129 | retval = -EINVAL; | ||
130 | goto out; | ||
131 | } | ||
132 | |||
133 | write_lock_irq(&zfcp_data.config_lock); | ||
134 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | ||
135 | if (port && (atomic_read(&port->refcount) == 0)) { | ||
136 | zfcp_port_get(port); | ||
137 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | ||
138 | list_move(&port->list, &adapter->port_remove_lh); | ||
139 | } | ||
140 | else { | ||
141 | port = NULL; | ||
142 | } | ||
143 | write_unlock_irq(&zfcp_data.config_lock); | ||
144 | |||
145 | if (!port) { | ||
146 | retval = -ENXIO; | ||
147 | goto out; | ||
148 | } | ||
149 | |||
150 | zfcp_erp_port_shutdown(port, 0, 92, NULL); | ||
151 | zfcp_erp_wait(adapter); | ||
152 | zfcp_port_put(port); | ||
153 | zfcp_port_dequeue(port); | ||
154 | out: | ||
155 | up(&zfcp_data.config_sema); | ||
156 | return retval ? retval : (ssize_t) count; | ||
157 | } | ||
158 | |||
159 | static DEVICE_ATTR(port_remove, S_IWUSR, NULL, zfcp_sysfs_port_remove_store); | ||
160 | |||
161 | /** | ||
162 | * zfcp_sysfs_adapter_failed_store - failed state of adapter | ||
163 | * @dev: pointer to belonging device | ||
164 | * @buf: pointer to input buffer | ||
165 | * @count: number of bytes in buffer | ||
166 | * | ||
167 | * Store function of the "failed" attribute of an adapter. | ||
168 | * If a "0" gets written to "failed", error recovery will be | ||
169 | * started for the belonging adapter. | ||
170 | */ | ||
171 | static ssize_t | ||
172 | zfcp_sysfs_adapter_failed_store(struct device *dev, struct device_attribute *attr, | ||
173 | const char *buf, size_t count) | ||
174 | { | ||
175 | struct zfcp_adapter *adapter; | ||
176 | unsigned int val; | ||
177 | char *endp; | ||
178 | int retval = 0; | ||
179 | |||
180 | down(&zfcp_data.config_sema); | ||
181 | |||
182 | adapter = dev_get_drvdata(dev); | ||
183 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status)) { | ||
184 | retval = -EBUSY; | ||
185 | goto out; | ||
186 | } | ||
187 | |||
188 | val = simple_strtoul(buf, &endp, 0); | ||
189 | if (((endp + 1) < (buf + count)) || (val != 0)) { | ||
190 | retval = -EINVAL; | ||
191 | goto out; | ||
192 | } | ||
193 | |||
194 | zfcp_erp_modify_adapter_status(adapter, 44, NULL, | ||
195 | ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); | ||
196 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 93, | ||
197 | NULL); | ||
198 | zfcp_erp_wait(adapter); | ||
199 | out: | ||
200 | up(&zfcp_data.config_sema); | ||
201 | return retval ? retval : (ssize_t) count; | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * zfcp_sysfs_adapter_failed_show - failed state of adapter | ||
206 | * @dev: pointer to belonging device | ||
207 | * @buf: pointer to input buffer | ||
208 | * | ||
209 | * Show function of "failed" attribute of adapter. Will be | ||
210 | * "0" if adapter is working, otherwise "1". | ||
211 | */ | ||
212 | static ssize_t | ||
213 | zfcp_sysfs_adapter_failed_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
214 | { | ||
215 | struct zfcp_adapter *adapter; | ||
216 | |||
217 | adapter = dev_get_drvdata(dev); | ||
218 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) | ||
219 | return sprintf(buf, "1\n"); | ||
220 | else | ||
221 | return sprintf(buf, "0\n"); | ||
222 | } | ||
223 | |||
224 | static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_adapter_failed_show, | ||
225 | zfcp_sysfs_adapter_failed_store); | ||
226 | |||
227 | static struct attribute *zfcp_adapter_attrs[] = { | ||
228 | &dev_attr_failed.attr, | ||
229 | &dev_attr_in_recovery.attr, | ||
230 | &dev_attr_port_remove.attr, | ||
231 | &dev_attr_port_add.attr, | ||
232 | &dev_attr_peer_wwnn.attr, | ||
233 | &dev_attr_peer_wwpn.attr, | ||
234 | &dev_attr_peer_d_id.attr, | ||
235 | &dev_attr_card_version.attr, | ||
236 | &dev_attr_lic_version.attr, | ||
237 | &dev_attr_status.attr, | ||
238 | &dev_attr_hardware_version.attr, | ||
239 | NULL | ||
240 | }; | ||
241 | |||
242 | static struct attribute_group zfcp_adapter_attr_group = { | ||
243 | .attrs = zfcp_adapter_attrs, | ||
244 | }; | ||
245 | |||
246 | /** | ||
247 | * zfcp_sysfs_create_adapter_files - create sysfs adapter files | ||
248 | * @dev: pointer to belonging device | ||
249 | * | ||
250 | * Create all attributes of the sysfs representation of an adapter. | ||
251 | */ | ||
252 | int | ||
253 | zfcp_sysfs_adapter_create_files(struct device *dev) | ||
254 | { | ||
255 | return sysfs_create_group(&dev->kobj, &zfcp_adapter_attr_group); | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * zfcp_sysfs_remove_adapter_files - remove sysfs adapter files | ||
260 | * @dev: pointer to belonging device | ||
261 | * | ||
262 | * Remove all attributes of the sysfs representation of an adapter. | ||
263 | */ | ||
264 | void | ||
265 | zfcp_sysfs_adapter_remove_files(struct device *dev) | ||
266 | { | ||
267 | sysfs_remove_group(&dev->kobj, &zfcp_adapter_attr_group); | ||
268 | } | ||
269 | |||
270 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_sysfs_driver.c b/drivers/s390/scsi/zfcp_sysfs_driver.c deleted file mode 100644 index 651edd58906a..000000000000 --- a/drivers/s390/scsi/zfcp_sysfs_driver.c +++ /dev/null | |||
@@ -1,106 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of the zfcp device driver for | ||
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | ||
5 | * (C) Copyright IBM Corp. 2002, 2006 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "zfcp_ext.h" | ||
23 | |||
24 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | ||
25 | |||
26 | /** | ||
27 | * ZFCP_DEFINE_DRIVER_ATTR - define for all loglevels sysfs attributes | ||
28 | * @_name: name of attribute | ||
29 | * @_define: name of ZFCP loglevel define | ||
30 | * | ||
31 | * Generates store function for a sysfs loglevel attribute of zfcp driver. | ||
32 | */ | ||
33 | #define ZFCP_DEFINE_DRIVER_ATTR(_name, _define) \ | ||
34 | static ssize_t zfcp_sysfs_loglevel_##_name##_store(struct device_driver *drv, \ | ||
35 | const char *buf, \ | ||
36 | size_t count) \ | ||
37 | { \ | ||
38 | unsigned int loglevel; \ | ||
39 | unsigned int new_loglevel; \ | ||
40 | char *endp; \ | ||
41 | \ | ||
42 | new_loglevel = simple_strtoul(buf, &endp, 0); \ | ||
43 | if ((endp + 1) < (buf + count)) \ | ||
44 | return -EINVAL; \ | ||
45 | if (new_loglevel > 3) \ | ||
46 | return -EINVAL; \ | ||
47 | down(&zfcp_data.config_sema); \ | ||
48 | loglevel = atomic_read(&zfcp_data.loglevel); \ | ||
49 | loglevel &= ~((unsigned int) 0xf << (ZFCP_LOG_AREA_##_define << 2)); \ | ||
50 | loglevel |= new_loglevel << (ZFCP_LOG_AREA_##_define << 2); \ | ||
51 | atomic_set(&zfcp_data.loglevel, loglevel); \ | ||
52 | up(&zfcp_data.config_sema); \ | ||
53 | return count; \ | ||
54 | } \ | ||
55 | \ | ||
56 | static ssize_t zfcp_sysfs_loglevel_##_name##_show(struct device_driver *dev, \ | ||
57 | char *buf) \ | ||
58 | { \ | ||
59 | return sprintf(buf,"%d\n", (unsigned int) \ | ||
60 | ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA_##_define)); \ | ||
61 | } \ | ||
62 | \ | ||
63 | static DRIVER_ATTR(loglevel_##_name, S_IWUSR | S_IRUGO, \ | ||
64 | zfcp_sysfs_loglevel_##_name##_show, \ | ||
65 | zfcp_sysfs_loglevel_##_name##_store); | ||
66 | |||
67 | ZFCP_DEFINE_DRIVER_ATTR(other, OTHER); | ||
68 | ZFCP_DEFINE_DRIVER_ATTR(scsi, SCSI); | ||
69 | ZFCP_DEFINE_DRIVER_ATTR(fsf, FSF); | ||
70 | ZFCP_DEFINE_DRIVER_ATTR(config, CONFIG); | ||
71 | ZFCP_DEFINE_DRIVER_ATTR(cio, CIO); | ||
72 | ZFCP_DEFINE_DRIVER_ATTR(qdio, QDIO); | ||
73 | ZFCP_DEFINE_DRIVER_ATTR(erp, ERP); | ||
74 | ZFCP_DEFINE_DRIVER_ATTR(fc, FC); | ||
75 | |||
76 | static ssize_t zfcp_sysfs_version_show(struct device_driver *dev, | ||
77 | char *buf) | ||
78 | { | ||
79 | return sprintf(buf, "%s\n", zfcp_data.driver_version); | ||
80 | } | ||
81 | |||
82 | static DRIVER_ATTR(version, S_IRUGO, zfcp_sysfs_version_show, NULL); | ||
83 | |||
84 | static struct attribute *zfcp_driver_attrs[] = { | ||
85 | &driver_attr_loglevel_other.attr, | ||
86 | &driver_attr_loglevel_scsi.attr, | ||
87 | &driver_attr_loglevel_fsf.attr, | ||
88 | &driver_attr_loglevel_config.attr, | ||
89 | &driver_attr_loglevel_cio.attr, | ||
90 | &driver_attr_loglevel_qdio.attr, | ||
91 | &driver_attr_loglevel_erp.attr, | ||
92 | &driver_attr_loglevel_fc.attr, | ||
93 | &driver_attr_version.attr, | ||
94 | NULL | ||
95 | }; | ||
96 | |||
97 | static struct attribute_group zfcp_driver_attr_group = { | ||
98 | .attrs = zfcp_driver_attrs, | ||
99 | }; | ||
100 | |||
101 | struct attribute_group *zfcp_driver_attr_groups[] = { | ||
102 | &zfcp_driver_attr_group, | ||
103 | NULL, | ||
104 | }; | ||
105 | |||
106 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_sysfs_port.c b/drivers/s390/scsi/zfcp_sysfs_port.c deleted file mode 100644 index 703c1b5cb602..000000000000 --- a/drivers/s390/scsi/zfcp_sysfs_port.c +++ /dev/null | |||
@@ -1,295 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of the zfcp device driver for | ||
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | ||
5 | * (C) Copyright IBM Corp. 2002, 2006 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "zfcp_ext.h" | ||
23 | |||
24 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | ||
25 | |||
26 | /** | ||
27 | * zfcp_sysfs_port_release - gets called when a struct device port is released | ||
28 | * @dev: pointer to belonging device | ||
29 | */ | ||
30 | void | ||
31 | zfcp_sysfs_port_release(struct device *dev) | ||
32 | { | ||
33 | kfree(dev); | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * ZFCP_DEFINE_PORT_ATTR | ||
38 | * @_name: name of show attribute | ||
39 | * @_format: format string | ||
40 | * @_value: value to print | ||
41 | * | ||
42 | * Generates attributes for a port. | ||
43 | */ | ||
44 | #define ZFCP_DEFINE_PORT_ATTR(_name, _format, _value) \ | ||
45 | static ssize_t zfcp_sysfs_port_##_name##_show(struct device *dev, struct device_attribute *attr, \ | ||
46 | char *buf) \ | ||
47 | { \ | ||
48 | struct zfcp_port *port; \ | ||
49 | \ | ||
50 | port = dev_get_drvdata(dev); \ | ||
51 | return sprintf(buf, _format, _value); \ | ||
52 | } \ | ||
53 | \ | ||
54 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_port_##_name##_show, NULL); | ||
55 | |||
56 | ZFCP_DEFINE_PORT_ATTR(status, "0x%08x\n", atomic_read(&port->status)); | ||
57 | ZFCP_DEFINE_PORT_ATTR(in_recovery, "%d\n", atomic_test_mask | ||
58 | (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)); | ||
59 | ZFCP_DEFINE_PORT_ATTR(access_denied, "%d\n", atomic_test_mask | ||
60 | (ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status)); | ||
61 | |||
62 | /** | ||
63 | * zfcp_sysfs_unit_add_store - add a unit to sysfs tree | ||
64 | * @dev: pointer to belonging device | ||
65 | * @buf: pointer to input buffer | ||
66 | * @count: number of bytes in buffer | ||
67 | * | ||
68 | * Store function of the "unit_add" attribute of a port. | ||
69 | */ | ||
70 | static ssize_t | ||
71 | zfcp_sysfs_unit_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
72 | { | ||
73 | fcp_lun_t fcp_lun; | ||
74 | char *endp; | ||
75 | struct zfcp_port *port; | ||
76 | struct zfcp_unit *unit; | ||
77 | int retval = -EINVAL; | ||
78 | |||
79 | down(&zfcp_data.config_sema); | ||
80 | |||
81 | port = dev_get_drvdata(dev); | ||
82 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { | ||
83 | retval = -EBUSY; | ||
84 | goto out; | ||
85 | } | ||
86 | |||
87 | fcp_lun = simple_strtoull(buf, &endp, 0); | ||
88 | if ((endp + 1) < (buf + count)) | ||
89 | goto out; | ||
90 | |||
91 | unit = zfcp_unit_enqueue(port, fcp_lun); | ||
92 | if (!unit) | ||
93 | goto out; | ||
94 | |||
95 | retval = 0; | ||
96 | |||
97 | zfcp_erp_unit_reopen(unit, 0, 94, NULL); | ||
98 | zfcp_erp_wait(unit->port->adapter); | ||
99 | zfcp_unit_put(unit); | ||
100 | out: | ||
101 | up(&zfcp_data.config_sema); | ||
102 | return retval ? retval : (ssize_t) count; | ||
103 | } | ||
104 | |||
105 | static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); | ||
106 | |||
107 | /** | ||
108 | * zfcp_sysfs_unit_remove_store - remove a unit from sysfs tree | ||
109 | * @dev: pointer to belonging device | ||
110 | * @buf: pointer to input buffer | ||
111 | * @count: number of bytes in buffer | ||
112 | */ | ||
113 | static ssize_t | ||
114 | zfcp_sysfs_unit_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
115 | { | ||
116 | struct zfcp_port *port; | ||
117 | struct zfcp_unit *unit; | ||
118 | fcp_lun_t fcp_lun; | ||
119 | char *endp; | ||
120 | int retval = 0; | ||
121 | |||
122 | down(&zfcp_data.config_sema); | ||
123 | |||
124 | port = dev_get_drvdata(dev); | ||
125 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { | ||
126 | retval = -EBUSY; | ||
127 | goto out; | ||
128 | } | ||
129 | |||
130 | fcp_lun = simple_strtoull(buf, &endp, 0); | ||
131 | if ((endp + 1) < (buf + count)) { | ||
132 | retval = -EINVAL; | ||
133 | goto out; | ||
134 | } | ||
135 | |||
136 | write_lock_irq(&zfcp_data.config_lock); | ||
137 | unit = zfcp_get_unit_by_lun(port, fcp_lun); | ||
138 | if (unit && (atomic_read(&unit->refcount) == 0)) { | ||
139 | zfcp_unit_get(unit); | ||
140 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | ||
141 | list_move(&unit->list, &port->unit_remove_lh); | ||
142 | } | ||
143 | else { | ||
144 | unit = NULL; | ||
145 | } | ||
146 | write_unlock_irq(&zfcp_data.config_lock); | ||
147 | |||
148 | if (!unit) { | ||
149 | retval = -ENXIO; | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | zfcp_erp_unit_shutdown(unit, 0, 95, NULL); | ||
154 | zfcp_erp_wait(unit->port->adapter); | ||
155 | zfcp_unit_put(unit); | ||
156 | zfcp_unit_dequeue(unit); | ||
157 | out: | ||
158 | up(&zfcp_data.config_sema); | ||
159 | return retval ? retval : (ssize_t) count; | ||
160 | } | ||
161 | |||
162 | static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); | ||
163 | |||
164 | /** | ||
165 | * zfcp_sysfs_port_failed_store - failed state of port | ||
166 | * @dev: pointer to belonging device | ||
167 | * @buf: pointer to input buffer | ||
168 | * @count: number of bytes in buffer | ||
169 | * | ||
170 | * Store function of the "failed" attribute of a port. | ||
171 | * If a "0" gets written to "failed", error recovery will be | ||
172 | * started for the belonging port. | ||
173 | */ | ||
174 | static ssize_t | ||
175 | zfcp_sysfs_port_failed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
176 | { | ||
177 | struct zfcp_port *port; | ||
178 | unsigned int val; | ||
179 | char *endp; | ||
180 | int retval = 0; | ||
181 | |||
182 | down(&zfcp_data.config_sema); | ||
183 | |||
184 | port = dev_get_drvdata(dev); | ||
185 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status)) { | ||
186 | retval = -EBUSY; | ||
187 | goto out; | ||
188 | } | ||
189 | |||
190 | val = simple_strtoul(buf, &endp, 0); | ||
191 | if (((endp + 1) < (buf + count)) || (val != 0)) { | ||
192 | retval = -EINVAL; | ||
193 | goto out; | ||
194 | } | ||
195 | |||
196 | zfcp_erp_modify_port_status(port, 45, NULL, | ||
197 | ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); | ||
198 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, 96, NULL); | ||
199 | zfcp_erp_wait(port->adapter); | ||
200 | out: | ||
201 | up(&zfcp_data.config_sema); | ||
202 | return retval ? retval : (ssize_t) count; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * zfcp_sysfs_port_failed_show - failed state of port | ||
207 | * @dev: pointer to belonging device | ||
208 | * @buf: pointer to input buffer | ||
209 | * | ||
210 | * Show function of "failed" attribute of port. Will be | ||
211 | * "0" if port is working, otherwise "1". | ||
212 | */ | ||
213 | static ssize_t | ||
214 | zfcp_sysfs_port_failed_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
215 | { | ||
216 | struct zfcp_port *port; | ||
217 | |||
218 | port = dev_get_drvdata(dev); | ||
219 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) | ||
220 | return sprintf(buf, "1\n"); | ||
221 | else | ||
222 | return sprintf(buf, "0\n"); | ||
223 | } | ||
224 | |||
225 | static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_port_failed_show, | ||
226 | zfcp_sysfs_port_failed_store); | ||
227 | |||
228 | /** | ||
229 | * zfcp_port_common_attrs | ||
230 | * sysfs attributes that are common for all kind of fc ports. | ||
231 | */ | ||
232 | static struct attribute *zfcp_port_common_attrs[] = { | ||
233 | &dev_attr_failed.attr, | ||
234 | &dev_attr_in_recovery.attr, | ||
235 | &dev_attr_status.attr, | ||
236 | &dev_attr_access_denied.attr, | ||
237 | NULL | ||
238 | }; | ||
239 | |||
240 | static struct attribute_group zfcp_port_common_attr_group = { | ||
241 | .attrs = zfcp_port_common_attrs, | ||
242 | }; | ||
243 | |||
244 | /** | ||
245 | * zfcp_port_no_ns_attrs | ||
246 | * sysfs attributes not to be used for nameserver ports. | ||
247 | */ | ||
248 | static struct attribute *zfcp_port_no_ns_attrs[] = { | ||
249 | &dev_attr_unit_add.attr, | ||
250 | &dev_attr_unit_remove.attr, | ||
251 | NULL | ||
252 | }; | ||
253 | |||
254 | static struct attribute_group zfcp_port_no_ns_attr_group = { | ||
255 | .attrs = zfcp_port_no_ns_attrs, | ||
256 | }; | ||
257 | |||
258 | /** | ||
259 | * zfcp_sysfs_port_create_files - create sysfs port files | ||
260 | * @dev: pointer to belonging device | ||
261 | * | ||
262 | * Create all attributes of the sysfs representation of a port. | ||
263 | */ | ||
264 | int | ||
265 | zfcp_sysfs_port_create_files(struct device *dev, u32 flags) | ||
266 | { | ||
267 | int retval; | ||
268 | |||
269 | retval = sysfs_create_group(&dev->kobj, &zfcp_port_common_attr_group); | ||
270 | |||
271 | if ((flags & ZFCP_STATUS_PORT_WKA) || retval) | ||
272 | return retval; | ||
273 | |||
274 | retval = sysfs_create_group(&dev->kobj, &zfcp_port_no_ns_attr_group); | ||
275 | if (retval) | ||
276 | sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group); | ||
277 | |||
278 | return retval; | ||
279 | } | ||
280 | |||
281 | /** | ||
282 | * zfcp_sysfs_port_remove_files - remove sysfs port files | ||
283 | * @dev: pointer to belonging device | ||
284 | * | ||
285 | * Remove all attributes of the sysfs representation of a port. | ||
286 | */ | ||
287 | void | ||
288 | zfcp_sysfs_port_remove_files(struct device *dev, u32 flags) | ||
289 | { | ||
290 | sysfs_remove_group(&dev->kobj, &zfcp_port_common_attr_group); | ||
291 | if (!(flags & ZFCP_STATUS_PORT_WKA)) | ||
292 | sysfs_remove_group(&dev->kobj, &zfcp_port_no_ns_attr_group); | ||
293 | } | ||
294 | |||
295 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/s390/scsi/zfcp_sysfs_unit.c b/drivers/s390/scsi/zfcp_sysfs_unit.c deleted file mode 100644 index 80fb2c2cf48a..000000000000 --- a/drivers/s390/scsi/zfcp_sysfs_unit.c +++ /dev/null | |||
@@ -1,167 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of the zfcp device driver for | ||
3 | * FCP adapters for IBM System z9 and zSeries. | ||
4 | * | ||
5 | * (C) Copyright IBM Corp. 2002, 2006 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include "zfcp_ext.h" | ||
23 | |||
24 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG | ||
25 | |||
26 | /** | ||
27 | * zfcp_sysfs_unit_release - gets called when a struct device unit is released | ||
28 | * @dev: pointer to belonging device | ||
29 | */ | ||
30 | void | ||
31 | zfcp_sysfs_unit_release(struct device *dev) | ||
32 | { | ||
33 | kfree(dev); | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * ZFCP_DEFINE_UNIT_ATTR | ||
38 | * @_name: name of show attribute | ||
39 | * @_format: format string | ||
40 | * @_value: value to print | ||
41 | * | ||
42 | * Generates attribute for a unit. | ||
43 | */ | ||
44 | #define ZFCP_DEFINE_UNIT_ATTR(_name, _format, _value) \ | ||
45 | static ssize_t zfcp_sysfs_unit_##_name##_show(struct device *dev, struct device_attribute *attr, \ | ||
46 | char *buf) \ | ||
47 | { \ | ||
48 | struct zfcp_unit *unit; \ | ||
49 | \ | ||
50 | unit = dev_get_drvdata(dev); \ | ||
51 | return sprintf(buf, _format, _value); \ | ||
52 | } \ | ||
53 | \ | ||
54 | static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_unit_##_name##_show, NULL); | ||
55 | |||
56 | ZFCP_DEFINE_UNIT_ATTR(status, "0x%08x\n", atomic_read(&unit->status)); | ||
57 | ZFCP_DEFINE_UNIT_ATTR(in_recovery, "%d\n", atomic_test_mask | ||
58 | (ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)); | ||
59 | ZFCP_DEFINE_UNIT_ATTR(access_denied, "%d\n", atomic_test_mask | ||
60 | (ZFCP_STATUS_COMMON_ACCESS_DENIED, &unit->status)); | ||
61 | ZFCP_DEFINE_UNIT_ATTR(access_shared, "%d\n", atomic_test_mask | ||
62 | (ZFCP_STATUS_UNIT_SHARED, &unit->status)); | ||
63 | ZFCP_DEFINE_UNIT_ATTR(access_readonly, "%d\n", atomic_test_mask | ||
64 | (ZFCP_STATUS_UNIT_READONLY, &unit->status)); | ||
65 | |||
66 | /** | ||
67 | * zfcp_sysfs_unit_failed_store - failed state of unit | ||
68 | * @dev: pointer to belonging device | ||
69 | * @buf: pointer to input buffer | ||
70 | * @count: number of bytes in buffer | ||
71 | * | ||
72 | * Store function of the "failed" attribute of a unit. | ||
73 | * If a "0" gets written to "failed", error recovery will be | ||
74 | * started for the belonging unit. | ||
75 | */ | ||
76 | static ssize_t | ||
77 | zfcp_sysfs_unit_failed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
78 | { | ||
79 | struct zfcp_unit *unit; | ||
80 | unsigned int val; | ||
81 | char *endp; | ||
82 | int retval = 0; | ||
83 | |||
84 | down(&zfcp_data.config_sema); | ||
85 | unit = dev_get_drvdata(dev); | ||
86 | if (atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status)) { | ||
87 | retval = -EBUSY; | ||
88 | goto out; | ||
89 | } | ||
90 | |||
91 | val = simple_strtoul(buf, &endp, 0); | ||
92 | if (((endp + 1) < (buf + count)) || (val != 0)) { | ||
93 | retval = -EINVAL; | ||
94 | goto out; | ||
95 | } | ||
96 | |||
97 | zfcp_erp_modify_unit_status(unit, 46, NULL, | ||
98 | ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); | ||
99 | zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, 97, NULL); | ||
100 | zfcp_erp_wait(unit->port->adapter); | ||
101 | out: | ||
102 | up(&zfcp_data.config_sema); | ||
103 | return retval ? retval : (ssize_t) count; | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * zfcp_sysfs_unit_failed_show - failed state of unit | ||
108 | * @dev: pointer to belonging device | ||
109 | * @buf: pointer to input buffer | ||
110 | * | ||
111 | * Show function of "failed" attribute of unit. Will be | ||
112 | * "0" if unit is working, otherwise "1". | ||
113 | */ | ||
114 | static ssize_t | ||
115 | zfcp_sysfs_unit_failed_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
116 | { | ||
117 | struct zfcp_unit *unit; | ||
118 | |||
119 | unit = dev_get_drvdata(dev); | ||
120 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) | ||
121 | return sprintf(buf, "1\n"); | ||
122 | else | ||
123 | return sprintf(buf, "0\n"); | ||
124 | } | ||
125 | |||
126 | static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_unit_failed_show, | ||
127 | zfcp_sysfs_unit_failed_store); | ||
128 | |||
129 | static struct attribute *zfcp_unit_attrs[] = { | ||
130 | &dev_attr_failed.attr, | ||
131 | &dev_attr_in_recovery.attr, | ||
132 | &dev_attr_status.attr, | ||
133 | &dev_attr_access_denied.attr, | ||
134 | &dev_attr_access_shared.attr, | ||
135 | &dev_attr_access_readonly.attr, | ||
136 | NULL | ||
137 | }; | ||
138 | |||
139 | static struct attribute_group zfcp_unit_attr_group = { | ||
140 | .attrs = zfcp_unit_attrs, | ||
141 | }; | ||
142 | |||
143 | /** | ||
144 | * zfcp_sysfs_create_unit_files - create sysfs unit files | ||
145 | * @dev: pointer to belonging device | ||
146 | * | ||
147 | * Create all attributes of the sysfs representation of a unit. | ||
148 | */ | ||
149 | int | ||
150 | zfcp_sysfs_unit_create_files(struct device *dev) | ||
151 | { | ||
152 | return sysfs_create_group(&dev->kobj, &zfcp_unit_attr_group); | ||
153 | } | ||
154 | |||
155 | /** | ||
156 | * zfcp_sysfs_remove_unit_files - remove sysfs unit files | ||
157 | * @dev: pointer to belonging device | ||
158 | * | ||
159 | * Remove all attributes of the sysfs representation of a unit. | ||
160 | */ | ||
161 | void | ||
162 | zfcp_sysfs_unit_remove_files(struct device *dev) | ||
163 | { | ||
164 | sysfs_remove_group(&dev->kobj, &zfcp_unit_attr_group); | ||
165 | } | ||
166 | |||
167 | #undef ZFCP_LOG_AREA | ||
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 81ccbd7f9e34..26be540d1dd3 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig | |||
@@ -888,6 +888,25 @@ config SCSI_IBMVSCSIS | |||
888 | To compile this driver as a module, choose M here: the | 888 | To compile this driver as a module, choose M here: the |
889 | module will be called ibmvstgt. | 889 | module will be called ibmvstgt. |
890 | 890 | ||
891 | config SCSI_IBMVFC | ||
892 | tristate "IBM Virtual FC support" | ||
893 | depends on PPC_PSERIES && SCSI | ||
894 | select SCSI_FC_ATTRS | ||
895 | help | ||
896 | This is the IBM POWER Virtual FC Client | ||
897 | |||
898 | To compile this driver as a module, choose M here: the | ||
899 | module will be called ibmvfc. | ||
900 | |||
901 | config SCSI_IBMVFC_TRACE | ||
902 | bool "enable driver internal trace" | ||
903 | depends on SCSI_IBMVFC | ||
904 | default y | ||
905 | help | ||
906 | If you say Y here, the driver will trace all commands issued | ||
907 | to the adapter. Performance impact is minimal. Trace can be | ||
908 | dumped using /sys/class/scsi_host/hostXX/trace. | ||
909 | |||
891 | config SCSI_INITIO | 910 | config SCSI_INITIO |
892 | tristate "Initio 9100U(W) support" | 911 | tristate "Initio 9100U(W) support" |
893 | depends on PCI && SCSI | 912 | depends on PCI && SCSI |
@@ -1738,10 +1757,12 @@ config SCSI_SUNESP | |||
1738 | select SCSI_SPI_ATTRS | 1757 | select SCSI_SPI_ATTRS |
1739 | help | 1758 | help |
1740 | This is the driver for the Sun ESP SCSI host adapter. The ESP | 1759 | This is the driver for the Sun ESP SCSI host adapter. The ESP |
1741 | chipset is present in most SPARC SBUS-based computers. | 1760 | chipset is present in most SPARC SBUS-based computers and |
1761 | supports the Emulex family of ESP SCSI chips (esp100, esp100A, | ||
1762 | esp236, fas101, fas236) as well as the Qlogic fas366 SCSI chip. | ||
1742 | 1763 | ||
1743 | To compile this driver as a module, choose M here: the | 1764 | To compile this driver as a module, choose M here: the |
1744 | module will be called esp. | 1765 | module will be called sun_esp. |
1745 | 1766 | ||
1746 | config ZFCP | 1767 | config ZFCP |
1747 | tristate "FCP host bus adapter driver for IBM eServer zSeries" | 1768 | tristate "FCP host bus adapter driver for IBM eServer zSeries" |
@@ -1771,4 +1792,6 @@ endif # SCSI_LOWLEVEL | |||
1771 | 1792 | ||
1772 | source "drivers/scsi/pcmcia/Kconfig" | 1793 | source "drivers/scsi/pcmcia/Kconfig" |
1773 | 1794 | ||
1795 | source "drivers/scsi/device_handler/Kconfig" | ||
1796 | |||
1774 | endmenu | 1797 | endmenu |
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 6c775e350c98..a8149677de23 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile | |||
@@ -34,6 +34,7 @@ obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o | |||
34 | obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o | 34 | obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o |
35 | obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/ | 35 | obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/ |
36 | obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o | 36 | obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o |
37 | obj-$(CONFIG_SCSI_DH) += device_handler/ | ||
37 | 38 | ||
38 | obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o | 39 | obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o |
39 | obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o | 40 | obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o |
@@ -118,6 +119,7 @@ obj-$(CONFIG_SCSI_IPR) += ipr.o | |||
118 | obj-$(CONFIG_SCSI_SRP) += libsrp.o | 119 | obj-$(CONFIG_SCSI_SRP) += libsrp.o |
119 | obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/ | 120 | obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/ |
120 | obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/ | 121 | obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/ |
122 | obj-$(CONFIG_SCSI_IBMVFC) += ibmvscsi/ | ||
121 | obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o | 123 | obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o |
122 | obj-$(CONFIG_SCSI_STEX) += stex.o | 124 | obj-$(CONFIG_SCSI_STEX) += stex.o |
123 | obj-$(CONFIG_SCSI_MVSAS) += mvsas.o | 125 | obj-$(CONFIG_SCSI_MVSAS) += mvsas.o |
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 5fd83deab36c..a7355260cfcf 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/kthread.h> | 41 | #include <linux/kthread.h> |
42 | #include <linux/semaphore.h> | 42 | #include <linux/semaphore.h> |
43 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
44 | #include <scsi/scsi_host.h> | ||
44 | 45 | ||
45 | #include "aacraid.h" | 46 | #include "aacraid.h" |
46 | 47 | ||
@@ -581,6 +582,14 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | |||
581 | for (i = 0; i < upsg->count; i++) { | 582 | for (i = 0; i < upsg->count; i++) { |
582 | u64 addr; | 583 | u64 addr; |
583 | void* p; | 584 | void* p; |
585 | if (upsg->sg[i].count > | ||
586 | (dev->adapter_info.options & | ||
587 | AAC_OPT_NEW_COMM) ? | ||
588 | (dev->scsi_host_ptr->max_sectors << 9) : | ||
589 | 65536) { | ||
590 | rcode = -EINVAL; | ||
591 | goto cleanup; | ||
592 | } | ||
584 | /* Does this really need to be GFP_DMA? */ | 593 | /* Does this really need to be GFP_DMA? */ |
585 | p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA); | 594 | p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA); |
586 | if(!p) { | 595 | if(!p) { |
@@ -625,6 +634,14 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | |||
625 | for (i = 0; i < usg->count; i++) { | 634 | for (i = 0; i < usg->count; i++) { |
626 | u64 addr; | 635 | u64 addr; |
627 | void* p; | 636 | void* p; |
637 | if (usg->sg[i].count > | ||
638 | (dev->adapter_info.options & | ||
639 | AAC_OPT_NEW_COMM) ? | ||
640 | (dev->scsi_host_ptr->max_sectors << 9) : | ||
641 | 65536) { | ||
642 | rcode = -EINVAL; | ||
643 | goto cleanup; | ||
644 | } | ||
628 | /* Does this really need to be GFP_DMA? */ | 645 | /* Does this really need to be GFP_DMA? */ |
629 | p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); | 646 | p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); |
630 | if(!p) { | 647 | if(!p) { |
@@ -667,6 +684,14 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | |||
667 | for (i = 0; i < upsg->count; i++) { | 684 | for (i = 0; i < upsg->count; i++) { |
668 | uintptr_t addr; | 685 | uintptr_t addr; |
669 | void* p; | 686 | void* p; |
687 | if (usg->sg[i].count > | ||
688 | (dev->adapter_info.options & | ||
689 | AAC_OPT_NEW_COMM) ? | ||
690 | (dev->scsi_host_ptr->max_sectors << 9) : | ||
691 | 65536) { | ||
692 | rcode = -EINVAL; | ||
693 | goto cleanup; | ||
694 | } | ||
670 | /* Does this really need to be GFP_DMA? */ | 695 | /* Does this really need to be GFP_DMA? */ |
671 | p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); | 696 | p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); |
672 | if(!p) { | 697 | if(!p) { |
@@ -698,6 +723,14 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | |||
698 | for (i = 0; i < upsg->count; i++) { | 723 | for (i = 0; i < upsg->count; i++) { |
699 | dma_addr_t addr; | 724 | dma_addr_t addr; |
700 | void* p; | 725 | void* p; |
726 | if (upsg->sg[i].count > | ||
727 | (dev->adapter_info.options & | ||
728 | AAC_OPT_NEW_COMM) ? | ||
729 | (dev->scsi_host_ptr->max_sectors << 9) : | ||
730 | 65536) { | ||
731 | rcode = -EINVAL; | ||
732 | goto cleanup; | ||
733 | } | ||
701 | p = kmalloc(upsg->sg[i].count, GFP_KERNEL); | 734 | p = kmalloc(upsg->sg[i].count, GFP_KERNEL); |
702 | if (!p) { | 735 | if (!p) { |
703 | dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", | 736 | dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", |
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 68c140e82673..9aa301c1ed07 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c | |||
@@ -865,7 +865,7 @@ static ssize_t aac_show_bios_version(struct device *device, | |||
865 | return len; | 865 | return len; |
866 | } | 866 | } |
867 | 867 | ||
868 | ssize_t aac_show_serial_number(struct device *device, | 868 | static ssize_t aac_show_serial_number(struct device *device, |
869 | struct device_attribute *attr, char *buf) | 869 | struct device_attribute *attr, char *buf) |
870 | { | 870 | { |
871 | struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata; | 871 | struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata; |
diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig new file mode 100644 index 000000000000..2adc0f666b68 --- /dev/null +++ b/drivers/scsi/device_handler/Kconfig | |||
@@ -0,0 +1,32 @@ | |||
1 | # | ||
2 | # SCSI Device Handler configuration | ||
3 | # | ||
4 | |||
5 | menuconfig SCSI_DH | ||
6 | tristate "SCSI Device Handlers" | ||
7 | depends on SCSI | ||
8 | default n | ||
9 | help | ||
10 | SCSI Device Handlers provide device specific support for | ||
11 | devices utilized in multipath configurations. Say Y here to | ||
12 | select support for specific hardware. | ||
13 | |||
14 | config SCSI_DH_RDAC | ||
15 | tristate "LSI RDAC Device Handler" | ||
16 | depends on SCSI_DH | ||
17 | help | ||
18 | If you have a LSI RDAC select y. Otherwise, say N. | ||
19 | |||
20 | config SCSI_DH_HP_SW | ||
21 | tristate "HP/COMPAQ MSA Device Handler" | ||
22 | depends on SCSI_DH | ||
23 | help | ||
24 | If you have a HP/COMPAQ MSA device that requires START_STOP to | ||
25 | be sent to start it and cannot upgrade the firmware then select y. | ||
26 | Otherwise, say N. | ||
27 | |||
28 | config SCSI_DH_EMC | ||
29 | tristate "EMC CLARiiON Device Handler" | ||
30 | depends on SCSI_DH | ||
31 | help | ||
32 | If you have a EMC CLARiiON select y. Otherwise, say N. | ||
diff --git a/drivers/scsi/device_handler/Makefile b/drivers/scsi/device_handler/Makefile new file mode 100644 index 000000000000..35272e93b1c8 --- /dev/null +++ b/drivers/scsi/device_handler/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # SCSI Device Handler | ||
3 | # | ||
4 | obj-$(CONFIG_SCSI_DH) += scsi_dh.o | ||
5 | obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o | ||
6 | obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o | ||
7 | obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o | ||
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c new file mode 100644 index 000000000000..ab6c21cd9689 --- /dev/null +++ b/drivers/scsi/device_handler/scsi_dh.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * SCSI device handler infrastruture. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along | ||
15 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | * | ||
18 | * Copyright IBM Corporation, 2007 | ||
19 | * Authors: | ||
20 | * Chandra Seetharaman <sekharan@us.ibm.com> | ||
21 | * Mike Anderson <andmike@linux.vnet.ibm.com> | ||
22 | */ | ||
23 | |||
24 | #include <scsi/scsi_dh.h> | ||
25 | #include "../scsi_priv.h" | ||
26 | |||
27 | static DEFINE_SPINLOCK(list_lock); | ||
28 | static LIST_HEAD(scsi_dh_list); | ||
29 | |||
30 | static struct scsi_device_handler *get_device_handler(const char *name) | ||
31 | { | ||
32 | struct scsi_device_handler *tmp, *found = NULL; | ||
33 | |||
34 | spin_lock(&list_lock); | ||
35 | list_for_each_entry(tmp, &scsi_dh_list, list) { | ||
36 | if (!strcmp(tmp->name, name)) { | ||
37 | found = tmp; | ||
38 | break; | ||
39 | } | ||
40 | } | ||
41 | spin_unlock(&list_lock); | ||
42 | return found; | ||
43 | } | ||
44 | |||
45 | static int scsi_dh_notifier_add(struct device *dev, void *data) | ||
46 | { | ||
47 | struct scsi_device_handler *scsi_dh = data; | ||
48 | |||
49 | scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_ADD_DEVICE, dev); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * scsi_register_device_handler - register a device handler personality | ||
55 | * module. | ||
56 | * @scsi_dh - device handler to be registered. | ||
57 | * | ||
58 | * Returns 0 on success, -EBUSY if handler already registered. | ||
59 | */ | ||
60 | int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) | ||
61 | { | ||
62 | int ret = -EBUSY; | ||
63 | struct scsi_device_handler *tmp; | ||
64 | |||
65 | tmp = get_device_handler(scsi_dh->name); | ||
66 | if (tmp) | ||
67 | goto done; | ||
68 | |||
69 | ret = bus_register_notifier(&scsi_bus_type, &scsi_dh->nb); | ||
70 | |||
71 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add); | ||
72 | spin_lock(&list_lock); | ||
73 | list_add(&scsi_dh->list, &scsi_dh_list); | ||
74 | spin_unlock(&list_lock); | ||
75 | |||
76 | done: | ||
77 | return ret; | ||
78 | } | ||
79 | EXPORT_SYMBOL_GPL(scsi_register_device_handler); | ||
80 | |||
81 | static int scsi_dh_notifier_remove(struct device *dev, void *data) | ||
82 | { | ||
83 | struct scsi_device_handler *scsi_dh = data; | ||
84 | |||
85 | scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_DEL_DEVICE, dev); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * scsi_unregister_device_handler - register a device handler personality | ||
91 | * module. | ||
92 | * @scsi_dh - device handler to be unregistered. | ||
93 | * | ||
94 | * Returns 0 on success, -ENODEV if handler not registered. | ||
95 | */ | ||
96 | int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) | ||
97 | { | ||
98 | int ret = -ENODEV; | ||
99 | struct scsi_device_handler *tmp; | ||
100 | |||
101 | tmp = get_device_handler(scsi_dh->name); | ||
102 | if (!tmp) | ||
103 | goto done; | ||
104 | |||
105 | ret = bus_unregister_notifier(&scsi_bus_type, &scsi_dh->nb); | ||
106 | |||
107 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, | ||
108 | scsi_dh_notifier_remove); | ||
109 | spin_lock(&list_lock); | ||
110 | list_del(&scsi_dh->list); | ||
111 | spin_unlock(&list_lock); | ||
112 | |||
113 | done: | ||
114 | return ret; | ||
115 | } | ||
116 | EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); | ||
117 | |||
118 | /* | ||
119 | * scsi_dh_activate - activate the path associated with the scsi_device | ||
120 | * corresponding to the given request queue. | ||
121 | * @q - Request queue that is associated with the scsi_device to be | ||
122 | * activated. | ||
123 | */ | ||
124 | int scsi_dh_activate(struct request_queue *q) | ||
125 | { | ||
126 | int err = 0; | ||
127 | unsigned long flags; | ||
128 | struct scsi_device *sdev; | ||
129 | struct scsi_device_handler *scsi_dh = NULL; | ||
130 | |||
131 | spin_lock_irqsave(q->queue_lock, flags); | ||
132 | sdev = q->queuedata; | ||
133 | if (sdev && sdev->scsi_dh_data) | ||
134 | scsi_dh = sdev->scsi_dh_data->scsi_dh; | ||
135 | if (!scsi_dh || !get_device(&sdev->sdev_gendev)) | ||
136 | err = SCSI_DH_NOSYS; | ||
137 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
138 | |||
139 | if (err) | ||
140 | return err; | ||
141 | |||
142 | if (scsi_dh->activate) | ||
143 | err = scsi_dh->activate(sdev); | ||
144 | put_device(&sdev->sdev_gendev); | ||
145 | return err; | ||
146 | } | ||
147 | EXPORT_SYMBOL_GPL(scsi_dh_activate); | ||
148 | |||
149 | /* | ||
150 | * scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for | ||
151 | * the given name. FALSE(0) otherwise. | ||
152 | * @name - name of the device handler. | ||
153 | */ | ||
154 | int scsi_dh_handler_exist(const char *name) | ||
155 | { | ||
156 | return (get_device_handler(name) != NULL); | ||
157 | } | ||
158 | EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); | ||
159 | |||
160 | MODULE_DESCRIPTION("SCSI device handler"); | ||
161 | MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>"); | ||
162 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c new file mode 100644 index 000000000000..ed53f14007a2 --- /dev/null +++ b/drivers/scsi/device_handler/scsi_dh_emc.c | |||
@@ -0,0 +1,499 @@ | |||
1 | /* | ||
2 | * Target driver for EMC CLARiiON AX/CX-series hardware. | ||
3 | * Based on code from Lars Marowsky-Bree <lmb@suse.de> | ||
4 | * and Ed Goggin <egoggin@emc.com>. | ||
5 | * | ||
6 | * Copyright (C) 2006 Red Hat, Inc. All rights reserved. | ||
7 | * Copyright (C) 2006 Mike Christie | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2, or (at your option) | ||
12 | * any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; see the file COPYING. If not, write to | ||
21 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | #include <scsi/scsi.h> | ||
24 | #include <scsi/scsi_eh.h> | ||
25 | #include <scsi/scsi_dh.h> | ||
26 | #include <scsi/scsi_device.h> | ||
27 | |||
28 | #define CLARIION_NAME "emc_clariion" | ||
29 | |||
30 | #define CLARIION_TRESPASS_PAGE 0x22 | ||
31 | #define CLARIION_BUFFER_SIZE 0x80 | ||
32 | #define CLARIION_TIMEOUT (60 * HZ) | ||
33 | #define CLARIION_RETRIES 3 | ||
34 | #define CLARIION_UNBOUND_LU -1 | ||
35 | |||
36 | static unsigned char long_trespass[] = { | ||
37 | 0, 0, 0, 0, | ||
38 | CLARIION_TRESPASS_PAGE, /* Page code */ | ||
39 | 0x09, /* Page length - 2 */ | ||
40 | 0x81, /* Trespass code + Honor reservation bit */ | ||
41 | 0xff, 0xff, /* Trespass target */ | ||
42 | 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ | ||
43 | }; | ||
44 | |||
45 | static unsigned char long_trespass_hr[] = { | ||
46 | 0, 0, 0, 0, | ||
47 | CLARIION_TRESPASS_PAGE, /* Page code */ | ||
48 | 0x09, /* Page length - 2 */ | ||
49 | 0x01, /* Trespass code + Honor reservation bit */ | ||
50 | 0xff, 0xff, /* Trespass target */ | ||
51 | 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ | ||
52 | }; | ||
53 | |||
54 | static unsigned char short_trespass[] = { | ||
55 | 0, 0, 0, 0, | ||
56 | CLARIION_TRESPASS_PAGE, /* Page code */ | ||
57 | 0x02, /* Page length - 2 */ | ||
58 | 0x81, /* Trespass code + Honor reservation bit */ | ||
59 | 0xff, /* Trespass target */ | ||
60 | }; | ||
61 | |||
62 | static unsigned char short_trespass_hr[] = { | ||
63 | 0, 0, 0, 0, | ||
64 | CLARIION_TRESPASS_PAGE, /* Page code */ | ||
65 | 0x02, /* Page length - 2 */ | ||
66 | 0x01, /* Trespass code + Honor reservation bit */ | ||
67 | 0xff, /* Trespass target */ | ||
68 | }; | ||
69 | |||
70 | struct clariion_dh_data { | ||
71 | /* | ||
72 | * Use short trespass command (FC-series) or the long version | ||
73 | * (default for AX/CX CLARiiON arrays). | ||
74 | */ | ||
75 | unsigned short_trespass; | ||
76 | /* | ||
77 | * Whether or not (default) to honor SCSI reservations when | ||
78 | * initiating a switch-over. | ||
79 | */ | ||
80 | unsigned hr; | ||
81 | /* I/O buffer for both MODE_SELECT and INQUIRY commands. */ | ||
82 | char buffer[CLARIION_BUFFER_SIZE]; | ||
83 | /* | ||
84 | * SCSI sense buffer for commands -- assumes serial issuance | ||
85 | * and completion sequence of all commands for same multipath. | ||
86 | */ | ||
87 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
88 | /* which SP (A=0,B=1,UNBOUND=-1) is dflt SP for path's mapped dev */ | ||
89 | int default_sp; | ||
90 | /* which SP (A=0,B=1,UNBOUND=-1) is active for path's mapped dev */ | ||
91 | int current_sp; | ||
92 | }; | ||
93 | |||
94 | static inline struct clariion_dh_data | ||
95 | *get_clariion_data(struct scsi_device *sdev) | ||
96 | { | ||
97 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; | ||
98 | BUG_ON(scsi_dh_data == NULL); | ||
99 | return ((struct clariion_dh_data *) scsi_dh_data->buf); | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * Parse MODE_SELECT cmd reply. | ||
104 | */ | ||
105 | static int trespass_endio(struct scsi_device *sdev, int result) | ||
106 | { | ||
107 | int err = SCSI_DH_OK; | ||
108 | struct scsi_sense_hdr sshdr; | ||
109 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | ||
110 | char *sense = csdev->sense; | ||
111 | |||
112 | if (status_byte(result) == CHECK_CONDITION && | ||
113 | scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { | ||
114 | sdev_printk(KERN_ERR, sdev, "Found valid sense data 0x%2x, " | ||
115 | "0x%2x, 0x%2x while sending CLARiiON trespass " | ||
116 | "command.\n", sshdr.sense_key, sshdr.asc, | ||
117 | sshdr.ascq); | ||
118 | |||
119 | if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) && | ||
120 | (sshdr.ascq == 0x00)) { | ||
121 | /* | ||
122 | * Array based copy in progress -- do not send | ||
123 | * mode_select or copy will be aborted mid-stream. | ||
124 | */ | ||
125 | sdev_printk(KERN_INFO, sdev, "Array Based Copy in " | ||
126 | "progress while sending CLARiiON trespass " | ||
127 | "command.\n"); | ||
128 | err = SCSI_DH_DEV_TEMP_BUSY; | ||
129 | } else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) && | ||
130 | (sshdr.ascq == 0x03)) { | ||
131 | /* | ||
132 | * LUN Not Ready - Manual Intervention Required | ||
133 | * indicates in-progress ucode upgrade (NDU). | ||
134 | */ | ||
135 | sdev_printk(KERN_INFO, sdev, "Detected in-progress " | ||
136 | "ucode upgrade NDU operation while sending " | ||
137 | "CLARiiON trespass command.\n"); | ||
138 | err = SCSI_DH_DEV_TEMP_BUSY; | ||
139 | } else | ||
140 | err = SCSI_DH_DEV_FAILED; | ||
141 | } else if (result) { | ||
142 | sdev_printk(KERN_ERR, sdev, "Error 0x%x while sending " | ||
143 | "CLARiiON trespass command.\n", result); | ||
144 | err = SCSI_DH_IO; | ||
145 | } | ||
146 | |||
147 | return err; | ||
148 | } | ||
149 | |||
150 | static int parse_sp_info_reply(struct scsi_device *sdev, int result, | ||
151 | int *default_sp, int *current_sp, int *new_current_sp) | ||
152 | { | ||
153 | int err = SCSI_DH_OK; | ||
154 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | ||
155 | |||
156 | if (result == 0) { | ||
157 | /* check for in-progress ucode upgrade (NDU) */ | ||
158 | if (csdev->buffer[48] != 0) { | ||
159 | sdev_printk(KERN_NOTICE, sdev, "Detected in-progress " | ||
160 | "ucode upgrade NDU operation while finding " | ||
161 | "current active SP."); | ||
162 | err = SCSI_DH_DEV_TEMP_BUSY; | ||
163 | } else { | ||
164 | *default_sp = csdev->buffer[5]; | ||
165 | |||
166 | if (csdev->buffer[4] == 2) | ||
167 | /* SP for path is current */ | ||
168 | *current_sp = csdev->buffer[8]; | ||
169 | else { | ||
170 | if (csdev->buffer[4] == 1) | ||
171 | /* SP for this path is NOT current */ | ||
172 | if (csdev->buffer[8] == 0) | ||
173 | *current_sp = 1; | ||
174 | else | ||
175 | *current_sp = 0; | ||
176 | else | ||
177 | /* unbound LU or LUNZ */ | ||
178 | *current_sp = CLARIION_UNBOUND_LU; | ||
179 | } | ||
180 | *new_current_sp = csdev->buffer[8]; | ||
181 | } | ||
182 | } else { | ||
183 | struct scsi_sense_hdr sshdr; | ||
184 | |||
185 | err = SCSI_DH_IO; | ||
186 | |||
187 | if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, | ||
188 | &sshdr)) | ||
189 | sdev_printk(KERN_ERR, sdev, "Found valid sense data " | ||
190 | "0x%2x, 0x%2x, 0x%2x while finding current " | ||
191 | "active SP.", sshdr.sense_key, sshdr.asc, | ||
192 | sshdr.ascq); | ||
193 | else | ||
194 | sdev_printk(KERN_ERR, sdev, "Error 0x%x finding " | ||
195 | "current active SP.", result); | ||
196 | } | ||
197 | |||
198 | return err; | ||
199 | } | ||
200 | |||
201 | static int sp_info_endio(struct scsi_device *sdev, int result, | ||
202 | int mode_select_sent, int *done) | ||
203 | { | ||
204 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | ||
205 | int err_flags, default_sp, current_sp, new_current_sp; | ||
206 | |||
207 | err_flags = parse_sp_info_reply(sdev, result, &default_sp, | ||
208 | ¤t_sp, &new_current_sp); | ||
209 | |||
210 | if (err_flags != SCSI_DH_OK) | ||
211 | goto done; | ||
212 | |||
213 | if (mode_select_sent) { | ||
214 | csdev->default_sp = default_sp; | ||
215 | csdev->current_sp = current_sp; | ||
216 | } else { | ||
217 | /* | ||
218 | * Issue the actual module_selec request IFF either | ||
219 | * (1) we do not know the identity of the current SP OR | ||
220 | * (2) what we think we know is actually correct. | ||
221 | */ | ||
222 | if ((current_sp != CLARIION_UNBOUND_LU) && | ||
223 | (new_current_sp != current_sp)) { | ||
224 | |||
225 | csdev->default_sp = default_sp; | ||
226 | csdev->current_sp = current_sp; | ||
227 | |||
228 | sdev_printk(KERN_INFO, sdev, "Ignoring path group " | ||
229 | "switch-over command for CLARiiON SP%s since " | ||
230 | " mapped device is already initialized.", | ||
231 | current_sp ? "B" : "A"); | ||
232 | if (done) | ||
233 | *done = 1; /* as good as doing it */ | ||
234 | } | ||
235 | } | ||
236 | done: | ||
237 | return err_flags; | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * Get block request for REQ_BLOCK_PC command issued to path. Currently | ||
242 | * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands. | ||
243 | * | ||
244 | * Uses data and sense buffers in hardware handler context structure and | ||
245 | * assumes serial servicing of commands, both issuance and completion. | ||
246 | */ | ||
247 | static struct request *get_req(struct scsi_device *sdev, int cmd) | ||
248 | { | ||
249 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | ||
250 | struct request *rq; | ||
251 | unsigned char *page22; | ||
252 | int len = 0; | ||
253 | |||
254 | rq = blk_get_request(sdev->request_queue, | ||
255 | (cmd == MODE_SELECT) ? WRITE : READ, GFP_ATOMIC); | ||
256 | if (!rq) { | ||
257 | sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); | ||
258 | return NULL; | ||
259 | } | ||
260 | |||
261 | memset(&rq->cmd, 0, BLK_MAX_CDB); | ||
262 | rq->cmd[0] = cmd; | ||
263 | rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); | ||
264 | |||
265 | switch (cmd) { | ||
266 | case MODE_SELECT: | ||
267 | if (csdev->short_trespass) { | ||
268 | page22 = csdev->hr ? short_trespass_hr : short_trespass; | ||
269 | len = sizeof(short_trespass); | ||
270 | } else { | ||
271 | page22 = csdev->hr ? long_trespass_hr : long_trespass; | ||
272 | len = sizeof(long_trespass); | ||
273 | } | ||
274 | /* | ||
275 | * Can't DMA from kernel BSS -- must copy selected trespass | ||
276 | * command mode page contents to context buffer which is | ||
277 | * allocated by kmalloc. | ||
278 | */ | ||
279 | BUG_ON((len > CLARIION_BUFFER_SIZE)); | ||
280 | memcpy(csdev->buffer, page22, len); | ||
281 | rq->cmd_flags |= REQ_RW; | ||
282 | rq->cmd[1] = 0x10; | ||
283 | break; | ||
284 | case INQUIRY: | ||
285 | rq->cmd[1] = 0x1; | ||
286 | rq->cmd[2] = 0xC0; | ||
287 | len = CLARIION_BUFFER_SIZE; | ||
288 | memset(csdev->buffer, 0, CLARIION_BUFFER_SIZE); | ||
289 | break; | ||
290 | default: | ||
291 | BUG_ON(1); | ||
292 | break; | ||
293 | } | ||
294 | |||
295 | rq->cmd[4] = len; | ||
296 | rq->cmd_type = REQ_TYPE_BLOCK_PC; | ||
297 | rq->cmd_flags |= REQ_FAILFAST; | ||
298 | rq->timeout = CLARIION_TIMEOUT; | ||
299 | rq->retries = CLARIION_RETRIES; | ||
300 | |||
301 | rq->sense = csdev->sense; | ||
302 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
303 | rq->sense_len = 0; | ||
304 | |||
305 | if (blk_rq_map_kern(sdev->request_queue, rq, csdev->buffer, | ||
306 | len, GFP_ATOMIC)) { | ||
307 | __blk_put_request(rq->q, rq); | ||
308 | return NULL; | ||
309 | } | ||
310 | |||
311 | return rq; | ||
312 | } | ||
313 | |||
314 | static int send_cmd(struct scsi_device *sdev, int cmd) | ||
315 | { | ||
316 | struct request *rq = get_req(sdev, cmd); | ||
317 | |||
318 | if (!rq) | ||
319 | return SCSI_DH_RES_TEMP_UNAVAIL; | ||
320 | |||
321 | return blk_execute_rq(sdev->request_queue, NULL, rq, 1); | ||
322 | } | ||
323 | |||
324 | static int clariion_activate(struct scsi_device *sdev) | ||
325 | { | ||
326 | int result, done = 0; | ||
327 | |||
328 | result = send_cmd(sdev, INQUIRY); | ||
329 | result = sp_info_endio(sdev, result, 0, &done); | ||
330 | if (result || done) | ||
331 | goto done; | ||
332 | |||
333 | result = send_cmd(sdev, MODE_SELECT); | ||
334 | result = trespass_endio(sdev, result); | ||
335 | if (result) | ||
336 | goto done; | ||
337 | |||
338 | result = send_cmd(sdev, INQUIRY); | ||
339 | result = sp_info_endio(sdev, result, 1, NULL); | ||
340 | done: | ||
341 | return result; | ||
342 | } | ||
343 | |||
344 | static int clariion_check_sense(struct scsi_device *sdev, | ||
345 | struct scsi_sense_hdr *sense_hdr) | ||
346 | { | ||
347 | switch (sense_hdr->sense_key) { | ||
348 | case NOT_READY: | ||
349 | if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x03) | ||
350 | /* | ||
351 | * LUN Not Ready - Manual Intervention Required | ||
352 | * indicates this is a passive path. | ||
353 | * | ||
354 | * FIXME: However, if this is seen and EVPD C0 | ||
355 | * indicates that this is due to a NDU in | ||
356 | * progress, we should set FAIL_PATH too. | ||
357 | * This indicates we might have to do a SCSI | ||
358 | * inquiry in the end_io path. Ugh. | ||
359 | * | ||
360 | * Can return FAILED only when we want the error | ||
361 | * recovery process to kick in. | ||
362 | */ | ||
363 | return SUCCESS; | ||
364 | break; | ||
365 | case ILLEGAL_REQUEST: | ||
366 | if (sense_hdr->asc == 0x25 && sense_hdr->ascq == 0x01) | ||
367 | /* | ||
368 | * An array based copy is in progress. Do not | ||
369 | * fail the path, do not bypass to another PG, | ||
370 | * do not retry. Fail the IO immediately. | ||
371 | * (Actually this is the same conclusion as in | ||
372 | * the default handler, but lets make sure.) | ||
373 | * | ||
374 | * Can return FAILED only when we want the error | ||
375 | * recovery process to kick in. | ||
376 | */ | ||
377 | return SUCCESS; | ||
378 | break; | ||
379 | case UNIT_ATTENTION: | ||
380 | if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) | ||
381 | /* | ||
382 | * Unit Attention Code. This is the first IO | ||
383 | * to the new path, so just retry. | ||
384 | */ | ||
385 | return NEEDS_RETRY; | ||
386 | break; | ||
387 | } | ||
388 | |||
389 | /* success just means we do not care what scsi-ml does */ | ||
390 | return SUCCESS; | ||
391 | } | ||
392 | |||
393 | static const struct { | ||
394 | char *vendor; | ||
395 | char *model; | ||
396 | } clariion_dev_list[] = { | ||
397 | {"DGC", "RAID"}, | ||
398 | {"DGC", "DISK"}, | ||
399 | {NULL, NULL}, | ||
400 | }; | ||
401 | |||
402 | static int clariion_bus_notify(struct notifier_block *, unsigned long, void *); | ||
403 | |||
404 | static struct scsi_device_handler clariion_dh = { | ||
405 | .name = CLARIION_NAME, | ||
406 | .module = THIS_MODULE, | ||
407 | .nb.notifier_call = clariion_bus_notify, | ||
408 | .check_sense = clariion_check_sense, | ||
409 | .activate = clariion_activate, | ||
410 | }; | ||
411 | |||
412 | /* | ||
413 | * TODO: need some interface so we can set trespass values | ||
414 | */ | ||
415 | static int clariion_bus_notify(struct notifier_block *nb, | ||
416 | unsigned long action, void *data) | ||
417 | { | ||
418 | struct device *dev = data; | ||
419 | struct scsi_device *sdev = to_scsi_device(dev); | ||
420 | struct scsi_dh_data *scsi_dh_data; | ||
421 | struct clariion_dh_data *h; | ||
422 | int i, found = 0; | ||
423 | unsigned long flags; | ||
424 | |||
425 | if (action == BUS_NOTIFY_ADD_DEVICE) { | ||
426 | for (i = 0; clariion_dev_list[i].vendor; i++) { | ||
427 | if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor, | ||
428 | strlen(clariion_dev_list[i].vendor)) && | ||
429 | !strncmp(sdev->model, clariion_dev_list[i].model, | ||
430 | strlen(clariion_dev_list[i].model))) { | ||
431 | found = 1; | ||
432 | break; | ||
433 | } | ||
434 | } | ||
435 | if (!found) | ||
436 | goto out; | ||
437 | |||
438 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | ||
439 | + sizeof(*h) , GFP_KERNEL); | ||
440 | if (!scsi_dh_data) { | ||
441 | sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", | ||
442 | CLARIION_NAME); | ||
443 | goto out; | ||
444 | } | ||
445 | |||
446 | scsi_dh_data->scsi_dh = &clariion_dh; | ||
447 | h = (struct clariion_dh_data *) scsi_dh_data->buf; | ||
448 | h->default_sp = CLARIION_UNBOUND_LU; | ||
449 | h->current_sp = CLARIION_UNBOUND_LU; | ||
450 | |||
451 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
452 | sdev->scsi_dh_data = scsi_dh_data; | ||
453 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
454 | |||
455 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME); | ||
456 | try_module_get(THIS_MODULE); | ||
457 | |||
458 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | ||
459 | if (sdev->scsi_dh_data == NULL || | ||
460 | sdev->scsi_dh_data->scsi_dh != &clariion_dh) | ||
461 | goto out; | ||
462 | |||
463 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
464 | scsi_dh_data = sdev->scsi_dh_data; | ||
465 | sdev->scsi_dh_data = NULL; | ||
466 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
467 | |||
468 | sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", | ||
469 | CLARIION_NAME); | ||
470 | |||
471 | kfree(scsi_dh_data); | ||
472 | module_put(THIS_MODULE); | ||
473 | } | ||
474 | |||
475 | out: | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | static int __init clariion_init(void) | ||
480 | { | ||
481 | int r; | ||
482 | |||
483 | r = scsi_register_device_handler(&clariion_dh); | ||
484 | if (r != 0) | ||
485 | printk(KERN_ERR "Failed to register scsi device handler."); | ||
486 | return r; | ||
487 | } | ||
488 | |||
489 | static void __exit clariion_exit(void) | ||
490 | { | ||
491 | scsi_unregister_device_handler(&clariion_dh); | ||
492 | } | ||
493 | |||
494 | module_init(clariion_init); | ||
495 | module_exit(clariion_exit); | ||
496 | |||
497 | MODULE_DESCRIPTION("EMC CX/AX/FC-family driver"); | ||
498 | MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, Chandra Seetharaman <sekharan@us.ibm.com>"); | ||
499 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c new file mode 100644 index 000000000000..12ceab7b3662 --- /dev/null +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * Basic HP/COMPAQ MSA 1000 support. This is only needed if your HW cannot be | ||
3 | * upgraded. | ||
4 | * | ||
5 | * Copyright (C) 2006 Red Hat, Inc. All rights reserved. | ||
6 | * Copyright (C) 2006 Mike Christie | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, write to | ||
20 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <scsi/scsi.h> | ||
24 | #include <scsi/scsi_dbg.h> | ||
25 | #include <scsi/scsi_eh.h> | ||
26 | #include <scsi/scsi_dh.h> | ||
27 | |||
28 | #define HP_SW_NAME "hp_sw" | ||
29 | |||
30 | #define HP_SW_TIMEOUT (60 * HZ) | ||
31 | #define HP_SW_RETRIES 3 | ||
32 | |||
33 | struct hp_sw_dh_data { | ||
34 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
35 | int retries; | ||
36 | }; | ||
37 | |||
38 | static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev) | ||
39 | { | ||
40 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; | ||
41 | BUG_ON(scsi_dh_data == NULL); | ||
42 | return ((struct hp_sw_dh_data *) scsi_dh_data->buf); | ||
43 | } | ||
44 | |||
45 | static int hp_sw_done(struct scsi_device *sdev) | ||
46 | { | ||
47 | struct hp_sw_dh_data *h = get_hp_sw_data(sdev); | ||
48 | struct scsi_sense_hdr sshdr; | ||
49 | int rc; | ||
50 | |||
51 | sdev_printk(KERN_INFO, sdev, "hp_sw_done\n"); | ||
52 | |||
53 | rc = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sshdr); | ||
54 | if (!rc) | ||
55 | goto done; | ||
56 | switch (sshdr.sense_key) { | ||
57 | case NOT_READY: | ||
58 | if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) { | ||
59 | rc = SCSI_DH_RETRY; | ||
60 | h->retries++; | ||
61 | break; | ||
62 | } | ||
63 | /* fall through */ | ||
64 | default: | ||
65 | h->retries++; | ||
66 | rc = SCSI_DH_IMM_RETRY; | ||
67 | } | ||
68 | |||
69 | done: | ||
70 | if (rc == SCSI_DH_OK || rc == SCSI_DH_IO) | ||
71 | h->retries = 0; | ||
72 | else if (h->retries > HP_SW_RETRIES) { | ||
73 | h->retries = 0; | ||
74 | rc = SCSI_DH_IO; | ||
75 | } | ||
76 | return rc; | ||
77 | } | ||
78 | |||
79 | static int hp_sw_activate(struct scsi_device *sdev) | ||
80 | { | ||
81 | struct hp_sw_dh_data *h = get_hp_sw_data(sdev); | ||
82 | struct request *req; | ||
83 | int ret = SCSI_DH_RES_TEMP_UNAVAIL; | ||
84 | |||
85 | req = blk_get_request(sdev->request_queue, WRITE, GFP_ATOMIC); | ||
86 | if (!req) | ||
87 | goto done; | ||
88 | |||
89 | sdev_printk(KERN_INFO, sdev, "sending START_STOP."); | ||
90 | |||
91 | req->cmd_type = REQ_TYPE_BLOCK_PC; | ||
92 | req->cmd_flags |= REQ_FAILFAST; | ||
93 | req->cmd_len = COMMAND_SIZE(START_STOP); | ||
94 | memset(req->cmd, 0, MAX_COMMAND_SIZE); | ||
95 | req->cmd[0] = START_STOP; | ||
96 | req->cmd[4] = 1; /* Start spin cycle */ | ||
97 | req->timeout = HP_SW_TIMEOUT; | ||
98 | req->sense = h->sense; | ||
99 | memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
100 | req->sense_len = 0; | ||
101 | |||
102 | ret = blk_execute_rq(req->q, NULL, req, 1); | ||
103 | if (!ret) /* SUCCESS */ | ||
104 | ret = hp_sw_done(sdev); | ||
105 | else | ||
106 | ret = SCSI_DH_IO; | ||
107 | done: | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | static const struct { | ||
112 | char *vendor; | ||
113 | char *model; | ||
114 | } hp_sw_dh_data_list[] = { | ||
115 | {"COMPAQ", "MSA"}, | ||
116 | {"HP", "HSV"}, | ||
117 | {"DEC", "HSG80"}, | ||
118 | {NULL, NULL}, | ||
119 | }; | ||
120 | |||
121 | static int hp_sw_bus_notify(struct notifier_block *, unsigned long, void *); | ||
122 | |||
123 | static struct scsi_device_handler hp_sw_dh = { | ||
124 | .name = HP_SW_NAME, | ||
125 | .module = THIS_MODULE, | ||
126 | .nb.notifier_call = hp_sw_bus_notify, | ||
127 | .activate = hp_sw_activate, | ||
128 | }; | ||
129 | |||
130 | static int hp_sw_bus_notify(struct notifier_block *nb, | ||
131 | unsigned long action, void *data) | ||
132 | { | ||
133 | struct device *dev = data; | ||
134 | struct scsi_device *sdev = to_scsi_device(dev); | ||
135 | struct scsi_dh_data *scsi_dh_data; | ||
136 | int i, found = 0; | ||
137 | unsigned long flags; | ||
138 | |||
139 | if (action == BUS_NOTIFY_ADD_DEVICE) { | ||
140 | for (i = 0; hp_sw_dh_data_list[i].vendor; i++) { | ||
141 | if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor, | ||
142 | strlen(hp_sw_dh_data_list[i].vendor)) && | ||
143 | !strncmp(sdev->model, hp_sw_dh_data_list[i].model, | ||
144 | strlen(hp_sw_dh_data_list[i].model))) { | ||
145 | found = 1; | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | if (!found) | ||
150 | goto out; | ||
151 | |||
152 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | ||
153 | + sizeof(struct hp_sw_dh_data) , GFP_KERNEL); | ||
154 | if (!scsi_dh_data) { | ||
155 | sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n", | ||
156 | HP_SW_NAME); | ||
157 | goto out; | ||
158 | } | ||
159 | |||
160 | scsi_dh_data->scsi_dh = &hp_sw_dh; | ||
161 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
162 | sdev->scsi_dh_data = scsi_dh_data; | ||
163 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
164 | try_module_get(THIS_MODULE); | ||
165 | |||
166 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME); | ||
167 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | ||
168 | if (sdev->scsi_dh_data == NULL || | ||
169 | sdev->scsi_dh_data->scsi_dh != &hp_sw_dh) | ||
170 | goto out; | ||
171 | |||
172 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
173 | scsi_dh_data = sdev->scsi_dh_data; | ||
174 | sdev->scsi_dh_data = NULL; | ||
175 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
176 | module_put(THIS_MODULE); | ||
177 | |||
178 | sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", HP_SW_NAME); | ||
179 | |||
180 | kfree(scsi_dh_data); | ||
181 | } | ||
182 | |||
183 | out: | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int __init hp_sw_init(void) | ||
188 | { | ||
189 | return scsi_register_device_handler(&hp_sw_dh); | ||
190 | } | ||
191 | |||
192 | static void __exit hp_sw_exit(void) | ||
193 | { | ||
194 | scsi_unregister_device_handler(&hp_sw_dh); | ||
195 | } | ||
196 | |||
197 | module_init(hp_sw_init); | ||
198 | module_exit(hp_sw_exit); | ||
199 | |||
200 | MODULE_DESCRIPTION("HP MSA 1000"); | ||
201 | MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu"); | ||
202 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c new file mode 100644 index 000000000000..6fff077a888d --- /dev/null +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c | |||
@@ -0,0 +1,691 @@ | |||
1 | /* | ||
2 | * Engenio/LSI RDAC SCSI Device Handler | ||
3 | * | ||
4 | * Copyright (C) 2005 Mike Christie. All rights reserved. | ||
5 | * Copyright (C) Chandra Seetharaman, IBM Corp. 2007 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | * | ||
21 | */ | ||
22 | #include <scsi/scsi.h> | ||
23 | #include <scsi/scsi_eh.h> | ||
24 | #include <scsi/scsi_dh.h> | ||
25 | |||
26 | #define RDAC_NAME "rdac" | ||
27 | |||
28 | /* | ||
29 | * LSI mode page stuff | ||
30 | * | ||
31 | * These struct definitions and the forming of the | ||
32 | * mode page were taken from the LSI RDAC 2.4 GPL'd | ||
33 | * driver, and then converted to Linux conventions. | ||
34 | */ | ||
35 | #define RDAC_QUIESCENCE_TIME 20; | ||
36 | /* | ||
37 | * Page Codes | ||
38 | */ | ||
39 | #define RDAC_PAGE_CODE_REDUNDANT_CONTROLLER 0x2c | ||
40 | |||
41 | /* | ||
42 | * Controller modes definitions | ||
43 | */ | ||
44 | #define RDAC_MODE_TRANSFER_SPECIFIED_LUNS 0x02 | ||
45 | |||
46 | /* | ||
47 | * RDAC Options field | ||
48 | */ | ||
49 | #define RDAC_FORCED_QUIESENCE 0x02 | ||
50 | |||
51 | #define RDAC_TIMEOUT (60 * HZ) | ||
52 | #define RDAC_RETRIES 3 | ||
53 | |||
54 | struct rdac_mode_6_hdr { | ||
55 | u8 data_len; | ||
56 | u8 medium_type; | ||
57 | u8 device_params; | ||
58 | u8 block_desc_len; | ||
59 | }; | ||
60 | |||
61 | struct rdac_mode_10_hdr { | ||
62 | u16 data_len; | ||
63 | u8 medium_type; | ||
64 | u8 device_params; | ||
65 | u16 reserved; | ||
66 | u16 block_desc_len; | ||
67 | }; | ||
68 | |||
69 | struct rdac_mode_common { | ||
70 | u8 controller_serial[16]; | ||
71 | u8 alt_controller_serial[16]; | ||
72 | u8 rdac_mode[2]; | ||
73 | u8 alt_rdac_mode[2]; | ||
74 | u8 quiescence_timeout; | ||
75 | u8 rdac_options; | ||
76 | }; | ||
77 | |||
78 | struct rdac_pg_legacy { | ||
79 | struct rdac_mode_6_hdr hdr; | ||
80 | u8 page_code; | ||
81 | u8 page_len; | ||
82 | struct rdac_mode_common common; | ||
83 | #define MODE6_MAX_LUN 32 | ||
84 | u8 lun_table[MODE6_MAX_LUN]; | ||
85 | u8 reserved2[32]; | ||
86 | u8 reserved3; | ||
87 | u8 reserved4; | ||
88 | }; | ||
89 | |||
90 | struct rdac_pg_expanded { | ||
91 | struct rdac_mode_10_hdr hdr; | ||
92 | u8 page_code; | ||
93 | u8 subpage_code; | ||
94 | u8 page_len[2]; | ||
95 | struct rdac_mode_common common; | ||
96 | u8 lun_table[256]; | ||
97 | u8 reserved3; | ||
98 | u8 reserved4; | ||
99 | }; | ||
100 | |||
101 | struct c9_inquiry { | ||
102 | u8 peripheral_info; | ||
103 | u8 page_code; /* 0xC9 */ | ||
104 | u8 reserved1; | ||
105 | u8 page_len; | ||
106 | u8 page_id[4]; /* "vace" */ | ||
107 | u8 avte_cvp; | ||
108 | u8 path_prio; | ||
109 | u8 reserved2[38]; | ||
110 | }; | ||
111 | |||
112 | #define SUBSYS_ID_LEN 16 | ||
113 | #define SLOT_ID_LEN 2 | ||
114 | |||
115 | struct c4_inquiry { | ||
116 | u8 peripheral_info; | ||
117 | u8 page_code; /* 0xC4 */ | ||
118 | u8 reserved1; | ||
119 | u8 page_len; | ||
120 | u8 page_id[4]; /* "subs" */ | ||
121 | u8 subsys_id[SUBSYS_ID_LEN]; | ||
122 | u8 revision[4]; | ||
123 | u8 slot_id[SLOT_ID_LEN]; | ||
124 | u8 reserved[2]; | ||
125 | }; | ||
126 | |||
127 | struct rdac_controller { | ||
128 | u8 subsys_id[SUBSYS_ID_LEN]; | ||
129 | u8 slot_id[SLOT_ID_LEN]; | ||
130 | int use_ms10; | ||
131 | struct kref kref; | ||
132 | struct list_head node; /* list of all controllers */ | ||
133 | union { | ||
134 | struct rdac_pg_legacy legacy; | ||
135 | struct rdac_pg_expanded expanded; | ||
136 | } mode_select; | ||
137 | }; | ||
138 | struct c8_inquiry { | ||
139 | u8 peripheral_info; | ||
140 | u8 page_code; /* 0xC8 */ | ||
141 | u8 reserved1; | ||
142 | u8 page_len; | ||
143 | u8 page_id[4]; /* "edid" */ | ||
144 | u8 reserved2[3]; | ||
145 | u8 vol_uniq_id_len; | ||
146 | u8 vol_uniq_id[16]; | ||
147 | u8 vol_user_label_len; | ||
148 | u8 vol_user_label[60]; | ||
149 | u8 array_uniq_id_len; | ||
150 | u8 array_unique_id[16]; | ||
151 | u8 array_user_label_len; | ||
152 | u8 array_user_label[60]; | ||
153 | u8 lun[8]; | ||
154 | }; | ||
155 | |||
156 | struct c2_inquiry { | ||
157 | u8 peripheral_info; | ||
158 | u8 page_code; /* 0xC2 */ | ||
159 | u8 reserved1; | ||
160 | u8 page_len; | ||
161 | u8 page_id[4]; /* "swr4" */ | ||
162 | u8 sw_version[3]; | ||
163 | u8 sw_date[3]; | ||
164 | u8 features_enabled; | ||
165 | u8 max_lun_supported; | ||
166 | u8 partitions[239]; /* Total allocation length should be 0xFF */ | ||
167 | }; | ||
168 | |||
169 | struct rdac_dh_data { | ||
170 | struct rdac_controller *ctlr; | ||
171 | #define UNINITIALIZED_LUN (1 << 8) | ||
172 | unsigned lun; | ||
173 | #define RDAC_STATE_ACTIVE 0 | ||
174 | #define RDAC_STATE_PASSIVE 1 | ||
175 | unsigned char state; | ||
176 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
177 | union { | ||
178 | struct c2_inquiry c2; | ||
179 | struct c4_inquiry c4; | ||
180 | struct c8_inquiry c8; | ||
181 | struct c9_inquiry c9; | ||
182 | } inq; | ||
183 | }; | ||
184 | |||
185 | static LIST_HEAD(ctlr_list); | ||
186 | static DEFINE_SPINLOCK(list_lock); | ||
187 | |||
188 | static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev) | ||
189 | { | ||
190 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; | ||
191 | BUG_ON(scsi_dh_data == NULL); | ||
192 | return ((struct rdac_dh_data *) scsi_dh_data->buf); | ||
193 | } | ||
194 | |||
195 | static struct request *get_rdac_req(struct scsi_device *sdev, | ||
196 | void *buffer, unsigned buflen, int rw) | ||
197 | { | ||
198 | struct request *rq; | ||
199 | struct request_queue *q = sdev->request_queue; | ||
200 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
201 | |||
202 | rq = blk_get_request(q, rw, GFP_KERNEL); | ||
203 | |||
204 | if (!rq) { | ||
205 | sdev_printk(KERN_INFO, sdev, | ||
206 | "get_rdac_req: blk_get_request failed.\n"); | ||
207 | return NULL; | ||
208 | } | ||
209 | |||
210 | if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_KERNEL)) { | ||
211 | blk_put_request(rq); | ||
212 | sdev_printk(KERN_INFO, sdev, | ||
213 | "get_rdac_req: blk_rq_map_kern failed.\n"); | ||
214 | return NULL; | ||
215 | } | ||
216 | |||
217 | memset(&rq->cmd, 0, BLK_MAX_CDB); | ||
218 | rq->sense = h->sense; | ||
219 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
220 | rq->sense_len = 0; | ||
221 | |||
222 | rq->cmd_type = REQ_TYPE_BLOCK_PC; | ||
223 | rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; | ||
224 | rq->retries = RDAC_RETRIES; | ||
225 | rq->timeout = RDAC_TIMEOUT; | ||
226 | |||
227 | return rq; | ||
228 | } | ||
229 | |||
230 | static struct request *rdac_failover_get(struct scsi_device *sdev) | ||
231 | { | ||
232 | struct request *rq; | ||
233 | struct rdac_mode_common *common; | ||
234 | unsigned data_size; | ||
235 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
236 | |||
237 | if (h->ctlr->use_ms10) { | ||
238 | struct rdac_pg_expanded *rdac_pg; | ||
239 | |||
240 | data_size = sizeof(struct rdac_pg_expanded); | ||
241 | rdac_pg = &h->ctlr->mode_select.expanded; | ||
242 | memset(rdac_pg, 0, data_size); | ||
243 | common = &rdac_pg->common; | ||
244 | rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER + 0x40; | ||
245 | rdac_pg->subpage_code = 0x1; | ||
246 | rdac_pg->page_len[0] = 0x01; | ||
247 | rdac_pg->page_len[1] = 0x28; | ||
248 | rdac_pg->lun_table[h->lun] = 0x81; | ||
249 | } else { | ||
250 | struct rdac_pg_legacy *rdac_pg; | ||
251 | |||
252 | data_size = sizeof(struct rdac_pg_legacy); | ||
253 | rdac_pg = &h->ctlr->mode_select.legacy; | ||
254 | memset(rdac_pg, 0, data_size); | ||
255 | common = &rdac_pg->common; | ||
256 | rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER; | ||
257 | rdac_pg->page_len = 0x68; | ||
258 | rdac_pg->lun_table[h->lun] = 0x81; | ||
259 | } | ||
260 | common->rdac_mode[1] = RDAC_MODE_TRANSFER_SPECIFIED_LUNS; | ||
261 | common->quiescence_timeout = RDAC_QUIESCENCE_TIME; | ||
262 | common->rdac_options = RDAC_FORCED_QUIESENCE; | ||
263 | |||
264 | /* get request for block layer packet command */ | ||
265 | rq = get_rdac_req(sdev, &h->ctlr->mode_select, data_size, WRITE); | ||
266 | if (!rq) | ||
267 | return NULL; | ||
268 | |||
269 | /* Prepare the command. */ | ||
270 | if (h->ctlr->use_ms10) { | ||
271 | rq->cmd[0] = MODE_SELECT_10; | ||
272 | rq->cmd[7] = data_size >> 8; | ||
273 | rq->cmd[8] = data_size & 0xff; | ||
274 | } else { | ||
275 | rq->cmd[0] = MODE_SELECT; | ||
276 | rq->cmd[4] = data_size; | ||
277 | } | ||
278 | rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); | ||
279 | |||
280 | return rq; | ||
281 | } | ||
282 | |||
283 | static void release_controller(struct kref *kref) | ||
284 | { | ||
285 | struct rdac_controller *ctlr; | ||
286 | ctlr = container_of(kref, struct rdac_controller, kref); | ||
287 | |||
288 | spin_lock(&list_lock); | ||
289 | list_del(&ctlr->node); | ||
290 | spin_unlock(&list_lock); | ||
291 | kfree(ctlr); | ||
292 | } | ||
293 | |||
294 | static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id) | ||
295 | { | ||
296 | struct rdac_controller *ctlr, *tmp; | ||
297 | |||
298 | spin_lock(&list_lock); | ||
299 | |||
300 | list_for_each_entry(tmp, &ctlr_list, node) { | ||
301 | if ((memcmp(tmp->subsys_id, subsys_id, SUBSYS_ID_LEN) == 0) && | ||
302 | (memcmp(tmp->slot_id, slot_id, SLOT_ID_LEN) == 0)) { | ||
303 | kref_get(&tmp->kref); | ||
304 | spin_unlock(&list_lock); | ||
305 | return tmp; | ||
306 | } | ||
307 | } | ||
308 | ctlr = kmalloc(sizeof(*ctlr), GFP_ATOMIC); | ||
309 | if (!ctlr) | ||
310 | goto done; | ||
311 | |||
312 | /* initialize fields of controller */ | ||
313 | memcpy(ctlr->subsys_id, subsys_id, SUBSYS_ID_LEN); | ||
314 | memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN); | ||
315 | kref_init(&ctlr->kref); | ||
316 | ctlr->use_ms10 = -1; | ||
317 | list_add(&ctlr->node, &ctlr_list); | ||
318 | done: | ||
319 | spin_unlock(&list_lock); | ||
320 | return ctlr; | ||
321 | } | ||
322 | |||
323 | static int submit_inquiry(struct scsi_device *sdev, int page_code, | ||
324 | unsigned int len) | ||
325 | { | ||
326 | struct request *rq; | ||
327 | struct request_queue *q = sdev->request_queue; | ||
328 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
329 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | ||
330 | |||
331 | rq = get_rdac_req(sdev, &h->inq, len, READ); | ||
332 | if (!rq) | ||
333 | goto done; | ||
334 | |||
335 | /* Prepare the command. */ | ||
336 | rq->cmd[0] = INQUIRY; | ||
337 | rq->cmd[1] = 1; | ||
338 | rq->cmd[2] = page_code; | ||
339 | rq->cmd[4] = len; | ||
340 | rq->cmd_len = COMMAND_SIZE(INQUIRY); | ||
341 | err = blk_execute_rq(q, NULL, rq, 1); | ||
342 | if (err == -EIO) | ||
343 | err = SCSI_DH_IO; | ||
344 | done: | ||
345 | return err; | ||
346 | } | ||
347 | |||
348 | static int get_lun(struct scsi_device *sdev) | ||
349 | { | ||
350 | int err; | ||
351 | struct c8_inquiry *inqp; | ||
352 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
353 | |||
354 | err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry)); | ||
355 | if (err == SCSI_DH_OK) { | ||
356 | inqp = &h->inq.c8; | ||
357 | h->lun = inqp->lun[7]; /* currently it uses only one byte */ | ||
358 | } | ||
359 | return err; | ||
360 | } | ||
361 | |||
362 | #define RDAC_OWNED 0 | ||
363 | #define RDAC_UNOWNED 1 | ||
364 | #define RDAC_FAILED 2 | ||
365 | static int check_ownership(struct scsi_device *sdev) | ||
366 | { | ||
367 | int err; | ||
368 | struct c9_inquiry *inqp; | ||
369 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
370 | |||
371 | err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry)); | ||
372 | if (err == SCSI_DH_OK) { | ||
373 | err = RDAC_UNOWNED; | ||
374 | inqp = &h->inq.c9; | ||
375 | /* | ||
376 | * If in AVT mode or if the path already owns the LUN, | ||
377 | * return RDAC_OWNED; | ||
378 | */ | ||
379 | if (((inqp->avte_cvp >> 7) == 0x1) || | ||
380 | ((inqp->avte_cvp & 0x1) != 0)) | ||
381 | err = RDAC_OWNED; | ||
382 | } else | ||
383 | err = RDAC_FAILED; | ||
384 | return err; | ||
385 | } | ||
386 | |||
387 | static int initialize_controller(struct scsi_device *sdev) | ||
388 | { | ||
389 | int err; | ||
390 | struct c4_inquiry *inqp; | ||
391 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
392 | |||
393 | err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry)); | ||
394 | if (err == SCSI_DH_OK) { | ||
395 | inqp = &h->inq.c4; | ||
396 | h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id); | ||
397 | if (!h->ctlr) | ||
398 | err = SCSI_DH_RES_TEMP_UNAVAIL; | ||
399 | } | ||
400 | return err; | ||
401 | } | ||
402 | |||
403 | static int set_mode_select(struct scsi_device *sdev) | ||
404 | { | ||
405 | int err; | ||
406 | struct c2_inquiry *inqp; | ||
407 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
408 | |||
409 | err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry)); | ||
410 | if (err == SCSI_DH_OK) { | ||
411 | inqp = &h->inq.c2; | ||
412 | /* | ||
413 | * If more than MODE6_MAX_LUN luns are supported, use | ||
414 | * mode select 10 | ||
415 | */ | ||
416 | if (inqp->max_lun_supported >= MODE6_MAX_LUN) | ||
417 | h->ctlr->use_ms10 = 1; | ||
418 | else | ||
419 | h->ctlr->use_ms10 = 0; | ||
420 | } | ||
421 | return err; | ||
422 | } | ||
423 | |||
424 | static int mode_select_handle_sense(struct scsi_device *sdev) | ||
425 | { | ||
426 | struct scsi_sense_hdr sense_hdr; | ||
427 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
428 | int sense, err = SCSI_DH_IO, ret; | ||
429 | |||
430 | ret = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr); | ||
431 | if (!ret) | ||
432 | goto done; | ||
433 | |||
434 | err = SCSI_DH_OK; | ||
435 | sense = (sense_hdr.sense_key << 16) | (sense_hdr.asc << 8) | | ||
436 | sense_hdr.ascq; | ||
437 | /* If it is retryable failure, submit the c9 inquiry again */ | ||
438 | if (sense == 0x59136 || sense == 0x68b02 || sense == 0xb8b02 || | ||
439 | sense == 0x62900) { | ||
440 | /* 0x59136 - Command lock contention | ||
441 | * 0x[6b]8b02 - Quiesense in progress or achieved | ||
442 | * 0x62900 - Power On, Reset, or Bus Device Reset | ||
443 | */ | ||
444 | err = SCSI_DH_RETRY; | ||
445 | } | ||
446 | |||
447 | if (sense) | ||
448 | sdev_printk(KERN_INFO, sdev, | ||
449 | "MODE_SELECT failed with sense 0x%x.\n", sense); | ||
450 | done: | ||
451 | return err; | ||
452 | } | ||
453 | |||
454 | static int send_mode_select(struct scsi_device *sdev) | ||
455 | { | ||
456 | struct request *rq; | ||
457 | struct request_queue *q = sdev->request_queue; | ||
458 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
459 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | ||
460 | |||
461 | rq = rdac_failover_get(sdev); | ||
462 | if (!rq) | ||
463 | goto done; | ||
464 | |||
465 | sdev_printk(KERN_INFO, sdev, "queueing MODE_SELECT command.\n"); | ||
466 | |||
467 | err = blk_execute_rq(q, NULL, rq, 1); | ||
468 | if (err != SCSI_DH_OK) | ||
469 | err = mode_select_handle_sense(sdev); | ||
470 | if (err == SCSI_DH_OK) | ||
471 | h->state = RDAC_STATE_ACTIVE; | ||
472 | done: | ||
473 | return err; | ||
474 | } | ||
475 | |||
476 | static int rdac_activate(struct scsi_device *sdev) | ||
477 | { | ||
478 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
479 | int err = SCSI_DH_OK; | ||
480 | |||
481 | if (h->lun == UNINITIALIZED_LUN) { | ||
482 | err = get_lun(sdev); | ||
483 | if (err != SCSI_DH_OK) | ||
484 | goto done; | ||
485 | } | ||
486 | |||
487 | err = check_ownership(sdev); | ||
488 | switch (err) { | ||
489 | case RDAC_UNOWNED: | ||
490 | break; | ||
491 | case RDAC_OWNED: | ||
492 | err = SCSI_DH_OK; | ||
493 | goto done; | ||
494 | case RDAC_FAILED: | ||
495 | default: | ||
496 | err = SCSI_DH_IO; | ||
497 | goto done; | ||
498 | } | ||
499 | |||
500 | if (!h->ctlr) { | ||
501 | err = initialize_controller(sdev); | ||
502 | if (err != SCSI_DH_OK) | ||
503 | goto done; | ||
504 | } | ||
505 | |||
506 | if (h->ctlr->use_ms10 == -1) { | ||
507 | err = set_mode_select(sdev); | ||
508 | if (err != SCSI_DH_OK) | ||
509 | goto done; | ||
510 | } | ||
511 | |||
512 | err = send_mode_select(sdev); | ||
513 | done: | ||
514 | return err; | ||
515 | } | ||
516 | |||
517 | static int rdac_prep_fn(struct scsi_device *sdev, struct request *req) | ||
518 | { | ||
519 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
520 | int ret = BLKPREP_OK; | ||
521 | |||
522 | if (h->state != RDAC_STATE_ACTIVE) { | ||
523 | ret = BLKPREP_KILL; | ||
524 | req->cmd_flags |= REQ_QUIET; | ||
525 | } | ||
526 | return ret; | ||
527 | |||
528 | } | ||
529 | |||
530 | static int rdac_check_sense(struct scsi_device *sdev, | ||
531 | struct scsi_sense_hdr *sense_hdr) | ||
532 | { | ||
533 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
534 | switch (sense_hdr->sense_key) { | ||
535 | case NOT_READY: | ||
536 | if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x81) | ||
537 | /* LUN Not Ready - Storage firmware incompatible | ||
538 | * Manual code synchonisation required. | ||
539 | * | ||
540 | * Nothing we can do here. Try to bypass the path. | ||
541 | */ | ||
542 | return SUCCESS; | ||
543 | if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0xA1) | ||
544 | /* LUN Not Ready - Quiescense in progress | ||
545 | * | ||
546 | * Just retry and wait. | ||
547 | */ | ||
548 | return NEEDS_RETRY; | ||
549 | break; | ||
550 | case ILLEGAL_REQUEST: | ||
551 | if (sense_hdr->asc == 0x94 && sense_hdr->ascq == 0x01) { | ||
552 | /* Invalid Request - Current Logical Unit Ownership. | ||
553 | * Controller is not the current owner of the LUN, | ||
554 | * Fail the path, so that the other path be used. | ||
555 | */ | ||
556 | h->state = RDAC_STATE_PASSIVE; | ||
557 | return SUCCESS; | ||
558 | } | ||
559 | break; | ||
560 | case UNIT_ATTENTION: | ||
561 | if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) | ||
562 | /* | ||
563 | * Power On, Reset, or Bus Device Reset, just retry. | ||
564 | */ | ||
565 | return NEEDS_RETRY; | ||
566 | break; | ||
567 | } | ||
568 | /* success just means we do not care what scsi-ml does */ | ||
569 | return SCSI_RETURN_NOT_HANDLED; | ||
570 | } | ||
571 | |||
572 | static const struct { | ||
573 | char *vendor; | ||
574 | char *model; | ||
575 | } rdac_dev_list[] = { | ||
576 | {"IBM", "1722"}, | ||
577 | {"IBM", "1724"}, | ||
578 | {"IBM", "1726"}, | ||
579 | {"IBM", "1742"}, | ||
580 | {"IBM", "1814"}, | ||
581 | {"IBM", "1815"}, | ||
582 | {"IBM", "1818"}, | ||
583 | {"IBM", "3526"}, | ||
584 | {"SGI", "TP9400"}, | ||
585 | {"SGI", "TP9500"}, | ||
586 | {"SGI", "IS"}, | ||
587 | {"STK", "OPENstorage D280"}, | ||
588 | {"SUN", "CSM200_R"}, | ||
589 | {"SUN", "LCSM100_F"}, | ||
590 | {NULL, NULL}, | ||
591 | }; | ||
592 | |||
593 | static int rdac_bus_notify(struct notifier_block *, unsigned long, void *); | ||
594 | |||
595 | static struct scsi_device_handler rdac_dh = { | ||
596 | .name = RDAC_NAME, | ||
597 | .module = THIS_MODULE, | ||
598 | .nb.notifier_call = rdac_bus_notify, | ||
599 | .prep_fn = rdac_prep_fn, | ||
600 | .check_sense = rdac_check_sense, | ||
601 | .activate = rdac_activate, | ||
602 | }; | ||
603 | |||
604 | /* | ||
605 | * TODO: need some interface so we can set trespass values | ||
606 | */ | ||
607 | static int rdac_bus_notify(struct notifier_block *nb, | ||
608 | unsigned long action, void *data) | ||
609 | { | ||
610 | struct device *dev = data; | ||
611 | struct scsi_device *sdev = to_scsi_device(dev); | ||
612 | struct scsi_dh_data *scsi_dh_data; | ||
613 | struct rdac_dh_data *h; | ||
614 | int i, found = 0; | ||
615 | unsigned long flags; | ||
616 | |||
617 | if (action == BUS_NOTIFY_ADD_DEVICE) { | ||
618 | for (i = 0; rdac_dev_list[i].vendor; i++) { | ||
619 | if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor, | ||
620 | strlen(rdac_dev_list[i].vendor)) && | ||
621 | !strncmp(sdev->model, rdac_dev_list[i].model, | ||
622 | strlen(rdac_dev_list[i].model))) { | ||
623 | found = 1; | ||
624 | break; | ||
625 | } | ||
626 | } | ||
627 | if (!found) | ||
628 | goto out; | ||
629 | |||
630 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | ||
631 | + sizeof(*h) , GFP_KERNEL); | ||
632 | if (!scsi_dh_data) { | ||
633 | sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", | ||
634 | RDAC_NAME); | ||
635 | goto out; | ||
636 | } | ||
637 | |||
638 | scsi_dh_data->scsi_dh = &rdac_dh; | ||
639 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | ||
640 | h->lun = UNINITIALIZED_LUN; | ||
641 | h->state = RDAC_STATE_ACTIVE; | ||
642 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
643 | sdev->scsi_dh_data = scsi_dh_data; | ||
644 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
645 | try_module_get(THIS_MODULE); | ||
646 | |||
647 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", RDAC_NAME); | ||
648 | |||
649 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | ||
650 | if (sdev->scsi_dh_data == NULL || | ||
651 | sdev->scsi_dh_data->scsi_dh != &rdac_dh) | ||
652 | goto out; | ||
653 | |||
654 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
655 | scsi_dh_data = sdev->scsi_dh_data; | ||
656 | sdev->scsi_dh_data = NULL; | ||
657 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
658 | |||
659 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | ||
660 | if (h->ctlr) | ||
661 | kref_put(&h->ctlr->kref, release_controller); | ||
662 | kfree(scsi_dh_data); | ||
663 | module_put(THIS_MODULE); | ||
664 | sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", RDAC_NAME); | ||
665 | } | ||
666 | |||
667 | out: | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static int __init rdac_init(void) | ||
672 | { | ||
673 | int r; | ||
674 | |||
675 | r = scsi_register_device_handler(&rdac_dh); | ||
676 | if (r != 0) | ||
677 | printk(KERN_ERR "Failed to register scsi device handler."); | ||
678 | return r; | ||
679 | } | ||
680 | |||
681 | static void __exit rdac_exit(void) | ||
682 | { | ||
683 | scsi_unregister_device_handler(&rdac_dh); | ||
684 | } | ||
685 | |||
686 | module_init(rdac_init); | ||
687 | module_exit(rdac_exit); | ||
688 | |||
689 | MODULE_DESCRIPTION("Multipath LSI/Engenio RDAC driver"); | ||
690 | MODULE_AUTHOR("Mike Christie, Chandra Seetharaman"); | ||
691 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 59fbef08d690..62a4618530d0 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c | |||
@@ -219,19 +219,10 @@ static void esp_reset_esp(struct esp *esp) | |||
219 | /* Now reset the ESP chip */ | 219 | /* Now reset the ESP chip */ |
220 | scsi_esp_cmd(esp, ESP_CMD_RC); | 220 | scsi_esp_cmd(esp, ESP_CMD_RC); |
221 | scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); | 221 | scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); |
222 | if (esp->rev == FAST) | ||
223 | esp_write8(ESP_CONFIG2_FENAB, ESP_CFG2); | ||
222 | scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); | 224 | scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); |
223 | 225 | ||
224 | /* Reload the configuration registers */ | ||
225 | esp_write8(esp->cfact, ESP_CFACT); | ||
226 | |||
227 | esp->prev_stp = 0; | ||
228 | esp_write8(esp->prev_stp, ESP_STP); | ||
229 | |||
230 | esp->prev_soff = 0; | ||
231 | esp_write8(esp->prev_soff, ESP_SOFF); | ||
232 | |||
233 | esp_write8(esp->neg_defp, ESP_TIMEO); | ||
234 | |||
235 | /* This is the only point at which it is reliable to read | 226 | /* This is the only point at which it is reliable to read |
236 | * the ID-code for a fast ESP chip variants. | 227 | * the ID-code for a fast ESP chip variants. |
237 | */ | 228 | */ |
@@ -316,6 +307,17 @@ static void esp_reset_esp(struct esp *esp) | |||
316 | break; | 307 | break; |
317 | } | 308 | } |
318 | 309 | ||
310 | /* Reload the configuration registers */ | ||
311 | esp_write8(esp->cfact, ESP_CFACT); | ||
312 | |||
313 | esp->prev_stp = 0; | ||
314 | esp_write8(esp->prev_stp, ESP_STP); | ||
315 | |||
316 | esp->prev_soff = 0; | ||
317 | esp_write8(esp->prev_soff, ESP_SOFF); | ||
318 | |||
319 | esp_write8(esp->neg_defp, ESP_TIMEO); | ||
320 | |||
319 | /* Eat any bitrot in the chip */ | 321 | /* Eat any bitrot in the chip */ |
320 | esp_read8(ESP_INTRPT); | 322 | esp_read8(ESP_INTRPT); |
321 | udelay(100); | 323 | udelay(100); |
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index c6457bfc8a49..35cd892dce04 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c | |||
@@ -290,7 +290,7 @@ static void scsi_host_dev_release(struct device *dev) | |||
290 | kfree(shost); | 290 | kfree(shost); |
291 | } | 291 | } |
292 | 292 | ||
293 | struct device_type scsi_host_type = { | 293 | static struct device_type scsi_host_type = { |
294 | .name = "scsi_host", | 294 | .name = "scsi_host", |
295 | .release = scsi_host_dev_release, | 295 | .release = scsi_host_dev_release, |
296 | }; | 296 | }; |
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile index 6ac0633d5452..a423d9633625 100644 --- a/drivers/scsi/ibmvscsi/Makefile +++ b/drivers/scsi/ibmvscsi/Makefile | |||
@@ -5,3 +5,4 @@ ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o | |||
5 | ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o | 5 | ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o |
6 | 6 | ||
7 | obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o | 7 | obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o |
8 | obj-$(CONFIG_SCSI_IBMVFC) += ibmvfc.o | ||
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c new file mode 100644 index 000000000000..eb702b96d57c --- /dev/null +++ b/drivers/scsi/ibmvscsi/ibmvfc.c | |||
@@ -0,0 +1,3910 @@ | |||
1 | /* | ||
2 | * ibmvfc.c -- driver for IBM Power Virtual Fibre Channel Adapter | ||
3 | * | ||
4 | * Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation | ||
5 | * | ||
6 | * Copyright (C) IBM Corporation, 2008 | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/dma-mapping.h> | ||
27 | #include <linux/dmapool.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/kthread.h> | ||
31 | #include <linux/of.h> | ||
32 | #include <linux/stringify.h> | ||
33 | #include <asm/firmware.h> | ||
34 | #include <asm/irq.h> | ||
35 | #include <asm/vio.h> | ||
36 | #include <scsi/scsi.h> | ||
37 | #include <scsi/scsi_cmnd.h> | ||
38 | #include <scsi/scsi_host.h> | ||
39 | #include <scsi/scsi_device.h> | ||
40 | #include <scsi/scsi_tcq.h> | ||
41 | #include <scsi/scsi_transport_fc.h> | ||
42 | #include "ibmvfc.h" | ||
43 | |||
44 | static unsigned int init_timeout = IBMVFC_INIT_TIMEOUT; | ||
45 | static unsigned int default_timeout = IBMVFC_DEFAULT_TIMEOUT; | ||
46 | static unsigned int max_lun = IBMVFC_MAX_LUN; | ||
47 | static unsigned int max_targets = IBMVFC_MAX_TARGETS; | ||
48 | static unsigned int max_requests = IBMVFC_MAX_REQUESTS_DEFAULT; | ||
49 | static unsigned int disc_threads = IBMVFC_MAX_DISC_THREADS; | ||
50 | static unsigned int dev_loss_tmo = IBMVFC_DEV_LOSS_TMO; | ||
51 | static unsigned int ibmvfc_debug = IBMVFC_DEBUG; | ||
52 | static unsigned int log_level = IBMVFC_DEFAULT_LOG_LEVEL; | ||
53 | static LIST_HEAD(ibmvfc_head); | ||
54 | static DEFINE_SPINLOCK(ibmvfc_driver_lock); | ||
55 | static struct scsi_transport_template *ibmvfc_transport_template; | ||
56 | |||
57 | MODULE_DESCRIPTION("IBM Virtual Fibre Channel Driver"); | ||
58 | MODULE_AUTHOR("Brian King <brking@linux.vnet.ibm.com>"); | ||
59 | MODULE_LICENSE("GPL"); | ||
60 | MODULE_VERSION(IBMVFC_DRIVER_VERSION); | ||
61 | |||
62 | module_param_named(init_timeout, init_timeout, uint, S_IRUGO | S_IWUSR); | ||
63 | MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds. " | ||
64 | "[Default=" __stringify(IBMVFC_INIT_TIMEOUT) "]"); | ||
65 | module_param_named(default_timeout, default_timeout, uint, S_IRUGO | S_IWUSR); | ||
66 | MODULE_PARM_DESC(default_timeout, | ||
67 | "Default timeout in seconds for initialization and EH commands. " | ||
68 | "[Default=" __stringify(IBMVFC_DEFAULT_TIMEOUT) "]"); | ||
69 | module_param_named(max_requests, max_requests, uint, S_IRUGO); | ||
70 | MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter. " | ||
71 | "[Default=" __stringify(IBMVFC_MAX_REQUESTS_DEFAULT) "]"); | ||
72 | module_param_named(max_lun, max_lun, uint, S_IRUGO); | ||
73 | MODULE_PARM_DESC(max_lun, "Maximum allowed LUN. " | ||
74 | "[Default=" __stringify(IBMVFC_MAX_LUN) "]"); | ||
75 | module_param_named(max_targets, max_targets, uint, S_IRUGO); | ||
76 | MODULE_PARM_DESC(max_targets, "Maximum allowed targets. " | ||
77 | "[Default=" __stringify(IBMVFC_MAX_TARGETS) "]"); | ||
78 | module_param_named(disc_threads, disc_threads, uint, S_IRUGO | S_IWUSR); | ||
79 | MODULE_PARM_DESC(disc_threads, "Number of device discovery threads to use. " | ||
80 | "[Default=" __stringify(IBMVFC_MAX_DISC_THREADS) "]"); | ||
81 | module_param_named(debug, ibmvfc_debug, uint, S_IRUGO | S_IWUSR); | ||
82 | MODULE_PARM_DESC(debug, "Enable driver debug information. " | ||
83 | "[Default=" __stringify(IBMVFC_DEBUG) "]"); | ||
84 | module_param_named(dev_loss_tmo, dev_loss_tmo, uint, S_IRUGO | S_IWUSR); | ||
85 | MODULE_PARM_DESC(dev_loss_tmo, "Maximum number of seconds that the FC " | ||
86 | "transport should insulate the loss of a remote port. Once this " | ||
87 | "value is exceeded, the scsi target is removed. " | ||
88 | "[Default=" __stringify(IBMVFC_DEV_LOSS_TMO) "]"); | ||
89 | module_param_named(log_level, log_level, uint, 0); | ||
90 | MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver. " | ||
91 | "[Default=" __stringify(IBMVFC_DEFAULT_LOG_LEVEL) "]"); | ||
92 | |||
93 | static const struct { | ||
94 | u16 status; | ||
95 | u16 error; | ||
96 | u8 result; | ||
97 | u8 retry; | ||
98 | int log; | ||
99 | char *name; | ||
100 | } cmd_status [] = { | ||
101 | { IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_ESTABLISH, DID_ERROR, 1, 1, "unable to establish" }, | ||
102 | { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_FAULT, DID_OK, 1, 0, "transport fault" }, | ||
103 | { IBMVFC_FABRIC_MAPPED, IBMVFC_CMD_TIMEOUT, DID_TIME_OUT, 1, 1, "command timeout" }, | ||
104 | { IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_NO_CONNECT, 1, 1, "network down" }, | ||
105 | { IBMVFC_FABRIC_MAPPED, IBMVFC_HW_FAILURE, DID_ERROR, 1, 1, "hardware failure" }, | ||
106 | { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DOWN_ERR, DID_REQUEUE, 0, 0, "link down" }, | ||
107 | { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DEAD_ERR, DID_ERROR, 0, 0, "link dead" }, | ||
108 | { IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_REGISTER, DID_ERROR, 1, 1, "unable to register" }, | ||
109 | { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_BUSY, DID_BUS_BUSY, 1, 0, "transport busy" }, | ||
110 | { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_DEAD, DID_ERROR, 0, 1, "transport dead" }, | ||
111 | { IBMVFC_FABRIC_MAPPED, IBMVFC_CONFIG_ERROR, DID_ERROR, 1, 1, "configuration error" }, | ||
112 | { IBMVFC_FABRIC_MAPPED, IBMVFC_NAME_SERVER_FAIL, DID_ERROR, 1, 1, "name server failure" }, | ||
113 | { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 0, 0, "link halted" }, | ||
114 | { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_GENERAL, DID_OK, 1, 0, "general transport error" }, | ||
115 | |||
116 | { IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" }, | ||
117 | { IBMVFC_VIOS_FAILURE, IBMVFC_SW_FAILURE, DID_ERROR, 0, 1, "software failure" }, | ||
118 | { IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ABORT, 0, 1, "invalid parameter" }, | ||
119 | { IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ABORT, 0, 1, "missing parameter" }, | ||
120 | { IBMVFC_VIOS_FAILURE, IBMVFC_HOST_IO_BUS, DID_ERROR, 1, 1, "host I/O bus failure" }, | ||
121 | { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ABORT, 0, 1, "transaction cancelled" }, | ||
122 | { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ABORT, 0, 1, "transaction cancelled implicit" }, | ||
123 | { IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" }, | ||
124 | { IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" }, | ||
125 | |||
126 | { IBMVFC_FC_FAILURE, IBMVFC_INVALID_ELS_CMD_CODE, DID_ERROR, 0, 1, "invalid ELS command code" }, | ||
127 | { IBMVFC_FC_FAILURE, IBMVFC_INVALID_VERSION, DID_ERROR, 0, 1, "invalid version level" }, | ||
128 | { IBMVFC_FC_FAILURE, IBMVFC_LOGICAL_ERROR, DID_ERROR, 1, 1, "logical error" }, | ||
129 | { IBMVFC_FC_FAILURE, IBMVFC_INVALID_CT_IU_SIZE, DID_ERROR, 0, 1, "invalid CT_IU size" }, | ||
130 | { IBMVFC_FC_FAILURE, IBMVFC_LOGICAL_BUSY, DID_REQUEUE, 1, 0, "logical busy" }, | ||
131 | { IBMVFC_FC_FAILURE, IBMVFC_PROTOCOL_ERROR, DID_ERROR, 1, 1, "protocol error" }, | ||
132 | { IBMVFC_FC_FAILURE, IBMVFC_UNABLE_TO_PERFORM_REQ, DID_ERROR, 1, 1, "unable to perform request" }, | ||
133 | { IBMVFC_FC_FAILURE, IBMVFC_CMD_NOT_SUPPORTED, DID_ERROR, 0, 0, "command not supported" }, | ||
134 | { IBMVFC_FC_FAILURE, IBMVFC_SERVER_NOT_AVAIL, DID_ERROR, 0, 1, "server not available" }, | ||
135 | { IBMVFC_FC_FAILURE, IBMVFC_CMD_IN_PROGRESS, DID_ERROR, 0, 1, "command already in progress" }, | ||
136 | { IBMVFC_FC_FAILURE, IBMVFC_VENDOR_SPECIFIC, DID_ERROR, 1, 1, "vendor specific" }, | ||
137 | |||
138 | { IBMVFC_FC_SCSI_ERROR, 0, DID_OK, 1, 0, "SCSI error" }, | ||
139 | }; | ||
140 | |||
141 | static void ibmvfc_npiv_login(struct ibmvfc_host *); | ||
142 | static void ibmvfc_tgt_send_prli(struct ibmvfc_target *); | ||
143 | static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *); | ||
144 | static void ibmvfc_tgt_query_target(struct ibmvfc_target *); | ||
145 | |||
146 | static const char *unknown_error = "unknown error"; | ||
147 | |||
148 | #ifdef CONFIG_SCSI_IBMVFC_TRACE | ||
149 | /** | ||
150 | * ibmvfc_trc_start - Log a start trace entry | ||
151 | * @evt: ibmvfc event struct | ||
152 | * | ||
153 | **/ | ||
154 | static void ibmvfc_trc_start(struct ibmvfc_event *evt) | ||
155 | { | ||
156 | struct ibmvfc_host *vhost = evt->vhost; | ||
157 | struct ibmvfc_cmd *vfc_cmd = &evt->iu.cmd; | ||
158 | struct ibmvfc_mad_common *mad = &evt->iu.mad_common; | ||
159 | struct ibmvfc_trace_entry *entry; | ||
160 | |||
161 | entry = &vhost->trace[vhost->trace_index++]; | ||
162 | entry->evt = evt; | ||
163 | entry->time = jiffies; | ||
164 | entry->fmt = evt->crq.format; | ||
165 | entry->type = IBMVFC_TRC_START; | ||
166 | |||
167 | switch (entry->fmt) { | ||
168 | case IBMVFC_CMD_FORMAT: | ||
169 | entry->op_code = vfc_cmd->iu.cdb[0]; | ||
170 | entry->scsi_id = vfc_cmd->tgt_scsi_id; | ||
171 | entry->lun = scsilun_to_int(&vfc_cmd->iu.lun); | ||
172 | entry->tmf_flags = vfc_cmd->iu.tmf_flags; | ||
173 | entry->u.start.xfer_len = vfc_cmd->iu.xfer_len; | ||
174 | break; | ||
175 | case IBMVFC_MAD_FORMAT: | ||
176 | entry->op_code = mad->opcode; | ||
177 | break; | ||
178 | default: | ||
179 | break; | ||
180 | }; | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * ibmvfc_trc_end - Log an end trace entry | ||
185 | * @evt: ibmvfc event struct | ||
186 | * | ||
187 | **/ | ||
188 | static void ibmvfc_trc_end(struct ibmvfc_event *evt) | ||
189 | { | ||
190 | struct ibmvfc_host *vhost = evt->vhost; | ||
191 | struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; | ||
192 | struct ibmvfc_mad_common *mad = &evt->xfer_iu->mad_common; | ||
193 | struct ibmvfc_trace_entry *entry = &vhost->trace[vhost->trace_index++]; | ||
194 | |||
195 | entry->evt = evt; | ||
196 | entry->time = jiffies; | ||
197 | entry->fmt = evt->crq.format; | ||
198 | entry->type = IBMVFC_TRC_END; | ||
199 | |||
200 | switch (entry->fmt) { | ||
201 | case IBMVFC_CMD_FORMAT: | ||
202 | entry->op_code = vfc_cmd->iu.cdb[0]; | ||
203 | entry->scsi_id = vfc_cmd->tgt_scsi_id; | ||
204 | entry->lun = scsilun_to_int(&vfc_cmd->iu.lun); | ||
205 | entry->tmf_flags = vfc_cmd->iu.tmf_flags; | ||
206 | entry->u.end.status = vfc_cmd->status; | ||
207 | entry->u.end.error = vfc_cmd->error; | ||
208 | entry->u.end.fcp_rsp_flags = vfc_cmd->rsp.flags; | ||
209 | entry->u.end.rsp_code = vfc_cmd->rsp.data.info.rsp_code; | ||
210 | entry->u.end.scsi_status = vfc_cmd->rsp.scsi_status; | ||
211 | break; | ||
212 | case IBMVFC_MAD_FORMAT: | ||
213 | entry->op_code = mad->opcode; | ||
214 | entry->u.end.status = mad->status; | ||
215 | break; | ||
216 | default: | ||
217 | break; | ||
218 | |||
219 | }; | ||
220 | } | ||
221 | |||
222 | #else | ||
223 | #define ibmvfc_trc_start(evt) do { } while (0) | ||
224 | #define ibmvfc_trc_end(evt) do { } while (0) | ||
225 | #endif | ||
226 | |||
227 | /** | ||
228 | * ibmvfc_get_err_index - Find the index into cmd_status for the fcp response | ||
229 | * @status: status / error class | ||
230 | * @error: error | ||
231 | * | ||
232 | * Return value: | ||
233 | * index into cmd_status / -EINVAL on failure | ||
234 | **/ | ||
235 | static int ibmvfc_get_err_index(u16 status, u16 error) | ||
236 | { | ||
237 | int i; | ||
238 | |||
239 | for (i = 0; i < ARRAY_SIZE(cmd_status); i++) | ||
240 | if ((cmd_status[i].status & status) == cmd_status[i].status && | ||
241 | cmd_status[i].error == error) | ||
242 | return i; | ||
243 | |||
244 | return -EINVAL; | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * ibmvfc_get_cmd_error - Find the error description for the fcp response | ||
249 | * @status: status / error class | ||
250 | * @error: error | ||
251 | * | ||
252 | * Return value: | ||
253 | * error description string | ||
254 | **/ | ||
255 | static const char *ibmvfc_get_cmd_error(u16 status, u16 error) | ||
256 | { | ||
257 | int rc = ibmvfc_get_err_index(status, error); | ||
258 | if (rc >= 0) | ||
259 | return cmd_status[rc].name; | ||
260 | return unknown_error; | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * ibmvfc_get_err_result - Find the scsi status to return for the fcp response | ||
265 | * @vfc_cmd: ibmvfc command struct | ||
266 | * | ||
267 | * Return value: | ||
268 | * SCSI result value to return for completed command | ||
269 | **/ | ||
270 | static int ibmvfc_get_err_result(struct ibmvfc_cmd *vfc_cmd) | ||
271 | { | ||
272 | int err; | ||
273 | struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; | ||
274 | int fc_rsp_len = rsp->fcp_rsp_len; | ||
275 | |||
276 | if ((rsp->flags & FCP_RSP_LEN_VALID) && | ||
277 | ((!fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) || | ||
278 | rsp->data.info.rsp_code)) | ||
279 | return DID_ERROR << 16; | ||
280 | |||
281 | if (!vfc_cmd->status) { | ||
282 | if (rsp->flags & FCP_RESID_OVER) | ||
283 | return rsp->scsi_status | (DID_ERROR << 16); | ||
284 | else | ||
285 | return rsp->scsi_status | (DID_OK << 16); | ||
286 | } | ||
287 | |||
288 | err = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); | ||
289 | if (err >= 0) | ||
290 | return rsp->scsi_status | (cmd_status[err].result << 16); | ||
291 | return rsp->scsi_status | (DID_ERROR << 16); | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * ibmvfc_retry_cmd - Determine if error status is retryable | ||
296 | * @status: status / error class | ||
297 | * @error: error | ||
298 | * | ||
299 | * Return value: | ||
300 | * 1 if error should be retried / 0 if it should not | ||
301 | **/ | ||
302 | static int ibmvfc_retry_cmd(u16 status, u16 error) | ||
303 | { | ||
304 | int rc = ibmvfc_get_err_index(status, error); | ||
305 | |||
306 | if (rc >= 0) | ||
307 | return cmd_status[rc].retry; | ||
308 | return 1; | ||
309 | } | ||
310 | |||
311 | static const char *unknown_fc_explain = "unknown fc explain"; | ||
312 | |||
313 | static const struct { | ||
314 | u16 fc_explain; | ||
315 | char *name; | ||
316 | } ls_explain [] = { | ||
317 | { 0x00, "no additional explanation" }, | ||
318 | { 0x01, "service parameter error - options" }, | ||
319 | { 0x03, "service parameter error - initiator control" }, | ||
320 | { 0x05, "service parameter error - recipient control" }, | ||
321 | { 0x07, "service parameter error - received data field size" }, | ||
322 | { 0x09, "service parameter error - concurrent seq" }, | ||
323 | { 0x0B, "service parameter error - credit" }, | ||
324 | { 0x0D, "invalid N_Port/F_Port_Name" }, | ||
325 | { 0x0E, "invalid node/Fabric Name" }, | ||
326 | { 0x0F, "invalid common service parameters" }, | ||
327 | { 0x11, "invalid association header" }, | ||
328 | { 0x13, "association header required" }, | ||
329 | { 0x15, "invalid originator S_ID" }, | ||
330 | { 0x17, "invalid OX_ID-RX-ID combination" }, | ||
331 | { 0x19, "command (request) already in progress" }, | ||
332 | { 0x1E, "N_Port Login requested" }, | ||
333 | { 0x1F, "Invalid N_Port_ID" }, | ||
334 | }; | ||
335 | |||
336 | static const struct { | ||
337 | u16 fc_explain; | ||
338 | char *name; | ||
339 | } gs_explain [] = { | ||
340 | { 0x00, "no additional explanation" }, | ||
341 | { 0x01, "port identifier not registered" }, | ||
342 | { 0x02, "port name not registered" }, | ||
343 | { 0x03, "node name not registered" }, | ||
344 | { 0x04, "class of service not registered" }, | ||
345 | { 0x06, "initial process associator not registered" }, | ||
346 | { 0x07, "FC-4 TYPEs not registered" }, | ||
347 | { 0x08, "symbolic port name not registered" }, | ||
348 | { 0x09, "symbolic node name not registered" }, | ||
349 | { 0x0A, "port type not registered" }, | ||
350 | { 0xF0, "authorization exception" }, | ||
351 | { 0xF1, "authentication exception" }, | ||
352 | { 0xF2, "data base full" }, | ||
353 | { 0xF3, "data base empty" }, | ||
354 | { 0xF4, "processing request" }, | ||
355 | { 0xF5, "unable to verify connection" }, | ||
356 | { 0xF6, "devices not in a common zone" }, | ||
357 | }; | ||
358 | |||
359 | /** | ||
360 | * ibmvfc_get_ls_explain - Return the FC Explain description text | ||
361 | * @status: FC Explain status | ||
362 | * | ||
363 | * Returns: | ||
364 | * error string | ||
365 | **/ | ||
366 | static const char *ibmvfc_get_ls_explain(u16 status) | ||
367 | { | ||
368 | int i; | ||
369 | |||
370 | for (i = 0; i < ARRAY_SIZE(ls_explain); i++) | ||
371 | if (ls_explain[i].fc_explain == status) | ||
372 | return ls_explain[i].name; | ||
373 | |||
374 | return unknown_fc_explain; | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * ibmvfc_get_gs_explain - Return the FC Explain description text | ||
379 | * @status: FC Explain status | ||
380 | * | ||
381 | * Returns: | ||
382 | * error string | ||
383 | **/ | ||
384 | static const char *ibmvfc_get_gs_explain(u16 status) | ||
385 | { | ||
386 | int i; | ||
387 | |||
388 | for (i = 0; i < ARRAY_SIZE(gs_explain); i++) | ||
389 | if (gs_explain[i].fc_explain == status) | ||
390 | return gs_explain[i].name; | ||
391 | |||
392 | return unknown_fc_explain; | ||
393 | } | ||
394 | |||
395 | static const struct { | ||
396 | enum ibmvfc_fc_type fc_type; | ||
397 | char *name; | ||
398 | } fc_type [] = { | ||
399 | { IBMVFC_FABRIC_REJECT, "fabric reject" }, | ||
400 | { IBMVFC_PORT_REJECT, "port reject" }, | ||
401 | { IBMVFC_LS_REJECT, "ELS reject" }, | ||
402 | { IBMVFC_FABRIC_BUSY, "fabric busy" }, | ||
403 | { IBMVFC_PORT_BUSY, "port busy" }, | ||
404 | { IBMVFC_BASIC_REJECT, "basic reject" }, | ||
405 | }; | ||
406 | |||
407 | static const char *unknown_fc_type = "unknown fc type"; | ||
408 | |||
409 | /** | ||
410 | * ibmvfc_get_fc_type - Return the FC Type description text | ||
411 | * @status: FC Type error status | ||
412 | * | ||
413 | * Returns: | ||
414 | * error string | ||
415 | **/ | ||
416 | static const char *ibmvfc_get_fc_type(u16 status) | ||
417 | { | ||
418 | int i; | ||
419 | |||
420 | for (i = 0; i < ARRAY_SIZE(fc_type); i++) | ||
421 | if (fc_type[i].fc_type == status) | ||
422 | return fc_type[i].name; | ||
423 | |||
424 | return unknown_fc_type; | ||
425 | } | ||
426 | |||
427 | /** | ||
428 | * ibmvfc_set_tgt_action - Set the next init action for the target | ||
429 | * @tgt: ibmvfc target struct | ||
430 | * @action: action to perform | ||
431 | * | ||
432 | **/ | ||
433 | static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt, | ||
434 | enum ibmvfc_target_action action) | ||
435 | { | ||
436 | switch (tgt->action) { | ||
437 | case IBMVFC_TGT_ACTION_DEL_RPORT: | ||
438 | break; | ||
439 | default: | ||
440 | tgt->action = action; | ||
441 | break; | ||
442 | } | ||
443 | } | ||
444 | |||
445 | /** | ||
446 | * ibmvfc_set_host_state - Set the state for the host | ||
447 | * @vhost: ibmvfc host struct | ||
448 | * @state: state to set host to | ||
449 | * | ||
450 | * Returns: | ||
451 | * 0 if state changed / non-zero if not changed | ||
452 | **/ | ||
453 | static int ibmvfc_set_host_state(struct ibmvfc_host *vhost, | ||
454 | enum ibmvfc_host_state state) | ||
455 | { | ||
456 | int rc = 0; | ||
457 | |||
458 | switch (vhost->state) { | ||
459 | case IBMVFC_HOST_OFFLINE: | ||
460 | rc = -EINVAL; | ||
461 | break; | ||
462 | default: | ||
463 | vhost->state = state; | ||
464 | break; | ||
465 | }; | ||
466 | |||
467 | return rc; | ||
468 | } | ||
469 | |||
470 | /** | ||
471 | * ibmvfc_set_host_action - Set the next init action for the host | ||
472 | * @vhost: ibmvfc host struct | ||
473 | * @action: action to perform | ||
474 | * | ||
475 | **/ | ||
476 | static void ibmvfc_set_host_action(struct ibmvfc_host *vhost, | ||
477 | enum ibmvfc_host_action action) | ||
478 | { | ||
479 | switch (action) { | ||
480 | case IBMVFC_HOST_ACTION_ALLOC_TGTS: | ||
481 | if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) | ||
482 | vhost->action = action; | ||
483 | break; | ||
484 | case IBMVFC_HOST_ACTION_INIT_WAIT: | ||
485 | if (vhost->action == IBMVFC_HOST_ACTION_INIT) | ||
486 | vhost->action = action; | ||
487 | break; | ||
488 | case IBMVFC_HOST_ACTION_QUERY: | ||
489 | switch (vhost->action) { | ||
490 | case IBMVFC_HOST_ACTION_INIT_WAIT: | ||
491 | case IBMVFC_HOST_ACTION_NONE: | ||
492 | case IBMVFC_HOST_ACTION_TGT_ADD: | ||
493 | vhost->action = action; | ||
494 | break; | ||
495 | default: | ||
496 | break; | ||
497 | }; | ||
498 | break; | ||
499 | case IBMVFC_HOST_ACTION_TGT_INIT: | ||
500 | if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS) | ||
501 | vhost->action = action; | ||
502 | break; | ||
503 | case IBMVFC_HOST_ACTION_INIT: | ||
504 | case IBMVFC_HOST_ACTION_TGT_DEL: | ||
505 | case IBMVFC_HOST_ACTION_QUERY_TGTS: | ||
506 | case IBMVFC_HOST_ACTION_TGT_ADD: | ||
507 | case IBMVFC_HOST_ACTION_NONE: | ||
508 | default: | ||
509 | vhost->action = action; | ||
510 | break; | ||
511 | }; | ||
512 | } | ||
513 | |||
514 | /** | ||
515 | * ibmvfc_reinit_host - Re-start host initialization (no NPIV Login) | ||
516 | * @vhost: ibmvfc host struct | ||
517 | * | ||
518 | * Return value: | ||
519 | * nothing | ||
520 | **/ | ||
521 | static void ibmvfc_reinit_host(struct ibmvfc_host *vhost) | ||
522 | { | ||
523 | if (vhost->action == IBMVFC_HOST_ACTION_NONE) { | ||
524 | scsi_block_requests(vhost->host); | ||
525 | ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING); | ||
526 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); | ||
527 | } else | ||
528 | vhost->reinit = 1; | ||
529 | |||
530 | wake_up(&vhost->work_wait_q); | ||
531 | } | ||
532 | |||
533 | /** | ||
534 | * ibmvfc_link_down - Handle a link down event from the adapter | ||
535 | * @vhost: ibmvfc host struct | ||
536 | * @state: ibmvfc host state to enter | ||
537 | * | ||
538 | **/ | ||
539 | static void ibmvfc_link_down(struct ibmvfc_host *vhost, | ||
540 | enum ibmvfc_host_state state) | ||
541 | { | ||
542 | struct ibmvfc_target *tgt; | ||
543 | |||
544 | ENTER; | ||
545 | scsi_block_requests(vhost->host); | ||
546 | list_for_each_entry(tgt, &vhost->targets, queue) | ||
547 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | ||
548 | ibmvfc_set_host_state(vhost, state); | ||
549 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); | ||
550 | vhost->events_to_log |= IBMVFC_AE_LINKDOWN; | ||
551 | wake_up(&vhost->work_wait_q); | ||
552 | LEAVE; | ||
553 | } | ||
554 | |||
555 | /** | ||
556 | * ibmvfc_init_host - Start host initialization | ||
557 | * @vhost: ibmvfc host struct | ||
558 | * | ||
559 | * Return value: | ||
560 | * nothing | ||
561 | **/ | ||
562 | static void ibmvfc_init_host(struct ibmvfc_host *vhost) | ||
563 | { | ||
564 | struct ibmvfc_target *tgt; | ||
565 | |||
566 | if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { | ||
567 | if (++vhost->init_retries > IBMVFC_MAX_INIT_RETRIES) { | ||
568 | dev_err(vhost->dev, | ||
569 | "Host initialization retries exceeded. Taking adapter offline\n"); | ||
570 | ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); | ||
571 | return; | ||
572 | } | ||
573 | } | ||
574 | |||
575 | if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { | ||
576 | list_for_each_entry(tgt, &vhost->targets, queue) | ||
577 | tgt->need_login = 1; | ||
578 | scsi_block_requests(vhost->host); | ||
579 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); | ||
580 | vhost->job_step = ibmvfc_npiv_login; | ||
581 | wake_up(&vhost->work_wait_q); | ||
582 | } | ||
583 | } | ||
584 | |||
585 | /** | ||
586 | * ibmvfc_send_crq - Send a CRQ | ||
587 | * @vhost: ibmvfc host struct | ||
588 | * @word1: the first 64 bits of the data | ||
589 | * @word2: the second 64 bits of the data | ||
590 | * | ||
591 | * Return value: | ||
592 | * 0 on success / other on failure | ||
593 | **/ | ||
594 | static int ibmvfc_send_crq(struct ibmvfc_host *vhost, u64 word1, u64 word2) | ||
595 | { | ||
596 | struct vio_dev *vdev = to_vio_dev(vhost->dev); | ||
597 | return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2); | ||
598 | } | ||
599 | |||
600 | /** | ||
601 | * ibmvfc_send_crq_init - Send a CRQ init message | ||
602 | * @vhost: ibmvfc host struct | ||
603 | * | ||
604 | * Return value: | ||
605 | * 0 on success / other on failure | ||
606 | **/ | ||
607 | static int ibmvfc_send_crq_init(struct ibmvfc_host *vhost) | ||
608 | { | ||
609 | ibmvfc_dbg(vhost, "Sending CRQ init\n"); | ||
610 | return ibmvfc_send_crq(vhost, 0xC001000000000000LL, 0); | ||
611 | } | ||
612 | |||
613 | /** | ||
614 | * ibmvfc_send_crq_init_complete - Send a CRQ init complete message | ||
615 | * @vhost: ibmvfc host struct | ||
616 | * | ||
617 | * Return value: | ||
618 | * 0 on success / other on failure | ||
619 | **/ | ||
620 | static int ibmvfc_send_crq_init_complete(struct ibmvfc_host *vhost) | ||
621 | { | ||
622 | ibmvfc_dbg(vhost, "Sending CRQ init complete\n"); | ||
623 | return ibmvfc_send_crq(vhost, 0xC002000000000000LL, 0); | ||
624 | } | ||
625 | |||
626 | /** | ||
627 | * ibmvfc_release_crq_queue - Deallocates data and unregisters CRQ | ||
628 | * @vhost: ibmvfc host struct | ||
629 | * | ||
630 | * Frees irq, deallocates a page for messages, unmaps dma, and unregisters | ||
631 | * the crq with the hypervisor. | ||
632 | **/ | ||
633 | static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost) | ||
634 | { | ||
635 | long rc; | ||
636 | struct vio_dev *vdev = to_vio_dev(vhost->dev); | ||
637 | struct ibmvfc_crq_queue *crq = &vhost->crq; | ||
638 | |||
639 | ibmvfc_dbg(vhost, "Releasing CRQ\n"); | ||
640 | free_irq(vdev->irq, vhost); | ||
641 | do { | ||
642 | rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); | ||
643 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
644 | |||
645 | vhost->state = IBMVFC_NO_CRQ; | ||
646 | dma_unmap_single(vhost->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); | ||
647 | free_page((unsigned long)crq->msgs); | ||
648 | } | ||
649 | |||
650 | /** | ||
651 | * ibmvfc_reenable_crq_queue - reenables the CRQ | ||
652 | * @vhost: ibmvfc host struct | ||
653 | * | ||
654 | * Return value: | ||
655 | * 0 on success / other on failure | ||
656 | **/ | ||
657 | static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost) | ||
658 | { | ||
659 | int rc; | ||
660 | struct vio_dev *vdev = to_vio_dev(vhost->dev); | ||
661 | |||
662 | /* Re-enable the CRQ */ | ||
663 | do { | ||
664 | rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address); | ||
665 | } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
666 | |||
667 | if (rc) | ||
668 | dev_err(vhost->dev, "Error enabling adapter (rc=%d)\n", rc); | ||
669 | |||
670 | return rc; | ||
671 | } | ||
672 | |||
673 | /** | ||
674 | * ibmvfc_reset_crq - resets a crq after a failure | ||
675 | * @vhost: ibmvfc host struct | ||
676 | * | ||
677 | * Return value: | ||
678 | * 0 on success / other on failure | ||
679 | **/ | ||
680 | static int ibmvfc_reset_crq(struct ibmvfc_host *vhost) | ||
681 | { | ||
682 | int rc; | ||
683 | struct vio_dev *vdev = to_vio_dev(vhost->dev); | ||
684 | struct ibmvfc_crq_queue *crq = &vhost->crq; | ||
685 | |||
686 | /* Close the CRQ */ | ||
687 | do { | ||
688 | rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); | ||
689 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
690 | |||
691 | vhost->state = IBMVFC_NO_CRQ; | ||
692 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); | ||
693 | |||
694 | /* Clean out the queue */ | ||
695 | memset(crq->msgs, 0, PAGE_SIZE); | ||
696 | crq->cur = 0; | ||
697 | |||
698 | /* And re-open it again */ | ||
699 | rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, | ||
700 | crq->msg_token, PAGE_SIZE); | ||
701 | |||
702 | if (rc == H_CLOSED) | ||
703 | /* Adapter is good, but other end is not ready */ | ||
704 | dev_warn(vhost->dev, "Partner adapter not ready\n"); | ||
705 | else if (rc != 0) | ||
706 | dev_warn(vhost->dev, "Couldn't register crq (rc=%d)\n", rc); | ||
707 | |||
708 | return rc; | ||
709 | } | ||
710 | |||
711 | /** | ||
712 | * ibmvfc_valid_event - Determines if event is valid. | ||
713 | * @pool: event_pool that contains the event | ||
714 | * @evt: ibmvfc event to be checked for validity | ||
715 | * | ||
716 | * Return value: | ||
717 | * 1 if event is valid / 0 if event is not valid | ||
718 | **/ | ||
719 | static int ibmvfc_valid_event(struct ibmvfc_event_pool *pool, | ||
720 | struct ibmvfc_event *evt) | ||
721 | { | ||
722 | int index = evt - pool->events; | ||
723 | if (index < 0 || index >= pool->size) /* outside of bounds */ | ||
724 | return 0; | ||
725 | if (evt != pool->events + index) /* unaligned */ | ||
726 | return 0; | ||
727 | return 1; | ||
728 | } | ||
729 | |||
730 | /** | ||
731 | * ibmvfc_free_event - Free the specified event | ||
732 | * @evt: ibmvfc_event to be freed | ||
733 | * | ||
734 | **/ | ||
735 | static void ibmvfc_free_event(struct ibmvfc_event *evt) | ||
736 | { | ||
737 | struct ibmvfc_host *vhost = evt->vhost; | ||
738 | struct ibmvfc_event_pool *pool = &vhost->pool; | ||
739 | |||
740 | BUG_ON(!ibmvfc_valid_event(pool, evt)); | ||
741 | BUG_ON(atomic_inc_return(&evt->free) != 1); | ||
742 | list_add_tail(&evt->queue, &vhost->free); | ||
743 | } | ||
744 | |||
745 | /** | ||
746 | * ibmvfc_scsi_eh_done - EH done function for queuecommand commands | ||
747 | * @evt: ibmvfc event struct | ||
748 | * | ||
749 | * This function does not setup any error status, that must be done | ||
750 | * before this function gets called. | ||
751 | **/ | ||
752 | static void ibmvfc_scsi_eh_done(struct ibmvfc_event *evt) | ||
753 | { | ||
754 | struct scsi_cmnd *cmnd = evt->cmnd; | ||
755 | |||
756 | if (cmnd) { | ||
757 | scsi_dma_unmap(cmnd); | ||
758 | cmnd->scsi_done(cmnd); | ||
759 | } | ||
760 | |||
761 | ibmvfc_free_event(evt); | ||
762 | } | ||
763 | |||
764 | /** | ||
765 | * ibmvfc_fail_request - Fail request with specified error code | ||
766 | * @evt: ibmvfc event struct | ||
767 | * @error_code: error code to fail request with | ||
768 | * | ||
769 | * Return value: | ||
770 | * none | ||
771 | **/ | ||
772 | static void ibmvfc_fail_request(struct ibmvfc_event *evt, int error_code) | ||
773 | { | ||
774 | if (evt->cmnd) { | ||
775 | evt->cmnd->result = (error_code << 16); | ||
776 | evt->done = ibmvfc_scsi_eh_done; | ||
777 | } else | ||
778 | evt->xfer_iu->mad_common.status = IBMVFC_MAD_DRIVER_FAILED; | ||
779 | |||
780 | list_del(&evt->queue); | ||
781 | del_timer(&evt->timer); | ||
782 | ibmvfc_trc_end(evt); | ||
783 | evt->done(evt); | ||
784 | } | ||
785 | |||
786 | /** | ||
787 | * ibmvfc_purge_requests - Our virtual adapter just shut down. Purge any sent requests | ||
788 | * @vhost: ibmvfc host struct | ||
789 | * @error_code: error code to fail requests with | ||
790 | * | ||
791 | * Return value: | ||
792 | * none | ||
793 | **/ | ||
794 | static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code) | ||
795 | { | ||
796 | struct ibmvfc_event *evt, *pos; | ||
797 | |||
798 | ibmvfc_dbg(vhost, "Purging all requests\n"); | ||
799 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) | ||
800 | ibmvfc_fail_request(evt, error_code); | ||
801 | } | ||
802 | |||
803 | /** | ||
804 | * __ibmvfc_reset_host - Reset the connection to the server (no locking) | ||
805 | * @vhost: struct ibmvfc host to reset | ||
806 | **/ | ||
807 | static void __ibmvfc_reset_host(struct ibmvfc_host *vhost) | ||
808 | { | ||
809 | int rc; | ||
810 | |||
811 | scsi_block_requests(vhost->host); | ||
812 | ibmvfc_purge_requests(vhost, DID_ERROR); | ||
813 | if ((rc = ibmvfc_reset_crq(vhost)) || | ||
814 | (rc = ibmvfc_send_crq_init(vhost)) || | ||
815 | (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) { | ||
816 | dev_err(vhost->dev, "Error after reset rc=%d\n", rc); | ||
817 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
818 | } else | ||
819 | ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); | ||
820 | } | ||
821 | |||
822 | /** | ||
823 | * ibmvfc_reset_host - Reset the connection to the server | ||
824 | * @vhost: struct ibmvfc host to reset | ||
825 | **/ | ||
826 | static void ibmvfc_reset_host(struct ibmvfc_host *vhost) | ||
827 | { | ||
828 | unsigned long flags; | ||
829 | |||
830 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
831 | __ibmvfc_reset_host(vhost); | ||
832 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
833 | } | ||
834 | |||
835 | /** | ||
836 | * ibmvfc_retry_host_init - Retry host initialization if allowed | ||
837 | * @vhost: ibmvfc host struct | ||
838 | * | ||
839 | **/ | ||
840 | static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost) | ||
841 | { | ||
842 | if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { | ||
843 | if (++vhost->init_retries > IBMVFC_MAX_INIT_RETRIES) { | ||
844 | dev_err(vhost->dev, | ||
845 | "Host initialization retries exceeded. Taking adapter offline\n"); | ||
846 | ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); | ||
847 | } else if (vhost->init_retries == IBMVFC_MAX_INIT_RETRIES) | ||
848 | __ibmvfc_reset_host(vhost); | ||
849 | else | ||
850 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); | ||
851 | } | ||
852 | |||
853 | wake_up(&vhost->work_wait_q); | ||
854 | } | ||
855 | |||
856 | /** | ||
857 | * __ibmvfc_find_target - Find the specified scsi_target (no locking) | ||
858 | * @starget: scsi target struct | ||
859 | * | ||
860 | * Return value: | ||
861 | * ibmvfc_target struct / NULL if not found | ||
862 | **/ | ||
863 | static struct ibmvfc_target *__ibmvfc_find_target(struct scsi_target *starget) | ||
864 | { | ||
865 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
866 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
867 | struct ibmvfc_target *tgt; | ||
868 | |||
869 | list_for_each_entry(tgt, &vhost->targets, queue) | ||
870 | if (tgt->target_id == starget->id) | ||
871 | return tgt; | ||
872 | return NULL; | ||
873 | } | ||
874 | |||
875 | /** | ||
876 | * ibmvfc_find_target - Find the specified scsi_target | ||
877 | * @starget: scsi target struct | ||
878 | * | ||
879 | * Return value: | ||
880 | * ibmvfc_target struct / NULL if not found | ||
881 | **/ | ||
882 | static struct ibmvfc_target *ibmvfc_find_target(struct scsi_target *starget) | ||
883 | { | ||
884 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
885 | struct ibmvfc_target *tgt; | ||
886 | unsigned long flags; | ||
887 | |||
888 | spin_lock_irqsave(shost->host_lock, flags); | ||
889 | tgt = __ibmvfc_find_target(starget); | ||
890 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
891 | return tgt; | ||
892 | } | ||
893 | |||
894 | /** | ||
895 | * ibmvfc_get_host_speed - Get host port speed | ||
896 | * @shost: scsi host struct | ||
897 | * | ||
898 | * Return value: | ||
899 | * none | ||
900 | **/ | ||
901 | static void ibmvfc_get_host_speed(struct Scsi_Host *shost) | ||
902 | { | ||
903 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
904 | unsigned long flags; | ||
905 | |||
906 | spin_lock_irqsave(shost->host_lock, flags); | ||
907 | if (vhost->state == IBMVFC_ACTIVE) { | ||
908 | switch (vhost->login_buf->resp.link_speed / 100) { | ||
909 | case 1: | ||
910 | fc_host_speed(shost) = FC_PORTSPEED_1GBIT; | ||
911 | break; | ||
912 | case 2: | ||
913 | fc_host_speed(shost) = FC_PORTSPEED_2GBIT; | ||
914 | break; | ||
915 | case 4: | ||
916 | fc_host_speed(shost) = FC_PORTSPEED_4GBIT; | ||
917 | break; | ||
918 | case 8: | ||
919 | fc_host_speed(shost) = FC_PORTSPEED_8GBIT; | ||
920 | break; | ||
921 | case 10: | ||
922 | fc_host_speed(shost) = FC_PORTSPEED_10GBIT; | ||
923 | break; | ||
924 | case 16: | ||
925 | fc_host_speed(shost) = FC_PORTSPEED_16GBIT; | ||
926 | break; | ||
927 | default: | ||
928 | ibmvfc_log(vhost, 3, "Unknown port speed: %ld Gbit\n", | ||
929 | vhost->login_buf->resp.link_speed / 100); | ||
930 | fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; | ||
931 | break; | ||
932 | } | ||
933 | } else | ||
934 | fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; | ||
935 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
936 | } | ||
937 | |||
938 | /** | ||
939 | * ibmvfc_get_host_port_state - Get host port state | ||
940 | * @shost: scsi host struct | ||
941 | * | ||
942 | * Return value: | ||
943 | * none | ||
944 | **/ | ||
945 | static void ibmvfc_get_host_port_state(struct Scsi_Host *shost) | ||
946 | { | ||
947 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
948 | unsigned long flags; | ||
949 | |||
950 | spin_lock_irqsave(shost->host_lock, flags); | ||
951 | switch (vhost->state) { | ||
952 | case IBMVFC_INITIALIZING: | ||
953 | case IBMVFC_ACTIVE: | ||
954 | fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; | ||
955 | break; | ||
956 | case IBMVFC_LINK_DOWN: | ||
957 | fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; | ||
958 | break; | ||
959 | case IBMVFC_LINK_DEAD: | ||
960 | case IBMVFC_HOST_OFFLINE: | ||
961 | fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; | ||
962 | break; | ||
963 | case IBMVFC_HALTED: | ||
964 | fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED; | ||
965 | break; | ||
966 | default: | ||
967 | ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state); | ||
968 | fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; | ||
969 | break; | ||
970 | } | ||
971 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
972 | } | ||
973 | |||
974 | /** | ||
975 | * ibmvfc_set_rport_dev_loss_tmo - Set rport's device loss timeout | ||
976 | * @rport: rport struct | ||
977 | * @timeout: timeout value | ||
978 | * | ||
979 | * Return value: | ||
980 | * none | ||
981 | **/ | ||
982 | static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) | ||
983 | { | ||
984 | if (timeout) | ||
985 | rport->dev_loss_tmo = timeout; | ||
986 | else | ||
987 | rport->dev_loss_tmo = 1; | ||
988 | } | ||
989 | |||
990 | /** | ||
991 | * ibmvfc_get_starget_node_name - Get SCSI target's node name | ||
992 | * @starget: scsi target struct | ||
993 | * | ||
994 | * Return value: | ||
995 | * none | ||
996 | **/ | ||
997 | static void ibmvfc_get_starget_node_name(struct scsi_target *starget) | ||
998 | { | ||
999 | struct ibmvfc_target *tgt = ibmvfc_find_target(starget); | ||
1000 | fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0; | ||
1001 | } | ||
1002 | |||
1003 | /** | ||
1004 | * ibmvfc_get_starget_port_name - Get SCSI target's port name | ||
1005 | * @starget: scsi target struct | ||
1006 | * | ||
1007 | * Return value: | ||
1008 | * none | ||
1009 | **/ | ||
1010 | static void ibmvfc_get_starget_port_name(struct scsi_target *starget) | ||
1011 | { | ||
1012 | struct ibmvfc_target *tgt = ibmvfc_find_target(starget); | ||
1013 | fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0; | ||
1014 | } | ||
1015 | |||
1016 | /** | ||
1017 | * ibmvfc_get_starget_port_id - Get SCSI target's port ID | ||
1018 | * @starget: scsi target struct | ||
1019 | * | ||
1020 | * Return value: | ||
1021 | * none | ||
1022 | **/ | ||
1023 | static void ibmvfc_get_starget_port_id(struct scsi_target *starget) | ||
1024 | { | ||
1025 | struct ibmvfc_target *tgt = ibmvfc_find_target(starget); | ||
1026 | fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1; | ||
1027 | } | ||
1028 | |||
1029 | /** | ||
1030 | * ibmvfc_wait_while_resetting - Wait while the host resets | ||
1031 | * @vhost: ibmvfc host struct | ||
1032 | * | ||
1033 | * Return value: | ||
1034 | * 0 on success / other on failure | ||
1035 | **/ | ||
1036 | static int ibmvfc_wait_while_resetting(struct ibmvfc_host *vhost) | ||
1037 | { | ||
1038 | long timeout = wait_event_timeout(vhost->init_wait_q, | ||
1039 | (vhost->state == IBMVFC_ACTIVE || | ||
1040 | vhost->state == IBMVFC_HOST_OFFLINE || | ||
1041 | vhost->state == IBMVFC_LINK_DEAD), | ||
1042 | (init_timeout * HZ)); | ||
1043 | |||
1044 | return timeout ? 0 : -EIO; | ||
1045 | } | ||
1046 | |||
1047 | /** | ||
1048 | * ibmvfc_issue_fc_host_lip - Re-initiate link initialization | ||
1049 | * @shost: scsi host struct | ||
1050 | * | ||
1051 | * Return value: | ||
1052 | * 0 on success / other on failure | ||
1053 | **/ | ||
1054 | static int ibmvfc_issue_fc_host_lip(struct Scsi_Host *shost) | ||
1055 | { | ||
1056 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
1057 | |||
1058 | dev_err(vhost->dev, "Initiating host LIP. Resetting connection\n"); | ||
1059 | ibmvfc_reset_host(vhost); | ||
1060 | return ibmvfc_wait_while_resetting(vhost); | ||
1061 | } | ||
1062 | |||
1063 | /** | ||
1064 | * ibmvfc_gather_partition_info - Gather info about the LPAR | ||
1065 | * | ||
1066 | * Return value: | ||
1067 | * none | ||
1068 | **/ | ||
1069 | static void ibmvfc_gather_partition_info(struct ibmvfc_host *vhost) | ||
1070 | { | ||
1071 | struct device_node *rootdn; | ||
1072 | const char *name; | ||
1073 | const unsigned int *num; | ||
1074 | |||
1075 | rootdn = of_find_node_by_path("/"); | ||
1076 | if (!rootdn) | ||
1077 | return; | ||
1078 | |||
1079 | name = of_get_property(rootdn, "ibm,partition-name", NULL); | ||
1080 | if (name) | ||
1081 | strncpy(vhost->partition_name, name, sizeof(vhost->partition_name)); | ||
1082 | num = of_get_property(rootdn, "ibm,partition-no", NULL); | ||
1083 | if (num) | ||
1084 | vhost->partition_number = *num; | ||
1085 | of_node_put(rootdn); | ||
1086 | } | ||
1087 | |||
1088 | /** | ||
1089 | * ibmvfc_set_login_info - Setup info for NPIV login | ||
1090 | * @vhost: ibmvfc host struct | ||
1091 | * | ||
1092 | * Return value: | ||
1093 | * none | ||
1094 | **/ | ||
1095 | static void ibmvfc_set_login_info(struct ibmvfc_host *vhost) | ||
1096 | { | ||
1097 | struct ibmvfc_npiv_login *login_info = &vhost->login_info; | ||
1098 | struct device_node *of_node = vhost->dev->archdata.of_node; | ||
1099 | const char *location; | ||
1100 | |||
1101 | memset(login_info, 0, sizeof(*login_info)); | ||
1102 | |||
1103 | login_info->ostype = IBMVFC_OS_LINUX; | ||
1104 | login_info->max_dma_len = IBMVFC_MAX_SECTORS << 9; | ||
1105 | login_info->max_payload = sizeof(struct ibmvfc_fcp_cmd_iu); | ||
1106 | login_info->max_response = sizeof(struct ibmvfc_fcp_rsp); | ||
1107 | login_info->partition_num = vhost->partition_number; | ||
1108 | login_info->vfc_frame_version = 1; | ||
1109 | login_info->fcp_version = 3; | ||
1110 | if (vhost->client_migrated) | ||
1111 | login_info->flags = IBMVFC_CLIENT_MIGRATED; | ||
1112 | |||
1113 | login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ; | ||
1114 | login_info->capabilities = IBMVFC_CAN_MIGRATE; | ||
1115 | login_info->async.va = vhost->async_crq.msg_token; | ||
1116 | login_info->async.len = vhost->async_crq.size; | ||
1117 | strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME); | ||
1118 | strncpy(login_info->device_name, | ||
1119 | vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME); | ||
1120 | |||
1121 | location = of_get_property(of_node, "ibm,loc-code", NULL); | ||
1122 | location = location ? location : vhost->dev->bus_id; | ||
1123 | strncpy(login_info->drc_name, location, IBMVFC_MAX_NAME); | ||
1124 | } | ||
1125 | |||
1126 | /** | ||
1127 | * ibmvfc_init_event_pool - Allocates and initializes the event pool for a host | ||
1128 | * @vhost: ibmvfc host who owns the event pool | ||
1129 | * | ||
1130 | * Returns zero on success. | ||
1131 | **/ | ||
1132 | static int ibmvfc_init_event_pool(struct ibmvfc_host *vhost) | ||
1133 | { | ||
1134 | int i; | ||
1135 | struct ibmvfc_event_pool *pool = &vhost->pool; | ||
1136 | |||
1137 | ENTER; | ||
1138 | pool->size = max_requests + IBMVFC_NUM_INTERNAL_REQ; | ||
1139 | pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL); | ||
1140 | if (!pool->events) | ||
1141 | return -ENOMEM; | ||
1142 | |||
1143 | pool->iu_storage = dma_alloc_coherent(vhost->dev, | ||
1144 | pool->size * sizeof(*pool->iu_storage), | ||
1145 | &pool->iu_token, 0); | ||
1146 | |||
1147 | if (!pool->iu_storage) { | ||
1148 | kfree(pool->events); | ||
1149 | return -ENOMEM; | ||
1150 | } | ||
1151 | |||
1152 | for (i = 0; i < pool->size; ++i) { | ||
1153 | struct ibmvfc_event *evt = &pool->events[i]; | ||
1154 | atomic_set(&evt->free, 1); | ||
1155 | evt->crq.valid = 0x80; | ||
1156 | evt->crq.ioba = pool->iu_token + (sizeof(*evt->xfer_iu) * i); | ||
1157 | evt->xfer_iu = pool->iu_storage + i; | ||
1158 | evt->vhost = vhost; | ||
1159 | evt->ext_list = NULL; | ||
1160 | list_add_tail(&evt->queue, &vhost->free); | ||
1161 | } | ||
1162 | |||
1163 | LEAVE; | ||
1164 | return 0; | ||
1165 | } | ||
1166 | |||
1167 | /** | ||
1168 | * ibmvfc_free_event_pool - Frees memory of the event pool of a host | ||
1169 | * @vhost: ibmvfc host who owns the event pool | ||
1170 | * | ||
1171 | **/ | ||
1172 | static void ibmvfc_free_event_pool(struct ibmvfc_host *vhost) | ||
1173 | { | ||
1174 | int i; | ||
1175 | struct ibmvfc_event_pool *pool = &vhost->pool; | ||
1176 | |||
1177 | ENTER; | ||
1178 | for (i = 0; i < pool->size; ++i) { | ||
1179 | list_del(&pool->events[i].queue); | ||
1180 | BUG_ON(atomic_read(&pool->events[i].free) != 1); | ||
1181 | if (pool->events[i].ext_list) | ||
1182 | dma_pool_free(vhost->sg_pool, | ||
1183 | pool->events[i].ext_list, | ||
1184 | pool->events[i].ext_list_token); | ||
1185 | } | ||
1186 | |||
1187 | kfree(pool->events); | ||
1188 | dma_free_coherent(vhost->dev, | ||
1189 | pool->size * sizeof(*pool->iu_storage), | ||
1190 | pool->iu_storage, pool->iu_token); | ||
1191 | LEAVE; | ||
1192 | } | ||
1193 | |||
1194 | /** | ||
1195 | * ibmvfc_get_event - Gets the next free event in pool | ||
1196 | * @vhost: ibmvfc host struct | ||
1197 | * | ||
1198 | * Returns a free event from the pool. | ||
1199 | **/ | ||
1200 | static struct ibmvfc_event *ibmvfc_get_event(struct ibmvfc_host *vhost) | ||
1201 | { | ||
1202 | struct ibmvfc_event *evt; | ||
1203 | |||
1204 | BUG_ON(list_empty(&vhost->free)); | ||
1205 | evt = list_entry(vhost->free.next, struct ibmvfc_event, queue); | ||
1206 | atomic_set(&evt->free, 0); | ||
1207 | list_del(&evt->queue); | ||
1208 | return evt; | ||
1209 | } | ||
1210 | |||
1211 | /** | ||
1212 | * ibmvfc_init_event - Initialize fields in an event struct that are always | ||
1213 | * required. | ||
1214 | * @evt: The event | ||
1215 | * @done: Routine to call when the event is responded to | ||
1216 | * @format: SRP or MAD format | ||
1217 | **/ | ||
1218 | static void ibmvfc_init_event(struct ibmvfc_event *evt, | ||
1219 | void (*done) (struct ibmvfc_event *), u8 format) | ||
1220 | { | ||
1221 | evt->cmnd = NULL; | ||
1222 | evt->sync_iu = NULL; | ||
1223 | evt->crq.format = format; | ||
1224 | evt->done = done; | ||
1225 | } | ||
1226 | |||
1227 | /** | ||
1228 | * ibmvfc_map_sg_list - Initialize scatterlist | ||
1229 | * @scmd: scsi command struct | ||
1230 | * @nseg: number of scatterlist segments | ||
1231 | * @md: memory descriptor list to initialize | ||
1232 | **/ | ||
1233 | static void ibmvfc_map_sg_list(struct scsi_cmnd *scmd, int nseg, | ||
1234 | struct srp_direct_buf *md) | ||
1235 | { | ||
1236 | int i; | ||
1237 | struct scatterlist *sg; | ||
1238 | |||
1239 | scsi_for_each_sg(scmd, sg, nseg, i) { | ||
1240 | md[i].va = sg_dma_address(sg); | ||
1241 | md[i].len = sg_dma_len(sg); | ||
1242 | md[i].key = 0; | ||
1243 | } | ||
1244 | } | ||
1245 | |||
1246 | /** | ||
1247 | * ibmvfc_map_sg_data - Maps dma for a scatterlist and initializes decriptor fields | ||
1248 | * @scmd: Scsi_Cmnd with the scatterlist | ||
1249 | * @evt: ibmvfc event struct | ||
1250 | * @vfc_cmd: vfc_cmd that contains the memory descriptor | ||
1251 | * @dev: device for which to map dma memory | ||
1252 | * | ||
1253 | * Returns: | ||
1254 | * 0 on success / non-zero on failure | ||
1255 | **/ | ||
1256 | static int ibmvfc_map_sg_data(struct scsi_cmnd *scmd, | ||
1257 | struct ibmvfc_event *evt, | ||
1258 | struct ibmvfc_cmd *vfc_cmd, struct device *dev) | ||
1259 | { | ||
1260 | |||
1261 | int sg_mapped; | ||
1262 | struct srp_direct_buf *data = &vfc_cmd->ioba; | ||
1263 | struct ibmvfc_host *vhost = dev_get_drvdata(dev); | ||
1264 | |||
1265 | sg_mapped = scsi_dma_map(scmd); | ||
1266 | if (!sg_mapped) { | ||
1267 | vfc_cmd->flags |= IBMVFC_NO_MEM_DESC; | ||
1268 | return 0; | ||
1269 | } else if (unlikely(sg_mapped < 0)) { | ||
1270 | if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) | ||
1271 | scmd_printk(KERN_ERR, scmd, "Failed to map DMA buffer for command\n"); | ||
1272 | return sg_mapped; | ||
1273 | } | ||
1274 | |||
1275 | if (scmd->sc_data_direction == DMA_TO_DEVICE) { | ||
1276 | vfc_cmd->flags |= IBMVFC_WRITE; | ||
1277 | vfc_cmd->iu.add_cdb_len |= IBMVFC_WRDATA; | ||
1278 | } else { | ||
1279 | vfc_cmd->flags |= IBMVFC_READ; | ||
1280 | vfc_cmd->iu.add_cdb_len |= IBMVFC_RDDATA; | ||
1281 | } | ||
1282 | |||
1283 | if (sg_mapped == 1) { | ||
1284 | ibmvfc_map_sg_list(scmd, sg_mapped, data); | ||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1288 | vfc_cmd->flags |= IBMVFC_SCATTERLIST; | ||
1289 | |||
1290 | if (!evt->ext_list) { | ||
1291 | evt->ext_list = dma_pool_alloc(vhost->sg_pool, GFP_ATOMIC, | ||
1292 | &evt->ext_list_token); | ||
1293 | |||
1294 | if (!evt->ext_list) { | ||
1295 | scmd_printk(KERN_ERR, scmd, "Can't allocate memory for scatterlist\n"); | ||
1296 | return -ENOMEM; | ||
1297 | } | ||
1298 | } | ||
1299 | |||
1300 | ibmvfc_map_sg_list(scmd, sg_mapped, evt->ext_list); | ||
1301 | |||
1302 | data->va = evt->ext_list_token; | ||
1303 | data->len = sg_mapped * sizeof(struct srp_direct_buf); | ||
1304 | data->key = 0; | ||
1305 | return 0; | ||
1306 | } | ||
1307 | |||
1308 | /** | ||
1309 | * ibmvfc_timeout - Internal command timeout handler | ||
1310 | * @evt: struct ibmvfc_event that timed out | ||
1311 | * | ||
1312 | * Called when an internally generated command times out | ||
1313 | **/ | ||
1314 | static void ibmvfc_timeout(struct ibmvfc_event *evt) | ||
1315 | { | ||
1316 | struct ibmvfc_host *vhost = evt->vhost; | ||
1317 | dev_err(vhost->dev, "Command timed out (%p). Resetting connection\n", evt); | ||
1318 | ibmvfc_reset_host(vhost); | ||
1319 | } | ||
1320 | |||
1321 | /** | ||
1322 | * ibmvfc_send_event - Transforms event to u64 array and calls send_crq() | ||
1323 | * @evt: event to be sent | ||
1324 | * @vhost: ibmvfc host struct | ||
1325 | * @timeout: timeout in seconds - 0 means do not time command | ||
1326 | * | ||
1327 | * Returns the value returned from ibmvfc_send_crq(). (Zero for success) | ||
1328 | **/ | ||
1329 | static int ibmvfc_send_event(struct ibmvfc_event *evt, | ||
1330 | struct ibmvfc_host *vhost, unsigned long timeout) | ||
1331 | { | ||
1332 | u64 *crq_as_u64 = (u64 *) &evt->crq; | ||
1333 | int rc; | ||
1334 | |||
1335 | /* Copy the IU into the transfer area */ | ||
1336 | *evt->xfer_iu = evt->iu; | ||
1337 | if (evt->crq.format == IBMVFC_CMD_FORMAT) | ||
1338 | evt->xfer_iu->cmd.tag = (u64)evt; | ||
1339 | else if (evt->crq.format == IBMVFC_MAD_FORMAT) | ||
1340 | evt->xfer_iu->mad_common.tag = (u64)evt; | ||
1341 | else | ||
1342 | BUG(); | ||
1343 | |||
1344 | list_add_tail(&evt->queue, &vhost->sent); | ||
1345 | init_timer(&evt->timer); | ||
1346 | |||
1347 | if (timeout) { | ||
1348 | evt->timer.data = (unsigned long) evt; | ||
1349 | evt->timer.expires = jiffies + (timeout * HZ); | ||
1350 | evt->timer.function = (void (*)(unsigned long))ibmvfc_timeout; | ||
1351 | add_timer(&evt->timer); | ||
1352 | } | ||
1353 | |||
1354 | if ((rc = ibmvfc_send_crq(vhost, crq_as_u64[0], crq_as_u64[1]))) { | ||
1355 | list_del(&evt->queue); | ||
1356 | del_timer(&evt->timer); | ||
1357 | |||
1358 | /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY. | ||
1359 | * Firmware will send a CRQ with a transport event (0xFF) to | ||
1360 | * tell this client what has happened to the transport. This | ||
1361 | * will be handled in ibmvfc_handle_crq() | ||
1362 | */ | ||
1363 | if (rc == H_CLOSED) { | ||
1364 | if (printk_ratelimit()) | ||
1365 | dev_warn(vhost->dev, "Send warning. Receive queue closed, will retry.\n"); | ||
1366 | if (evt->cmnd) | ||
1367 | scsi_dma_unmap(evt->cmnd); | ||
1368 | ibmvfc_free_event(evt); | ||
1369 | return SCSI_MLQUEUE_HOST_BUSY; | ||
1370 | } | ||
1371 | |||
1372 | dev_err(vhost->dev, "Send error (rc=%d)\n", rc); | ||
1373 | if (evt->cmnd) { | ||
1374 | evt->cmnd->result = DID_ERROR << 16; | ||
1375 | evt->done = ibmvfc_scsi_eh_done; | ||
1376 | } else | ||
1377 | evt->xfer_iu->mad_common.status = IBMVFC_MAD_CRQ_ERROR; | ||
1378 | |||
1379 | evt->done(evt); | ||
1380 | } else | ||
1381 | ibmvfc_trc_start(evt); | ||
1382 | |||
1383 | return 0; | ||
1384 | } | ||
1385 | |||
1386 | /** | ||
1387 | * ibmvfc_log_error - Log an error for the failed command if appropriate | ||
1388 | * @evt: ibmvfc event to log | ||
1389 | * | ||
1390 | **/ | ||
1391 | static void ibmvfc_log_error(struct ibmvfc_event *evt) | ||
1392 | { | ||
1393 | struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; | ||
1394 | struct ibmvfc_host *vhost = evt->vhost; | ||
1395 | struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; | ||
1396 | struct scsi_cmnd *cmnd = evt->cmnd; | ||
1397 | const char *err = unknown_error; | ||
1398 | int index = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); | ||
1399 | int logerr = 0; | ||
1400 | int rsp_code = 0; | ||
1401 | |||
1402 | if (index >= 0) { | ||
1403 | logerr = cmd_status[index].log; | ||
1404 | err = cmd_status[index].name; | ||
1405 | } | ||
1406 | |||
1407 | if (!logerr && (vhost->log_level <= IBMVFC_DEFAULT_LOG_LEVEL)) | ||
1408 | return; | ||
1409 | |||
1410 | if (rsp->flags & FCP_RSP_LEN_VALID) | ||
1411 | rsp_code = rsp->data.info.rsp_code; | ||
1412 | |||
1413 | scmd_printk(KERN_ERR, cmnd, "Command (%02X) failed: %s (%x:%x) " | ||
1414 | "flags: %x fcp_rsp: %x, resid=%d, scsi_status: %x\n", | ||
1415 | cmnd->cmnd[0], err, vfc_cmd->status, vfc_cmd->error, | ||
1416 | rsp->flags, rsp_code, scsi_get_resid(cmnd), rsp->scsi_status); | ||
1417 | } | ||
1418 | |||
1419 | /** | ||
1420 | * ibmvfc_scsi_done - Handle responses from commands | ||
1421 | * @evt: ibmvfc event to be handled | ||
1422 | * | ||
1423 | * Used as a callback when sending scsi cmds. | ||
1424 | **/ | ||
1425 | static void ibmvfc_scsi_done(struct ibmvfc_event *evt) | ||
1426 | { | ||
1427 | struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; | ||
1428 | struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; | ||
1429 | struct scsi_cmnd *cmnd = evt->cmnd; | ||
1430 | int rsp_len = 0; | ||
1431 | int sense_len = rsp->fcp_sense_len; | ||
1432 | |||
1433 | if (cmnd) { | ||
1434 | if (vfc_cmd->response_flags & IBMVFC_ADAPTER_RESID_VALID) | ||
1435 | scsi_set_resid(cmnd, vfc_cmd->adapter_resid); | ||
1436 | else if (rsp->flags & FCP_RESID_UNDER) | ||
1437 | scsi_set_resid(cmnd, rsp->fcp_resid); | ||
1438 | else | ||
1439 | scsi_set_resid(cmnd, 0); | ||
1440 | |||
1441 | if (vfc_cmd->status) { | ||
1442 | cmnd->result = ibmvfc_get_err_result(vfc_cmd); | ||
1443 | |||
1444 | if (rsp->flags & FCP_RSP_LEN_VALID) | ||
1445 | rsp_len = rsp->fcp_rsp_len; | ||
1446 | if ((sense_len + rsp_len) > SCSI_SENSE_BUFFERSIZE) | ||
1447 | sense_len = SCSI_SENSE_BUFFERSIZE - rsp_len; | ||
1448 | if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len) | ||
1449 | memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len); | ||
1450 | |||
1451 | ibmvfc_log_error(evt); | ||
1452 | } | ||
1453 | |||
1454 | if (!cmnd->result && | ||
1455 | (scsi_bufflen(cmnd) - scsi_get_resid(cmnd) < cmnd->underflow)) | ||
1456 | cmnd->result = (DID_ERROR << 16); | ||
1457 | |||
1458 | scsi_dma_unmap(cmnd); | ||
1459 | cmnd->scsi_done(cmnd); | ||
1460 | } | ||
1461 | |||
1462 | ibmvfc_free_event(evt); | ||
1463 | } | ||
1464 | |||
1465 | /** | ||
1466 | * ibmvfc_host_chkready - Check if the host can accept commands | ||
1467 | * @vhost: struct ibmvfc host | ||
1468 | * | ||
1469 | * Returns: | ||
1470 | * 1 if host can accept command / 0 if not | ||
1471 | **/ | ||
1472 | static inline int ibmvfc_host_chkready(struct ibmvfc_host *vhost) | ||
1473 | { | ||
1474 | int result = 0; | ||
1475 | |||
1476 | switch (vhost->state) { | ||
1477 | case IBMVFC_LINK_DEAD: | ||
1478 | case IBMVFC_HOST_OFFLINE: | ||
1479 | result = DID_NO_CONNECT << 16; | ||
1480 | break; | ||
1481 | case IBMVFC_NO_CRQ: | ||
1482 | case IBMVFC_INITIALIZING: | ||
1483 | case IBMVFC_HALTED: | ||
1484 | case IBMVFC_LINK_DOWN: | ||
1485 | result = DID_REQUEUE << 16; | ||
1486 | break; | ||
1487 | case IBMVFC_ACTIVE: | ||
1488 | result = 0; | ||
1489 | break; | ||
1490 | }; | ||
1491 | |||
1492 | return result; | ||
1493 | } | ||
1494 | |||
1495 | /** | ||
1496 | * ibmvfc_queuecommand - The queuecommand function of the scsi template | ||
1497 | * @cmnd: struct scsi_cmnd to be executed | ||
1498 | * @done: Callback function to be called when cmnd is completed | ||
1499 | * | ||
1500 | * Returns: | ||
1501 | * 0 on success / other on failure | ||
1502 | **/ | ||
1503 | static int ibmvfc_queuecommand(struct scsi_cmnd *cmnd, | ||
1504 | void (*done) (struct scsi_cmnd *)) | ||
1505 | { | ||
1506 | struct ibmvfc_host *vhost = shost_priv(cmnd->device->host); | ||
1507 | struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); | ||
1508 | struct ibmvfc_cmd *vfc_cmd; | ||
1509 | struct ibmvfc_event *evt; | ||
1510 | u8 tag[2]; | ||
1511 | int rc; | ||
1512 | |||
1513 | if (unlikely((rc = fc_remote_port_chkready(rport))) || | ||
1514 | unlikely((rc = ibmvfc_host_chkready(vhost)))) { | ||
1515 | cmnd->result = rc; | ||
1516 | done(cmnd); | ||
1517 | return 0; | ||
1518 | } | ||
1519 | |||
1520 | cmnd->result = (DID_OK << 16); | ||
1521 | evt = ibmvfc_get_event(vhost); | ||
1522 | ibmvfc_init_event(evt, ibmvfc_scsi_done, IBMVFC_CMD_FORMAT); | ||
1523 | evt->cmnd = cmnd; | ||
1524 | cmnd->scsi_done = done; | ||
1525 | vfc_cmd = &evt->iu.cmd; | ||
1526 | memset(vfc_cmd, 0, sizeof(*vfc_cmd)); | ||
1527 | vfc_cmd->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); | ||
1528 | vfc_cmd->resp.len = sizeof(vfc_cmd->rsp); | ||
1529 | vfc_cmd->frame_type = IBMVFC_SCSI_FCP_TYPE; | ||
1530 | vfc_cmd->payload_len = sizeof(vfc_cmd->iu); | ||
1531 | vfc_cmd->resp_len = sizeof(vfc_cmd->rsp); | ||
1532 | vfc_cmd->cancel_key = (unsigned long)cmnd->device->hostdata; | ||
1533 | vfc_cmd->tgt_scsi_id = rport->port_id; | ||
1534 | if ((rport->supported_classes & FC_COS_CLASS3) && | ||
1535 | (fc_host_supported_classes(vhost->host) & FC_COS_CLASS3)) | ||
1536 | vfc_cmd->flags = IBMVFC_CLASS_3_ERR; | ||
1537 | vfc_cmd->iu.xfer_len = scsi_bufflen(cmnd); | ||
1538 | int_to_scsilun(cmnd->device->lun, &vfc_cmd->iu.lun); | ||
1539 | memcpy(vfc_cmd->iu.cdb, cmnd->cmnd, cmnd->cmd_len); | ||
1540 | |||
1541 | if (scsi_populate_tag_msg(cmnd, tag)) { | ||
1542 | vfc_cmd->task_tag = tag[1]; | ||
1543 | switch (tag[0]) { | ||
1544 | case MSG_SIMPLE_TAG: | ||
1545 | vfc_cmd->iu.pri_task_attr = IBMVFC_SIMPLE_TASK; | ||
1546 | break; | ||
1547 | case MSG_HEAD_TAG: | ||
1548 | vfc_cmd->iu.pri_task_attr = IBMVFC_HEAD_OF_QUEUE; | ||
1549 | break; | ||
1550 | case MSG_ORDERED_TAG: | ||
1551 | vfc_cmd->iu.pri_task_attr = IBMVFC_ORDERED_TASK; | ||
1552 | break; | ||
1553 | }; | ||
1554 | } | ||
1555 | |||
1556 | if (likely(!(rc = ibmvfc_map_sg_data(cmnd, evt, vfc_cmd, vhost->dev)))) | ||
1557 | return ibmvfc_send_event(evt, vhost, 0); | ||
1558 | |||
1559 | ibmvfc_free_event(evt); | ||
1560 | if (rc == -ENOMEM) | ||
1561 | return SCSI_MLQUEUE_HOST_BUSY; | ||
1562 | |||
1563 | if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) | ||
1564 | scmd_printk(KERN_ERR, cmnd, | ||
1565 | "Failed to map DMA buffer for command. rc=%d\n", rc); | ||
1566 | |||
1567 | cmnd->result = DID_ERROR << 16; | ||
1568 | done(cmnd); | ||
1569 | return 0; | ||
1570 | } | ||
1571 | |||
1572 | /** | ||
1573 | * ibmvfc_sync_completion - Signal that a synchronous command has completed | ||
1574 | * @evt: ibmvfc event struct | ||
1575 | * | ||
1576 | **/ | ||
1577 | static void ibmvfc_sync_completion(struct ibmvfc_event *evt) | ||
1578 | { | ||
1579 | /* copy the response back */ | ||
1580 | if (evt->sync_iu) | ||
1581 | *evt->sync_iu = *evt->xfer_iu; | ||
1582 | |||
1583 | complete(&evt->comp); | ||
1584 | } | ||
1585 | |||
1586 | /** | ||
1587 | * ibmvfc_reset_device - Reset the device with the specified reset type | ||
1588 | * @sdev: scsi device to reset | ||
1589 | * @type: reset type | ||
1590 | * @desc: reset type description for log messages | ||
1591 | * | ||
1592 | * Returns: | ||
1593 | * 0 on success / other on failure | ||
1594 | **/ | ||
1595 | static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc) | ||
1596 | { | ||
1597 | struct ibmvfc_host *vhost = shost_priv(sdev->host); | ||
1598 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | ||
1599 | struct ibmvfc_cmd *tmf; | ||
1600 | struct ibmvfc_event *evt; | ||
1601 | union ibmvfc_iu rsp_iu; | ||
1602 | struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; | ||
1603 | int rsp_rc = -EBUSY; | ||
1604 | unsigned long flags; | ||
1605 | int rsp_code = 0; | ||
1606 | |||
1607 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1608 | if (vhost->state == IBMVFC_ACTIVE) { | ||
1609 | evt = ibmvfc_get_event(vhost); | ||
1610 | ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); | ||
1611 | |||
1612 | tmf = &evt->iu.cmd; | ||
1613 | memset(tmf, 0, sizeof(*tmf)); | ||
1614 | tmf->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); | ||
1615 | tmf->resp.len = sizeof(tmf->rsp); | ||
1616 | tmf->frame_type = IBMVFC_SCSI_FCP_TYPE; | ||
1617 | tmf->payload_len = sizeof(tmf->iu); | ||
1618 | tmf->resp_len = sizeof(tmf->rsp); | ||
1619 | tmf->cancel_key = (unsigned long)sdev->hostdata; | ||
1620 | tmf->tgt_scsi_id = rport->port_id; | ||
1621 | int_to_scsilun(sdev->lun, &tmf->iu.lun); | ||
1622 | tmf->flags = (IBMVFC_NO_MEM_DESC | IBMVFC_TMF); | ||
1623 | tmf->iu.tmf_flags = type; | ||
1624 | evt->sync_iu = &rsp_iu; | ||
1625 | |||
1626 | init_completion(&evt->comp); | ||
1627 | rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); | ||
1628 | } | ||
1629 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1630 | |||
1631 | if (rsp_rc != 0) { | ||
1632 | sdev_printk(KERN_ERR, sdev, "Failed to send %s reset event. rc=%d\n", | ||
1633 | desc, rsp_rc); | ||
1634 | return -EIO; | ||
1635 | } | ||
1636 | |||
1637 | sdev_printk(KERN_INFO, sdev, "Resetting %s\n", desc); | ||
1638 | wait_for_completion(&evt->comp); | ||
1639 | |||
1640 | if (rsp_iu.cmd.status) { | ||
1641 | if (fc_rsp->flags & FCP_RSP_LEN_VALID) | ||
1642 | rsp_code = fc_rsp->data.info.rsp_code; | ||
1643 | |||
1644 | sdev_printk(KERN_ERR, sdev, "%s reset failed: %s (%x:%x) " | ||
1645 | "flags: %x fcp_rsp: %x, scsi_status: %x\n", | ||
1646 | desc, ibmvfc_get_cmd_error(rsp_iu.cmd.status, rsp_iu.cmd.error), | ||
1647 | rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code, | ||
1648 | fc_rsp->scsi_status); | ||
1649 | rsp_rc = -EIO; | ||
1650 | } else | ||
1651 | sdev_printk(KERN_INFO, sdev, "%s reset successful\n", desc); | ||
1652 | |||
1653 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1654 | ibmvfc_free_event(evt); | ||
1655 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1656 | return rsp_rc; | ||
1657 | } | ||
1658 | |||
1659 | /** | ||
1660 | * ibmvfc_abort_task_set - Abort outstanding commands to the device | ||
1661 | * @sdev: scsi device to abort commands | ||
1662 | * | ||
1663 | * This sends an Abort Task Set to the VIOS for the specified device. This does | ||
1664 | * NOT send any cancel to the VIOS. That must be done separately. | ||
1665 | * | ||
1666 | * Returns: | ||
1667 | * 0 on success / other on failure | ||
1668 | **/ | ||
1669 | static int ibmvfc_abort_task_set(struct scsi_device *sdev) | ||
1670 | { | ||
1671 | struct ibmvfc_host *vhost = shost_priv(sdev->host); | ||
1672 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | ||
1673 | struct ibmvfc_cmd *tmf; | ||
1674 | struct ibmvfc_event *evt, *found_evt; | ||
1675 | union ibmvfc_iu rsp_iu; | ||
1676 | struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; | ||
1677 | int rsp_rc = -EBUSY; | ||
1678 | unsigned long flags; | ||
1679 | int rsp_code = 0; | ||
1680 | |||
1681 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1682 | found_evt = NULL; | ||
1683 | list_for_each_entry(evt, &vhost->sent, queue) { | ||
1684 | if (evt->cmnd && evt->cmnd->device == sdev) { | ||
1685 | found_evt = evt; | ||
1686 | break; | ||
1687 | } | ||
1688 | } | ||
1689 | |||
1690 | if (!found_evt) { | ||
1691 | if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) | ||
1692 | sdev_printk(KERN_INFO, sdev, "No events found to abort\n"); | ||
1693 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1697 | if (vhost->state == IBMVFC_ACTIVE) { | ||
1698 | evt = ibmvfc_get_event(vhost); | ||
1699 | ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); | ||
1700 | |||
1701 | tmf = &evt->iu.cmd; | ||
1702 | memset(tmf, 0, sizeof(*tmf)); | ||
1703 | tmf->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); | ||
1704 | tmf->resp.len = sizeof(tmf->rsp); | ||
1705 | tmf->frame_type = IBMVFC_SCSI_FCP_TYPE; | ||
1706 | tmf->payload_len = sizeof(tmf->iu); | ||
1707 | tmf->resp_len = sizeof(tmf->rsp); | ||
1708 | tmf->cancel_key = (unsigned long)sdev->hostdata; | ||
1709 | tmf->tgt_scsi_id = rport->port_id; | ||
1710 | int_to_scsilun(sdev->lun, &tmf->iu.lun); | ||
1711 | tmf->flags = (IBMVFC_NO_MEM_DESC | IBMVFC_TMF); | ||
1712 | tmf->iu.tmf_flags = IBMVFC_ABORT_TASK_SET; | ||
1713 | evt->sync_iu = &rsp_iu; | ||
1714 | |||
1715 | init_completion(&evt->comp); | ||
1716 | rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); | ||
1717 | } | ||
1718 | |||
1719 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1720 | |||
1721 | if (rsp_rc != 0) { | ||
1722 | sdev_printk(KERN_ERR, sdev, "Failed to send abort. rc=%d\n", rsp_rc); | ||
1723 | return -EIO; | ||
1724 | } | ||
1725 | |||
1726 | sdev_printk(KERN_INFO, sdev, "Aborting outstanding commands\n"); | ||
1727 | wait_for_completion(&evt->comp); | ||
1728 | |||
1729 | if (rsp_iu.cmd.status) { | ||
1730 | if (fc_rsp->flags & FCP_RSP_LEN_VALID) | ||
1731 | rsp_code = fc_rsp->data.info.rsp_code; | ||
1732 | |||
1733 | sdev_printk(KERN_ERR, sdev, "Abort failed: %s (%x:%x) " | ||
1734 | "flags: %x fcp_rsp: %x, scsi_status: %x\n", | ||
1735 | ibmvfc_get_cmd_error(rsp_iu.cmd.status, rsp_iu.cmd.error), | ||
1736 | rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code, | ||
1737 | fc_rsp->scsi_status); | ||
1738 | rsp_rc = -EIO; | ||
1739 | } else | ||
1740 | sdev_printk(KERN_INFO, sdev, "Abort successful\n"); | ||
1741 | |||
1742 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1743 | ibmvfc_free_event(evt); | ||
1744 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1745 | return rsp_rc; | ||
1746 | } | ||
1747 | |||
1748 | /** | ||
1749 | * ibmvfc_cancel_all - Cancel all outstanding commands to the device | ||
1750 | * @sdev: scsi device to cancel commands | ||
1751 | * @type: type of error recovery being performed | ||
1752 | * | ||
1753 | * This sends a cancel to the VIOS for the specified device. This does | ||
1754 | * NOT send any abort to the actual device. That must be done separately. | ||
1755 | * | ||
1756 | * Returns: | ||
1757 | * 0 on success / other on failure | ||
1758 | **/ | ||
1759 | static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) | ||
1760 | { | ||
1761 | struct ibmvfc_host *vhost = shost_priv(sdev->host); | ||
1762 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | ||
1763 | struct ibmvfc_tmf *tmf; | ||
1764 | struct ibmvfc_event *evt, *found_evt; | ||
1765 | union ibmvfc_iu rsp; | ||
1766 | int rsp_rc = -EBUSY; | ||
1767 | unsigned long flags; | ||
1768 | u16 status; | ||
1769 | |||
1770 | ENTER; | ||
1771 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1772 | found_evt = NULL; | ||
1773 | list_for_each_entry(evt, &vhost->sent, queue) { | ||
1774 | if (evt->cmnd && evt->cmnd->device == sdev) { | ||
1775 | found_evt = evt; | ||
1776 | break; | ||
1777 | } | ||
1778 | } | ||
1779 | |||
1780 | if (!found_evt) { | ||
1781 | if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) | ||
1782 | sdev_printk(KERN_INFO, sdev, "No events found to cancel\n"); | ||
1783 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1784 | return 0; | ||
1785 | } | ||
1786 | |||
1787 | if (vhost->state == IBMVFC_ACTIVE) { | ||
1788 | evt = ibmvfc_get_event(vhost); | ||
1789 | ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT); | ||
1790 | |||
1791 | tmf = &evt->iu.tmf; | ||
1792 | memset(tmf, 0, sizeof(*tmf)); | ||
1793 | tmf->common.version = 1; | ||
1794 | tmf->common.opcode = IBMVFC_TMF_MAD; | ||
1795 | tmf->common.length = sizeof(*tmf); | ||
1796 | tmf->scsi_id = rport->port_id; | ||
1797 | int_to_scsilun(sdev->lun, &tmf->lun); | ||
1798 | tmf->flags = (type | IBMVFC_TMF_LUA_VALID); | ||
1799 | tmf->cancel_key = (unsigned long)sdev->hostdata; | ||
1800 | tmf->my_cancel_key = (IBMVFC_TMF_CANCEL_KEY | (unsigned long)sdev->hostdata); | ||
1801 | |||
1802 | evt->sync_iu = &rsp; | ||
1803 | init_completion(&evt->comp); | ||
1804 | rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); | ||
1805 | } | ||
1806 | |||
1807 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1808 | |||
1809 | if (rsp_rc != 0) { | ||
1810 | sdev_printk(KERN_ERR, sdev, "Failed to send cancel event. rc=%d\n", rsp_rc); | ||
1811 | return -EIO; | ||
1812 | } | ||
1813 | |||
1814 | sdev_printk(KERN_INFO, sdev, "Cancelling outstanding commands.\n"); | ||
1815 | |||
1816 | wait_for_completion(&evt->comp); | ||
1817 | status = rsp.mad_common.status; | ||
1818 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1819 | ibmvfc_free_event(evt); | ||
1820 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1821 | |||
1822 | if (status != IBMVFC_MAD_SUCCESS) { | ||
1823 | sdev_printk(KERN_WARNING, sdev, "Cancel failed with rc=%x\n", status); | ||
1824 | return -EIO; | ||
1825 | } | ||
1826 | |||
1827 | sdev_printk(KERN_INFO, sdev, "Successfully cancelled outstanding commands\n"); | ||
1828 | return 0; | ||
1829 | } | ||
1830 | |||
1831 | /** | ||
1832 | * ibmvfc_eh_abort_handler - Abort a command | ||
1833 | * @cmd: scsi command to abort | ||
1834 | * | ||
1835 | * Returns: | ||
1836 | * SUCCESS / FAILED | ||
1837 | **/ | ||
1838 | static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd) | ||
1839 | { | ||
1840 | struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | ||
1841 | struct ibmvfc_event *evt, *pos; | ||
1842 | int cancel_rc, abort_rc; | ||
1843 | unsigned long flags; | ||
1844 | |||
1845 | ENTER; | ||
1846 | ibmvfc_wait_while_resetting(vhost); | ||
1847 | cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_ABORT_TASK_SET); | ||
1848 | abort_rc = ibmvfc_abort_task_set(cmd->device); | ||
1849 | |||
1850 | if (!cancel_rc && !abort_rc) { | ||
1851 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1852 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | ||
1853 | if (evt->cmnd && evt->cmnd->device == cmd->device) | ||
1854 | ibmvfc_fail_request(evt, DID_ABORT); | ||
1855 | } | ||
1856 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1857 | LEAVE; | ||
1858 | return SUCCESS; | ||
1859 | } | ||
1860 | |||
1861 | LEAVE; | ||
1862 | return FAILED; | ||
1863 | } | ||
1864 | |||
1865 | /** | ||
1866 | * ibmvfc_eh_device_reset_handler - Reset a single LUN | ||
1867 | * @cmd: scsi command struct | ||
1868 | * | ||
1869 | * Returns: | ||
1870 | * SUCCESS / FAILED | ||
1871 | **/ | ||
1872 | static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd) | ||
1873 | { | ||
1874 | struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | ||
1875 | struct ibmvfc_event *evt, *pos; | ||
1876 | int cancel_rc, reset_rc; | ||
1877 | unsigned long flags; | ||
1878 | |||
1879 | ENTER; | ||
1880 | ibmvfc_wait_while_resetting(vhost); | ||
1881 | cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_LUN_RESET); | ||
1882 | reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_LUN_RESET, "LUN"); | ||
1883 | |||
1884 | if (!cancel_rc && !reset_rc) { | ||
1885 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1886 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | ||
1887 | if (evt->cmnd && evt->cmnd->device == cmd->device) | ||
1888 | ibmvfc_fail_request(evt, DID_ABORT); | ||
1889 | } | ||
1890 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1891 | LEAVE; | ||
1892 | return SUCCESS; | ||
1893 | } | ||
1894 | |||
1895 | LEAVE; | ||
1896 | return FAILED; | ||
1897 | } | ||
1898 | |||
1899 | /** | ||
1900 | * ibmvfc_dev_cancel_all - Device iterated cancel all function | ||
1901 | * @sdev: scsi device struct | ||
1902 | * @data: return code | ||
1903 | * | ||
1904 | **/ | ||
1905 | static void ibmvfc_dev_cancel_all(struct scsi_device *sdev, void *data) | ||
1906 | { | ||
1907 | unsigned long *rc = data; | ||
1908 | *rc |= ibmvfc_cancel_all(sdev, IBMVFC_TMF_TGT_RESET); | ||
1909 | } | ||
1910 | |||
1911 | /** | ||
1912 | * ibmvfc_dev_abort_all - Device iterated abort task set function | ||
1913 | * @sdev: scsi device struct | ||
1914 | * @data: return code | ||
1915 | * | ||
1916 | **/ | ||
1917 | static void ibmvfc_dev_abort_all(struct scsi_device *sdev, void *data) | ||
1918 | { | ||
1919 | unsigned long *rc = data; | ||
1920 | *rc |= ibmvfc_abort_task_set(sdev); | ||
1921 | } | ||
1922 | |||
1923 | /** | ||
1924 | * ibmvfc_eh_target_reset_handler - Reset the target | ||
1925 | * @cmd: scsi command struct | ||
1926 | * | ||
1927 | * Returns: | ||
1928 | * SUCCESS / FAILED | ||
1929 | **/ | ||
1930 | static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd) | ||
1931 | { | ||
1932 | struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | ||
1933 | struct scsi_target *starget = scsi_target(cmd->device); | ||
1934 | struct ibmvfc_event *evt, *pos; | ||
1935 | int reset_rc; | ||
1936 | unsigned long cancel_rc = 0; | ||
1937 | unsigned long flags; | ||
1938 | |||
1939 | ENTER; | ||
1940 | ibmvfc_wait_while_resetting(vhost); | ||
1941 | starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); | ||
1942 | reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_TARGET_RESET, "target"); | ||
1943 | |||
1944 | if (!cancel_rc && !reset_rc) { | ||
1945 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1946 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | ||
1947 | if (evt->cmnd && scsi_target(evt->cmnd->device) == starget) | ||
1948 | ibmvfc_fail_request(evt, DID_ABORT); | ||
1949 | } | ||
1950 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1951 | LEAVE; | ||
1952 | return SUCCESS; | ||
1953 | } | ||
1954 | |||
1955 | LEAVE; | ||
1956 | return FAILED; | ||
1957 | } | ||
1958 | |||
1959 | /** | ||
1960 | * ibmvfc_eh_host_reset_handler - Reset the connection to the server | ||
1961 | * @cmd: struct scsi_cmnd having problems | ||
1962 | * | ||
1963 | **/ | ||
1964 | static int ibmvfc_eh_host_reset_handler(struct scsi_cmnd *cmd) | ||
1965 | { | ||
1966 | int rc; | ||
1967 | struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | ||
1968 | |||
1969 | dev_err(vhost->dev, "Resetting connection due to error recovery\n"); | ||
1970 | rc = ibmvfc_issue_fc_host_lip(vhost->host); | ||
1971 | return rc ? FAILED : SUCCESS; | ||
1972 | } | ||
1973 | |||
1974 | /** | ||
1975 | * ibmvfc_terminate_rport_io - Terminate all pending I/O to the rport. | ||
1976 | * @rport: rport struct | ||
1977 | * | ||
1978 | * Return value: | ||
1979 | * none | ||
1980 | **/ | ||
1981 | static void ibmvfc_terminate_rport_io(struct fc_rport *rport) | ||
1982 | { | ||
1983 | struct scsi_target *starget = to_scsi_target(&rport->dev); | ||
1984 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
1985 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
1986 | struct ibmvfc_event *evt, *pos; | ||
1987 | unsigned long cancel_rc = 0; | ||
1988 | unsigned long abort_rc = 0; | ||
1989 | unsigned long flags; | ||
1990 | |||
1991 | ENTER; | ||
1992 | starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); | ||
1993 | starget_for_each_device(starget, &abort_rc, ibmvfc_dev_abort_all); | ||
1994 | |||
1995 | if (!cancel_rc && !abort_rc) { | ||
1996 | spin_lock_irqsave(shost->host_lock, flags); | ||
1997 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | ||
1998 | if (evt->cmnd && scsi_target(evt->cmnd->device) == starget) | ||
1999 | ibmvfc_fail_request(evt, DID_ABORT); | ||
2000 | } | ||
2001 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2002 | } else | ||
2003 | ibmvfc_issue_fc_host_lip(shost); | ||
2004 | |||
2005 | scsi_target_unblock(&rport->dev); | ||
2006 | LEAVE; | ||
2007 | } | ||
2008 | |||
2009 | static const struct { | ||
2010 | enum ibmvfc_async_event ae; | ||
2011 | const char *desc; | ||
2012 | } ae_desc [] = { | ||
2013 | { IBMVFC_AE_ELS_PLOGI, "PLOGI" }, | ||
2014 | { IBMVFC_AE_ELS_LOGO, "LOGO" }, | ||
2015 | { IBMVFC_AE_ELS_PRLO, "PRLO" }, | ||
2016 | { IBMVFC_AE_SCN_NPORT, "N-Port SCN" }, | ||
2017 | { IBMVFC_AE_SCN_GROUP, "Group SCN" }, | ||
2018 | { IBMVFC_AE_SCN_DOMAIN, "Domain SCN" }, | ||
2019 | { IBMVFC_AE_SCN_FABRIC, "Fabric SCN" }, | ||
2020 | { IBMVFC_AE_LINK_UP, "Link Up" }, | ||
2021 | { IBMVFC_AE_LINK_DOWN, "Link Down" }, | ||
2022 | { IBMVFC_AE_LINK_DEAD, "Link Dead" }, | ||
2023 | { IBMVFC_AE_HALT, "Halt" }, | ||
2024 | { IBMVFC_AE_RESUME, "Resume" }, | ||
2025 | { IBMVFC_AE_ADAPTER_FAILED, "Adapter Failed" }, | ||
2026 | }; | ||
2027 | |||
2028 | static const char *unknown_ae = "Unknown async"; | ||
2029 | |||
2030 | /** | ||
2031 | * ibmvfc_get_ae_desc - Get text description for async event | ||
2032 | * @ae: async event | ||
2033 | * | ||
2034 | **/ | ||
2035 | static const char *ibmvfc_get_ae_desc(u64 ae) | ||
2036 | { | ||
2037 | int i; | ||
2038 | |||
2039 | for (i = 0; i < ARRAY_SIZE(ae_desc); i++) | ||
2040 | if (ae_desc[i].ae == ae) | ||
2041 | return ae_desc[i].desc; | ||
2042 | |||
2043 | return unknown_ae; | ||
2044 | } | ||
2045 | |||
2046 | /** | ||
2047 | * ibmvfc_handle_async - Handle an async event from the adapter | ||
2048 | * @crq: crq to process | ||
2049 | * @vhost: ibmvfc host struct | ||
2050 | * | ||
2051 | **/ | ||
2052 | static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, | ||
2053 | struct ibmvfc_host *vhost) | ||
2054 | { | ||
2055 | const char *desc = ibmvfc_get_ae_desc(crq->event); | ||
2056 | |||
2057 | ibmvfc_log(vhost, 2, "%s event received\n", desc); | ||
2058 | |||
2059 | switch (crq->event) { | ||
2060 | case IBMVFC_AE_LINK_UP: | ||
2061 | case IBMVFC_AE_RESUME: | ||
2062 | vhost->events_to_log |= IBMVFC_AE_LINKUP; | ||
2063 | ibmvfc_init_host(vhost); | ||
2064 | break; | ||
2065 | case IBMVFC_AE_SCN_FABRIC: | ||
2066 | vhost->events_to_log |= IBMVFC_AE_RSCN; | ||
2067 | ibmvfc_init_host(vhost); | ||
2068 | break; | ||
2069 | case IBMVFC_AE_SCN_NPORT: | ||
2070 | case IBMVFC_AE_SCN_GROUP: | ||
2071 | case IBMVFC_AE_SCN_DOMAIN: | ||
2072 | vhost->events_to_log |= IBMVFC_AE_RSCN; | ||
2073 | case IBMVFC_AE_ELS_LOGO: | ||
2074 | case IBMVFC_AE_ELS_PRLO: | ||
2075 | case IBMVFC_AE_ELS_PLOGI: | ||
2076 | ibmvfc_reinit_host(vhost); | ||
2077 | break; | ||
2078 | case IBMVFC_AE_LINK_DOWN: | ||
2079 | case IBMVFC_AE_ADAPTER_FAILED: | ||
2080 | ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); | ||
2081 | break; | ||
2082 | case IBMVFC_AE_LINK_DEAD: | ||
2083 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
2084 | break; | ||
2085 | case IBMVFC_AE_HALT: | ||
2086 | ibmvfc_link_down(vhost, IBMVFC_HALTED); | ||
2087 | break; | ||
2088 | default: | ||
2089 | dev_err(vhost->dev, "Unknown async event received: %ld\n", crq->event); | ||
2090 | break; | ||
2091 | }; | ||
2092 | } | ||
2093 | |||
2094 | /** | ||
2095 | * ibmvfc_handle_crq - Handles and frees received events in the CRQ | ||
2096 | * @crq: Command/Response queue | ||
2097 | * @vhost: ibmvfc host struct | ||
2098 | * | ||
2099 | **/ | ||
2100 | static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost) | ||
2101 | { | ||
2102 | long rc; | ||
2103 | struct ibmvfc_event *evt = (struct ibmvfc_event *)crq->ioba; | ||
2104 | |||
2105 | switch (crq->valid) { | ||
2106 | case IBMVFC_CRQ_INIT_RSP: | ||
2107 | switch (crq->format) { | ||
2108 | case IBMVFC_CRQ_INIT: | ||
2109 | dev_info(vhost->dev, "Partner initialized\n"); | ||
2110 | /* Send back a response */ | ||
2111 | rc = ibmvfc_send_crq_init_complete(vhost); | ||
2112 | if (rc == 0) | ||
2113 | ibmvfc_init_host(vhost); | ||
2114 | else | ||
2115 | dev_err(vhost->dev, "Unable to send init rsp. rc=%ld\n", rc); | ||
2116 | break; | ||
2117 | case IBMVFC_CRQ_INIT_COMPLETE: | ||
2118 | dev_info(vhost->dev, "Partner initialization complete\n"); | ||
2119 | ibmvfc_init_host(vhost); | ||
2120 | break; | ||
2121 | default: | ||
2122 | dev_err(vhost->dev, "Unknown crq message type: %d\n", crq->format); | ||
2123 | } | ||
2124 | return; | ||
2125 | case IBMVFC_CRQ_XPORT_EVENT: | ||
2126 | vhost->state = IBMVFC_NO_CRQ; | ||
2127 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); | ||
2128 | if (crq->format == IBMVFC_PARTITION_MIGRATED) { | ||
2129 | /* We need to re-setup the interpartition connection */ | ||
2130 | dev_info(vhost->dev, "Re-enabling adapter\n"); | ||
2131 | vhost->client_migrated = 1; | ||
2132 | ibmvfc_purge_requests(vhost, DID_REQUEUE); | ||
2133 | if ((rc = ibmvfc_reenable_crq_queue(vhost)) || | ||
2134 | (rc = ibmvfc_send_crq_init(vhost))) { | ||
2135 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
2136 | dev_err(vhost->dev, "Error after enable (rc=%ld)\n", rc); | ||
2137 | } else | ||
2138 | ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); | ||
2139 | } else { | ||
2140 | dev_err(vhost->dev, "Virtual adapter failed (rc=%d)\n", crq->format); | ||
2141 | |||
2142 | ibmvfc_purge_requests(vhost, DID_ERROR); | ||
2143 | if ((rc = ibmvfc_reset_crq(vhost)) || | ||
2144 | (rc = ibmvfc_send_crq_init(vhost))) { | ||
2145 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
2146 | dev_err(vhost->dev, "Error after reset (rc=%ld)\n", rc); | ||
2147 | } else | ||
2148 | ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); | ||
2149 | } | ||
2150 | return; | ||
2151 | case IBMVFC_CRQ_CMD_RSP: | ||
2152 | break; | ||
2153 | default: | ||
2154 | dev_err(vhost->dev, "Got an invalid message type 0x%02x\n", crq->valid); | ||
2155 | return; | ||
2156 | } | ||
2157 | |||
2158 | if (crq->format == IBMVFC_ASYNC_EVENT) | ||
2159 | return; | ||
2160 | |||
2161 | /* The only kind of payload CRQs we should get are responses to | ||
2162 | * things we send. Make sure this response is to something we | ||
2163 | * actually sent | ||
2164 | */ | ||
2165 | if (unlikely(!ibmvfc_valid_event(&vhost->pool, evt))) { | ||
2166 | dev_err(vhost->dev, "Returned correlation_token 0x%08lx is invalid!\n", | ||
2167 | crq->ioba); | ||
2168 | return; | ||
2169 | } | ||
2170 | |||
2171 | if (unlikely(atomic_read(&evt->free))) { | ||
2172 | dev_err(vhost->dev, "Received duplicate correlation_token 0x%08lx!\n", | ||
2173 | crq->ioba); | ||
2174 | return; | ||
2175 | } | ||
2176 | |||
2177 | del_timer(&evt->timer); | ||
2178 | list_del(&evt->queue); | ||
2179 | ibmvfc_trc_end(evt); | ||
2180 | evt->done(evt); | ||
2181 | } | ||
2182 | |||
2183 | /** | ||
2184 | * ibmvfc_scan_finished - Check if the device scan is done. | ||
2185 | * @shost: scsi host struct | ||
2186 | * @time: current elapsed time | ||
2187 | * | ||
2188 | * Returns: | ||
2189 | * 0 if scan is not done / 1 if scan is done | ||
2190 | **/ | ||
2191 | static int ibmvfc_scan_finished(struct Scsi_Host *shost, unsigned long time) | ||
2192 | { | ||
2193 | unsigned long flags; | ||
2194 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2195 | int done = 0; | ||
2196 | |||
2197 | spin_lock_irqsave(shost->host_lock, flags); | ||
2198 | if (time >= (init_timeout * HZ)) { | ||
2199 | dev_info(vhost->dev, "Scan taking longer than %d seconds, " | ||
2200 | "continuing initialization\n", init_timeout); | ||
2201 | done = 1; | ||
2202 | } | ||
2203 | |||
2204 | if (vhost->state != IBMVFC_NO_CRQ && vhost->action == IBMVFC_HOST_ACTION_NONE) | ||
2205 | done = 1; | ||
2206 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2207 | return done; | ||
2208 | } | ||
2209 | |||
2210 | /** | ||
2211 | * ibmvfc_slave_alloc - Setup the device's task set value | ||
2212 | * @sdev: struct scsi_device device to configure | ||
2213 | * | ||
2214 | * Set the device's task set value so that error handling works as | ||
2215 | * expected. | ||
2216 | * | ||
2217 | * Returns: | ||
2218 | * 0 on success / -ENXIO if device does not exist | ||
2219 | **/ | ||
2220 | static int ibmvfc_slave_alloc(struct scsi_device *sdev) | ||
2221 | { | ||
2222 | struct Scsi_Host *shost = sdev->host; | ||
2223 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | ||
2224 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2225 | unsigned long flags = 0; | ||
2226 | |||
2227 | if (!rport || fc_remote_port_chkready(rport)) | ||
2228 | return -ENXIO; | ||
2229 | |||
2230 | spin_lock_irqsave(shost->host_lock, flags); | ||
2231 | sdev->hostdata = (void *)(unsigned long)vhost->task_set++; | ||
2232 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2233 | return 0; | ||
2234 | } | ||
2235 | |||
2236 | /** | ||
2237 | * ibmvfc_slave_configure - Configure the device | ||
2238 | * @sdev: struct scsi_device device to configure | ||
2239 | * | ||
2240 | * Enable allow_restart for a device if it is a disk. Adjust the | ||
2241 | * queue_depth here also. | ||
2242 | * | ||
2243 | * Returns: | ||
2244 | * 0 | ||
2245 | **/ | ||
2246 | static int ibmvfc_slave_configure(struct scsi_device *sdev) | ||
2247 | { | ||
2248 | struct Scsi_Host *shost = sdev->host; | ||
2249 | struct fc_rport *rport = starget_to_rport(sdev->sdev_target); | ||
2250 | unsigned long flags = 0; | ||
2251 | |||
2252 | spin_lock_irqsave(shost->host_lock, flags); | ||
2253 | if (sdev->type == TYPE_DISK) | ||
2254 | sdev->allow_restart = 1; | ||
2255 | |||
2256 | if (sdev->tagged_supported) { | ||
2257 | scsi_set_tag_type(sdev, MSG_SIMPLE_TAG); | ||
2258 | scsi_activate_tcq(sdev, sdev->queue_depth); | ||
2259 | } else | ||
2260 | scsi_deactivate_tcq(sdev, sdev->queue_depth); | ||
2261 | |||
2262 | rport->dev_loss_tmo = dev_loss_tmo; | ||
2263 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2264 | return 0; | ||
2265 | } | ||
2266 | |||
2267 | /** | ||
2268 | * ibmvfc_change_queue_depth - Change the device's queue depth | ||
2269 | * @sdev: scsi device struct | ||
2270 | * @qdepth: depth to set | ||
2271 | * | ||
2272 | * Return value: | ||
2273 | * actual depth set | ||
2274 | **/ | ||
2275 | static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth) | ||
2276 | { | ||
2277 | if (qdepth > IBMVFC_MAX_CMDS_PER_LUN) | ||
2278 | qdepth = IBMVFC_MAX_CMDS_PER_LUN; | ||
2279 | |||
2280 | scsi_adjust_queue_depth(sdev, 0, qdepth); | ||
2281 | return sdev->queue_depth; | ||
2282 | } | ||
2283 | |||
2284 | /** | ||
2285 | * ibmvfc_change_queue_type - Change the device's queue type | ||
2286 | * @sdev: scsi device struct | ||
2287 | * @tag_type: type of tags to use | ||
2288 | * | ||
2289 | * Return value: | ||
2290 | * actual queue type set | ||
2291 | **/ | ||
2292 | static int ibmvfc_change_queue_type(struct scsi_device *sdev, int tag_type) | ||
2293 | { | ||
2294 | if (sdev->tagged_supported) { | ||
2295 | scsi_set_tag_type(sdev, tag_type); | ||
2296 | |||
2297 | if (tag_type) | ||
2298 | scsi_activate_tcq(sdev, sdev->queue_depth); | ||
2299 | else | ||
2300 | scsi_deactivate_tcq(sdev, sdev->queue_depth); | ||
2301 | } else | ||
2302 | tag_type = 0; | ||
2303 | |||
2304 | return tag_type; | ||
2305 | } | ||
2306 | |||
2307 | static ssize_t ibmvfc_show_host_partition_name(struct device *dev, | ||
2308 | struct device_attribute *attr, char *buf) | ||
2309 | { | ||
2310 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2311 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2312 | |||
2313 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
2314 | vhost->login_buf->resp.partition_name); | ||
2315 | } | ||
2316 | |||
2317 | static struct device_attribute ibmvfc_host_partition_name = { | ||
2318 | .attr = { | ||
2319 | .name = "partition_name", | ||
2320 | .mode = S_IRUGO, | ||
2321 | }, | ||
2322 | .show = ibmvfc_show_host_partition_name, | ||
2323 | }; | ||
2324 | |||
2325 | static ssize_t ibmvfc_show_host_device_name(struct device *dev, | ||
2326 | struct device_attribute *attr, char *buf) | ||
2327 | { | ||
2328 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2329 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2330 | |||
2331 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
2332 | vhost->login_buf->resp.device_name); | ||
2333 | } | ||
2334 | |||
2335 | static struct device_attribute ibmvfc_host_device_name = { | ||
2336 | .attr = { | ||
2337 | .name = "device_name", | ||
2338 | .mode = S_IRUGO, | ||
2339 | }, | ||
2340 | .show = ibmvfc_show_host_device_name, | ||
2341 | }; | ||
2342 | |||
2343 | static ssize_t ibmvfc_show_host_loc_code(struct device *dev, | ||
2344 | struct device_attribute *attr, char *buf) | ||
2345 | { | ||
2346 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2347 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2348 | |||
2349 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
2350 | vhost->login_buf->resp.port_loc_code); | ||
2351 | } | ||
2352 | |||
2353 | static struct device_attribute ibmvfc_host_loc_code = { | ||
2354 | .attr = { | ||
2355 | .name = "port_loc_code", | ||
2356 | .mode = S_IRUGO, | ||
2357 | }, | ||
2358 | .show = ibmvfc_show_host_loc_code, | ||
2359 | }; | ||
2360 | |||
2361 | static ssize_t ibmvfc_show_host_drc_name(struct device *dev, | ||
2362 | struct device_attribute *attr, char *buf) | ||
2363 | { | ||
2364 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2365 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2366 | |||
2367 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
2368 | vhost->login_buf->resp.drc_name); | ||
2369 | } | ||
2370 | |||
2371 | static struct device_attribute ibmvfc_host_drc_name = { | ||
2372 | .attr = { | ||
2373 | .name = "drc_name", | ||
2374 | .mode = S_IRUGO, | ||
2375 | }, | ||
2376 | .show = ibmvfc_show_host_drc_name, | ||
2377 | }; | ||
2378 | |||
2379 | static ssize_t ibmvfc_show_host_npiv_version(struct device *dev, | ||
2380 | struct device_attribute *attr, char *buf) | ||
2381 | { | ||
2382 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2383 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2384 | return snprintf(buf, PAGE_SIZE, "%d\n", vhost->login_buf->resp.version); | ||
2385 | } | ||
2386 | |||
2387 | static struct device_attribute ibmvfc_host_npiv_version = { | ||
2388 | .attr = { | ||
2389 | .name = "npiv_version", | ||
2390 | .mode = S_IRUGO, | ||
2391 | }, | ||
2392 | .show = ibmvfc_show_host_npiv_version, | ||
2393 | }; | ||
2394 | |||
2395 | /** | ||
2396 | * ibmvfc_show_log_level - Show the adapter's error logging level | ||
2397 | * @dev: class device struct | ||
2398 | * @buf: buffer | ||
2399 | * | ||
2400 | * Return value: | ||
2401 | * number of bytes printed to buffer | ||
2402 | **/ | ||
2403 | static ssize_t ibmvfc_show_log_level(struct device *dev, | ||
2404 | struct device_attribute *attr, char *buf) | ||
2405 | { | ||
2406 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2407 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2408 | unsigned long flags = 0; | ||
2409 | int len; | ||
2410 | |||
2411 | spin_lock_irqsave(shost->host_lock, flags); | ||
2412 | len = snprintf(buf, PAGE_SIZE, "%d\n", vhost->log_level); | ||
2413 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2414 | return len; | ||
2415 | } | ||
2416 | |||
2417 | /** | ||
2418 | * ibmvfc_store_log_level - Change the adapter's error logging level | ||
2419 | * @dev: class device struct | ||
2420 | * @buf: buffer | ||
2421 | * | ||
2422 | * Return value: | ||
2423 | * number of bytes printed to buffer | ||
2424 | **/ | ||
2425 | static ssize_t ibmvfc_store_log_level(struct device *dev, | ||
2426 | struct device_attribute *attr, | ||
2427 | const char *buf, size_t count) | ||
2428 | { | ||
2429 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2430 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2431 | unsigned long flags = 0; | ||
2432 | |||
2433 | spin_lock_irqsave(shost->host_lock, flags); | ||
2434 | vhost->log_level = simple_strtoul(buf, NULL, 10); | ||
2435 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2436 | return strlen(buf); | ||
2437 | } | ||
2438 | |||
2439 | static struct device_attribute ibmvfc_log_level_attr = { | ||
2440 | .attr = { | ||
2441 | .name = "log_level", | ||
2442 | .mode = S_IRUGO | S_IWUSR, | ||
2443 | }, | ||
2444 | .show = ibmvfc_show_log_level, | ||
2445 | .store = ibmvfc_store_log_level | ||
2446 | }; | ||
2447 | |||
2448 | #ifdef CONFIG_SCSI_IBMVFC_TRACE | ||
2449 | /** | ||
2450 | * ibmvfc_read_trace - Dump the adapter trace | ||
2451 | * @kobj: kobject struct | ||
2452 | * @bin_attr: bin_attribute struct | ||
2453 | * @buf: buffer | ||
2454 | * @off: offset | ||
2455 | * @count: buffer size | ||
2456 | * | ||
2457 | * Return value: | ||
2458 | * number of bytes printed to buffer | ||
2459 | **/ | ||
2460 | static ssize_t ibmvfc_read_trace(struct kobject *kobj, | ||
2461 | struct bin_attribute *bin_attr, | ||
2462 | char *buf, loff_t off, size_t count) | ||
2463 | { | ||
2464 | struct device *dev = container_of(kobj, struct device, kobj); | ||
2465 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2466 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2467 | unsigned long flags = 0; | ||
2468 | int size = IBMVFC_TRACE_SIZE; | ||
2469 | char *src = (char *)vhost->trace; | ||
2470 | |||
2471 | if (off > size) | ||
2472 | return 0; | ||
2473 | if (off + count > size) { | ||
2474 | size -= off; | ||
2475 | count = size; | ||
2476 | } | ||
2477 | |||
2478 | spin_lock_irqsave(shost->host_lock, flags); | ||
2479 | memcpy(buf, &src[off], count); | ||
2480 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2481 | return count; | ||
2482 | } | ||
2483 | |||
2484 | static struct bin_attribute ibmvfc_trace_attr = { | ||
2485 | .attr = { | ||
2486 | .name = "trace", | ||
2487 | .mode = S_IRUGO, | ||
2488 | }, | ||
2489 | .size = 0, | ||
2490 | .read = ibmvfc_read_trace, | ||
2491 | }; | ||
2492 | #endif | ||
2493 | |||
2494 | static struct device_attribute *ibmvfc_attrs[] = { | ||
2495 | &ibmvfc_host_partition_name, | ||
2496 | &ibmvfc_host_device_name, | ||
2497 | &ibmvfc_host_loc_code, | ||
2498 | &ibmvfc_host_drc_name, | ||
2499 | &ibmvfc_host_npiv_version, | ||
2500 | &ibmvfc_log_level_attr, | ||
2501 | NULL | ||
2502 | }; | ||
2503 | |||
2504 | static struct scsi_host_template driver_template = { | ||
2505 | .module = THIS_MODULE, | ||
2506 | .name = "IBM POWER Virtual FC Adapter", | ||
2507 | .proc_name = IBMVFC_NAME, | ||
2508 | .queuecommand = ibmvfc_queuecommand, | ||
2509 | .eh_abort_handler = ibmvfc_eh_abort_handler, | ||
2510 | .eh_device_reset_handler = ibmvfc_eh_device_reset_handler, | ||
2511 | .eh_target_reset_handler = ibmvfc_eh_target_reset_handler, | ||
2512 | .eh_host_reset_handler = ibmvfc_eh_host_reset_handler, | ||
2513 | .slave_alloc = ibmvfc_slave_alloc, | ||
2514 | .slave_configure = ibmvfc_slave_configure, | ||
2515 | .scan_finished = ibmvfc_scan_finished, | ||
2516 | .change_queue_depth = ibmvfc_change_queue_depth, | ||
2517 | .change_queue_type = ibmvfc_change_queue_type, | ||
2518 | .cmd_per_lun = 16, | ||
2519 | .can_queue = IBMVFC_MAX_REQUESTS_DEFAULT, | ||
2520 | .this_id = -1, | ||
2521 | .sg_tablesize = SG_ALL, | ||
2522 | .max_sectors = IBMVFC_MAX_SECTORS, | ||
2523 | .use_clustering = ENABLE_CLUSTERING, | ||
2524 | .shost_attrs = ibmvfc_attrs, | ||
2525 | }; | ||
2526 | |||
2527 | /** | ||
2528 | * ibmvfc_next_async_crq - Returns the next entry in async queue | ||
2529 | * @vhost: ibmvfc host struct | ||
2530 | * | ||
2531 | * Returns: | ||
2532 | * Pointer to next entry in queue / NULL if empty | ||
2533 | **/ | ||
2534 | static struct ibmvfc_async_crq *ibmvfc_next_async_crq(struct ibmvfc_host *vhost) | ||
2535 | { | ||
2536 | struct ibmvfc_async_crq_queue *async_crq = &vhost->async_crq; | ||
2537 | struct ibmvfc_async_crq *crq; | ||
2538 | |||
2539 | crq = &async_crq->msgs[async_crq->cur]; | ||
2540 | if (crq->valid & 0x80) { | ||
2541 | if (++async_crq->cur == async_crq->size) | ||
2542 | async_crq->cur = 0; | ||
2543 | } else | ||
2544 | crq = NULL; | ||
2545 | |||
2546 | return crq; | ||
2547 | } | ||
2548 | |||
2549 | /** | ||
2550 | * ibmvfc_next_crq - Returns the next entry in message queue | ||
2551 | * @vhost: ibmvfc host struct | ||
2552 | * | ||
2553 | * Returns: | ||
2554 | * Pointer to next entry in queue / NULL if empty | ||
2555 | **/ | ||
2556 | static struct ibmvfc_crq *ibmvfc_next_crq(struct ibmvfc_host *vhost) | ||
2557 | { | ||
2558 | struct ibmvfc_crq_queue *queue = &vhost->crq; | ||
2559 | struct ibmvfc_crq *crq; | ||
2560 | |||
2561 | crq = &queue->msgs[queue->cur]; | ||
2562 | if (crq->valid & 0x80) { | ||
2563 | if (++queue->cur == queue->size) | ||
2564 | queue->cur = 0; | ||
2565 | } else | ||
2566 | crq = NULL; | ||
2567 | |||
2568 | return crq; | ||
2569 | } | ||
2570 | |||
2571 | /** | ||
2572 | * ibmvfc_interrupt - Interrupt handler | ||
2573 | * @irq: number of irq to handle, not used | ||
2574 | * @dev_instance: ibmvfc_host that received interrupt | ||
2575 | * | ||
2576 | * Returns: | ||
2577 | * IRQ_HANDLED | ||
2578 | **/ | ||
2579 | static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance) | ||
2580 | { | ||
2581 | struct ibmvfc_host *vhost = (struct ibmvfc_host *)dev_instance; | ||
2582 | struct vio_dev *vdev = to_vio_dev(vhost->dev); | ||
2583 | struct ibmvfc_crq *crq; | ||
2584 | struct ibmvfc_async_crq *async; | ||
2585 | unsigned long flags; | ||
2586 | int done = 0; | ||
2587 | |||
2588 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
2589 | vio_disable_interrupts(to_vio_dev(vhost->dev)); | ||
2590 | while (!done) { | ||
2591 | /* Pull all the valid messages off the CRQ */ | ||
2592 | while ((crq = ibmvfc_next_crq(vhost)) != NULL) { | ||
2593 | ibmvfc_handle_crq(crq, vhost); | ||
2594 | crq->valid = 0; | ||
2595 | } | ||
2596 | |||
2597 | /* Pull all the valid messages off the async CRQ */ | ||
2598 | while ((async = ibmvfc_next_async_crq(vhost)) != NULL) { | ||
2599 | ibmvfc_handle_async(async, vhost); | ||
2600 | async->valid = 0; | ||
2601 | } | ||
2602 | |||
2603 | vio_enable_interrupts(vdev); | ||
2604 | if ((crq = ibmvfc_next_crq(vhost)) != NULL) { | ||
2605 | vio_disable_interrupts(vdev); | ||
2606 | ibmvfc_handle_crq(crq, vhost); | ||
2607 | crq->valid = 0; | ||
2608 | } else if ((async = ibmvfc_next_async_crq(vhost)) != NULL) { | ||
2609 | vio_disable_interrupts(vdev); | ||
2610 | ibmvfc_handle_async(async, vhost); | ||
2611 | crq->valid = 0; | ||
2612 | } else | ||
2613 | done = 1; | ||
2614 | } | ||
2615 | |||
2616 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
2617 | return IRQ_HANDLED; | ||
2618 | } | ||
2619 | |||
2620 | /** | ||
2621 | * ibmvfc_init_tgt - Set the next init job step for the target | ||
2622 | * @tgt: ibmvfc target struct | ||
2623 | * @job_step: job step to perform | ||
2624 | * | ||
2625 | **/ | ||
2626 | static void ibmvfc_init_tgt(struct ibmvfc_target *tgt, | ||
2627 | void (*job_step) (struct ibmvfc_target *)) | ||
2628 | { | ||
2629 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT); | ||
2630 | tgt->job_step = job_step; | ||
2631 | wake_up(&tgt->vhost->work_wait_q); | ||
2632 | } | ||
2633 | |||
2634 | /** | ||
2635 | * ibmvfc_retry_tgt_init - Attempt to retry a step in target initialization | ||
2636 | * @tgt: ibmvfc target struct | ||
2637 | * @job_step: initialization job step | ||
2638 | * | ||
2639 | **/ | ||
2640 | static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, | ||
2641 | void (*job_step) (struct ibmvfc_target *)) | ||
2642 | { | ||
2643 | if (++tgt->init_retries > IBMVFC_MAX_INIT_RETRIES) { | ||
2644 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | ||
2645 | wake_up(&tgt->vhost->work_wait_q); | ||
2646 | } else | ||
2647 | ibmvfc_init_tgt(tgt, job_step); | ||
2648 | } | ||
2649 | |||
2650 | /** | ||
2651 | * ibmvfc_release_tgt - Free memory allocated for a target | ||
2652 | * @kref: kref struct | ||
2653 | * | ||
2654 | **/ | ||
2655 | static void ibmvfc_release_tgt(struct kref *kref) | ||
2656 | { | ||
2657 | struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref); | ||
2658 | kfree(tgt); | ||
2659 | } | ||
2660 | |||
2661 | /** | ||
2662 | * ibmvfc_tgt_prli_done - Completion handler for Process Login | ||
2663 | * @evt: ibmvfc event struct | ||
2664 | * | ||
2665 | **/ | ||
2666 | static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) | ||
2667 | { | ||
2668 | struct ibmvfc_target *tgt = evt->tgt; | ||
2669 | struct ibmvfc_host *vhost = evt->vhost; | ||
2670 | struct ibmvfc_process_login *rsp = &evt->xfer_iu->prli; | ||
2671 | u32 status = rsp->common.status; | ||
2672 | |||
2673 | vhost->discovery_threads--; | ||
2674 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2675 | switch (status) { | ||
2676 | case IBMVFC_MAD_SUCCESS: | ||
2677 | tgt_dbg(tgt, "Process Login succeeded\n"); | ||
2678 | tgt->need_login = 0; | ||
2679 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT); | ||
2680 | break; | ||
2681 | case IBMVFC_MAD_DRIVER_FAILED: | ||
2682 | break; | ||
2683 | case IBMVFC_MAD_CRQ_ERROR: | ||
2684 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); | ||
2685 | break; | ||
2686 | case IBMVFC_MAD_FAILED: | ||
2687 | default: | ||
2688 | tgt_err(tgt, "Process Login failed: %s (%x:%x) rc=0x%02X\n", | ||
2689 | ibmvfc_get_cmd_error(rsp->status, rsp->error), | ||
2690 | rsp->status, rsp->error, status); | ||
2691 | if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | ||
2692 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); | ||
2693 | break; | ||
2694 | }; | ||
2695 | |||
2696 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2697 | ibmvfc_free_event(evt); | ||
2698 | wake_up(&vhost->work_wait_q); | ||
2699 | } | ||
2700 | |||
2701 | /** | ||
2702 | * ibmvfc_tgt_send_prli - Send a process login | ||
2703 | * @tgt: ibmvfc target struct | ||
2704 | * | ||
2705 | **/ | ||
2706 | static void ibmvfc_tgt_send_prli(struct ibmvfc_target *tgt) | ||
2707 | { | ||
2708 | struct ibmvfc_process_login *prli; | ||
2709 | struct ibmvfc_host *vhost = tgt->vhost; | ||
2710 | struct ibmvfc_event *evt; | ||
2711 | |||
2712 | if (vhost->discovery_threads >= disc_threads) | ||
2713 | return; | ||
2714 | |||
2715 | kref_get(&tgt->kref); | ||
2716 | evt = ibmvfc_get_event(vhost); | ||
2717 | vhost->discovery_threads++; | ||
2718 | ibmvfc_init_event(evt, ibmvfc_tgt_prli_done, IBMVFC_MAD_FORMAT); | ||
2719 | evt->tgt = tgt; | ||
2720 | prli = &evt->iu.prli; | ||
2721 | memset(prli, 0, sizeof(*prli)); | ||
2722 | prli->common.version = 1; | ||
2723 | prli->common.opcode = IBMVFC_PROCESS_LOGIN; | ||
2724 | prli->common.length = sizeof(*prli); | ||
2725 | prli->scsi_id = tgt->scsi_id; | ||
2726 | |||
2727 | prli->parms.type = IBMVFC_SCSI_FCP_TYPE; | ||
2728 | prli->parms.flags = IBMVFC_PRLI_EST_IMG_PAIR; | ||
2729 | prli->parms.service_parms = IBMVFC_PRLI_INITIATOR_FUNC; | ||
2730 | |||
2731 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); | ||
2732 | if (ibmvfc_send_event(evt, vhost, default_timeout)) { | ||
2733 | vhost->discovery_threads--; | ||
2734 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2735 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2736 | } else | ||
2737 | tgt_dbg(tgt, "Sent process login\n"); | ||
2738 | } | ||
2739 | |||
2740 | /** | ||
2741 | * ibmvfc_tgt_plogi_done - Completion handler for Port Login | ||
2742 | * @evt: ibmvfc event struct | ||
2743 | * | ||
2744 | **/ | ||
2745 | static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt) | ||
2746 | { | ||
2747 | struct ibmvfc_target *tgt = evt->tgt; | ||
2748 | struct ibmvfc_host *vhost = evt->vhost; | ||
2749 | struct ibmvfc_port_login *rsp = &evt->xfer_iu->plogi; | ||
2750 | u32 status = rsp->common.status; | ||
2751 | |||
2752 | vhost->discovery_threads--; | ||
2753 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2754 | switch (status) { | ||
2755 | case IBMVFC_MAD_SUCCESS: | ||
2756 | tgt_dbg(tgt, "Port Login succeeded\n"); | ||
2757 | if (tgt->ids.port_name && | ||
2758 | tgt->ids.port_name != wwn_to_u64(rsp->service_parms.port_name)) { | ||
2759 | vhost->reinit = 1; | ||
2760 | tgt_dbg(tgt, "Port re-init required\n"); | ||
2761 | break; | ||
2762 | } | ||
2763 | tgt->ids.node_name = wwn_to_u64(rsp->service_parms.node_name); | ||
2764 | tgt->ids.port_name = wwn_to_u64(rsp->service_parms.port_name); | ||
2765 | tgt->ids.port_id = tgt->scsi_id; | ||
2766 | tgt->ids.roles = FC_PORT_ROLE_FCP_TARGET; | ||
2767 | memcpy(&tgt->service_parms, &rsp->service_parms, | ||
2768 | sizeof(tgt->service_parms)); | ||
2769 | memcpy(&tgt->service_parms_change, &rsp->service_parms_change, | ||
2770 | sizeof(tgt->service_parms_change)); | ||
2771 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_prli); | ||
2772 | break; | ||
2773 | case IBMVFC_MAD_DRIVER_FAILED: | ||
2774 | break; | ||
2775 | case IBMVFC_MAD_CRQ_ERROR: | ||
2776 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); | ||
2777 | break; | ||
2778 | case IBMVFC_MAD_FAILED: | ||
2779 | default: | ||
2780 | tgt_err(tgt, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", | ||
2781 | ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, | ||
2782 | ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, | ||
2783 | ibmvfc_get_ls_explain(rsp->fc_explain), rsp->fc_explain, status); | ||
2784 | |||
2785 | if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | ||
2786 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); | ||
2787 | break; | ||
2788 | }; | ||
2789 | |||
2790 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2791 | ibmvfc_free_event(evt); | ||
2792 | wake_up(&vhost->work_wait_q); | ||
2793 | } | ||
2794 | |||
2795 | /** | ||
2796 | * ibmvfc_tgt_send_plogi - Send PLOGI to the specified target | ||
2797 | * @tgt: ibmvfc target struct | ||
2798 | * | ||
2799 | **/ | ||
2800 | static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *tgt) | ||
2801 | { | ||
2802 | struct ibmvfc_port_login *plogi; | ||
2803 | struct ibmvfc_host *vhost = tgt->vhost; | ||
2804 | struct ibmvfc_event *evt; | ||
2805 | |||
2806 | if (vhost->discovery_threads >= disc_threads) | ||
2807 | return; | ||
2808 | |||
2809 | kref_get(&tgt->kref); | ||
2810 | evt = ibmvfc_get_event(vhost); | ||
2811 | vhost->discovery_threads++; | ||
2812 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); | ||
2813 | ibmvfc_init_event(evt, ibmvfc_tgt_plogi_done, IBMVFC_MAD_FORMAT); | ||
2814 | evt->tgt = tgt; | ||
2815 | plogi = &evt->iu.plogi; | ||
2816 | memset(plogi, 0, sizeof(*plogi)); | ||
2817 | plogi->common.version = 1; | ||
2818 | plogi->common.opcode = IBMVFC_PORT_LOGIN; | ||
2819 | plogi->common.length = sizeof(*plogi); | ||
2820 | plogi->scsi_id = tgt->scsi_id; | ||
2821 | |||
2822 | if (ibmvfc_send_event(evt, vhost, default_timeout)) { | ||
2823 | vhost->discovery_threads--; | ||
2824 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2825 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2826 | } else | ||
2827 | tgt_dbg(tgt, "Sent port login\n"); | ||
2828 | } | ||
2829 | |||
2830 | /** | ||
2831 | * ibmvfc_tgt_implicit_logout_done - Completion handler for Implicit Logout MAD | ||
2832 | * @evt: ibmvfc event struct | ||
2833 | * | ||
2834 | **/ | ||
2835 | static void ibmvfc_tgt_implicit_logout_done(struct ibmvfc_event *evt) | ||
2836 | { | ||
2837 | struct ibmvfc_target *tgt = evt->tgt; | ||
2838 | struct ibmvfc_host *vhost = evt->vhost; | ||
2839 | struct ibmvfc_implicit_logout *rsp = &evt->xfer_iu->implicit_logout; | ||
2840 | u32 status = rsp->common.status; | ||
2841 | |||
2842 | vhost->discovery_threads--; | ||
2843 | ibmvfc_free_event(evt); | ||
2844 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2845 | |||
2846 | switch (status) { | ||
2847 | case IBMVFC_MAD_SUCCESS: | ||
2848 | tgt_dbg(tgt, "Implicit Logout succeeded\n"); | ||
2849 | break; | ||
2850 | case IBMVFC_MAD_DRIVER_FAILED: | ||
2851 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2852 | wake_up(&vhost->work_wait_q); | ||
2853 | return; | ||
2854 | case IBMVFC_MAD_FAILED: | ||
2855 | default: | ||
2856 | tgt_err(tgt, "Implicit Logout failed: rc=0x%02X\n", status); | ||
2857 | break; | ||
2858 | }; | ||
2859 | |||
2860 | if (vhost->action == IBMVFC_HOST_ACTION_TGT_INIT) | ||
2861 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_plogi); | ||
2862 | else if (vhost->action == IBMVFC_HOST_ACTION_QUERY_TGTS && | ||
2863 | tgt->scsi_id != tgt->new_scsi_id) | ||
2864 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | ||
2865 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2866 | wake_up(&vhost->work_wait_q); | ||
2867 | } | ||
2868 | |||
2869 | /** | ||
2870 | * ibmvfc_tgt_implicit_logout - Initiate an Implicit Logout for specified target | ||
2871 | * @tgt: ibmvfc target struct | ||
2872 | * | ||
2873 | **/ | ||
2874 | static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) | ||
2875 | { | ||
2876 | struct ibmvfc_implicit_logout *mad; | ||
2877 | struct ibmvfc_host *vhost = tgt->vhost; | ||
2878 | struct ibmvfc_event *evt; | ||
2879 | |||
2880 | if (vhost->discovery_threads >= disc_threads) | ||
2881 | return; | ||
2882 | |||
2883 | kref_get(&tgt->kref); | ||
2884 | evt = ibmvfc_get_event(vhost); | ||
2885 | vhost->discovery_threads++; | ||
2886 | ibmvfc_init_event(evt, ibmvfc_tgt_implicit_logout_done, IBMVFC_MAD_FORMAT); | ||
2887 | evt->tgt = tgt; | ||
2888 | mad = &evt->iu.implicit_logout; | ||
2889 | memset(mad, 0, sizeof(*mad)); | ||
2890 | mad->common.version = 1; | ||
2891 | mad->common.opcode = IBMVFC_IMPLICIT_LOGOUT; | ||
2892 | mad->common.length = sizeof(*mad); | ||
2893 | mad->old_scsi_id = tgt->scsi_id; | ||
2894 | |||
2895 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); | ||
2896 | if (ibmvfc_send_event(evt, vhost, default_timeout)) { | ||
2897 | vhost->discovery_threads--; | ||
2898 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2899 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2900 | } else | ||
2901 | tgt_dbg(tgt, "Sent Implicit Logout\n"); | ||
2902 | } | ||
2903 | |||
2904 | /** | ||
2905 | * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD | ||
2906 | * @evt: ibmvfc event struct | ||
2907 | * | ||
2908 | **/ | ||
2909 | static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) | ||
2910 | { | ||
2911 | struct ibmvfc_target *tgt = evt->tgt; | ||
2912 | struct ibmvfc_host *vhost = evt->vhost; | ||
2913 | struct ibmvfc_query_tgt *rsp = &evt->xfer_iu->query_tgt; | ||
2914 | u32 status = rsp->common.status; | ||
2915 | |||
2916 | vhost->discovery_threads--; | ||
2917 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2918 | switch (status) { | ||
2919 | case IBMVFC_MAD_SUCCESS: | ||
2920 | tgt_dbg(tgt, "Query Target succeeded\n"); | ||
2921 | tgt->new_scsi_id = rsp->scsi_id; | ||
2922 | if (rsp->scsi_id != tgt->scsi_id) | ||
2923 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); | ||
2924 | break; | ||
2925 | case IBMVFC_MAD_DRIVER_FAILED: | ||
2926 | break; | ||
2927 | case IBMVFC_MAD_CRQ_ERROR: | ||
2928 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); | ||
2929 | break; | ||
2930 | case IBMVFC_MAD_FAILED: | ||
2931 | default: | ||
2932 | tgt_err(tgt, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", | ||
2933 | ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, | ||
2934 | ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, | ||
2935 | ibmvfc_get_gs_explain(rsp->fc_explain), rsp->fc_explain, status); | ||
2936 | |||
2937 | if ((rsp->status & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED && | ||
2938 | rsp->error == IBMVFC_UNABLE_TO_PERFORM_REQ && | ||
2939 | rsp->fc_explain == IBMVFC_PORT_NAME_NOT_REG) | ||
2940 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | ||
2941 | else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | ||
2942 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); | ||
2943 | break; | ||
2944 | }; | ||
2945 | |||
2946 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2947 | ibmvfc_free_event(evt); | ||
2948 | wake_up(&vhost->work_wait_q); | ||
2949 | } | ||
2950 | |||
2951 | /** | ||
2952 | * ibmvfc_tgt_query_target - Initiate a Query Target for specified target | ||
2953 | * @tgt: ibmvfc target struct | ||
2954 | * | ||
2955 | **/ | ||
2956 | static void ibmvfc_tgt_query_target(struct ibmvfc_target *tgt) | ||
2957 | { | ||
2958 | struct ibmvfc_query_tgt *query_tgt; | ||
2959 | struct ibmvfc_host *vhost = tgt->vhost; | ||
2960 | struct ibmvfc_event *evt; | ||
2961 | |||
2962 | if (vhost->discovery_threads >= disc_threads) | ||
2963 | return; | ||
2964 | |||
2965 | kref_get(&tgt->kref); | ||
2966 | evt = ibmvfc_get_event(vhost); | ||
2967 | vhost->discovery_threads++; | ||
2968 | evt->tgt = tgt; | ||
2969 | ibmvfc_init_event(evt, ibmvfc_tgt_query_target_done, IBMVFC_MAD_FORMAT); | ||
2970 | query_tgt = &evt->iu.query_tgt; | ||
2971 | memset(query_tgt, 0, sizeof(*query_tgt)); | ||
2972 | query_tgt->common.version = 1; | ||
2973 | query_tgt->common.opcode = IBMVFC_QUERY_TARGET; | ||
2974 | query_tgt->common.length = sizeof(*query_tgt); | ||
2975 | query_tgt->wwpn = tgt->ids.port_name; | ||
2976 | |||
2977 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); | ||
2978 | if (ibmvfc_send_event(evt, vhost, default_timeout)) { | ||
2979 | vhost->discovery_threads--; | ||
2980 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2981 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2982 | } else | ||
2983 | tgt_dbg(tgt, "Sent Query Target\n"); | ||
2984 | } | ||
2985 | |||
2986 | /** | ||
2987 | * ibmvfc_alloc_target - Allocate and initialize an ibmvfc target | ||
2988 | * @vhost: ibmvfc host struct | ||
2989 | * @scsi_id: SCSI ID to allocate target for | ||
2990 | * | ||
2991 | * Returns: | ||
2992 | * 0 on success / other on failure | ||
2993 | **/ | ||
2994 | static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id) | ||
2995 | { | ||
2996 | struct ibmvfc_target *tgt; | ||
2997 | unsigned long flags; | ||
2998 | |||
2999 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3000 | list_for_each_entry(tgt, &vhost->targets, queue) { | ||
3001 | if (tgt->scsi_id == scsi_id) { | ||
3002 | if (tgt->need_login) | ||
3003 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); | ||
3004 | goto unlock_out; | ||
3005 | } | ||
3006 | } | ||
3007 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3008 | |||
3009 | tgt = mempool_alloc(vhost->tgt_pool, GFP_KERNEL); | ||
3010 | if (!tgt) { | ||
3011 | dev_err(vhost->dev, "Target allocation failure for scsi id %08lx\n", | ||
3012 | scsi_id); | ||
3013 | return -ENOMEM; | ||
3014 | } | ||
3015 | |||
3016 | tgt->scsi_id = scsi_id; | ||
3017 | tgt->new_scsi_id = scsi_id; | ||
3018 | tgt->vhost = vhost; | ||
3019 | tgt->need_login = 1; | ||
3020 | kref_init(&tgt->kref); | ||
3021 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); | ||
3022 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3023 | list_add_tail(&tgt->queue, &vhost->targets); | ||
3024 | |||
3025 | unlock_out: | ||
3026 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3027 | return 0; | ||
3028 | } | ||
3029 | |||
3030 | /** | ||
3031 | * ibmvfc_alloc_targets - Allocate and initialize ibmvfc targets | ||
3032 | * @vhost: ibmvfc host struct | ||
3033 | * | ||
3034 | * Returns: | ||
3035 | * 0 on success / other on failure | ||
3036 | **/ | ||
3037 | static int ibmvfc_alloc_targets(struct ibmvfc_host *vhost) | ||
3038 | { | ||
3039 | int i, rc; | ||
3040 | |||
3041 | for (i = 0, rc = 0; !rc && i < vhost->num_targets; i++) | ||
3042 | rc = ibmvfc_alloc_target(vhost, | ||
3043 | vhost->disc_buf->scsi_id[i] & IBMVFC_DISC_TGT_SCSI_ID_MASK); | ||
3044 | |||
3045 | return rc; | ||
3046 | } | ||
3047 | |||
3048 | /** | ||
3049 | * ibmvfc_discover_targets_done - Completion handler for discover targets MAD | ||
3050 | * @evt: ibmvfc event struct | ||
3051 | * | ||
3052 | **/ | ||
3053 | static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt) | ||
3054 | { | ||
3055 | struct ibmvfc_host *vhost = evt->vhost; | ||
3056 | struct ibmvfc_discover_targets *rsp = &evt->xfer_iu->discover_targets; | ||
3057 | u32 mad_status = rsp->common.status; | ||
3058 | |||
3059 | switch (mad_status) { | ||
3060 | case IBMVFC_MAD_SUCCESS: | ||
3061 | ibmvfc_dbg(vhost, "Discover Targets succeeded\n"); | ||
3062 | vhost->num_targets = rsp->num_written; | ||
3063 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS); | ||
3064 | break; | ||
3065 | case IBMVFC_MAD_FAILED: | ||
3066 | dev_err(vhost->dev, "Discover Targets failed: %s (%x:%x)\n", | ||
3067 | ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); | ||
3068 | ibmvfc_retry_host_init(vhost); | ||
3069 | break; | ||
3070 | case IBMVFC_MAD_DRIVER_FAILED: | ||
3071 | break; | ||
3072 | default: | ||
3073 | dev_err(vhost->dev, "Invalid Discover Targets response: 0x%x\n", mad_status); | ||
3074 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3075 | break; | ||
3076 | } | ||
3077 | |||
3078 | ibmvfc_free_event(evt); | ||
3079 | wake_up(&vhost->work_wait_q); | ||
3080 | } | ||
3081 | |||
3082 | /** | ||
3083 | * ibmvfc_discover_targets - Send Discover Targets MAD | ||
3084 | * @vhost: ibmvfc host struct | ||
3085 | * | ||
3086 | **/ | ||
3087 | static void ibmvfc_discover_targets(struct ibmvfc_host *vhost) | ||
3088 | { | ||
3089 | struct ibmvfc_discover_targets *mad; | ||
3090 | struct ibmvfc_event *evt = ibmvfc_get_event(vhost); | ||
3091 | |||
3092 | ibmvfc_init_event(evt, ibmvfc_discover_targets_done, IBMVFC_MAD_FORMAT); | ||
3093 | mad = &evt->iu.discover_targets; | ||
3094 | memset(mad, 0, sizeof(*mad)); | ||
3095 | mad->common.version = 1; | ||
3096 | mad->common.opcode = IBMVFC_DISC_TARGETS; | ||
3097 | mad->common.length = sizeof(*mad); | ||
3098 | mad->bufflen = vhost->disc_buf_sz; | ||
3099 | mad->buffer.va = vhost->disc_buf_dma; | ||
3100 | mad->buffer.len = vhost->disc_buf_sz; | ||
3101 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT); | ||
3102 | |||
3103 | if (!ibmvfc_send_event(evt, vhost, default_timeout)) | ||
3104 | ibmvfc_dbg(vhost, "Sent discover targets\n"); | ||
3105 | else | ||
3106 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3107 | } | ||
3108 | |||
3109 | /** | ||
3110 | * ibmvfc_npiv_login_done - Completion handler for NPIV Login | ||
3111 | * @evt: ibmvfc event struct | ||
3112 | * | ||
3113 | **/ | ||
3114 | static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt) | ||
3115 | { | ||
3116 | struct ibmvfc_host *vhost = evt->vhost; | ||
3117 | u32 mad_status = evt->xfer_iu->npiv_login.common.status; | ||
3118 | struct ibmvfc_npiv_login_resp *rsp = &vhost->login_buf->resp; | ||
3119 | unsigned int npiv_max_sectors; | ||
3120 | |||
3121 | switch (mad_status) { | ||
3122 | case IBMVFC_MAD_SUCCESS: | ||
3123 | ibmvfc_free_event(evt); | ||
3124 | break; | ||
3125 | case IBMVFC_MAD_FAILED: | ||
3126 | dev_err(vhost->dev, "NPIV Login failed: %s (%x:%x)\n", | ||
3127 | ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); | ||
3128 | if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | ||
3129 | ibmvfc_retry_host_init(vhost); | ||
3130 | else | ||
3131 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3132 | ibmvfc_free_event(evt); | ||
3133 | return; | ||
3134 | case IBMVFC_MAD_CRQ_ERROR: | ||
3135 | ibmvfc_retry_host_init(vhost); | ||
3136 | case IBMVFC_MAD_DRIVER_FAILED: | ||
3137 | ibmvfc_free_event(evt); | ||
3138 | return; | ||
3139 | default: | ||
3140 | dev_err(vhost->dev, "Invalid NPIV Login response: 0x%x\n", mad_status); | ||
3141 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3142 | ibmvfc_free_event(evt); | ||
3143 | return; | ||
3144 | } | ||
3145 | |||
3146 | vhost->client_migrated = 0; | ||
3147 | |||
3148 | if (!(rsp->flags & IBMVFC_NATIVE_FC)) { | ||
3149 | dev_err(vhost->dev, "Virtual adapter does not support FC. %x\n", | ||
3150 | rsp->flags); | ||
3151 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3152 | wake_up(&vhost->work_wait_q); | ||
3153 | return; | ||
3154 | } | ||
3155 | |||
3156 | if (rsp->max_cmds <= IBMVFC_NUM_INTERNAL_REQ) { | ||
3157 | dev_err(vhost->dev, "Virtual adapter supported queue depth too small: %d\n", | ||
3158 | rsp->max_cmds); | ||
3159 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3160 | wake_up(&vhost->work_wait_q); | ||
3161 | return; | ||
3162 | } | ||
3163 | |||
3164 | npiv_max_sectors = min((uint)(rsp->max_dma_len >> 9), IBMVFC_MAX_SECTORS); | ||
3165 | dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n", | ||
3166 | rsp->partition_name, rsp->device_name, rsp->port_loc_code, | ||
3167 | rsp->drc_name, npiv_max_sectors); | ||
3168 | |||
3169 | fc_host_fabric_name(vhost->host) = rsp->node_name; | ||
3170 | fc_host_node_name(vhost->host) = rsp->node_name; | ||
3171 | fc_host_port_name(vhost->host) = rsp->port_name; | ||
3172 | fc_host_port_id(vhost->host) = rsp->scsi_id; | ||
3173 | fc_host_port_type(vhost->host) = FC_PORTTYPE_NPIV; | ||
3174 | fc_host_supported_classes(vhost->host) = 0; | ||
3175 | if (rsp->service_parms.class1_parms[0] & 0x80000000) | ||
3176 | fc_host_supported_classes(vhost->host) |= FC_COS_CLASS1; | ||
3177 | if (rsp->service_parms.class2_parms[0] & 0x80000000) | ||
3178 | fc_host_supported_classes(vhost->host) |= FC_COS_CLASS2; | ||
3179 | if (rsp->service_parms.class3_parms[0] & 0x80000000) | ||
3180 | fc_host_supported_classes(vhost->host) |= FC_COS_CLASS3; | ||
3181 | fc_host_maxframe_size(vhost->host) = | ||
3182 | rsp->service_parms.common.bb_rcv_sz & 0x0fff; | ||
3183 | |||
3184 | vhost->host->can_queue = rsp->max_cmds - IBMVFC_NUM_INTERNAL_REQ; | ||
3185 | vhost->host->max_sectors = npiv_max_sectors; | ||
3186 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); | ||
3187 | wake_up(&vhost->work_wait_q); | ||
3188 | } | ||
3189 | |||
3190 | /** | ||
3191 | * ibmvfc_npiv_login - Sends NPIV login | ||
3192 | * @vhost: ibmvfc host struct | ||
3193 | * | ||
3194 | **/ | ||
3195 | static void ibmvfc_npiv_login(struct ibmvfc_host *vhost) | ||
3196 | { | ||
3197 | struct ibmvfc_npiv_login_mad *mad; | ||
3198 | struct ibmvfc_event *evt = ibmvfc_get_event(vhost); | ||
3199 | |||
3200 | ibmvfc_gather_partition_info(vhost); | ||
3201 | ibmvfc_set_login_info(vhost); | ||
3202 | ibmvfc_init_event(evt, ibmvfc_npiv_login_done, IBMVFC_MAD_FORMAT); | ||
3203 | |||
3204 | memcpy(vhost->login_buf, &vhost->login_info, sizeof(vhost->login_info)); | ||
3205 | mad = &evt->iu.npiv_login; | ||
3206 | memset(mad, 0, sizeof(struct ibmvfc_npiv_login_mad)); | ||
3207 | mad->common.version = 1; | ||
3208 | mad->common.opcode = IBMVFC_NPIV_LOGIN; | ||
3209 | mad->common.length = sizeof(struct ibmvfc_npiv_login_mad); | ||
3210 | mad->buffer.va = vhost->login_buf_dma; | ||
3211 | mad->buffer.len = sizeof(*vhost->login_buf); | ||
3212 | |||
3213 | memset(vhost->async_crq.msgs, 0, PAGE_SIZE); | ||
3214 | vhost->async_crq.cur = 0; | ||
3215 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT); | ||
3216 | |||
3217 | if (!ibmvfc_send_event(evt, vhost, default_timeout)) | ||
3218 | ibmvfc_dbg(vhost, "Sent NPIV login\n"); | ||
3219 | else | ||
3220 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3221 | }; | ||
3222 | |||
3223 | /** | ||
3224 | * ibmvfc_dev_init_to_do - Is there target initialization work to do? | ||
3225 | * @vhost: ibmvfc host struct | ||
3226 | * | ||
3227 | * Returns: | ||
3228 | * 1 if work to do / 0 if not | ||
3229 | **/ | ||
3230 | static int ibmvfc_dev_init_to_do(struct ibmvfc_host *vhost) | ||
3231 | { | ||
3232 | struct ibmvfc_target *tgt; | ||
3233 | |||
3234 | list_for_each_entry(tgt, &vhost->targets, queue) { | ||
3235 | if (tgt->action == IBMVFC_TGT_ACTION_INIT || | ||
3236 | tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) | ||
3237 | return 1; | ||
3238 | } | ||
3239 | |||
3240 | return 0; | ||
3241 | } | ||
3242 | |||
3243 | /** | ||
3244 | * __ibmvfc_work_to_do - Is there task level work to do? (no locking) | ||
3245 | * @vhost: ibmvfc host struct | ||
3246 | * | ||
3247 | * Returns: | ||
3248 | * 1 if work to do / 0 if not | ||
3249 | **/ | ||
3250 | static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) | ||
3251 | { | ||
3252 | struct ibmvfc_target *tgt; | ||
3253 | |||
3254 | if (kthread_should_stop()) | ||
3255 | return 1; | ||
3256 | switch (vhost->action) { | ||
3257 | case IBMVFC_HOST_ACTION_NONE: | ||
3258 | case IBMVFC_HOST_ACTION_INIT_WAIT: | ||
3259 | return 0; | ||
3260 | case IBMVFC_HOST_ACTION_TGT_INIT: | ||
3261 | case IBMVFC_HOST_ACTION_QUERY_TGTS: | ||
3262 | if (vhost->discovery_threads == disc_threads) | ||
3263 | return 0; | ||
3264 | list_for_each_entry(tgt, &vhost->targets, queue) | ||
3265 | if (tgt->action == IBMVFC_TGT_ACTION_INIT) | ||
3266 | return 1; | ||
3267 | list_for_each_entry(tgt, &vhost->targets, queue) | ||
3268 | if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) | ||
3269 | return 0; | ||
3270 | return 1; | ||
3271 | case IBMVFC_HOST_ACTION_INIT: | ||
3272 | case IBMVFC_HOST_ACTION_ALLOC_TGTS: | ||
3273 | case IBMVFC_HOST_ACTION_TGT_ADD: | ||
3274 | case IBMVFC_HOST_ACTION_TGT_DEL: | ||
3275 | case IBMVFC_HOST_ACTION_QUERY: | ||
3276 | default: | ||
3277 | break; | ||
3278 | }; | ||
3279 | |||
3280 | return 1; | ||
3281 | } | ||
3282 | |||
3283 | /** | ||
3284 | * ibmvfc_work_to_do - Is there task level work to do? | ||
3285 | * @vhost: ibmvfc host struct | ||
3286 | * | ||
3287 | * Returns: | ||
3288 | * 1 if work to do / 0 if not | ||
3289 | **/ | ||
3290 | static int ibmvfc_work_to_do(struct ibmvfc_host *vhost) | ||
3291 | { | ||
3292 | unsigned long flags; | ||
3293 | int rc; | ||
3294 | |||
3295 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3296 | rc = __ibmvfc_work_to_do(vhost); | ||
3297 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3298 | return rc; | ||
3299 | } | ||
3300 | |||
3301 | /** | ||
3302 | * ibmvfc_log_ae - Log async events if necessary | ||
3303 | * @vhost: ibmvfc host struct | ||
3304 | * @events: events to log | ||
3305 | * | ||
3306 | **/ | ||
3307 | static void ibmvfc_log_ae(struct ibmvfc_host *vhost, int events) | ||
3308 | { | ||
3309 | if (events & IBMVFC_AE_RSCN) | ||
3310 | fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_RSCN, 0); | ||
3311 | if ((events & IBMVFC_AE_LINKDOWN) && | ||
3312 | vhost->state >= IBMVFC_HALTED) | ||
3313 | fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_LINKDOWN, 0); | ||
3314 | if ((events & IBMVFC_AE_LINKUP) && | ||
3315 | vhost->state == IBMVFC_INITIALIZING) | ||
3316 | fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_LINKUP, 0); | ||
3317 | } | ||
3318 | |||
3319 | /** | ||
3320 | * ibmvfc_tgt_add_rport - Tell the FC transport about a new remote port | ||
3321 | * @tgt: ibmvfc target struct | ||
3322 | * | ||
3323 | **/ | ||
3324 | static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) | ||
3325 | { | ||
3326 | struct ibmvfc_host *vhost = tgt->vhost; | ||
3327 | struct fc_rport *rport; | ||
3328 | unsigned long flags; | ||
3329 | |||
3330 | tgt_dbg(tgt, "Adding rport\n"); | ||
3331 | rport = fc_remote_port_add(vhost->host, 0, &tgt->ids); | ||
3332 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3333 | tgt->rport = rport; | ||
3334 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
3335 | if (rport) { | ||
3336 | tgt_dbg(tgt, "rport add succeeded\n"); | ||
3337 | rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff; | ||
3338 | rport->supported_classes = 0; | ||
3339 | if (tgt->service_parms.class1_parms[0] & 0x80000000) | ||
3340 | rport->supported_classes |= FC_COS_CLASS1; | ||
3341 | if (tgt->service_parms.class2_parms[0] & 0x80000000) | ||
3342 | rport->supported_classes |= FC_COS_CLASS2; | ||
3343 | if (tgt->service_parms.class3_parms[0] & 0x80000000) | ||
3344 | rport->supported_classes |= FC_COS_CLASS3; | ||
3345 | } else | ||
3346 | tgt_dbg(tgt, "rport add failed\n"); | ||
3347 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3348 | } | ||
3349 | |||
3350 | /** | ||
3351 | * ibmvfc_do_work - Do task level work | ||
3352 | * @vhost: ibmvfc host struct | ||
3353 | * | ||
3354 | **/ | ||
3355 | static void ibmvfc_do_work(struct ibmvfc_host *vhost) | ||
3356 | { | ||
3357 | struct ibmvfc_target *tgt; | ||
3358 | unsigned long flags; | ||
3359 | struct fc_rport *rport; | ||
3360 | |||
3361 | ibmvfc_log_ae(vhost, vhost->events_to_log); | ||
3362 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3363 | vhost->events_to_log = 0; | ||
3364 | switch (vhost->action) { | ||
3365 | case IBMVFC_HOST_ACTION_NONE: | ||
3366 | case IBMVFC_HOST_ACTION_INIT_WAIT: | ||
3367 | break; | ||
3368 | case IBMVFC_HOST_ACTION_INIT: | ||
3369 | BUG_ON(vhost->state != IBMVFC_INITIALIZING); | ||
3370 | vhost->job_step(vhost); | ||
3371 | break; | ||
3372 | case IBMVFC_HOST_ACTION_QUERY: | ||
3373 | list_for_each_entry(tgt, &vhost->targets, queue) | ||
3374 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_query_target); | ||
3375 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY_TGTS); | ||
3376 | break; | ||
3377 | case IBMVFC_HOST_ACTION_QUERY_TGTS: | ||
3378 | list_for_each_entry(tgt, &vhost->targets, queue) { | ||
3379 | if (tgt->action == IBMVFC_TGT_ACTION_INIT) { | ||
3380 | tgt->job_step(tgt); | ||
3381 | break; | ||
3382 | } | ||
3383 | } | ||
3384 | |||
3385 | if (!ibmvfc_dev_init_to_do(vhost)) | ||
3386 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); | ||
3387 | break; | ||
3388 | case IBMVFC_HOST_ACTION_TGT_DEL: | ||
3389 | list_for_each_entry(tgt, &vhost->targets, queue) { | ||
3390 | if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { | ||
3391 | tgt_dbg(tgt, "Deleting rport\n"); | ||
3392 | rport = tgt->rport; | ||
3393 | tgt->rport = NULL; | ||
3394 | list_del(&tgt->queue); | ||
3395 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3396 | if (rport) | ||
3397 | fc_remote_port_delete(rport); | ||
3398 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
3399 | return; | ||
3400 | } | ||
3401 | } | ||
3402 | |||
3403 | if (vhost->state == IBMVFC_INITIALIZING) { | ||
3404 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); | ||
3405 | vhost->job_step = ibmvfc_discover_targets; | ||
3406 | } else { | ||
3407 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); | ||
3408 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3409 | scsi_unblock_requests(vhost->host); | ||
3410 | wake_up(&vhost->init_wait_q); | ||
3411 | return; | ||
3412 | } | ||
3413 | break; | ||
3414 | case IBMVFC_HOST_ACTION_ALLOC_TGTS: | ||
3415 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_INIT); | ||
3416 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3417 | ibmvfc_alloc_targets(vhost); | ||
3418 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3419 | break; | ||
3420 | case IBMVFC_HOST_ACTION_TGT_INIT: | ||
3421 | list_for_each_entry(tgt, &vhost->targets, queue) { | ||
3422 | if (tgt->action == IBMVFC_TGT_ACTION_INIT) { | ||
3423 | tgt->job_step(tgt); | ||
3424 | break; | ||
3425 | } | ||
3426 | } | ||
3427 | |||
3428 | if (!ibmvfc_dev_init_to_do(vhost)) { | ||
3429 | ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); | ||
3430 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); | ||
3431 | vhost->init_retries = 0; | ||
3432 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3433 | scsi_unblock_requests(vhost->host); | ||
3434 | return; | ||
3435 | } | ||
3436 | break; | ||
3437 | case IBMVFC_HOST_ACTION_TGT_ADD: | ||
3438 | list_for_each_entry(tgt, &vhost->targets, queue) { | ||
3439 | if (tgt->action == IBMVFC_TGT_ACTION_ADD_RPORT) { | ||
3440 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3441 | ibmvfc_tgt_add_rport(tgt); | ||
3442 | return; | ||
3443 | } else if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { | ||
3444 | tgt_dbg(tgt, "Deleting rport\n"); | ||
3445 | rport = tgt->rport; | ||
3446 | tgt->rport = NULL; | ||
3447 | list_del(&tgt->queue); | ||
3448 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3449 | if (rport) | ||
3450 | fc_remote_port_delete(rport); | ||
3451 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
3452 | return; | ||
3453 | } | ||
3454 | } | ||
3455 | |||
3456 | if (vhost->reinit) { | ||
3457 | vhost->reinit = 0; | ||
3458 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); | ||
3459 | } else { | ||
3460 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); | ||
3461 | wake_up(&vhost->init_wait_q); | ||
3462 | } | ||
3463 | break; | ||
3464 | default: | ||
3465 | break; | ||
3466 | }; | ||
3467 | |||
3468 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3469 | } | ||
3470 | |||
3471 | /** | ||
3472 | * ibmvfc_work - Do task level work | ||
3473 | * @data: ibmvfc host struct | ||
3474 | * | ||
3475 | * Returns: | ||
3476 | * zero | ||
3477 | **/ | ||
3478 | static int ibmvfc_work(void *data) | ||
3479 | { | ||
3480 | struct ibmvfc_host *vhost = data; | ||
3481 | int rc; | ||
3482 | |||
3483 | set_user_nice(current, -20); | ||
3484 | |||
3485 | while (1) { | ||
3486 | rc = wait_event_interruptible(vhost->work_wait_q, | ||
3487 | ibmvfc_work_to_do(vhost)); | ||
3488 | |||
3489 | BUG_ON(rc); | ||
3490 | |||
3491 | if (kthread_should_stop()) | ||
3492 | break; | ||
3493 | |||
3494 | ibmvfc_do_work(vhost); | ||
3495 | } | ||
3496 | |||
3497 | ibmvfc_dbg(vhost, "ibmvfc kthread exiting...\n"); | ||
3498 | return 0; | ||
3499 | } | ||
3500 | |||
3501 | /** | ||
3502 | * ibmvfc_init_crq - Initializes and registers CRQ with hypervisor | ||
3503 | * @vhost: ibmvfc host struct | ||
3504 | * | ||
3505 | * Allocates a page for messages, maps it for dma, and registers | ||
3506 | * the crq with the hypervisor. | ||
3507 | * | ||
3508 | * Return value: | ||
3509 | * zero on success / other on failure | ||
3510 | **/ | ||
3511 | static int ibmvfc_init_crq(struct ibmvfc_host *vhost) | ||
3512 | { | ||
3513 | int rc, retrc = -ENOMEM; | ||
3514 | struct device *dev = vhost->dev; | ||
3515 | struct vio_dev *vdev = to_vio_dev(dev); | ||
3516 | struct ibmvfc_crq_queue *crq = &vhost->crq; | ||
3517 | |||
3518 | ENTER; | ||
3519 | crq->msgs = (struct ibmvfc_crq *)get_zeroed_page(GFP_KERNEL); | ||
3520 | |||
3521 | if (!crq->msgs) | ||
3522 | return -ENOMEM; | ||
3523 | |||
3524 | crq->size = PAGE_SIZE / sizeof(*crq->msgs); | ||
3525 | crq->msg_token = dma_map_single(dev, crq->msgs, | ||
3526 | PAGE_SIZE, DMA_BIDIRECTIONAL); | ||
3527 | |||
3528 | if (dma_mapping_error(crq->msg_token)) | ||
3529 | goto map_failed; | ||
3530 | |||
3531 | retrc = rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, | ||
3532 | crq->msg_token, PAGE_SIZE); | ||
3533 | |||
3534 | if (rc == H_RESOURCE) | ||
3535 | /* maybe kexecing and resource is busy. try a reset */ | ||
3536 | retrc = rc = ibmvfc_reset_crq(vhost); | ||
3537 | |||
3538 | if (rc == H_CLOSED) | ||
3539 | dev_warn(dev, "Partner adapter not ready\n"); | ||
3540 | else if (rc) { | ||
3541 | dev_warn(dev, "Error %d opening adapter\n", rc); | ||
3542 | goto reg_crq_failed; | ||
3543 | } | ||
3544 | |||
3545 | retrc = 0; | ||
3546 | |||
3547 | if ((rc = request_irq(vdev->irq, ibmvfc_interrupt, 0, IBMVFC_NAME, vhost))) { | ||
3548 | dev_err(dev, "Couldn't register irq 0x%x. rc=%d\n", vdev->irq, rc); | ||
3549 | goto req_irq_failed; | ||
3550 | } | ||
3551 | |||
3552 | if ((rc = vio_enable_interrupts(vdev))) { | ||
3553 | dev_err(dev, "Error %d enabling interrupts\n", rc); | ||
3554 | goto req_irq_failed; | ||
3555 | } | ||
3556 | |||
3557 | crq->cur = 0; | ||
3558 | LEAVE; | ||
3559 | return retrc; | ||
3560 | |||
3561 | req_irq_failed: | ||
3562 | do { | ||
3563 | rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); | ||
3564 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
3565 | reg_crq_failed: | ||
3566 | dma_unmap_single(dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); | ||
3567 | map_failed: | ||
3568 | free_page((unsigned long)crq->msgs); | ||
3569 | return retrc; | ||
3570 | } | ||
3571 | |||
3572 | /** | ||
3573 | * ibmvfc_free_mem - Free memory for vhost | ||
3574 | * @vhost: ibmvfc host struct | ||
3575 | * | ||
3576 | * Return value: | ||
3577 | * none | ||
3578 | **/ | ||
3579 | static void ibmvfc_free_mem(struct ibmvfc_host *vhost) | ||
3580 | { | ||
3581 | struct ibmvfc_async_crq_queue *async_q = &vhost->async_crq; | ||
3582 | |||
3583 | ENTER; | ||
3584 | mempool_destroy(vhost->tgt_pool); | ||
3585 | kfree(vhost->trace); | ||
3586 | dma_free_coherent(vhost->dev, vhost->disc_buf_sz, vhost->disc_buf, | ||
3587 | vhost->disc_buf_dma); | ||
3588 | dma_free_coherent(vhost->dev, sizeof(*vhost->login_buf), | ||
3589 | vhost->login_buf, vhost->login_buf_dma); | ||
3590 | dma_pool_destroy(vhost->sg_pool); | ||
3591 | dma_unmap_single(vhost->dev, async_q->msg_token, | ||
3592 | async_q->size * sizeof(*async_q->msgs), DMA_BIDIRECTIONAL); | ||
3593 | free_page((unsigned long)async_q->msgs); | ||
3594 | LEAVE; | ||
3595 | } | ||
3596 | |||
3597 | /** | ||
3598 | * ibmvfc_alloc_mem - Allocate memory for vhost | ||
3599 | * @vhost: ibmvfc host struct | ||
3600 | * | ||
3601 | * Return value: | ||
3602 | * 0 on success / non-zero on failure | ||
3603 | **/ | ||
3604 | static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost) | ||
3605 | { | ||
3606 | struct ibmvfc_async_crq_queue *async_q = &vhost->async_crq; | ||
3607 | struct device *dev = vhost->dev; | ||
3608 | |||
3609 | ENTER; | ||
3610 | async_q->msgs = (struct ibmvfc_async_crq *)get_zeroed_page(GFP_KERNEL); | ||
3611 | if (!async_q->msgs) { | ||
3612 | dev_err(dev, "Couldn't allocate async queue.\n"); | ||
3613 | goto nomem; | ||
3614 | } | ||
3615 | |||
3616 | async_q->size = PAGE_SIZE / sizeof(struct ibmvfc_async_crq); | ||
3617 | async_q->msg_token = dma_map_single(dev, async_q->msgs, | ||
3618 | async_q->size * sizeof(*async_q->msgs), | ||
3619 | DMA_BIDIRECTIONAL); | ||
3620 | |||
3621 | if (dma_mapping_error(async_q->msg_token)) { | ||
3622 | dev_err(dev, "Failed to map async queue\n"); | ||
3623 | goto free_async_crq; | ||
3624 | } | ||
3625 | |||
3626 | vhost->sg_pool = dma_pool_create(IBMVFC_NAME, dev, | ||
3627 | SG_ALL * sizeof(struct srp_direct_buf), | ||
3628 | sizeof(struct srp_direct_buf), 0); | ||
3629 | |||
3630 | if (!vhost->sg_pool) { | ||
3631 | dev_err(dev, "Failed to allocate sg pool\n"); | ||
3632 | goto unmap_async_crq; | ||
3633 | } | ||
3634 | |||
3635 | vhost->login_buf = dma_alloc_coherent(dev, sizeof(*vhost->login_buf), | ||
3636 | &vhost->login_buf_dma, GFP_KERNEL); | ||
3637 | |||
3638 | if (!vhost->login_buf) { | ||
3639 | dev_err(dev, "Couldn't allocate NPIV login buffer\n"); | ||
3640 | goto free_sg_pool; | ||
3641 | } | ||
3642 | |||
3643 | vhost->disc_buf_sz = sizeof(vhost->disc_buf->scsi_id[0]) * max_targets; | ||
3644 | vhost->disc_buf = dma_alloc_coherent(dev, vhost->disc_buf_sz, | ||
3645 | &vhost->disc_buf_dma, GFP_KERNEL); | ||
3646 | |||
3647 | if (!vhost->disc_buf) { | ||
3648 | dev_err(dev, "Couldn't allocate Discover Targets buffer\n"); | ||
3649 | goto free_login_buffer; | ||
3650 | } | ||
3651 | |||
3652 | vhost->trace = kcalloc(IBMVFC_NUM_TRACE_ENTRIES, | ||
3653 | sizeof(struct ibmvfc_trace_entry), GFP_KERNEL); | ||
3654 | |||
3655 | if (!vhost->trace) | ||
3656 | goto free_disc_buffer; | ||
3657 | |||
3658 | vhost->tgt_pool = mempool_create_kzalloc_pool(IBMVFC_TGT_MEMPOOL_SZ, | ||
3659 | sizeof(struct ibmvfc_target)); | ||
3660 | |||
3661 | if (!vhost->tgt_pool) { | ||
3662 | dev_err(dev, "Couldn't allocate target memory pool\n"); | ||
3663 | goto free_trace; | ||
3664 | } | ||
3665 | |||
3666 | LEAVE; | ||
3667 | return 0; | ||
3668 | |||
3669 | free_trace: | ||
3670 | kfree(vhost->trace); | ||
3671 | free_disc_buffer: | ||
3672 | dma_free_coherent(dev, vhost->disc_buf_sz, vhost->disc_buf, | ||
3673 | vhost->disc_buf_dma); | ||
3674 | free_login_buffer: | ||
3675 | dma_free_coherent(dev, sizeof(*vhost->login_buf), | ||
3676 | vhost->login_buf, vhost->login_buf_dma); | ||
3677 | free_sg_pool: | ||
3678 | dma_pool_destroy(vhost->sg_pool); | ||
3679 | unmap_async_crq: | ||
3680 | dma_unmap_single(dev, async_q->msg_token, | ||
3681 | async_q->size * sizeof(*async_q->msgs), DMA_BIDIRECTIONAL); | ||
3682 | free_async_crq: | ||
3683 | free_page((unsigned long)async_q->msgs); | ||
3684 | nomem: | ||
3685 | LEAVE; | ||
3686 | return -ENOMEM; | ||
3687 | } | ||
3688 | |||
3689 | /** | ||
3690 | * ibmvfc_probe - Adapter hot plug add entry point | ||
3691 | * @vdev: vio device struct | ||
3692 | * @id: vio device id struct | ||
3693 | * | ||
3694 | * Return value: | ||
3695 | * 0 on success / non-zero on failure | ||
3696 | **/ | ||
3697 | static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id) | ||
3698 | { | ||
3699 | struct ibmvfc_host *vhost; | ||
3700 | struct Scsi_Host *shost; | ||
3701 | struct device *dev = &vdev->dev; | ||
3702 | int rc = -ENOMEM; | ||
3703 | |||
3704 | ENTER; | ||
3705 | shost = scsi_host_alloc(&driver_template, sizeof(*vhost)); | ||
3706 | if (!shost) { | ||
3707 | dev_err(dev, "Couldn't allocate host data\n"); | ||
3708 | goto out; | ||
3709 | } | ||
3710 | |||
3711 | shost->transportt = ibmvfc_transport_template; | ||
3712 | shost->can_queue = max_requests; | ||
3713 | shost->max_lun = max_lun; | ||
3714 | shost->max_id = max_targets; | ||
3715 | shost->max_sectors = IBMVFC_MAX_SECTORS; | ||
3716 | shost->max_cmd_len = IBMVFC_MAX_CDB_LEN; | ||
3717 | shost->unique_id = shost->host_no; | ||
3718 | |||
3719 | vhost = shost_priv(shost); | ||
3720 | INIT_LIST_HEAD(&vhost->sent); | ||
3721 | INIT_LIST_HEAD(&vhost->free); | ||
3722 | INIT_LIST_HEAD(&vhost->targets); | ||
3723 | sprintf(vhost->name, IBMVFC_NAME); | ||
3724 | vhost->host = shost; | ||
3725 | vhost->dev = dev; | ||
3726 | vhost->partition_number = -1; | ||
3727 | vhost->log_level = log_level; | ||
3728 | strcpy(vhost->partition_name, "UNKNOWN"); | ||
3729 | init_waitqueue_head(&vhost->work_wait_q); | ||
3730 | init_waitqueue_head(&vhost->init_wait_q); | ||
3731 | |||
3732 | if ((rc = ibmvfc_alloc_mem(vhost))) | ||
3733 | goto free_scsi_host; | ||
3734 | |||
3735 | vhost->work_thread = kthread_run(ibmvfc_work, vhost, "%s_%d", IBMVFC_NAME, | ||
3736 | shost->host_no); | ||
3737 | |||
3738 | if (IS_ERR(vhost->work_thread)) { | ||
3739 | dev_err(dev, "Couldn't create kernel thread: %ld\n", | ||
3740 | PTR_ERR(vhost->work_thread)); | ||
3741 | goto free_host_mem; | ||
3742 | } | ||
3743 | |||
3744 | if ((rc = ibmvfc_init_crq(vhost))) { | ||
3745 | dev_err(dev, "Couldn't initialize crq. rc=%d\n", rc); | ||
3746 | goto kill_kthread; | ||
3747 | } | ||
3748 | |||
3749 | if ((rc = ibmvfc_init_event_pool(vhost))) { | ||
3750 | dev_err(dev, "Couldn't initialize event pool. rc=%d\n", rc); | ||
3751 | goto release_crq; | ||
3752 | } | ||
3753 | |||
3754 | if ((rc = scsi_add_host(shost, dev))) | ||
3755 | goto release_event_pool; | ||
3756 | |||
3757 | if ((rc = ibmvfc_create_trace_file(&shost->shost_dev.kobj, | ||
3758 | &ibmvfc_trace_attr))) { | ||
3759 | dev_err(dev, "Failed to create trace file. rc=%d\n", rc); | ||
3760 | goto remove_shost; | ||
3761 | } | ||
3762 | |||
3763 | dev_set_drvdata(dev, vhost); | ||
3764 | spin_lock(&ibmvfc_driver_lock); | ||
3765 | list_add_tail(&vhost->queue, &ibmvfc_head); | ||
3766 | spin_unlock(&ibmvfc_driver_lock); | ||
3767 | |||
3768 | ibmvfc_send_crq_init(vhost); | ||
3769 | scsi_scan_host(shost); | ||
3770 | return 0; | ||
3771 | |||
3772 | remove_shost: | ||
3773 | scsi_remove_host(shost); | ||
3774 | release_event_pool: | ||
3775 | ibmvfc_free_event_pool(vhost); | ||
3776 | release_crq: | ||
3777 | ibmvfc_release_crq_queue(vhost); | ||
3778 | kill_kthread: | ||
3779 | kthread_stop(vhost->work_thread); | ||
3780 | free_host_mem: | ||
3781 | ibmvfc_free_mem(vhost); | ||
3782 | free_scsi_host: | ||
3783 | scsi_host_put(shost); | ||
3784 | out: | ||
3785 | LEAVE; | ||
3786 | return rc; | ||
3787 | } | ||
3788 | |||
3789 | /** | ||
3790 | * ibmvfc_remove - Adapter hot plug remove entry point | ||
3791 | * @vdev: vio device struct | ||
3792 | * | ||
3793 | * Return value: | ||
3794 | * 0 | ||
3795 | **/ | ||
3796 | static int ibmvfc_remove(struct vio_dev *vdev) | ||
3797 | { | ||
3798 | struct ibmvfc_host *vhost = dev_get_drvdata(&vdev->dev); | ||
3799 | unsigned long flags; | ||
3800 | |||
3801 | ENTER; | ||
3802 | ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr); | ||
3803 | kthread_stop(vhost->work_thread); | ||
3804 | fc_remove_host(vhost->host); | ||
3805 | scsi_remove_host(vhost->host); | ||
3806 | ibmvfc_release_crq_queue(vhost); | ||
3807 | |||
3808 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3809 | ibmvfc_purge_requests(vhost, DID_ERROR); | ||
3810 | ibmvfc_free_event_pool(vhost); | ||
3811 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3812 | |||
3813 | ibmvfc_free_mem(vhost); | ||
3814 | spin_lock(&ibmvfc_driver_lock); | ||
3815 | list_del(&vhost->queue); | ||
3816 | spin_unlock(&ibmvfc_driver_lock); | ||
3817 | scsi_host_put(vhost->host); | ||
3818 | LEAVE; | ||
3819 | return 0; | ||
3820 | } | ||
3821 | |||
3822 | static struct vio_device_id ibmvfc_device_table[] __devinitdata = { | ||
3823 | {"fcp", "IBM,vfc-client"}, | ||
3824 | { "", "" } | ||
3825 | }; | ||
3826 | MODULE_DEVICE_TABLE(vio, ibmvfc_device_table); | ||
3827 | |||
3828 | static struct vio_driver ibmvfc_driver = { | ||
3829 | .id_table = ibmvfc_device_table, | ||
3830 | .probe = ibmvfc_probe, | ||
3831 | .remove = ibmvfc_remove, | ||
3832 | .driver = { | ||
3833 | .name = IBMVFC_NAME, | ||
3834 | .owner = THIS_MODULE, | ||
3835 | } | ||
3836 | }; | ||
3837 | |||
3838 | static struct fc_function_template ibmvfc_transport_functions = { | ||
3839 | .show_host_fabric_name = 1, | ||
3840 | .show_host_node_name = 1, | ||
3841 | .show_host_port_name = 1, | ||
3842 | .show_host_supported_classes = 1, | ||
3843 | .show_host_port_type = 1, | ||
3844 | .show_host_port_id = 1, | ||
3845 | |||
3846 | .get_host_port_state = ibmvfc_get_host_port_state, | ||
3847 | .show_host_port_state = 1, | ||
3848 | |||
3849 | .get_host_speed = ibmvfc_get_host_speed, | ||
3850 | .show_host_speed = 1, | ||
3851 | |||
3852 | .issue_fc_host_lip = ibmvfc_issue_fc_host_lip, | ||
3853 | .terminate_rport_io = ibmvfc_terminate_rport_io, | ||
3854 | |||
3855 | .show_rport_maxframe_size = 1, | ||
3856 | .show_rport_supported_classes = 1, | ||
3857 | |||
3858 | .set_rport_dev_loss_tmo = ibmvfc_set_rport_dev_loss_tmo, | ||
3859 | .show_rport_dev_loss_tmo = 1, | ||
3860 | |||
3861 | .get_starget_node_name = ibmvfc_get_starget_node_name, | ||
3862 | .show_starget_node_name = 1, | ||
3863 | |||
3864 | .get_starget_port_name = ibmvfc_get_starget_port_name, | ||
3865 | .show_starget_port_name = 1, | ||
3866 | |||
3867 | .get_starget_port_id = ibmvfc_get_starget_port_id, | ||
3868 | .show_starget_port_id = 1, | ||
3869 | }; | ||
3870 | |||
3871 | /** | ||
3872 | * ibmvfc_module_init - Initialize the ibmvfc module | ||
3873 | * | ||
3874 | * Return value: | ||
3875 | * 0 on success / other on failure | ||
3876 | **/ | ||
3877 | static int __init ibmvfc_module_init(void) | ||
3878 | { | ||
3879 | int rc; | ||
3880 | |||
3881 | if (!firmware_has_feature(FW_FEATURE_VIO)) | ||
3882 | return -ENODEV; | ||
3883 | |||
3884 | printk(KERN_INFO IBMVFC_NAME": IBM Virtual Fibre Channel Driver version: %s %s\n", | ||
3885 | IBMVFC_DRIVER_VERSION, IBMVFC_DRIVER_DATE); | ||
3886 | |||
3887 | ibmvfc_transport_template = fc_attach_transport(&ibmvfc_transport_functions); | ||
3888 | if (!ibmvfc_transport_template) | ||
3889 | return -ENOMEM; | ||
3890 | |||
3891 | rc = vio_register_driver(&ibmvfc_driver); | ||
3892 | if (rc) | ||
3893 | fc_release_transport(ibmvfc_transport_template); | ||
3894 | return rc; | ||
3895 | } | ||
3896 | |||
3897 | /** | ||
3898 | * ibmvfc_module_exit - Teardown the ibmvfc module | ||
3899 | * | ||
3900 | * Return value: | ||
3901 | * nothing | ||
3902 | **/ | ||
3903 | static void __exit ibmvfc_module_exit(void) | ||
3904 | { | ||
3905 | vio_unregister_driver(&ibmvfc_driver); | ||
3906 | fc_release_transport(ibmvfc_transport_template); | ||
3907 | } | ||
3908 | |||
3909 | module_init(ibmvfc_module_init); | ||
3910 | module_exit(ibmvfc_module_exit); | ||
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h new file mode 100644 index 000000000000..057f3c01ed61 --- /dev/null +++ b/drivers/scsi/ibmvscsi/ibmvfc.h | |||
@@ -0,0 +1,682 @@ | |||
1 | /* | ||
2 | * ibmvfc.h -- driver for IBM Power Virtual Fibre Channel Adapter | ||
3 | * | ||
4 | * Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation | ||
5 | * | ||
6 | * Copyright (C) IBM Corporation, 2008 | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef _IBMVFC_H | ||
25 | #define _IBMVFC_H | ||
26 | |||
27 | #include <linux/list.h> | ||
28 | #include <linux/types.h> | ||
29 | #include "viosrp.h" | ||
30 | |||
31 | #define IBMVFC_NAME "ibmvfc" | ||
32 | #define IBMVFC_DRIVER_VERSION "1.0.0" | ||
33 | #define IBMVFC_DRIVER_DATE "(July 1, 2008)" | ||
34 | |||
35 | #define IBMVFC_DEFAULT_TIMEOUT 15 | ||
36 | #define IBMVFC_INIT_TIMEOUT 30 | ||
37 | #define IBMVFC_MAX_REQUESTS_DEFAULT 100 | ||
38 | |||
39 | #define IBMVFC_DEBUG 0 | ||
40 | #define IBMVFC_MAX_TARGETS 1024 | ||
41 | #define IBMVFC_MAX_LUN 0xffffffff | ||
42 | #define IBMVFC_MAX_SECTORS 0xffffu | ||
43 | #define IBMVFC_MAX_DISC_THREADS 4 | ||
44 | #define IBMVFC_TGT_MEMPOOL_SZ 64 | ||
45 | #define IBMVFC_MAX_CMDS_PER_LUN 64 | ||
46 | #define IBMVFC_MAX_INIT_RETRIES 3 | ||
47 | #define IBMVFC_DEV_LOSS_TMO (5 * 60) | ||
48 | #define IBMVFC_DEFAULT_LOG_LEVEL 2 | ||
49 | #define IBMVFC_MAX_CDB_LEN 16 | ||
50 | |||
51 | /* | ||
52 | * Ensure we have resources for ERP and initialization: | ||
53 | * 1 for ERP | ||
54 | * 1 for initialization | ||
55 | * 1 for each discovery thread | ||
56 | */ | ||
57 | #define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + disc_threads) | ||
58 | |||
59 | #define IBMVFC_MAD_SUCCESS 0x00 | ||
60 | #define IBMVFC_MAD_NOT_SUPPORTED 0xF1 | ||
61 | #define IBMVFC_MAD_FAILED 0xF7 | ||
62 | #define IBMVFC_MAD_DRIVER_FAILED 0xEE | ||
63 | #define IBMVFC_MAD_CRQ_ERROR 0xEF | ||
64 | |||
65 | enum ibmvfc_crq_valid { | ||
66 | IBMVFC_CRQ_CMD_RSP = 0x80, | ||
67 | IBMVFC_CRQ_INIT_RSP = 0xC0, | ||
68 | IBMVFC_CRQ_XPORT_EVENT = 0xFF, | ||
69 | }; | ||
70 | |||
71 | enum ibmvfc_crq_format { | ||
72 | IBMVFC_CRQ_INIT = 0x01, | ||
73 | IBMVFC_CRQ_INIT_COMPLETE = 0x02, | ||
74 | IBMVFC_PARTITION_MIGRATED = 0x06, | ||
75 | }; | ||
76 | |||
77 | enum ibmvfc_cmd_status_flags { | ||
78 | IBMVFC_FABRIC_MAPPED = 0x0001, | ||
79 | IBMVFC_VIOS_FAILURE = 0x0002, | ||
80 | IBMVFC_FC_FAILURE = 0x0004, | ||
81 | IBMVFC_FC_SCSI_ERROR = 0x0008, | ||
82 | IBMVFC_HW_EVENT_LOGGED = 0x0010, | ||
83 | IBMVFC_VIOS_LOGGED = 0x0020, | ||
84 | }; | ||
85 | |||
86 | enum ibmvfc_fabric_mapped_errors { | ||
87 | IBMVFC_UNABLE_TO_ESTABLISH = 0x0001, | ||
88 | IBMVFC_XPORT_FAULT = 0x0002, | ||
89 | IBMVFC_CMD_TIMEOUT = 0x0003, | ||
90 | IBMVFC_ENETDOWN = 0x0004, | ||
91 | IBMVFC_HW_FAILURE = 0x0005, | ||
92 | IBMVFC_LINK_DOWN_ERR = 0x0006, | ||
93 | IBMVFC_LINK_DEAD_ERR = 0x0007, | ||
94 | IBMVFC_UNABLE_TO_REGISTER = 0x0008, | ||
95 | IBMVFC_XPORT_BUSY = 0x000A, | ||
96 | IBMVFC_XPORT_DEAD = 0x000B, | ||
97 | IBMVFC_CONFIG_ERROR = 0x000C, | ||
98 | IBMVFC_NAME_SERVER_FAIL = 0x000D, | ||
99 | IBMVFC_LINK_HALTED = 0x000E, | ||
100 | IBMVFC_XPORT_GENERAL = 0x8000, | ||
101 | }; | ||
102 | |||
103 | enum ibmvfc_vios_errors { | ||
104 | IBMVFC_CRQ_FAILURE = 0x0001, | ||
105 | IBMVFC_SW_FAILURE = 0x0002, | ||
106 | IBMVFC_INVALID_PARAMETER = 0x0003, | ||
107 | IBMVFC_MISSING_PARAMETER = 0x0004, | ||
108 | IBMVFC_HOST_IO_BUS = 0x0005, | ||
109 | IBMVFC_TRANS_CANCELLED = 0x0006, | ||
110 | IBMVFC_TRANS_CANCELLED_IMPLICIT = 0x0007, | ||
111 | IBMVFC_INSUFFICIENT_RESOURCE = 0x0008, | ||
112 | IBMVFC_COMMAND_FAILED = 0x8000, | ||
113 | }; | ||
114 | |||
115 | enum ibmvfc_mad_types { | ||
116 | IBMVFC_NPIV_LOGIN = 0x0001, | ||
117 | IBMVFC_DISC_TARGETS = 0x0002, | ||
118 | IBMVFC_PORT_LOGIN = 0x0004, | ||
119 | IBMVFC_PROCESS_LOGIN = 0x0008, | ||
120 | IBMVFC_QUERY_TARGET = 0x0010, | ||
121 | IBMVFC_IMPLICIT_LOGOUT = 0x0040, | ||
122 | IBMVFC_TMF_MAD = 0x0100, | ||
123 | }; | ||
124 | |||
125 | struct ibmvfc_mad_common { | ||
126 | u32 version; | ||
127 | u32 reserved; | ||
128 | u32 opcode; | ||
129 | u16 status; | ||
130 | u16 length; | ||
131 | u64 tag; | ||
132 | }__attribute__((packed, aligned (8))); | ||
133 | |||
134 | struct ibmvfc_npiv_login_mad { | ||
135 | struct ibmvfc_mad_common common; | ||
136 | struct srp_direct_buf buffer; | ||
137 | }__attribute__((packed, aligned (8))); | ||
138 | |||
139 | #define IBMVFC_MAX_NAME 256 | ||
140 | |||
141 | struct ibmvfc_npiv_login { | ||
142 | u32 ostype; | ||
143 | #define IBMVFC_OS_LINUX 0x02 | ||
144 | u32 pad; | ||
145 | u64 max_dma_len; | ||
146 | u32 max_payload; | ||
147 | u32 max_response; | ||
148 | u32 partition_num; | ||
149 | u32 vfc_frame_version; | ||
150 | u16 fcp_version; | ||
151 | u16 flags; | ||
152 | #define IBMVFC_CLIENT_MIGRATED 0x01 | ||
153 | #define IBMVFC_FLUSH_ON_HALT 0x02 | ||
154 | u32 max_cmds; | ||
155 | u64 capabilities; | ||
156 | #define IBMVFC_CAN_MIGRATE 0x01 | ||
157 | u64 node_name; | ||
158 | struct srp_direct_buf async; | ||
159 | u8 partition_name[IBMVFC_MAX_NAME]; | ||
160 | u8 device_name[IBMVFC_MAX_NAME]; | ||
161 | u8 drc_name[IBMVFC_MAX_NAME]; | ||
162 | u64 reserved2[2]; | ||
163 | }__attribute__((packed, aligned (8))); | ||
164 | |||
165 | struct ibmvfc_common_svc_parms { | ||
166 | u16 fcph_version; | ||
167 | u16 b2b_credit; | ||
168 | u16 features; | ||
169 | u16 bb_rcv_sz; /* upper nibble is BB_SC_N */ | ||
170 | u32 ratov; | ||
171 | u32 edtov; | ||
172 | }__attribute__((packed, aligned (4))); | ||
173 | |||
174 | struct ibmvfc_service_parms { | ||
175 | struct ibmvfc_common_svc_parms common; | ||
176 | u8 port_name[8]; | ||
177 | u8 node_name[8]; | ||
178 | u32 class1_parms[4]; | ||
179 | u32 class2_parms[4]; | ||
180 | u32 class3_parms[4]; | ||
181 | u32 obsolete[4]; | ||
182 | u32 vendor_version[4]; | ||
183 | u32 services_avail[2]; | ||
184 | u32 ext_len; | ||
185 | u32 reserved[30]; | ||
186 | u32 clk_sync_qos[2]; | ||
187 | }__attribute__((packed, aligned (4))); | ||
188 | |||
189 | struct ibmvfc_npiv_login_resp { | ||
190 | u32 version; | ||
191 | u16 status; | ||
192 | u16 error; | ||
193 | u32 flags; | ||
194 | #define IBMVFC_NATIVE_FC 0x01 | ||
195 | #define IBMVFC_CAN_FLUSH_ON_HALT 0x08 | ||
196 | u32 reserved; | ||
197 | u64 capabilites; | ||
198 | u32 max_cmds; | ||
199 | u32 scsi_id_sz; | ||
200 | u64 max_dma_len; | ||
201 | u64 scsi_id; | ||
202 | u64 port_name; | ||
203 | u64 node_name; | ||
204 | u64 link_speed; | ||
205 | u8 partition_name[IBMVFC_MAX_NAME]; | ||
206 | u8 device_name[IBMVFC_MAX_NAME]; | ||
207 | u8 port_loc_code[IBMVFC_MAX_NAME]; | ||
208 | u8 drc_name[IBMVFC_MAX_NAME]; | ||
209 | struct ibmvfc_service_parms service_parms; | ||
210 | u64 reserved2; | ||
211 | }__attribute__((packed, aligned (8))); | ||
212 | |||
213 | union ibmvfc_npiv_login_data { | ||
214 | struct ibmvfc_npiv_login login; | ||
215 | struct ibmvfc_npiv_login_resp resp; | ||
216 | }__attribute__((packed, aligned (8))); | ||
217 | |||
218 | struct ibmvfc_discover_targets_buf { | ||
219 | u32 scsi_id[1]; | ||
220 | #define IBMVFC_DISC_TGT_SCSI_ID_MASK 0x00ffffff | ||
221 | }; | ||
222 | |||
223 | struct ibmvfc_discover_targets { | ||
224 | struct ibmvfc_mad_common common; | ||
225 | struct srp_direct_buf buffer; | ||
226 | u32 flags; | ||
227 | u16 status; | ||
228 | u16 error; | ||
229 | u32 bufflen; | ||
230 | u32 num_avail; | ||
231 | u32 num_written; | ||
232 | u64 reserved[2]; | ||
233 | }__attribute__((packed, aligned (8))); | ||
234 | |||
235 | enum ibmvfc_fc_reason { | ||
236 | IBMVFC_INVALID_ELS_CMD_CODE = 0x01, | ||
237 | IBMVFC_INVALID_VERSION = 0x02, | ||
238 | IBMVFC_LOGICAL_ERROR = 0x03, | ||
239 | IBMVFC_INVALID_CT_IU_SIZE = 0x04, | ||
240 | IBMVFC_LOGICAL_BUSY = 0x05, | ||
241 | IBMVFC_PROTOCOL_ERROR = 0x07, | ||
242 | IBMVFC_UNABLE_TO_PERFORM_REQ = 0x09, | ||
243 | IBMVFC_CMD_NOT_SUPPORTED = 0x0B, | ||
244 | IBMVFC_SERVER_NOT_AVAIL = 0x0D, | ||
245 | IBMVFC_CMD_IN_PROGRESS = 0x0E, | ||
246 | IBMVFC_VENDOR_SPECIFIC = 0xFF, | ||
247 | }; | ||
248 | |||
249 | enum ibmvfc_fc_type { | ||
250 | IBMVFC_FABRIC_REJECT = 0x01, | ||
251 | IBMVFC_PORT_REJECT = 0x02, | ||
252 | IBMVFC_LS_REJECT = 0x03, | ||
253 | IBMVFC_FABRIC_BUSY = 0x04, | ||
254 | IBMVFC_PORT_BUSY = 0x05, | ||
255 | IBMVFC_BASIC_REJECT = 0x06, | ||
256 | }; | ||
257 | |||
258 | enum ibmvfc_gs_explain { | ||
259 | IBMVFC_PORT_NAME_NOT_REG = 0x02, | ||
260 | }; | ||
261 | |||
262 | struct ibmvfc_port_login { | ||
263 | struct ibmvfc_mad_common common; | ||
264 | u64 scsi_id; | ||
265 | u16 reserved; | ||
266 | u16 fc_service_class; | ||
267 | u32 blksz; | ||
268 | u32 hdr_per_blk; | ||
269 | u16 status; | ||
270 | u16 error; /* also fc_reason */ | ||
271 | u16 fc_explain; | ||
272 | u16 fc_type; | ||
273 | u32 reserved2; | ||
274 | struct ibmvfc_service_parms service_parms; | ||
275 | struct ibmvfc_service_parms service_parms_change; | ||
276 | u64 reserved3[2]; | ||
277 | }__attribute__((packed, aligned (8))); | ||
278 | |||
279 | struct ibmvfc_prli_svc_parms { | ||
280 | u8 type; | ||
281 | #define IBMVFC_SCSI_FCP_TYPE 0x08 | ||
282 | u8 type_ext; | ||
283 | u16 flags; | ||
284 | #define IBMVFC_PRLI_ORIG_PA_VALID 0x8000 | ||
285 | #define IBMVFC_PRLI_RESP_PA_VALID 0x4000 | ||
286 | #define IBMVFC_PRLI_EST_IMG_PAIR 0x2000 | ||
287 | u32 orig_pa; | ||
288 | u32 resp_pa; | ||
289 | u32 service_parms; | ||
290 | #define IBMVFC_PRLI_TASK_RETRY 0x00000200 | ||
291 | #define IBMVFC_PRLI_RETRY 0x00000100 | ||
292 | #define IBMVFC_PRLI_DATA_OVERLAY 0x00000040 | ||
293 | #define IBMVFC_PRLI_INITIATOR_FUNC 0x00000020 | ||
294 | #define IBMVFC_PRLI_TARGET_FUNC 0x00000010 | ||
295 | #define IBMVFC_PRLI_READ_FCP_XFER_RDY_DISABLED 0x00000002 | ||
296 | #define IBMVFC_PRLI_WR_FCP_XFER_RDY_DISABLED 0x00000001 | ||
297 | }__attribute__((packed, aligned (4))); | ||
298 | |||
299 | struct ibmvfc_process_login { | ||
300 | struct ibmvfc_mad_common common; | ||
301 | u64 scsi_id; | ||
302 | struct ibmvfc_prli_svc_parms parms; | ||
303 | u8 reserved[48]; | ||
304 | u16 status; | ||
305 | u16 error; /* also fc_reason */ | ||
306 | u32 reserved2; | ||
307 | u64 reserved3[2]; | ||
308 | }__attribute__((packed, aligned (8))); | ||
309 | |||
310 | struct ibmvfc_query_tgt { | ||
311 | struct ibmvfc_mad_common common; | ||
312 | u64 wwpn; | ||
313 | u64 scsi_id; | ||
314 | u16 status; | ||
315 | u16 error; | ||
316 | u16 fc_explain; | ||
317 | u16 fc_type; | ||
318 | u64 reserved[2]; | ||
319 | }__attribute__((packed, aligned (8))); | ||
320 | |||
321 | struct ibmvfc_implicit_logout { | ||
322 | struct ibmvfc_mad_common common; | ||
323 | u64 old_scsi_id; | ||
324 | u64 reserved[2]; | ||
325 | }__attribute__((packed, aligned (8))); | ||
326 | |||
327 | struct ibmvfc_tmf { | ||
328 | struct ibmvfc_mad_common common; | ||
329 | u64 scsi_id; | ||
330 | struct scsi_lun lun; | ||
331 | u32 flags; | ||
332 | #define IBMVFC_TMF_ABORT_TASK 0x02 | ||
333 | #define IBMVFC_TMF_ABORT_TASK_SET 0x04 | ||
334 | #define IBMVFC_TMF_LUN_RESET 0x10 | ||
335 | #define IBMVFC_TMF_TGT_RESET 0x20 | ||
336 | #define IBMVFC_TMF_LUA_VALID 0x40 | ||
337 | u32 cancel_key; | ||
338 | u32 my_cancel_key; | ||
339 | #define IBMVFC_TMF_CANCEL_KEY 0x80000000 | ||
340 | u32 pad; | ||
341 | u64 reserved[2]; | ||
342 | }__attribute__((packed, aligned (8))); | ||
343 | |||
344 | enum ibmvfc_fcp_rsp_info_codes { | ||
345 | RSP_NO_FAILURE = 0x00, | ||
346 | RSP_TMF_REJECTED = 0x04, | ||
347 | RSP_TMF_FAILED = 0x05, | ||
348 | RSP_TMF_INVALID_LUN = 0x09, | ||
349 | }; | ||
350 | |||
351 | struct ibmvfc_fcp_rsp_info { | ||
352 | u16 reserved; | ||
353 | u8 rsp_code; | ||
354 | u8 reserved2[4]; | ||
355 | }__attribute__((packed, aligned (2))); | ||
356 | |||
357 | enum ibmvfc_fcp_rsp_flags { | ||
358 | FCP_BIDI_RSP = 0x80, | ||
359 | FCP_BIDI_READ_RESID_UNDER = 0x40, | ||
360 | FCP_BIDI_READ_RESID_OVER = 0x20, | ||
361 | FCP_CONF_REQ = 0x10, | ||
362 | FCP_RESID_UNDER = 0x08, | ||
363 | FCP_RESID_OVER = 0x04, | ||
364 | FCP_SNS_LEN_VALID = 0x02, | ||
365 | FCP_RSP_LEN_VALID = 0x01, | ||
366 | }; | ||
367 | |||
368 | union ibmvfc_fcp_rsp_data { | ||
369 | struct ibmvfc_fcp_rsp_info info; | ||
370 | u8 sense[SCSI_SENSE_BUFFERSIZE + sizeof(struct ibmvfc_fcp_rsp_info)]; | ||
371 | }__attribute__((packed, aligned (8))); | ||
372 | |||
373 | struct ibmvfc_fcp_rsp { | ||
374 | u64 reserved; | ||
375 | u16 retry_delay_timer; | ||
376 | u8 flags; | ||
377 | u8 scsi_status; | ||
378 | u32 fcp_resid; | ||
379 | u32 fcp_sense_len; | ||
380 | u32 fcp_rsp_len; | ||
381 | union ibmvfc_fcp_rsp_data data; | ||
382 | }__attribute__((packed, aligned (8))); | ||
383 | |||
384 | enum ibmvfc_cmd_flags { | ||
385 | IBMVFC_SCATTERLIST = 0x0001, | ||
386 | IBMVFC_NO_MEM_DESC = 0x0002, | ||
387 | IBMVFC_READ = 0x0004, | ||
388 | IBMVFC_WRITE = 0x0008, | ||
389 | IBMVFC_TMF = 0x0080, | ||
390 | IBMVFC_CLASS_3_ERR = 0x0100, | ||
391 | }; | ||
392 | |||
393 | enum ibmvfc_fc_task_attr { | ||
394 | IBMVFC_SIMPLE_TASK = 0x00, | ||
395 | IBMVFC_HEAD_OF_QUEUE = 0x01, | ||
396 | IBMVFC_ORDERED_TASK = 0x02, | ||
397 | IBMVFC_ACA_TASK = 0x04, | ||
398 | }; | ||
399 | |||
400 | enum ibmvfc_fc_tmf_flags { | ||
401 | IBMVFC_ABORT_TASK_SET = 0x02, | ||
402 | IBMVFC_LUN_RESET = 0x10, | ||
403 | IBMVFC_TARGET_RESET = 0x20, | ||
404 | }; | ||
405 | |||
406 | struct ibmvfc_fcp_cmd_iu { | ||
407 | struct scsi_lun lun; | ||
408 | u8 crn; | ||
409 | u8 pri_task_attr; | ||
410 | u8 tmf_flags; | ||
411 | u8 add_cdb_len; | ||
412 | #define IBMVFC_RDDATA 0x02 | ||
413 | #define IBMVFC_WRDATA 0x01 | ||
414 | u8 cdb[IBMVFC_MAX_CDB_LEN]; | ||
415 | u32 xfer_len; | ||
416 | }__attribute__((packed, aligned (4))); | ||
417 | |||
418 | struct ibmvfc_cmd { | ||
419 | u64 task_tag; | ||
420 | u32 frame_type; | ||
421 | u32 payload_len; | ||
422 | u32 resp_len; | ||
423 | u32 adapter_resid; | ||
424 | u16 status; | ||
425 | u16 error; | ||
426 | u16 flags; | ||
427 | u16 response_flags; | ||
428 | #define IBMVFC_ADAPTER_RESID_VALID 0x01 | ||
429 | u32 cancel_key; | ||
430 | u32 exchange_id; | ||
431 | struct srp_direct_buf ext_func; | ||
432 | struct srp_direct_buf ioba; | ||
433 | struct srp_direct_buf resp; | ||
434 | u64 correlation; | ||
435 | u64 tgt_scsi_id; | ||
436 | u64 tag; | ||
437 | u64 reserved3[2]; | ||
438 | struct ibmvfc_fcp_cmd_iu iu; | ||
439 | struct ibmvfc_fcp_rsp rsp; | ||
440 | }__attribute__((packed, aligned (8))); | ||
441 | |||
442 | struct ibmvfc_trace_start_entry { | ||
443 | u32 xfer_len; | ||
444 | }__attribute__((packed)); | ||
445 | |||
446 | struct ibmvfc_trace_end_entry { | ||
447 | u16 status; | ||
448 | u16 error; | ||
449 | u8 fcp_rsp_flags; | ||
450 | u8 rsp_code; | ||
451 | u8 scsi_status; | ||
452 | u8 reserved; | ||
453 | }__attribute__((packed)); | ||
454 | |||
455 | struct ibmvfc_trace_entry { | ||
456 | struct ibmvfc_event *evt; | ||
457 | u32 time; | ||
458 | u32 scsi_id; | ||
459 | u32 lun; | ||
460 | u8 fmt; | ||
461 | u8 op_code; | ||
462 | u8 tmf_flags; | ||
463 | u8 type; | ||
464 | #define IBMVFC_TRC_START 0x00 | ||
465 | #define IBMVFC_TRC_END 0xff | ||
466 | union { | ||
467 | struct ibmvfc_trace_start_entry start; | ||
468 | struct ibmvfc_trace_end_entry end; | ||
469 | } u; | ||
470 | }__attribute__((packed, aligned (8))); | ||
471 | |||
472 | enum ibmvfc_crq_formats { | ||
473 | IBMVFC_CMD_FORMAT = 0x01, | ||
474 | IBMVFC_ASYNC_EVENT = 0x02, | ||
475 | IBMVFC_MAD_FORMAT = 0x04, | ||
476 | }; | ||
477 | |||
478 | enum ibmvfc_async_event { | ||
479 | IBMVFC_AE_ELS_PLOGI = 0x0001, | ||
480 | IBMVFC_AE_ELS_LOGO = 0x0002, | ||
481 | IBMVFC_AE_ELS_PRLO = 0x0004, | ||
482 | IBMVFC_AE_SCN_NPORT = 0x0008, | ||
483 | IBMVFC_AE_SCN_GROUP = 0x0010, | ||
484 | IBMVFC_AE_SCN_DOMAIN = 0x0020, | ||
485 | IBMVFC_AE_SCN_FABRIC = 0x0040, | ||
486 | IBMVFC_AE_LINK_UP = 0x0080, | ||
487 | IBMVFC_AE_LINK_DOWN = 0x0100, | ||
488 | IBMVFC_AE_LINK_DEAD = 0x0200, | ||
489 | IBMVFC_AE_HALT = 0x0400, | ||
490 | IBMVFC_AE_RESUME = 0x0800, | ||
491 | IBMVFC_AE_ADAPTER_FAILED = 0x1000, | ||
492 | }; | ||
493 | |||
494 | struct ibmvfc_crq { | ||
495 | u8 valid; | ||
496 | u8 format; | ||
497 | u8 reserved[6]; | ||
498 | u64 ioba; | ||
499 | }__attribute__((packed, aligned (8))); | ||
500 | |||
501 | struct ibmvfc_crq_queue { | ||
502 | struct ibmvfc_crq *msgs; | ||
503 | int size, cur; | ||
504 | dma_addr_t msg_token; | ||
505 | }; | ||
506 | |||
507 | struct ibmvfc_async_crq { | ||
508 | u8 valid; | ||
509 | u8 pad[3]; | ||
510 | u32 pad2; | ||
511 | u64 event; | ||
512 | u64 scsi_id; | ||
513 | u64 wwpn; | ||
514 | u64 node_name; | ||
515 | u64 reserved; | ||
516 | }__attribute__((packed, aligned (8))); | ||
517 | |||
518 | struct ibmvfc_async_crq_queue { | ||
519 | struct ibmvfc_async_crq *msgs; | ||
520 | int size, cur; | ||
521 | dma_addr_t msg_token; | ||
522 | }; | ||
523 | |||
524 | union ibmvfc_iu { | ||
525 | struct ibmvfc_mad_common mad_common; | ||
526 | struct ibmvfc_npiv_login_mad npiv_login; | ||
527 | struct ibmvfc_discover_targets discover_targets; | ||
528 | struct ibmvfc_port_login plogi; | ||
529 | struct ibmvfc_process_login prli; | ||
530 | struct ibmvfc_query_tgt query_tgt; | ||
531 | struct ibmvfc_implicit_logout implicit_logout; | ||
532 | struct ibmvfc_tmf tmf; | ||
533 | struct ibmvfc_cmd cmd; | ||
534 | }__attribute__((packed, aligned (8))); | ||
535 | |||
536 | enum ibmvfc_target_action { | ||
537 | IBMVFC_TGT_ACTION_NONE = 0, | ||
538 | IBMVFC_TGT_ACTION_INIT, | ||
539 | IBMVFC_TGT_ACTION_INIT_WAIT, | ||
540 | IBMVFC_TGT_ACTION_ADD_RPORT, | ||
541 | IBMVFC_TGT_ACTION_DEL_RPORT, | ||
542 | }; | ||
543 | |||
544 | struct ibmvfc_target { | ||
545 | struct list_head queue; | ||
546 | struct ibmvfc_host *vhost; | ||
547 | u64 scsi_id; | ||
548 | u64 new_scsi_id; | ||
549 | struct fc_rport *rport; | ||
550 | int target_id; | ||
551 | enum ibmvfc_target_action action; | ||
552 | int need_login; | ||
553 | int init_retries; | ||
554 | struct ibmvfc_service_parms service_parms; | ||
555 | struct ibmvfc_service_parms service_parms_change; | ||
556 | struct fc_rport_identifiers ids; | ||
557 | void (*job_step) (struct ibmvfc_target *); | ||
558 | struct kref kref; | ||
559 | }; | ||
560 | |||
561 | /* a unit of work for the hosting partition */ | ||
562 | struct ibmvfc_event { | ||
563 | struct list_head queue; | ||
564 | struct ibmvfc_host *vhost; | ||
565 | struct ibmvfc_target *tgt; | ||
566 | struct scsi_cmnd *cmnd; | ||
567 | atomic_t free; | ||
568 | union ibmvfc_iu *xfer_iu; | ||
569 | void (*done) (struct ibmvfc_event *); | ||
570 | struct ibmvfc_crq crq; | ||
571 | union ibmvfc_iu iu; | ||
572 | union ibmvfc_iu *sync_iu; | ||
573 | struct srp_direct_buf *ext_list; | ||
574 | dma_addr_t ext_list_token; | ||
575 | struct completion comp; | ||
576 | struct timer_list timer; | ||
577 | }; | ||
578 | |||
579 | /* a pool of event structs for use */ | ||
580 | struct ibmvfc_event_pool { | ||
581 | struct ibmvfc_event *events; | ||
582 | u32 size; | ||
583 | union ibmvfc_iu *iu_storage; | ||
584 | dma_addr_t iu_token; | ||
585 | }; | ||
586 | |||
587 | enum ibmvfc_host_action { | ||
588 | IBMVFC_HOST_ACTION_NONE = 0, | ||
589 | IBMVFC_HOST_ACTION_INIT, | ||
590 | IBMVFC_HOST_ACTION_INIT_WAIT, | ||
591 | IBMVFC_HOST_ACTION_QUERY, | ||
592 | IBMVFC_HOST_ACTION_QUERY_TGTS, | ||
593 | IBMVFC_HOST_ACTION_TGT_DEL, | ||
594 | IBMVFC_HOST_ACTION_ALLOC_TGTS, | ||
595 | IBMVFC_HOST_ACTION_TGT_INIT, | ||
596 | IBMVFC_HOST_ACTION_TGT_ADD, | ||
597 | }; | ||
598 | |||
599 | enum ibmvfc_host_state { | ||
600 | IBMVFC_NO_CRQ = 0, | ||
601 | IBMVFC_INITIALIZING, | ||
602 | IBMVFC_ACTIVE, | ||
603 | IBMVFC_HALTED, | ||
604 | IBMVFC_LINK_DOWN, | ||
605 | IBMVFC_LINK_DEAD, | ||
606 | IBMVFC_HOST_OFFLINE, | ||
607 | }; | ||
608 | |||
609 | struct ibmvfc_host { | ||
610 | char name[8]; | ||
611 | struct list_head queue; | ||
612 | struct Scsi_Host *host; | ||
613 | enum ibmvfc_host_state state; | ||
614 | enum ibmvfc_host_action action; | ||
615 | #define IBMVFC_NUM_TRACE_INDEX_BITS 8 | ||
616 | #define IBMVFC_NUM_TRACE_ENTRIES (1 << IBMVFC_NUM_TRACE_INDEX_BITS) | ||
617 | #define IBMVFC_TRACE_SIZE (sizeof(struct ibmvfc_trace_entry) * IBMVFC_NUM_TRACE_ENTRIES) | ||
618 | struct ibmvfc_trace_entry *trace; | ||
619 | u32 trace_index:IBMVFC_NUM_TRACE_INDEX_BITS; | ||
620 | int num_targets; | ||
621 | struct list_head targets; | ||
622 | struct list_head sent; | ||
623 | struct list_head free; | ||
624 | struct device *dev; | ||
625 | struct ibmvfc_event_pool pool; | ||
626 | struct dma_pool *sg_pool; | ||
627 | mempool_t *tgt_pool; | ||
628 | struct ibmvfc_crq_queue crq; | ||
629 | struct ibmvfc_async_crq_queue async_crq; | ||
630 | struct ibmvfc_npiv_login login_info; | ||
631 | union ibmvfc_npiv_login_data *login_buf; | ||
632 | dma_addr_t login_buf_dma; | ||
633 | int disc_buf_sz; | ||
634 | int log_level; | ||
635 | struct ibmvfc_discover_targets_buf *disc_buf; | ||
636 | int task_set; | ||
637 | int init_retries; | ||
638 | int discovery_threads; | ||
639 | int client_migrated; | ||
640 | int reinit; | ||
641 | int events_to_log; | ||
642 | #define IBMVFC_AE_LINKUP 0x0001 | ||
643 | #define IBMVFC_AE_LINKDOWN 0x0002 | ||
644 | #define IBMVFC_AE_RSCN 0x0004 | ||
645 | dma_addr_t disc_buf_dma; | ||
646 | unsigned int partition_number; | ||
647 | char partition_name[97]; | ||
648 | void (*job_step) (struct ibmvfc_host *); | ||
649 | struct task_struct *work_thread; | ||
650 | wait_queue_head_t init_wait_q; | ||
651 | wait_queue_head_t work_wait_q; | ||
652 | }; | ||
653 | |||
654 | #define DBG_CMD(CMD) do { if (ibmvfc_debug) CMD; } while (0) | ||
655 | |||
656 | #define tgt_dbg(t, fmt, ...) \ | ||
657 | DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)) | ||
658 | |||
659 | #define tgt_err(t, fmt, ...) \ | ||
660 | dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__) | ||
661 | |||
662 | #define ibmvfc_dbg(vhost, ...) \ | ||
663 | DBG_CMD(dev_info((vhost)->dev, ##__VA_ARGS__)) | ||
664 | |||
665 | #define ibmvfc_log(vhost, level, ...) \ | ||
666 | do { \ | ||
667 | if (level >= (vhost)->log_level) \ | ||
668 | dev_err((vhost)->dev, ##__VA_ARGS__); \ | ||
669 | } while (0) | ||
670 | |||
671 | #define ENTER DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Entering %s\n", __FUNCTION__)) | ||
672 | #define LEAVE DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Leaving %s\n", __FUNCTION__)) | ||
673 | |||
674 | #ifdef CONFIG_SCSI_IBMVFC_TRACE | ||
675 | #define ibmvfc_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr) | ||
676 | #define ibmvfc_remove_trace_file(kobj, attr) sysfs_remove_bin_file(kobj, attr) | ||
677 | #else | ||
678 | #define ibmvfc_create_trace_file(kobj, attr) 0 | ||
679 | #define ibmvfc_remove_trace_file(kobj, attr) do { } while (0) | ||
680 | #endif | ||
681 | |||
682 | #endif | ||
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 72b9b2a0eba3..2a2f0094570f 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c | |||
@@ -64,6 +64,10 @@ MODULE_LICENSE("GPL"); | |||
64 | #define BUG_ON(expr) | 64 | #define BUG_ON(expr) |
65 | #endif | 65 | #endif |
66 | 66 | ||
67 | static struct scsi_transport_template *iscsi_tcp_scsi_transport; | ||
68 | static struct scsi_host_template iscsi_sht; | ||
69 | static struct iscsi_transport iscsi_tcp_transport; | ||
70 | |||
67 | static unsigned int iscsi_max_lun = 512; | 71 | static unsigned int iscsi_max_lun = 512; |
68 | module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); | 72 | module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); |
69 | 73 | ||
@@ -494,39 +498,43 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn) | |||
494 | * must be called with session lock | 498 | * must be called with session lock |
495 | */ | 499 | */ |
496 | static void | 500 | static void |
497 | iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | 501 | iscsi_tcp_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task) |
498 | { | 502 | { |
499 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 503 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
500 | struct iscsi_r2t_info *r2t; | 504 | struct iscsi_r2t_info *r2t; |
501 | 505 | ||
502 | /* flush ctask's r2t queues */ | 506 | /* nothing to do for mgmt tasks */ |
503 | while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) { | 507 | if (!task->sc) |
504 | __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, | 508 | return; |
509 | |||
510 | /* flush task's r2t queues */ | ||
511 | while (__kfifo_get(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) { | ||
512 | __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t, | ||
505 | sizeof(void*)); | 513 | sizeof(void*)); |
506 | debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n"); | 514 | debug_scsi("iscsi_tcp_cleanup_task pending r2t dropped\n"); |
507 | } | 515 | } |
508 | 516 | ||
509 | r2t = tcp_ctask->r2t; | 517 | r2t = tcp_task->r2t; |
510 | if (r2t != NULL) { | 518 | if (r2t != NULL) { |
511 | __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, | 519 | __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t, |
512 | sizeof(void*)); | 520 | sizeof(void*)); |
513 | tcp_ctask->r2t = NULL; | 521 | tcp_task->r2t = NULL; |
514 | } | 522 | } |
515 | } | 523 | } |
516 | 524 | ||
517 | /** | 525 | /** |
518 | * iscsi_data_rsp - SCSI Data-In Response processing | 526 | * iscsi_data_rsp - SCSI Data-In Response processing |
519 | * @conn: iscsi connection | 527 | * @conn: iscsi connection |
520 | * @ctask: scsi command task | 528 | * @task: scsi command task |
521 | **/ | 529 | **/ |
522 | static int | 530 | static int |
523 | iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | 531 | iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_task *task) |
524 | { | 532 | { |
525 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 533 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
526 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 534 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
527 | struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; | 535 | struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; |
528 | struct iscsi_session *session = conn->session; | 536 | struct iscsi_session *session = conn->session; |
529 | struct scsi_cmnd *sc = ctask->sc; | 537 | struct scsi_cmnd *sc = task->sc; |
530 | int datasn = be32_to_cpu(rhdr->datasn); | 538 | int datasn = be32_to_cpu(rhdr->datasn); |
531 | unsigned total_in_length = scsi_in(sc)->length; | 539 | unsigned total_in_length = scsi_in(sc)->length; |
532 | 540 | ||
@@ -534,18 +542,18 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
534 | if (tcp_conn->in.datalen == 0) | 542 | if (tcp_conn->in.datalen == 0) |
535 | return 0; | 543 | return 0; |
536 | 544 | ||
537 | if (tcp_ctask->exp_datasn != datasn) { | 545 | if (tcp_task->exp_datasn != datasn) { |
538 | debug_tcp("%s: ctask->exp_datasn(%d) != rhdr->datasn(%d)\n", | 546 | debug_tcp("%s: task->exp_datasn(%d) != rhdr->datasn(%d)\n", |
539 | __FUNCTION__, tcp_ctask->exp_datasn, datasn); | 547 | __func__, tcp_task->exp_datasn, datasn); |
540 | return ISCSI_ERR_DATASN; | 548 | return ISCSI_ERR_DATASN; |
541 | } | 549 | } |
542 | 550 | ||
543 | tcp_ctask->exp_datasn++; | 551 | tcp_task->exp_datasn++; |
544 | 552 | ||
545 | tcp_ctask->data_offset = be32_to_cpu(rhdr->offset); | 553 | tcp_task->data_offset = be32_to_cpu(rhdr->offset); |
546 | if (tcp_ctask->data_offset + tcp_conn->in.datalen > total_in_length) { | 554 | if (tcp_task->data_offset + tcp_conn->in.datalen > total_in_length) { |
547 | debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n", | 555 | debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n", |
548 | __FUNCTION__, tcp_ctask->data_offset, | 556 | __func__, tcp_task->data_offset, |
549 | tcp_conn->in.datalen, total_in_length); | 557 | tcp_conn->in.datalen, total_in_length); |
550 | return ISCSI_ERR_DATA_OFFSET; | 558 | return ISCSI_ERR_DATA_OFFSET; |
551 | } | 559 | } |
@@ -574,7 +582,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
574 | /** | 582 | /** |
575 | * iscsi_solicit_data_init - initialize first Data-Out | 583 | * iscsi_solicit_data_init - initialize first Data-Out |
576 | * @conn: iscsi connection | 584 | * @conn: iscsi connection |
577 | * @ctask: scsi command task | 585 | * @task: scsi command task |
578 | * @r2t: R2T info | 586 | * @r2t: R2T info |
579 | * | 587 | * |
580 | * Notes: | 588 | * Notes: |
@@ -584,7 +592,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
584 | * This function is called with connection lock taken. | 592 | * This function is called with connection lock taken. |
585 | **/ | 593 | **/ |
586 | static void | 594 | static void |
587 | iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | 595 | iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_task *task, |
588 | struct iscsi_r2t_info *r2t) | 596 | struct iscsi_r2t_info *r2t) |
589 | { | 597 | { |
590 | struct iscsi_data *hdr; | 598 | struct iscsi_data *hdr; |
@@ -595,8 +603,8 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
595 | hdr->datasn = cpu_to_be32(r2t->solicit_datasn); | 603 | hdr->datasn = cpu_to_be32(r2t->solicit_datasn); |
596 | r2t->solicit_datasn++; | 604 | r2t->solicit_datasn++; |
597 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; | 605 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; |
598 | memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); | 606 | memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun)); |
599 | hdr->itt = ctask->hdr->itt; | 607 | hdr->itt = task->hdr->itt; |
600 | hdr->exp_statsn = r2t->exp_statsn; | 608 | hdr->exp_statsn = r2t->exp_statsn; |
601 | hdr->offset = cpu_to_be32(r2t->data_offset); | 609 | hdr->offset = cpu_to_be32(r2t->data_offset); |
602 | if (r2t->data_length > conn->max_xmit_dlength) { | 610 | if (r2t->data_length > conn->max_xmit_dlength) { |
@@ -616,14 +624,14 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
616 | /** | 624 | /** |
617 | * iscsi_r2t_rsp - iSCSI R2T Response processing | 625 | * iscsi_r2t_rsp - iSCSI R2T Response processing |
618 | * @conn: iscsi connection | 626 | * @conn: iscsi connection |
619 | * @ctask: scsi command task | 627 | * @task: scsi command task |
620 | **/ | 628 | **/ |
621 | static int | 629 | static int |
622 | iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | 630 | iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) |
623 | { | 631 | { |
624 | struct iscsi_r2t_info *r2t; | 632 | struct iscsi_r2t_info *r2t; |
625 | struct iscsi_session *session = conn->session; | 633 | struct iscsi_session *session = conn->session; |
626 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 634 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
627 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 635 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
628 | struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr; | 636 | struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr; |
629 | int r2tsn = be32_to_cpu(rhdr->r2tsn); | 637 | int r2tsn = be32_to_cpu(rhdr->r2tsn); |
@@ -636,23 +644,23 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
636 | return ISCSI_ERR_DATALEN; | 644 | return ISCSI_ERR_DATALEN; |
637 | } | 645 | } |
638 | 646 | ||
639 | if (tcp_ctask->exp_datasn != r2tsn){ | 647 | if (tcp_task->exp_datasn != r2tsn){ |
640 | debug_tcp("%s: ctask->exp_datasn(%d) != rhdr->r2tsn(%d)\n", | 648 | debug_tcp("%s: task->exp_datasn(%d) != rhdr->r2tsn(%d)\n", |
641 | __FUNCTION__, tcp_ctask->exp_datasn, r2tsn); | 649 | __func__, tcp_task->exp_datasn, r2tsn); |
642 | return ISCSI_ERR_R2TSN; | 650 | return ISCSI_ERR_R2TSN; |
643 | } | 651 | } |
644 | 652 | ||
645 | /* fill-in new R2T associated with the task */ | 653 | /* fill-in new R2T associated with the task */ |
646 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); | 654 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); |
647 | 655 | ||
648 | if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) { | 656 | if (!task->sc || session->state != ISCSI_STATE_LOGGED_IN) { |
649 | iscsi_conn_printk(KERN_INFO, conn, | 657 | iscsi_conn_printk(KERN_INFO, conn, |
650 | "dropping R2T itt %d in recovery.\n", | 658 | "dropping R2T itt %d in recovery.\n", |
651 | ctask->itt); | 659 | task->itt); |
652 | return 0; | 660 | return 0; |
653 | } | 661 | } |
654 | 662 | ||
655 | rc = __kfifo_get(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); | 663 | rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); |
656 | BUG_ON(!rc); | 664 | BUG_ON(!rc); |
657 | 665 | ||
658 | r2t->exp_statsn = rhdr->statsn; | 666 | r2t->exp_statsn = rhdr->statsn; |
@@ -660,7 +668,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
660 | if (r2t->data_length == 0) { | 668 | if (r2t->data_length == 0) { |
661 | iscsi_conn_printk(KERN_ERR, conn, | 669 | iscsi_conn_printk(KERN_ERR, conn, |
662 | "invalid R2T with zero data len\n"); | 670 | "invalid R2T with zero data len\n"); |
663 | __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, | 671 | __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t, |
664 | sizeof(void*)); | 672 | sizeof(void*)); |
665 | return ISCSI_ERR_DATALEN; | 673 | return ISCSI_ERR_DATALEN; |
666 | } | 674 | } |
@@ -671,12 +679,12 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
671 | r2t->data_length, session->max_burst); | 679 | r2t->data_length, session->max_burst); |
672 | 680 | ||
673 | r2t->data_offset = be32_to_cpu(rhdr->data_offset); | 681 | r2t->data_offset = be32_to_cpu(rhdr->data_offset); |
674 | if (r2t->data_offset + r2t->data_length > scsi_out(ctask->sc)->length) { | 682 | if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) { |
675 | iscsi_conn_printk(KERN_ERR, conn, | 683 | iscsi_conn_printk(KERN_ERR, conn, |
676 | "invalid R2T with data len %u at offset %u " | 684 | "invalid R2T with data len %u at offset %u " |
677 | "and total length %d\n", r2t->data_length, | 685 | "and total length %d\n", r2t->data_length, |
678 | r2t->data_offset, scsi_out(ctask->sc)->length); | 686 | r2t->data_offset, scsi_out(task->sc)->length); |
679 | __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, | 687 | __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t, |
680 | sizeof(void*)); | 688 | sizeof(void*)); |
681 | return ISCSI_ERR_DATALEN; | 689 | return ISCSI_ERR_DATALEN; |
682 | } | 690 | } |
@@ -684,13 +692,13 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
684 | r2t->ttt = rhdr->ttt; /* no flip */ | 692 | r2t->ttt = rhdr->ttt; /* no flip */ |
685 | r2t->solicit_datasn = 0; | 693 | r2t->solicit_datasn = 0; |
686 | 694 | ||
687 | iscsi_solicit_data_init(conn, ctask, r2t); | 695 | iscsi_solicit_data_init(conn, task, r2t); |
688 | 696 | ||
689 | tcp_ctask->exp_datasn = r2tsn + 1; | 697 | tcp_task->exp_datasn = r2tsn + 1; |
690 | __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)); | 698 | __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*)); |
691 | conn->r2t_pdus_cnt++; | 699 | conn->r2t_pdus_cnt++; |
692 | 700 | ||
693 | iscsi_requeue_ctask(ctask); | 701 | iscsi_requeue_task(task); |
694 | return 0; | 702 | return 0; |
695 | } | 703 | } |
696 | 704 | ||
@@ -733,10 +741,8 @@ static int | |||
733 | iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | 741 | iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) |
734 | { | 742 | { |
735 | int rc = 0, opcode, ahslen; | 743 | int rc = 0, opcode, ahslen; |
736 | struct iscsi_session *session = conn->session; | ||
737 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 744 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
738 | struct iscsi_cmd_task *ctask; | 745 | struct iscsi_task *task; |
739 | uint32_t itt; | ||
740 | 746 | ||
741 | /* verify PDU length */ | 747 | /* verify PDU length */ |
742 | tcp_conn->in.datalen = ntoh24(hdr->dlength); | 748 | tcp_conn->in.datalen = ntoh24(hdr->dlength); |
@@ -754,7 +760,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
754 | 760 | ||
755 | opcode = hdr->opcode & ISCSI_OPCODE_MASK; | 761 | opcode = hdr->opcode & ISCSI_OPCODE_MASK; |
756 | /* verify itt (itt encoding: age+cid+itt) */ | 762 | /* verify itt (itt encoding: age+cid+itt) */ |
757 | rc = iscsi_verify_itt(conn, hdr, &itt); | 763 | rc = iscsi_verify_itt(conn, hdr->itt); |
758 | if (rc) | 764 | if (rc) |
759 | return rc; | 765 | return rc; |
760 | 766 | ||
@@ -763,16 +769,21 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
763 | 769 | ||
764 | switch(opcode) { | 770 | switch(opcode) { |
765 | case ISCSI_OP_SCSI_DATA_IN: | 771 | case ISCSI_OP_SCSI_DATA_IN: |
766 | ctask = session->cmds[itt]; | ||
767 | spin_lock(&conn->session->lock); | 772 | spin_lock(&conn->session->lock); |
768 | rc = iscsi_data_rsp(conn, ctask); | 773 | task = iscsi_itt_to_ctask(conn, hdr->itt); |
769 | spin_unlock(&conn->session->lock); | 774 | if (!task) |
770 | if (rc) | 775 | rc = ISCSI_ERR_BAD_ITT; |
771 | return rc; | 776 | else |
777 | rc = iscsi_data_rsp(conn, task); | ||
778 | if (rc) { | ||
779 | spin_unlock(&conn->session->lock); | ||
780 | break; | ||
781 | } | ||
782 | |||
772 | if (tcp_conn->in.datalen) { | 783 | if (tcp_conn->in.datalen) { |
773 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 784 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
774 | struct hash_desc *rx_hash = NULL; | 785 | struct hash_desc *rx_hash = NULL; |
775 | struct scsi_data_buffer *sdb = scsi_in(ctask->sc); | 786 | struct scsi_data_buffer *sdb = scsi_in(task->sc); |
776 | 787 | ||
777 | /* | 788 | /* |
778 | * Setup copy of Data-In into the Scsi_Cmnd | 789 | * Setup copy of Data-In into the Scsi_Cmnd |
@@ -787,17 +798,21 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
787 | 798 | ||
788 | debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, " | 799 | debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, " |
789 | "datalen=%d)\n", tcp_conn, | 800 | "datalen=%d)\n", tcp_conn, |
790 | tcp_ctask->data_offset, | 801 | tcp_task->data_offset, |
791 | tcp_conn->in.datalen); | 802 | tcp_conn->in.datalen); |
792 | return iscsi_segment_seek_sg(&tcp_conn->in.segment, | 803 | rc = iscsi_segment_seek_sg(&tcp_conn->in.segment, |
793 | sdb->table.sgl, | 804 | sdb->table.sgl, |
794 | sdb->table.nents, | 805 | sdb->table.nents, |
795 | tcp_ctask->data_offset, | 806 | tcp_task->data_offset, |
796 | tcp_conn->in.datalen, | 807 | tcp_conn->in.datalen, |
797 | iscsi_tcp_process_data_in, | 808 | iscsi_tcp_process_data_in, |
798 | rx_hash); | 809 | rx_hash); |
810 | spin_unlock(&conn->session->lock); | ||
811 | return rc; | ||
799 | } | 812 | } |
800 | /* fall through */ | 813 | rc = __iscsi_complete_pdu(conn, hdr, NULL, 0); |
814 | spin_unlock(&conn->session->lock); | ||
815 | break; | ||
801 | case ISCSI_OP_SCSI_CMD_RSP: | 816 | case ISCSI_OP_SCSI_CMD_RSP: |
802 | if (tcp_conn->in.datalen) { | 817 | if (tcp_conn->in.datalen) { |
803 | iscsi_tcp_data_recv_prep(tcp_conn); | 818 | iscsi_tcp_data_recv_prep(tcp_conn); |
@@ -806,15 +821,17 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
806 | rc = iscsi_complete_pdu(conn, hdr, NULL, 0); | 821 | rc = iscsi_complete_pdu(conn, hdr, NULL, 0); |
807 | break; | 822 | break; |
808 | case ISCSI_OP_R2T: | 823 | case ISCSI_OP_R2T: |
809 | ctask = session->cmds[itt]; | 824 | spin_lock(&conn->session->lock); |
810 | if (ahslen) | 825 | task = iscsi_itt_to_ctask(conn, hdr->itt); |
826 | if (!task) | ||
827 | rc = ISCSI_ERR_BAD_ITT; | ||
828 | else if (ahslen) | ||
811 | rc = ISCSI_ERR_AHSLEN; | 829 | rc = ISCSI_ERR_AHSLEN; |
812 | else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) { | 830 | else if (task->sc->sc_data_direction == DMA_TO_DEVICE) |
813 | spin_lock(&session->lock); | 831 | rc = iscsi_r2t_rsp(conn, task); |
814 | rc = iscsi_r2t_rsp(conn, ctask); | 832 | else |
815 | spin_unlock(&session->lock); | ||
816 | } else | ||
817 | rc = ISCSI_ERR_PROTO; | 833 | rc = ISCSI_ERR_PROTO; |
834 | spin_unlock(&conn->session->lock); | ||
818 | break; | 835 | break; |
819 | case ISCSI_OP_LOGIN_RSP: | 836 | case ISCSI_OP_LOGIN_RSP: |
820 | case ISCSI_OP_TEXT_RSP: | 837 | case ISCSI_OP_TEXT_RSP: |
@@ -1176,7 +1193,7 @@ iscsi_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, size_t hdrlen) | |||
1176 | { | 1193 | { |
1177 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 1194 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
1178 | 1195 | ||
1179 | debug_tcp("%s(%p%s)\n", __FUNCTION__, tcp_conn, | 1196 | debug_tcp("%s(%p%s)\n", __func__, tcp_conn, |
1180 | conn->hdrdgst_en? ", digest enabled" : ""); | 1197 | conn->hdrdgst_en? ", digest enabled" : ""); |
1181 | 1198 | ||
1182 | /* Clear the data segment - needs to be filled in by the | 1199 | /* Clear the data segment - needs to be filled in by the |
@@ -1185,7 +1202,7 @@ iscsi_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, size_t hdrlen) | |||
1185 | 1202 | ||
1186 | /* If header digest is enabled, compute the CRC and | 1203 | /* If header digest is enabled, compute the CRC and |
1187 | * place the digest into the same buffer. We make | 1204 | * place the digest into the same buffer. We make |
1188 | * sure that both iscsi_tcp_ctask and mtask have | 1205 | * sure that both iscsi_tcp_task and mtask have |
1189 | * sufficient room. | 1206 | * sufficient room. |
1190 | */ | 1207 | */ |
1191 | if (conn->hdrdgst_en) { | 1208 | if (conn->hdrdgst_en) { |
@@ -1217,7 +1234,7 @@ iscsi_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg, | |||
1217 | struct hash_desc *tx_hash = NULL; | 1234 | struct hash_desc *tx_hash = NULL; |
1218 | unsigned int hdr_spec_len; | 1235 | unsigned int hdr_spec_len; |
1219 | 1236 | ||
1220 | debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __FUNCTION__, | 1237 | debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __func__, |
1221 | tcp_conn, offset, len, | 1238 | tcp_conn, offset, len, |
1222 | conn->datadgst_en? ", digest enabled" : ""); | 1239 | conn->datadgst_en? ", digest enabled" : ""); |
1223 | 1240 | ||
@@ -1242,7 +1259,7 @@ iscsi_tcp_send_linear_data_prepare(struct iscsi_conn *conn, void *data, | |||
1242 | struct hash_desc *tx_hash = NULL; | 1259 | struct hash_desc *tx_hash = NULL; |
1243 | unsigned int hdr_spec_len; | 1260 | unsigned int hdr_spec_len; |
1244 | 1261 | ||
1245 | debug_tcp("%s(%p, datalen=%d%s)\n", __FUNCTION__, tcp_conn, len, | 1262 | debug_tcp("%s(%p, datalen=%d%s)\n", __func__, tcp_conn, len, |
1246 | conn->datadgst_en? ", digest enabled" : ""); | 1263 | conn->datadgst_en? ", digest enabled" : ""); |
1247 | 1264 | ||
1248 | /* Make sure the datalen matches what the caller | 1265 | /* Make sure the datalen matches what the caller |
@@ -1260,7 +1277,7 @@ iscsi_tcp_send_linear_data_prepare(struct iscsi_conn *conn, void *data, | |||
1260 | /** | 1277 | /** |
1261 | * iscsi_solicit_data_cont - initialize next Data-Out | 1278 | * iscsi_solicit_data_cont - initialize next Data-Out |
1262 | * @conn: iscsi connection | 1279 | * @conn: iscsi connection |
1263 | * @ctask: scsi command task | 1280 | * @task: scsi command task |
1264 | * @r2t: R2T info | 1281 | * @r2t: R2T info |
1265 | * @left: bytes left to transfer | 1282 | * @left: bytes left to transfer |
1266 | * | 1283 | * |
@@ -1271,7 +1288,7 @@ iscsi_tcp_send_linear_data_prepare(struct iscsi_conn *conn, void *data, | |||
1271 | * Called under connection lock. | 1288 | * Called under connection lock. |
1272 | **/ | 1289 | **/ |
1273 | static int | 1290 | static int |
1274 | iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | 1291 | iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_task *task, |
1275 | struct iscsi_r2t_info *r2t) | 1292 | struct iscsi_r2t_info *r2t) |
1276 | { | 1293 | { |
1277 | struct iscsi_data *hdr; | 1294 | struct iscsi_data *hdr; |
@@ -1288,8 +1305,8 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1288 | hdr->datasn = cpu_to_be32(r2t->solicit_datasn); | 1305 | hdr->datasn = cpu_to_be32(r2t->solicit_datasn); |
1289 | r2t->solicit_datasn++; | 1306 | r2t->solicit_datasn++; |
1290 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; | 1307 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; |
1291 | memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); | 1308 | memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun)); |
1292 | hdr->itt = ctask->hdr->itt; | 1309 | hdr->itt = task->hdr->itt; |
1293 | hdr->exp_statsn = r2t->exp_statsn; | 1310 | hdr->exp_statsn = r2t->exp_statsn; |
1294 | new_offset = r2t->data_offset + r2t->sent; | 1311 | new_offset = r2t->data_offset + r2t->sent; |
1295 | hdr->offset = cpu_to_be32(new_offset); | 1312 | hdr->offset = cpu_to_be32(new_offset); |
@@ -1307,89 +1324,76 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1307 | } | 1324 | } |
1308 | 1325 | ||
1309 | /** | 1326 | /** |
1310 | * iscsi_tcp_ctask - Initialize iSCSI SCSI_READ or SCSI_WRITE commands | 1327 | * iscsi_tcp_task - Initialize iSCSI SCSI_READ or SCSI_WRITE commands |
1311 | * @conn: iscsi connection | 1328 | * @conn: iscsi connection |
1312 | * @ctask: scsi command task | 1329 | * @task: scsi command task |
1313 | * @sc: scsi command | 1330 | * @sc: scsi command |
1314 | **/ | 1331 | **/ |
1315 | static int | 1332 | static int |
1316 | iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask) | 1333 | iscsi_tcp_task_init(struct iscsi_task *task) |
1317 | { | 1334 | { |
1318 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1335 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
1319 | struct iscsi_conn *conn = ctask->conn; | 1336 | struct iscsi_conn *conn = task->conn; |
1320 | struct scsi_cmnd *sc = ctask->sc; | 1337 | struct scsi_cmnd *sc = task->sc; |
1321 | int err; | 1338 | int err; |
1322 | 1339 | ||
1323 | BUG_ON(__kfifo_len(tcp_ctask->r2tqueue)); | 1340 | if (!sc) { |
1324 | tcp_ctask->sent = 0; | 1341 | /* |
1325 | tcp_ctask->exp_datasn = 0; | 1342 | * mgmt tasks do not have a scatterlist since they come |
1343 | * in from the iscsi interface. | ||
1344 | */ | ||
1345 | debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, | ||
1346 | task->itt); | ||
1347 | |||
1348 | /* Prepare PDU, optionally w/ immediate data */ | ||
1349 | iscsi_tcp_send_hdr_prep(conn, task->hdr, sizeof(*task->hdr)); | ||
1350 | |||
1351 | /* If we have immediate data, attach a payload */ | ||
1352 | if (task->data_count) | ||
1353 | iscsi_tcp_send_linear_data_prepare(conn, task->data, | ||
1354 | task->data_count); | ||
1355 | return 0; | ||
1356 | } | ||
1357 | |||
1358 | BUG_ON(__kfifo_len(tcp_task->r2tqueue)); | ||
1359 | tcp_task->sent = 0; | ||
1360 | tcp_task->exp_datasn = 0; | ||
1326 | 1361 | ||
1327 | /* Prepare PDU, optionally w/ immediate data */ | 1362 | /* Prepare PDU, optionally w/ immediate data */ |
1328 | debug_scsi("ctask deq [cid %d itt 0x%x imm %d unsol %d]\n", | 1363 | debug_scsi("task deq [cid %d itt 0x%x imm %d unsol %d]\n", |
1329 | conn->id, ctask->itt, ctask->imm_count, | 1364 | conn->id, task->itt, task->imm_count, |
1330 | ctask->unsol_count); | 1365 | task->unsol_count); |
1331 | iscsi_tcp_send_hdr_prep(conn, ctask->hdr, ctask->hdr_len); | 1366 | iscsi_tcp_send_hdr_prep(conn, task->hdr, task->hdr_len); |
1332 | 1367 | ||
1333 | if (!ctask->imm_count) | 1368 | if (!task->imm_count) |
1334 | return 0; | 1369 | return 0; |
1335 | 1370 | ||
1336 | /* If we have immediate data, attach a payload */ | 1371 | /* If we have immediate data, attach a payload */ |
1337 | err = iscsi_tcp_send_data_prep(conn, scsi_out(sc)->table.sgl, | 1372 | err = iscsi_tcp_send_data_prep(conn, scsi_out(sc)->table.sgl, |
1338 | scsi_out(sc)->table.nents, | 1373 | scsi_out(sc)->table.nents, |
1339 | 0, ctask->imm_count); | 1374 | 0, task->imm_count); |
1340 | if (err) | 1375 | if (err) |
1341 | return err; | 1376 | return err; |
1342 | tcp_ctask->sent += ctask->imm_count; | 1377 | tcp_task->sent += task->imm_count; |
1343 | ctask->imm_count = 0; | 1378 | task->imm_count = 0; |
1344 | return 0; | ||
1345 | } | ||
1346 | |||
1347 | /** | ||
1348 | * iscsi_tcp_mtask_xmit - xmit management(immediate) task | ||
1349 | * @conn: iscsi connection | ||
1350 | * @mtask: task management task | ||
1351 | * | ||
1352 | * Notes: | ||
1353 | * The function can return -EAGAIN in which case caller must | ||
1354 | * call it again later, or recover. '0' return code means successful | ||
1355 | * xmit. | ||
1356 | **/ | ||
1357 | static int | ||
1358 | iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) | ||
1359 | { | ||
1360 | int rc; | ||
1361 | |||
1362 | /* Flush any pending data first. */ | ||
1363 | rc = iscsi_tcp_flush(conn); | ||
1364 | if (rc < 0) | ||
1365 | return rc; | ||
1366 | |||
1367 | if (mtask->hdr->itt == RESERVED_ITT) { | ||
1368 | struct iscsi_session *session = conn->session; | ||
1369 | |||
1370 | spin_lock_bh(&session->lock); | ||
1371 | iscsi_free_mgmt_task(conn, mtask); | ||
1372 | spin_unlock_bh(&session->lock); | ||
1373 | } | ||
1374 | |||
1375 | return 0; | 1379 | return 0; |
1376 | } | 1380 | } |
1377 | 1381 | ||
1378 | /* | 1382 | /* |
1379 | * iscsi_tcp_ctask_xmit - xmit normal PDU task | 1383 | * iscsi_tcp_task_xmit - xmit normal PDU task |
1380 | * @conn: iscsi connection | 1384 | * @task: iscsi command task |
1381 | * @ctask: iscsi command task | ||
1382 | * | 1385 | * |
1383 | * We're expected to return 0 when everything was transmitted succesfully, | 1386 | * We're expected to return 0 when everything was transmitted succesfully, |
1384 | * -EAGAIN if there's still data in the queue, or != 0 for any other kind | 1387 | * -EAGAIN if there's still data in the queue, or != 0 for any other kind |
1385 | * of error. | 1388 | * of error. |
1386 | */ | 1389 | */ |
1387 | static int | 1390 | static int |
1388 | iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | 1391 | iscsi_tcp_task_xmit(struct iscsi_task *task) |
1389 | { | 1392 | { |
1390 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1393 | struct iscsi_conn *conn = task->conn; |
1391 | struct scsi_cmnd *sc = ctask->sc; | 1394 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
1392 | struct scsi_data_buffer *sdb = scsi_out(sc); | 1395 | struct scsi_cmnd *sc = task->sc; |
1396 | struct scsi_data_buffer *sdb; | ||
1393 | int rc = 0; | 1397 | int rc = 0; |
1394 | 1398 | ||
1395 | flush: | 1399 | flush: |
@@ -1398,31 +1402,39 @@ flush: | |||
1398 | if (rc < 0) | 1402 | if (rc < 0) |
1399 | return rc; | 1403 | return rc; |
1400 | 1404 | ||
1405 | /* mgmt command */ | ||
1406 | if (!sc) { | ||
1407 | if (task->hdr->itt == RESERVED_ITT) | ||
1408 | iscsi_put_task(task); | ||
1409 | return 0; | ||
1410 | } | ||
1411 | |||
1401 | /* Are we done already? */ | 1412 | /* Are we done already? */ |
1402 | if (sc->sc_data_direction != DMA_TO_DEVICE) | 1413 | if (sc->sc_data_direction != DMA_TO_DEVICE) |
1403 | return 0; | 1414 | return 0; |
1404 | 1415 | ||
1405 | if (ctask->unsol_count != 0) { | 1416 | sdb = scsi_out(sc); |
1406 | struct iscsi_data *hdr = &tcp_ctask->unsol_dtask.hdr; | 1417 | if (task->unsol_count != 0) { |
1418 | struct iscsi_data *hdr = &tcp_task->unsol_dtask.hdr; | ||
1407 | 1419 | ||
1408 | /* Prepare a header for the unsolicited PDU. | 1420 | /* Prepare a header for the unsolicited PDU. |
1409 | * The amount of data we want to send will be | 1421 | * The amount of data we want to send will be |
1410 | * in ctask->data_count. | 1422 | * in task->data_count. |
1411 | * FIXME: return the data count instead. | 1423 | * FIXME: return the data count instead. |
1412 | */ | 1424 | */ |
1413 | iscsi_prep_unsolicit_data_pdu(ctask, hdr); | 1425 | iscsi_prep_unsolicit_data_pdu(task, hdr); |
1414 | 1426 | ||
1415 | debug_tcp("unsol dout [itt 0x%x doff %d dlen %d]\n", | 1427 | debug_tcp("unsol dout [itt 0x%x doff %d dlen %d]\n", |
1416 | ctask->itt, tcp_ctask->sent, ctask->data_count); | 1428 | task->itt, tcp_task->sent, task->data_count); |
1417 | 1429 | ||
1418 | iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr)); | 1430 | iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr)); |
1419 | rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl, | 1431 | rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl, |
1420 | sdb->table.nents, tcp_ctask->sent, | 1432 | sdb->table.nents, tcp_task->sent, |
1421 | ctask->data_count); | 1433 | task->data_count); |
1422 | if (rc) | 1434 | if (rc) |
1423 | goto fail; | 1435 | goto fail; |
1424 | tcp_ctask->sent += ctask->data_count; | 1436 | tcp_task->sent += task->data_count; |
1425 | ctask->unsol_count -= ctask->data_count; | 1437 | task->unsol_count -= task->data_count; |
1426 | goto flush; | 1438 | goto flush; |
1427 | } else { | 1439 | } else { |
1428 | struct iscsi_session *session = conn->session; | 1440 | struct iscsi_session *session = conn->session; |
@@ -1431,22 +1443,22 @@ flush: | |||
1431 | /* All unsolicited PDUs sent. Check for solicited PDUs. | 1443 | /* All unsolicited PDUs sent. Check for solicited PDUs. |
1432 | */ | 1444 | */ |
1433 | spin_lock_bh(&session->lock); | 1445 | spin_lock_bh(&session->lock); |
1434 | r2t = tcp_ctask->r2t; | 1446 | r2t = tcp_task->r2t; |
1435 | if (r2t != NULL) { | 1447 | if (r2t != NULL) { |
1436 | /* Continue with this R2T? */ | 1448 | /* Continue with this R2T? */ |
1437 | if (!iscsi_solicit_data_cont(conn, ctask, r2t)) { | 1449 | if (!iscsi_solicit_data_cont(conn, task, r2t)) { |
1438 | debug_scsi(" done with r2t %p\n", r2t); | 1450 | debug_scsi(" done with r2t %p\n", r2t); |
1439 | 1451 | ||
1440 | __kfifo_put(tcp_ctask->r2tpool.queue, | 1452 | __kfifo_put(tcp_task->r2tpool.queue, |
1441 | (void*)&r2t, sizeof(void*)); | 1453 | (void*)&r2t, sizeof(void*)); |
1442 | tcp_ctask->r2t = r2t = NULL; | 1454 | tcp_task->r2t = r2t = NULL; |
1443 | } | 1455 | } |
1444 | } | 1456 | } |
1445 | 1457 | ||
1446 | if (r2t == NULL) { | 1458 | if (r2t == NULL) { |
1447 | __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t, | 1459 | __kfifo_get(tcp_task->r2tqueue, (void*)&tcp_task->r2t, |
1448 | sizeof(void*)); | 1460 | sizeof(void*)); |
1449 | r2t = tcp_ctask->r2t; | 1461 | r2t = tcp_task->r2t; |
1450 | } | 1462 | } |
1451 | spin_unlock_bh(&session->lock); | 1463 | spin_unlock_bh(&session->lock); |
1452 | 1464 | ||
@@ -1457,7 +1469,7 @@ flush: | |||
1457 | } | 1469 | } |
1458 | 1470 | ||
1459 | debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n", | 1471 | debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n", |
1460 | r2t, r2t->solicit_datasn - 1, ctask->itt, | 1472 | r2t, r2t->solicit_datasn - 1, task->itt, |
1461 | r2t->data_offset + r2t->sent, r2t->data_count); | 1473 | r2t->data_offset + r2t->sent, r2t->data_count); |
1462 | 1474 | ||
1463 | iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr, | 1475 | iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr, |
@@ -1469,7 +1481,7 @@ flush: | |||
1469 | r2t->data_count); | 1481 | r2t->data_count); |
1470 | if (rc) | 1482 | if (rc) |
1471 | goto fail; | 1483 | goto fail; |
1472 | tcp_ctask->sent += r2t->data_count; | 1484 | tcp_task->sent += r2t->data_count; |
1473 | r2t->sent += r2t->data_count; | 1485 | r2t->sent += r2t->data_count; |
1474 | goto flush; | 1486 | goto flush; |
1475 | } | 1487 | } |
@@ -1486,7 +1498,7 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1486 | struct iscsi_cls_conn *cls_conn; | 1498 | struct iscsi_cls_conn *cls_conn; |
1487 | struct iscsi_tcp_conn *tcp_conn; | 1499 | struct iscsi_tcp_conn *tcp_conn; |
1488 | 1500 | ||
1489 | cls_conn = iscsi_conn_setup(cls_session, conn_idx); | 1501 | cls_conn = iscsi_conn_setup(cls_session, sizeof(*tcp_conn), conn_idx); |
1490 | if (!cls_conn) | 1502 | if (!cls_conn) |
1491 | return NULL; | 1503 | return NULL; |
1492 | conn = cls_conn->dd_data; | 1504 | conn = cls_conn->dd_data; |
@@ -1496,18 +1508,14 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1496 | */ | 1508 | */ |
1497 | conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN; | 1509 | conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN; |
1498 | 1510 | ||
1499 | tcp_conn = kzalloc(sizeof(*tcp_conn), GFP_KERNEL); | 1511 | tcp_conn = conn->dd_data; |
1500 | if (!tcp_conn) | ||
1501 | goto tcp_conn_alloc_fail; | ||
1502 | |||
1503 | conn->dd_data = tcp_conn; | ||
1504 | tcp_conn->iscsi_conn = conn; | 1512 | tcp_conn->iscsi_conn = conn; |
1505 | 1513 | ||
1506 | tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, | 1514 | tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, |
1507 | CRYPTO_ALG_ASYNC); | 1515 | CRYPTO_ALG_ASYNC); |
1508 | tcp_conn->tx_hash.flags = 0; | 1516 | tcp_conn->tx_hash.flags = 0; |
1509 | if (IS_ERR(tcp_conn->tx_hash.tfm)) | 1517 | if (IS_ERR(tcp_conn->tx_hash.tfm)) |
1510 | goto free_tcp_conn; | 1518 | goto free_conn; |
1511 | 1519 | ||
1512 | tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, | 1520 | tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, |
1513 | CRYPTO_ALG_ASYNC); | 1521 | CRYPTO_ALG_ASYNC); |
@@ -1519,14 +1527,12 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1519 | 1527 | ||
1520 | free_tx_tfm: | 1528 | free_tx_tfm: |
1521 | crypto_free_hash(tcp_conn->tx_hash.tfm); | 1529 | crypto_free_hash(tcp_conn->tx_hash.tfm); |
1522 | free_tcp_conn: | 1530 | free_conn: |
1523 | iscsi_conn_printk(KERN_ERR, conn, | 1531 | iscsi_conn_printk(KERN_ERR, conn, |
1524 | "Could not create connection due to crc32c " | 1532 | "Could not create connection due to crc32c " |
1525 | "loading error. Make sure the crc32c " | 1533 | "loading error. Make sure the crc32c " |
1526 | "module is built as a module or into the " | 1534 | "module is built as a module or into the " |
1527 | "kernel\n"); | 1535 | "kernel\n"); |
1528 | kfree(tcp_conn); | ||
1529 | tcp_conn_alloc_fail: | ||
1530 | iscsi_conn_teardown(cls_conn); | 1536 | iscsi_conn_teardown(cls_conn); |
1531 | return NULL; | 1537 | return NULL; |
1532 | } | 1538 | } |
@@ -1547,7 +1553,6 @@ iscsi_tcp_release_conn(struct iscsi_conn *conn) | |||
1547 | 1553 | ||
1548 | spin_lock_bh(&session->lock); | 1554 | spin_lock_bh(&session->lock); |
1549 | tcp_conn->sock = NULL; | 1555 | tcp_conn->sock = NULL; |
1550 | conn->recv_lock = NULL; | ||
1551 | spin_unlock_bh(&session->lock); | 1556 | spin_unlock_bh(&session->lock); |
1552 | sockfd_put(sock); | 1557 | sockfd_put(sock); |
1553 | } | 1558 | } |
@@ -1559,20 +1564,32 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) | |||
1559 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 1564 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
1560 | 1565 | ||
1561 | iscsi_tcp_release_conn(conn); | 1566 | iscsi_tcp_release_conn(conn); |
1562 | iscsi_conn_teardown(cls_conn); | ||
1563 | 1567 | ||
1564 | if (tcp_conn->tx_hash.tfm) | 1568 | if (tcp_conn->tx_hash.tfm) |
1565 | crypto_free_hash(tcp_conn->tx_hash.tfm); | 1569 | crypto_free_hash(tcp_conn->tx_hash.tfm); |
1566 | if (tcp_conn->rx_hash.tfm) | 1570 | if (tcp_conn->rx_hash.tfm) |
1567 | crypto_free_hash(tcp_conn->rx_hash.tfm); | 1571 | crypto_free_hash(tcp_conn->rx_hash.tfm); |
1568 | 1572 | ||
1569 | kfree(tcp_conn); | 1573 | iscsi_conn_teardown(cls_conn); |
1570 | } | 1574 | } |
1571 | 1575 | ||
1572 | static void | 1576 | static void |
1573 | iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | 1577 | iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) |
1574 | { | 1578 | { |
1575 | struct iscsi_conn *conn = cls_conn->dd_data; | 1579 | struct iscsi_conn *conn = cls_conn->dd_data; |
1580 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | ||
1581 | |||
1582 | /* userspace may have goofed up and not bound us */ | ||
1583 | if (!tcp_conn->sock) | ||
1584 | return; | ||
1585 | /* | ||
1586 | * Make sure our recv side is stopped. | ||
1587 | * Older tools called conn stop before ep_disconnect | ||
1588 | * so IO could still be coming in. | ||
1589 | */ | ||
1590 | write_lock_bh(&tcp_conn->sock->sk->sk_callback_lock); | ||
1591 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); | ||
1592 | write_unlock_bh(&tcp_conn->sock->sk->sk_callback_lock); | ||
1576 | 1593 | ||
1577 | iscsi_conn_stop(cls_conn, flag); | 1594 | iscsi_conn_stop(cls_conn, flag); |
1578 | iscsi_tcp_release_conn(conn); | 1595 | iscsi_tcp_release_conn(conn); |
@@ -1623,6 +1640,8 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, | |||
1623 | struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, | 1640 | struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, |
1624 | int is_leading) | 1641 | int is_leading) |
1625 | { | 1642 | { |
1643 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); | ||
1644 | struct iscsi_host *ihost = shost_priv(shost); | ||
1626 | struct iscsi_conn *conn = cls_conn->dd_data; | 1645 | struct iscsi_conn *conn = cls_conn->dd_data; |
1627 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 1646 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
1628 | struct sock *sk; | 1647 | struct sock *sk; |
@@ -1646,8 +1665,8 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, | |||
1646 | if (err) | 1665 | if (err) |
1647 | goto free_socket; | 1666 | goto free_socket; |
1648 | 1667 | ||
1649 | err = iscsi_tcp_get_addr(conn, sock, conn->local_address, | 1668 | err = iscsi_tcp_get_addr(conn, sock, ihost->local_address, |
1650 | &conn->local_port, kernel_getsockname); | 1669 | &ihost->local_port, kernel_getsockname); |
1651 | if (err) | 1670 | if (err) |
1652 | goto free_socket; | 1671 | goto free_socket; |
1653 | 1672 | ||
@@ -1664,13 +1683,6 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, | |||
1664 | sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */ | 1683 | sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */ |
1665 | sk->sk_allocation = GFP_ATOMIC; | 1684 | sk->sk_allocation = GFP_ATOMIC; |
1666 | 1685 | ||
1667 | /* FIXME: disable Nagle's algorithm */ | ||
1668 | |||
1669 | /* | ||
1670 | * Intercept TCP callbacks for sendfile like receive | ||
1671 | * processing. | ||
1672 | */ | ||
1673 | conn->recv_lock = &sk->sk_callback_lock; | ||
1674 | iscsi_conn_set_callbacks(conn); | 1686 | iscsi_conn_set_callbacks(conn); |
1675 | tcp_conn->sendpage = tcp_conn->sock->ops->sendpage; | 1687 | tcp_conn->sendpage = tcp_conn->sock->ops->sendpage; |
1676 | /* | 1688 | /* |
@@ -1684,21 +1696,6 @@ free_socket: | |||
1684 | return err; | 1696 | return err; |
1685 | } | 1697 | } |
1686 | 1698 | ||
1687 | /* called with host lock */ | ||
1688 | static void | ||
1689 | iscsi_tcp_mtask_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) | ||
1690 | { | ||
1691 | debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt); | ||
1692 | |||
1693 | /* Prepare PDU, optionally w/ immediate data */ | ||
1694 | iscsi_tcp_send_hdr_prep(conn, mtask->hdr, sizeof(*mtask->hdr)); | ||
1695 | |||
1696 | /* If we have immediate data, attach a payload */ | ||
1697 | if (mtask->data_count) | ||
1698 | iscsi_tcp_send_linear_data_prepare(conn, mtask->data, | ||
1699 | mtask->data_count); | ||
1700 | } | ||
1701 | |||
1702 | static int | 1699 | static int |
1703 | iscsi_r2tpool_alloc(struct iscsi_session *session) | 1700 | iscsi_r2tpool_alloc(struct iscsi_session *session) |
1704 | { | 1701 | { |
@@ -1709,8 +1706,8 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) | |||
1709 | * initialize per-task: R2T pool and xmit queue | 1706 | * initialize per-task: R2T pool and xmit queue |
1710 | */ | 1707 | */ |
1711 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { | 1708 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { |
1712 | struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; | 1709 | struct iscsi_task *task = session->cmds[cmd_i]; |
1713 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1710 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
1714 | 1711 | ||
1715 | /* | 1712 | /* |
1716 | * pre-allocated x4 as much r2ts to handle race when | 1713 | * pre-allocated x4 as much r2ts to handle race when |
@@ -1719,16 +1716,16 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) | |||
1719 | */ | 1716 | */ |
1720 | 1717 | ||
1721 | /* R2T pool */ | 1718 | /* R2T pool */ |
1722 | if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, NULL, | 1719 | if (iscsi_pool_init(&tcp_task->r2tpool, session->max_r2t * 4, NULL, |
1723 | sizeof(struct iscsi_r2t_info))) { | 1720 | sizeof(struct iscsi_r2t_info))) { |
1724 | goto r2t_alloc_fail; | 1721 | goto r2t_alloc_fail; |
1725 | } | 1722 | } |
1726 | 1723 | ||
1727 | /* R2T xmit queue */ | 1724 | /* R2T xmit queue */ |
1728 | tcp_ctask->r2tqueue = kfifo_alloc( | 1725 | tcp_task->r2tqueue = kfifo_alloc( |
1729 | session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL); | 1726 | session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL); |
1730 | if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) { | 1727 | if (tcp_task->r2tqueue == ERR_PTR(-ENOMEM)) { |
1731 | iscsi_pool_free(&tcp_ctask->r2tpool); | 1728 | iscsi_pool_free(&tcp_task->r2tpool); |
1732 | goto r2t_alloc_fail; | 1729 | goto r2t_alloc_fail; |
1733 | } | 1730 | } |
1734 | } | 1731 | } |
@@ -1737,11 +1734,11 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) | |||
1737 | 1734 | ||
1738 | r2t_alloc_fail: | 1735 | r2t_alloc_fail: |
1739 | for (i = 0; i < cmd_i; i++) { | 1736 | for (i = 0; i < cmd_i; i++) { |
1740 | struct iscsi_cmd_task *ctask = session->cmds[i]; | 1737 | struct iscsi_task *task = session->cmds[i]; |
1741 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1738 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
1742 | 1739 | ||
1743 | kfifo_free(tcp_ctask->r2tqueue); | 1740 | kfifo_free(tcp_task->r2tqueue); |
1744 | iscsi_pool_free(&tcp_ctask->r2tpool); | 1741 | iscsi_pool_free(&tcp_task->r2tpool); |
1745 | } | 1742 | } |
1746 | return -ENOMEM; | 1743 | return -ENOMEM; |
1747 | } | 1744 | } |
@@ -1752,11 +1749,11 @@ iscsi_r2tpool_free(struct iscsi_session *session) | |||
1752 | int i; | 1749 | int i; |
1753 | 1750 | ||
1754 | for (i = 0; i < session->cmds_max; i++) { | 1751 | for (i = 0; i < session->cmds_max; i++) { |
1755 | struct iscsi_cmd_task *ctask = session->cmds[i]; | 1752 | struct iscsi_task *task = session->cmds[i]; |
1756 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1753 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
1757 | 1754 | ||
1758 | kfifo_free(tcp_ctask->r2tqueue); | 1755 | kfifo_free(tcp_task->r2tqueue); |
1759 | iscsi_pool_free(&tcp_ctask->r2tpool); | 1756 | iscsi_pool_free(&tcp_task->r2tpool); |
1760 | } | 1757 | } |
1761 | } | 1758 | } |
1762 | 1759 | ||
@@ -1821,29 +1818,6 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, | |||
1821 | return len; | 1818 | return len; |
1822 | } | 1819 | } |
1823 | 1820 | ||
1824 | static int | ||
1825 | iscsi_tcp_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, | ||
1826 | char *buf) | ||
1827 | { | ||
1828 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | ||
1829 | int len; | ||
1830 | |||
1831 | switch (param) { | ||
1832 | case ISCSI_HOST_PARAM_IPADDRESS: | ||
1833 | spin_lock_bh(&session->lock); | ||
1834 | if (!session->leadconn) | ||
1835 | len = -ENODEV; | ||
1836 | else | ||
1837 | len = sprintf(buf, "%s\n", | ||
1838 | session->leadconn->local_address); | ||
1839 | spin_unlock_bh(&session->lock); | ||
1840 | break; | ||
1841 | default: | ||
1842 | return iscsi_host_get_param(shost, param, buf); | ||
1843 | } | ||
1844 | return len; | ||
1845 | } | ||
1846 | |||
1847 | static void | 1821 | static void |
1848 | iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) | 1822 | iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) |
1849 | { | 1823 | { |
@@ -1869,54 +1843,70 @@ iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) | |||
1869 | } | 1843 | } |
1870 | 1844 | ||
1871 | static struct iscsi_cls_session * | 1845 | static struct iscsi_cls_session * |
1872 | iscsi_tcp_session_create(struct iscsi_transport *iscsit, | 1846 | iscsi_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, |
1873 | struct scsi_transport_template *scsit, | 1847 | uint16_t qdepth, uint32_t initial_cmdsn, |
1874 | uint16_t cmds_max, uint16_t qdepth, | 1848 | uint32_t *hostno) |
1875 | uint32_t initial_cmdsn, uint32_t *hostno) | ||
1876 | { | 1849 | { |
1877 | struct iscsi_cls_session *cls_session; | 1850 | struct iscsi_cls_session *cls_session; |
1878 | struct iscsi_session *session; | 1851 | struct iscsi_session *session; |
1879 | uint32_t hn; | 1852 | struct Scsi_Host *shost; |
1880 | int cmd_i; | 1853 | int cmd_i; |
1881 | 1854 | ||
1882 | cls_session = iscsi_session_setup(iscsit, scsit, cmds_max, qdepth, | 1855 | if (ep) { |
1883 | sizeof(struct iscsi_tcp_cmd_task), | 1856 | printk(KERN_ERR "iscsi_tcp: invalid ep %p.\n", ep); |
1884 | sizeof(struct iscsi_tcp_mgmt_task), | ||
1885 | initial_cmdsn, &hn); | ||
1886 | if (!cls_session) | ||
1887 | return NULL; | 1857 | return NULL; |
1888 | *hostno = hn; | ||
1889 | |||
1890 | session = class_to_transport_session(cls_session); | ||
1891 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { | ||
1892 | struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; | ||
1893 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | ||
1894 | |||
1895 | ctask->hdr = &tcp_ctask->hdr.cmd_hdr; | ||
1896 | ctask->hdr_max = sizeof(tcp_ctask->hdr) - ISCSI_DIGEST_SIZE; | ||
1897 | } | 1858 | } |
1898 | 1859 | ||
1899 | for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { | 1860 | shost = iscsi_host_alloc(&iscsi_sht, 0, qdepth); |
1900 | struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i]; | 1861 | if (!shost) |
1901 | struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; | 1862 | return NULL; |
1863 | shost->transportt = iscsi_tcp_scsi_transport; | ||
1864 | shost->max_lun = iscsi_max_lun; | ||
1865 | shost->max_id = 0; | ||
1866 | shost->max_channel = 0; | ||
1867 | shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE; | ||
1868 | |||
1869 | if (iscsi_host_add(shost, NULL)) | ||
1870 | goto free_host; | ||
1871 | *hostno = shost->host_no; | ||
1872 | |||
1873 | cls_session = iscsi_session_setup(&iscsi_tcp_transport, shost, cmds_max, | ||
1874 | sizeof(struct iscsi_tcp_task), | ||
1875 | initial_cmdsn, 0); | ||
1876 | if (!cls_session) | ||
1877 | goto remove_host; | ||
1878 | session = cls_session->dd_data; | ||
1879 | |||
1880 | shost->can_queue = session->scsi_cmds_max; | ||
1881 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { | ||
1882 | struct iscsi_task *task = session->cmds[cmd_i]; | ||
1883 | struct iscsi_tcp_task *tcp_task = task->dd_data; | ||
1902 | 1884 | ||
1903 | mtask->hdr = (struct iscsi_hdr *) &tcp_mtask->hdr; | 1885 | task->hdr = &tcp_task->hdr.cmd_hdr; |
1886 | task->hdr_max = sizeof(tcp_task->hdr) - ISCSI_DIGEST_SIZE; | ||
1904 | } | 1887 | } |
1905 | 1888 | ||
1906 | if (iscsi_r2tpool_alloc(class_to_transport_session(cls_session))) | 1889 | if (iscsi_r2tpool_alloc(session)) |
1907 | goto r2tpool_alloc_fail; | 1890 | goto remove_session; |
1908 | |||
1909 | return cls_session; | 1891 | return cls_session; |
1910 | 1892 | ||
1911 | r2tpool_alloc_fail: | 1893 | remove_session: |
1912 | iscsi_session_teardown(cls_session); | 1894 | iscsi_session_teardown(cls_session); |
1895 | remove_host: | ||
1896 | iscsi_host_remove(shost); | ||
1897 | free_host: | ||
1898 | iscsi_host_free(shost); | ||
1913 | return NULL; | 1899 | return NULL; |
1914 | } | 1900 | } |
1915 | 1901 | ||
1916 | static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session) | 1902 | static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session) |
1917 | { | 1903 | { |
1918 | iscsi_r2tpool_free(class_to_transport_session(cls_session)); | 1904 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); |
1919 | iscsi_session_teardown(cls_session); | 1905 | |
1906 | iscsi_r2tpool_free(cls_session->dd_data); | ||
1907 | |||
1908 | iscsi_host_remove(shost); | ||
1909 | iscsi_host_free(shost); | ||
1920 | } | 1910 | } |
1921 | 1911 | ||
1922 | static int iscsi_tcp_slave_configure(struct scsi_device *sdev) | 1912 | static int iscsi_tcp_slave_configure(struct scsi_device *sdev) |
@@ -1971,14 +1961,11 @@ static struct iscsi_transport iscsi_tcp_transport = { | |||
1971 | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | | 1961 | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | |
1972 | ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | | 1962 | ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | |
1973 | ISCSI_LU_RESET_TMO | | 1963 | ISCSI_LU_RESET_TMO | |
1974 | ISCSI_PING_TMO | ISCSI_RECV_TMO, | 1964 | ISCSI_PING_TMO | ISCSI_RECV_TMO | |
1965 | ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, | ||
1975 | .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | | 1966 | .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | |
1976 | ISCSI_HOST_INITIATOR_NAME | | 1967 | ISCSI_HOST_INITIATOR_NAME | |
1977 | ISCSI_HOST_NETDEV_NAME, | 1968 | ISCSI_HOST_NETDEV_NAME, |
1978 | .host_template = &iscsi_sht, | ||
1979 | .conndata_size = sizeof(struct iscsi_conn), | ||
1980 | .max_conn = 1, | ||
1981 | .max_cmd_len = 16, | ||
1982 | /* session management */ | 1969 | /* session management */ |
1983 | .create_session = iscsi_tcp_session_create, | 1970 | .create_session = iscsi_tcp_session_create, |
1984 | .destroy_session = iscsi_tcp_session_destroy, | 1971 | .destroy_session = iscsi_tcp_session_destroy, |
@@ -1992,16 +1979,14 @@ static struct iscsi_transport iscsi_tcp_transport = { | |||
1992 | .start_conn = iscsi_conn_start, | 1979 | .start_conn = iscsi_conn_start, |
1993 | .stop_conn = iscsi_tcp_conn_stop, | 1980 | .stop_conn = iscsi_tcp_conn_stop, |
1994 | /* iscsi host params */ | 1981 | /* iscsi host params */ |
1995 | .get_host_param = iscsi_tcp_host_get_param, | 1982 | .get_host_param = iscsi_host_get_param, |
1996 | .set_host_param = iscsi_host_set_param, | 1983 | .set_host_param = iscsi_host_set_param, |
1997 | /* IO */ | 1984 | /* IO */ |
1998 | .send_pdu = iscsi_conn_send_pdu, | 1985 | .send_pdu = iscsi_conn_send_pdu, |
1999 | .get_stats = iscsi_conn_get_stats, | 1986 | .get_stats = iscsi_conn_get_stats, |
2000 | .init_cmd_task = iscsi_tcp_ctask_init, | 1987 | .init_task = iscsi_tcp_task_init, |
2001 | .init_mgmt_task = iscsi_tcp_mtask_init, | 1988 | .xmit_task = iscsi_tcp_task_xmit, |
2002 | .xmit_cmd_task = iscsi_tcp_ctask_xmit, | 1989 | .cleanup_task = iscsi_tcp_cleanup_task, |
2003 | .xmit_mgmt_task = iscsi_tcp_mtask_xmit, | ||
2004 | .cleanup_cmd_task = iscsi_tcp_cleanup_ctask, | ||
2005 | /* recovery */ | 1990 | /* recovery */ |
2006 | .session_recovery_timedout = iscsi_session_recovery_timedout, | 1991 | .session_recovery_timedout = iscsi_session_recovery_timedout, |
2007 | }; | 1992 | }; |
@@ -2014,9 +1999,10 @@ iscsi_tcp_init(void) | |||
2014 | iscsi_max_lun); | 1999 | iscsi_max_lun); |
2015 | return -EINVAL; | 2000 | return -EINVAL; |
2016 | } | 2001 | } |
2017 | iscsi_tcp_transport.max_lun = iscsi_max_lun; | ||
2018 | 2002 | ||
2019 | if (!iscsi_register_transport(&iscsi_tcp_transport)) | 2003 | iscsi_tcp_scsi_transport = iscsi_register_transport( |
2004 | &iscsi_tcp_transport); | ||
2005 | if (!iscsi_tcp_scsi_transport) | ||
2020 | return -ENODEV; | 2006 | return -ENODEV; |
2021 | 2007 | ||
2022 | return 0; | 2008 | return 0; |
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index ed0b991d1e72..498d8ca39848 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h | |||
@@ -103,11 +103,6 @@ struct iscsi_data_task { | |||
103 | char hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */ | 103 | char hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */ |
104 | }; | 104 | }; |
105 | 105 | ||
106 | struct iscsi_tcp_mgmt_task { | ||
107 | struct iscsi_hdr hdr; | ||
108 | char hdrext[ISCSI_DIGEST_SIZE]; /* Header-Digest */ | ||
109 | }; | ||
110 | |||
111 | struct iscsi_r2t_info { | 106 | struct iscsi_r2t_info { |
112 | __be32 ttt; /* copied from R2T */ | 107 | __be32 ttt; /* copied from R2T */ |
113 | __be32 exp_statsn; /* copied from R2T */ | 108 | __be32 exp_statsn; /* copied from R2T */ |
@@ -119,7 +114,7 @@ struct iscsi_r2t_info { | |||
119 | struct iscsi_data_task dtask; /* Data-Out header buf */ | 114 | struct iscsi_data_task dtask; /* Data-Out header buf */ |
120 | }; | 115 | }; |
121 | 116 | ||
122 | struct iscsi_tcp_cmd_task { | 117 | struct iscsi_tcp_task { |
123 | struct iscsi_hdr_buff { | 118 | struct iscsi_hdr_buff { |
124 | struct iscsi_cmd cmd_hdr; | 119 | struct iscsi_cmd cmd_hdr; |
125 | char hdrextbuf[ISCSI_MAX_AHS_SIZE + | 120 | char hdrextbuf[ISCSI_MAX_AHS_SIZE + |
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index b43bf1d60dac..299e075a7b34 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -38,14 +38,6 @@ | |||
38 | #include <scsi/scsi_transport_iscsi.h> | 38 | #include <scsi/scsi_transport_iscsi.h> |
39 | #include <scsi/libiscsi.h> | 39 | #include <scsi/libiscsi.h> |
40 | 40 | ||
41 | struct iscsi_session * | ||
42 | class_to_transport_session(struct iscsi_cls_session *cls_session) | ||
43 | { | ||
44 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); | ||
45 | return iscsi_hostdata(shost->hostdata); | ||
46 | } | ||
47 | EXPORT_SYMBOL_GPL(class_to_transport_session); | ||
48 | |||
49 | /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ | 41 | /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ |
50 | #define SNA32_CHECK 2147483648UL | 42 | #define SNA32_CHECK 2147483648UL |
51 | 43 | ||
@@ -87,68 +79,70 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) | |||
87 | * xmit thread | 79 | * xmit thread |
88 | */ | 80 | */ |
89 | if (!list_empty(&session->leadconn->xmitqueue) || | 81 | if (!list_empty(&session->leadconn->xmitqueue) || |
90 | !list_empty(&session->leadconn->mgmtqueue)) | 82 | !list_empty(&session->leadconn->mgmtqueue)) { |
91 | scsi_queue_work(session->host, | 83 | if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD)) |
92 | &session->leadconn->xmitwork); | 84 | scsi_queue_work(session->host, |
85 | &session->leadconn->xmitwork); | ||
86 | } | ||
93 | } | 87 | } |
94 | } | 88 | } |
95 | EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); | 89 | EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); |
96 | 90 | ||
97 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, | 91 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_task *task, |
98 | struct iscsi_data *hdr) | 92 | struct iscsi_data *hdr) |
99 | { | 93 | { |
100 | struct iscsi_conn *conn = ctask->conn; | 94 | struct iscsi_conn *conn = task->conn; |
101 | 95 | ||
102 | memset(hdr, 0, sizeof(struct iscsi_data)); | 96 | memset(hdr, 0, sizeof(struct iscsi_data)); |
103 | hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); | 97 | hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); |
104 | hdr->datasn = cpu_to_be32(ctask->unsol_datasn); | 98 | hdr->datasn = cpu_to_be32(task->unsol_datasn); |
105 | ctask->unsol_datasn++; | 99 | task->unsol_datasn++; |
106 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; | 100 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; |
107 | memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); | 101 | memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun)); |
108 | 102 | ||
109 | hdr->itt = ctask->hdr->itt; | 103 | hdr->itt = task->hdr->itt; |
110 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); | 104 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); |
111 | hdr->offset = cpu_to_be32(ctask->unsol_offset); | 105 | hdr->offset = cpu_to_be32(task->unsol_offset); |
112 | 106 | ||
113 | if (ctask->unsol_count > conn->max_xmit_dlength) { | 107 | if (task->unsol_count > conn->max_xmit_dlength) { |
114 | hton24(hdr->dlength, conn->max_xmit_dlength); | 108 | hton24(hdr->dlength, conn->max_xmit_dlength); |
115 | ctask->data_count = conn->max_xmit_dlength; | 109 | task->data_count = conn->max_xmit_dlength; |
116 | ctask->unsol_offset += ctask->data_count; | 110 | task->unsol_offset += task->data_count; |
117 | hdr->flags = 0; | 111 | hdr->flags = 0; |
118 | } else { | 112 | } else { |
119 | hton24(hdr->dlength, ctask->unsol_count); | 113 | hton24(hdr->dlength, task->unsol_count); |
120 | ctask->data_count = ctask->unsol_count; | 114 | task->data_count = task->unsol_count; |
121 | hdr->flags = ISCSI_FLAG_CMD_FINAL; | 115 | hdr->flags = ISCSI_FLAG_CMD_FINAL; |
122 | } | 116 | } |
123 | } | 117 | } |
124 | EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); | 118 | EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); |
125 | 119 | ||
126 | static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len) | 120 | static int iscsi_add_hdr(struct iscsi_task *task, unsigned len) |
127 | { | 121 | { |
128 | unsigned exp_len = ctask->hdr_len + len; | 122 | unsigned exp_len = task->hdr_len + len; |
129 | 123 | ||
130 | if (exp_len > ctask->hdr_max) { | 124 | if (exp_len > task->hdr_max) { |
131 | WARN_ON(1); | 125 | WARN_ON(1); |
132 | return -EINVAL; | 126 | return -EINVAL; |
133 | } | 127 | } |
134 | 128 | ||
135 | WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */ | 129 | WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */ |
136 | ctask->hdr_len = exp_len; | 130 | task->hdr_len = exp_len; |
137 | return 0; | 131 | return 0; |
138 | } | 132 | } |
139 | 133 | ||
140 | /* | 134 | /* |
141 | * make an extended cdb AHS | 135 | * make an extended cdb AHS |
142 | */ | 136 | */ |
143 | static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask) | 137 | static int iscsi_prep_ecdb_ahs(struct iscsi_task *task) |
144 | { | 138 | { |
145 | struct scsi_cmnd *cmd = ctask->sc; | 139 | struct scsi_cmnd *cmd = task->sc; |
146 | unsigned rlen, pad_len; | 140 | unsigned rlen, pad_len; |
147 | unsigned short ahslength; | 141 | unsigned short ahslength; |
148 | struct iscsi_ecdb_ahdr *ecdb_ahdr; | 142 | struct iscsi_ecdb_ahdr *ecdb_ahdr; |
149 | int rc; | 143 | int rc; |
150 | 144 | ||
151 | ecdb_ahdr = iscsi_next_hdr(ctask); | 145 | ecdb_ahdr = iscsi_next_hdr(task); |
152 | rlen = cmd->cmd_len - ISCSI_CDB_SIZE; | 146 | rlen = cmd->cmd_len - ISCSI_CDB_SIZE; |
153 | 147 | ||
154 | BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb)); | 148 | BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb)); |
@@ -156,7 +150,7 @@ static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask) | |||
156 | 150 | ||
157 | pad_len = iscsi_padding(rlen); | 151 | pad_len = iscsi_padding(rlen); |
158 | 152 | ||
159 | rc = iscsi_add_hdr(ctask, sizeof(ecdb_ahdr->ahslength) + | 153 | rc = iscsi_add_hdr(task, sizeof(ecdb_ahdr->ahslength) + |
160 | sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len); | 154 | sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len); |
161 | if (rc) | 155 | if (rc) |
162 | return rc; | 156 | return rc; |
@@ -171,19 +165,19 @@ static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask) | |||
171 | 165 | ||
172 | debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d " | 166 | debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d " |
173 | "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n", | 167 | "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n", |
174 | cmd->cmd_len, rlen, pad_len, ahslength, ctask->hdr_len); | 168 | cmd->cmd_len, rlen, pad_len, ahslength, task->hdr_len); |
175 | 169 | ||
176 | return 0; | 170 | return 0; |
177 | } | 171 | } |
178 | 172 | ||
179 | static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask) | 173 | static int iscsi_prep_bidi_ahs(struct iscsi_task *task) |
180 | { | 174 | { |
181 | struct scsi_cmnd *sc = ctask->sc; | 175 | struct scsi_cmnd *sc = task->sc; |
182 | struct iscsi_rlength_ahdr *rlen_ahdr; | 176 | struct iscsi_rlength_ahdr *rlen_ahdr; |
183 | int rc; | 177 | int rc; |
184 | 178 | ||
185 | rlen_ahdr = iscsi_next_hdr(ctask); | 179 | rlen_ahdr = iscsi_next_hdr(task); |
186 | rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr)); | 180 | rc = iscsi_add_hdr(task, sizeof(*rlen_ahdr)); |
187 | if (rc) | 181 | if (rc) |
188 | return rc; | 182 | return rc; |
189 | 183 | ||
@@ -203,28 +197,28 @@ static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask) | |||
203 | 197 | ||
204 | /** | 198 | /** |
205 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu | 199 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu |
206 | * @ctask: iscsi cmd task | 200 | * @task: iscsi task |
207 | * | 201 | * |
208 | * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set | 202 | * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set |
209 | * fields like dlength or final based on how much data it sends | 203 | * fields like dlength or final based on how much data it sends |
210 | */ | 204 | */ |
211 | static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | 205 | static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) |
212 | { | 206 | { |
213 | struct iscsi_conn *conn = ctask->conn; | 207 | struct iscsi_conn *conn = task->conn; |
214 | struct iscsi_session *session = conn->session; | 208 | struct iscsi_session *session = conn->session; |
215 | struct iscsi_cmd *hdr = ctask->hdr; | 209 | struct iscsi_cmd *hdr = task->hdr; |
216 | struct scsi_cmnd *sc = ctask->sc; | 210 | struct scsi_cmnd *sc = task->sc; |
217 | unsigned hdrlength, cmd_len; | 211 | unsigned hdrlength, cmd_len; |
218 | int rc; | 212 | int rc; |
219 | 213 | ||
220 | ctask->hdr_len = 0; | 214 | task->hdr_len = 0; |
221 | rc = iscsi_add_hdr(ctask, sizeof(*hdr)); | 215 | rc = iscsi_add_hdr(task, sizeof(*hdr)); |
222 | if (rc) | 216 | if (rc) |
223 | return rc; | 217 | return rc; |
224 | hdr->opcode = ISCSI_OP_SCSI_CMD; | 218 | hdr->opcode = ISCSI_OP_SCSI_CMD; |
225 | hdr->flags = ISCSI_ATTR_SIMPLE; | 219 | hdr->flags = ISCSI_ATTR_SIMPLE; |
226 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); | 220 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); |
227 | hdr->itt = build_itt(ctask->itt, session->age); | 221 | hdr->itt = build_itt(task->itt, session->age); |
228 | hdr->cmdsn = cpu_to_be32(session->cmdsn); | 222 | hdr->cmdsn = cpu_to_be32(session->cmdsn); |
229 | session->cmdsn++; | 223 | session->cmdsn++; |
230 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); | 224 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); |
@@ -232,17 +226,17 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
232 | if (cmd_len < ISCSI_CDB_SIZE) | 226 | if (cmd_len < ISCSI_CDB_SIZE) |
233 | memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len); | 227 | memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len); |
234 | else if (cmd_len > ISCSI_CDB_SIZE) { | 228 | else if (cmd_len > ISCSI_CDB_SIZE) { |
235 | rc = iscsi_prep_ecdb_ahs(ctask); | 229 | rc = iscsi_prep_ecdb_ahs(task); |
236 | if (rc) | 230 | if (rc) |
237 | return rc; | 231 | return rc; |
238 | cmd_len = ISCSI_CDB_SIZE; | 232 | cmd_len = ISCSI_CDB_SIZE; |
239 | } | 233 | } |
240 | memcpy(hdr->cdb, sc->cmnd, cmd_len); | 234 | memcpy(hdr->cdb, sc->cmnd, cmd_len); |
241 | 235 | ||
242 | ctask->imm_count = 0; | 236 | task->imm_count = 0; |
243 | if (scsi_bidi_cmnd(sc)) { | 237 | if (scsi_bidi_cmnd(sc)) { |
244 | hdr->flags |= ISCSI_FLAG_CMD_READ; | 238 | hdr->flags |= ISCSI_FLAG_CMD_READ; |
245 | rc = iscsi_prep_bidi_ahs(ctask); | 239 | rc = iscsi_prep_bidi_ahs(task); |
246 | if (rc) | 240 | if (rc) |
247 | return rc; | 241 | return rc; |
248 | } | 242 | } |
@@ -264,28 +258,28 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
264 | * | 258 | * |
265 | * pad_count bytes to be sent as zero-padding | 259 | * pad_count bytes to be sent as zero-padding |
266 | */ | 260 | */ |
267 | ctask->unsol_count = 0; | 261 | task->unsol_count = 0; |
268 | ctask->unsol_offset = 0; | 262 | task->unsol_offset = 0; |
269 | ctask->unsol_datasn = 0; | 263 | task->unsol_datasn = 0; |
270 | 264 | ||
271 | if (session->imm_data_en) { | 265 | if (session->imm_data_en) { |
272 | if (out_len >= session->first_burst) | 266 | if (out_len >= session->first_burst) |
273 | ctask->imm_count = min(session->first_burst, | 267 | task->imm_count = min(session->first_burst, |
274 | conn->max_xmit_dlength); | 268 | conn->max_xmit_dlength); |
275 | else | 269 | else |
276 | ctask->imm_count = min(out_len, | 270 | task->imm_count = min(out_len, |
277 | conn->max_xmit_dlength); | 271 | conn->max_xmit_dlength); |
278 | hton24(hdr->dlength, ctask->imm_count); | 272 | hton24(hdr->dlength, task->imm_count); |
279 | } else | 273 | } else |
280 | zero_data(hdr->dlength); | 274 | zero_data(hdr->dlength); |
281 | 275 | ||
282 | if (!session->initial_r2t_en) { | 276 | if (!session->initial_r2t_en) { |
283 | ctask->unsol_count = min(session->first_burst, out_len) | 277 | task->unsol_count = min(session->first_burst, out_len) |
284 | - ctask->imm_count; | 278 | - task->imm_count; |
285 | ctask->unsol_offset = ctask->imm_count; | 279 | task->unsol_offset = task->imm_count; |
286 | } | 280 | } |
287 | 281 | ||
288 | if (!ctask->unsol_count) | 282 | if (!task->unsol_count) |
289 | /* No unsolicit Data-Out's */ | 283 | /* No unsolicit Data-Out's */ |
290 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 284 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
291 | } else { | 285 | } else { |
@@ -298,7 +292,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
298 | } | 292 | } |
299 | 293 | ||
300 | /* calculate size of additional header segments (AHSs) */ | 294 | /* calculate size of additional header segments (AHSs) */ |
301 | hdrlength = ctask->hdr_len - sizeof(*hdr); | 295 | hdrlength = task->hdr_len - sizeof(*hdr); |
302 | 296 | ||
303 | WARN_ON(hdrlength & (ISCSI_PAD_LEN-1)); | 297 | WARN_ON(hdrlength & (ISCSI_PAD_LEN-1)); |
304 | hdrlength /= ISCSI_PAD_LEN; | 298 | hdrlength /= ISCSI_PAD_LEN; |
@@ -306,76 +300,115 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
306 | WARN_ON(hdrlength >= 256); | 300 | WARN_ON(hdrlength >= 256); |
307 | hdr->hlength = hdrlength & 0xFF; | 301 | hdr->hlength = hdrlength & 0xFF; |
308 | 302 | ||
309 | if (conn->session->tt->init_cmd_task(conn->ctask)) | 303 | if (conn->session->tt->init_task && |
310 | return EIO; | 304 | conn->session->tt->init_task(task)) |
305 | return -EIO; | ||
306 | |||
307 | task->state = ISCSI_TASK_RUNNING; | ||
308 | list_move_tail(&task->running, &conn->run_list); | ||
311 | 309 | ||
312 | conn->scsicmd_pdus_cnt++; | 310 | conn->scsicmd_pdus_cnt++; |
313 | debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x " | 311 | debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " |
314 | "len %d bidi_len %d cmdsn %d win %d]\n", | 312 | "bidi_len %d cmdsn %d win %d]\n", scsi_bidi_cmnd(sc) ? |
315 | scsi_bidi_cmnd(sc) ? "bidirectional" : | 313 | "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ? |
316 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | 314 | "write" : "read", conn->id, sc, sc->cmnd[0], task->itt, |
317 | conn->id, sc, sc->cmnd[0], ctask->itt, | 315 | scsi_bufflen(sc), |
318 | scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, | 316 | scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, |
319 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); | 317 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); |
320 | return 0; | 318 | return 0; |
321 | } | 319 | } |
322 | 320 | ||
323 | /** | 321 | /** |
324 | * iscsi_complete_command - return command back to scsi-ml | 322 | * iscsi_complete_command - finish a task |
325 | * @ctask: iscsi cmd task | 323 | * @task: iscsi cmd task |
326 | * | 324 | * |
327 | * Must be called with session lock. | 325 | * Must be called with session lock. |
328 | * This function returns the scsi command to scsi-ml and returns | 326 | * This function returns the scsi command to scsi-ml or cleans |
329 | * the cmd task to the pool of available cmd tasks. | 327 | * up mgmt tasks then returns the task to the pool. |
330 | */ | 328 | */ |
331 | static void iscsi_complete_command(struct iscsi_cmd_task *ctask) | 329 | static void iscsi_complete_command(struct iscsi_task *task) |
332 | { | 330 | { |
333 | struct iscsi_conn *conn = ctask->conn; | 331 | struct iscsi_conn *conn = task->conn; |
334 | struct iscsi_session *session = conn->session; | 332 | struct iscsi_session *session = conn->session; |
335 | struct scsi_cmnd *sc = ctask->sc; | 333 | struct scsi_cmnd *sc = task->sc; |
336 | 334 | ||
337 | ctask->state = ISCSI_TASK_COMPLETED; | 335 | list_del_init(&task->running); |
338 | ctask->sc = NULL; | 336 | task->state = ISCSI_TASK_COMPLETED; |
339 | /* SCSI eh reuses commands to verify us */ | 337 | task->sc = NULL; |
340 | sc->SCp.ptr = NULL; | 338 | |
341 | if (conn->ctask == ctask) | 339 | if (conn->task == task) |
342 | conn->ctask = NULL; | 340 | conn->task = NULL; |
343 | list_del_init(&ctask->running); | 341 | /* |
344 | __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); | 342 | * login task is preallocated so do not free |
345 | sc->scsi_done(sc); | 343 | */ |
344 | if (conn->login_task == task) | ||
345 | return; | ||
346 | |||
347 | __kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*)); | ||
348 | |||
349 | if (conn->ping_task == task) | ||
350 | conn->ping_task = NULL; | ||
351 | |||
352 | if (sc) { | ||
353 | task->sc = NULL; | ||
354 | /* SCSI eh reuses commands to verify us */ | ||
355 | sc->SCp.ptr = NULL; | ||
356 | /* | ||
357 | * queue command may call this to free the task, but | ||
358 | * not have setup the sc callback | ||
359 | */ | ||
360 | if (sc->scsi_done) | ||
361 | sc->scsi_done(sc); | ||
362 | } | ||
363 | } | ||
364 | |||
365 | void __iscsi_get_task(struct iscsi_task *task) | ||
366 | { | ||
367 | atomic_inc(&task->refcount); | ||
346 | } | 368 | } |
369 | EXPORT_SYMBOL_GPL(__iscsi_get_task); | ||
347 | 370 | ||
348 | static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask) | 371 | static void __iscsi_put_task(struct iscsi_task *task) |
349 | { | 372 | { |
350 | atomic_inc(&ctask->refcount); | 373 | if (atomic_dec_and_test(&task->refcount)) |
374 | iscsi_complete_command(task); | ||
351 | } | 375 | } |
352 | 376 | ||
353 | static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) | 377 | void iscsi_put_task(struct iscsi_task *task) |
354 | { | 378 | { |
355 | if (atomic_dec_and_test(&ctask->refcount)) | 379 | struct iscsi_session *session = task->conn->session; |
356 | iscsi_complete_command(ctask); | 380 | |
381 | spin_lock_bh(&session->lock); | ||
382 | __iscsi_put_task(task); | ||
383 | spin_unlock_bh(&session->lock); | ||
357 | } | 384 | } |
385 | EXPORT_SYMBOL_GPL(iscsi_put_task); | ||
358 | 386 | ||
359 | /* | 387 | /* |
360 | * session lock must be held | 388 | * session lock must be held |
361 | */ | 389 | */ |
362 | static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | 390 | static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task, |
363 | int err) | 391 | int err) |
364 | { | 392 | { |
365 | struct scsi_cmnd *sc; | 393 | struct scsi_cmnd *sc; |
366 | 394 | ||
367 | sc = ctask->sc; | 395 | sc = task->sc; |
368 | if (!sc) | 396 | if (!sc) |
369 | return; | 397 | return; |
370 | 398 | ||
371 | if (ctask->state == ISCSI_TASK_PENDING) | 399 | if (task->state == ISCSI_TASK_PENDING) |
372 | /* | 400 | /* |
373 | * cmd never made it to the xmit thread, so we should not count | 401 | * cmd never made it to the xmit thread, so we should not count |
374 | * the cmd in the sequencing | 402 | * the cmd in the sequencing |
375 | */ | 403 | */ |
376 | conn->session->queued_cmdsn--; | 404 | conn->session->queued_cmdsn--; |
377 | else | 405 | else |
378 | conn->session->tt->cleanup_cmd_task(conn, ctask); | 406 | conn->session->tt->cleanup_task(conn, task); |
407 | /* | ||
408 | * Check if cleanup_task dropped the lock and the command completed, | ||
409 | */ | ||
410 | if (!task->sc) | ||
411 | return; | ||
379 | 412 | ||
380 | sc->result = err; | 413 | sc->result = err; |
381 | if (!scsi_bidi_cmnd(sc)) | 414 | if (!scsi_bidi_cmnd(sc)) |
@@ -384,39 +417,63 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
384 | scsi_out(sc)->resid = scsi_out(sc)->length; | 417 | scsi_out(sc)->resid = scsi_out(sc)->length; |
385 | scsi_in(sc)->resid = scsi_in(sc)->length; | 418 | scsi_in(sc)->resid = scsi_in(sc)->length; |
386 | } | 419 | } |
387 | if (conn->ctask == ctask) | 420 | |
388 | conn->ctask = NULL; | 421 | if (conn->task == task) |
422 | conn->task = NULL; | ||
389 | /* release ref from queuecommand */ | 423 | /* release ref from queuecommand */ |
390 | __iscsi_put_ctask(ctask); | 424 | __iscsi_put_task(task); |
391 | } | 425 | } |
392 | 426 | ||
393 | /** | 427 | static int iscsi_prep_mgmt_task(struct iscsi_conn *conn, |
394 | * iscsi_free_mgmt_task - return mgmt task back to pool | 428 | struct iscsi_task *task) |
395 | * @conn: iscsi connection | ||
396 | * @mtask: mtask | ||
397 | * | ||
398 | * Must be called with session lock. | ||
399 | */ | ||
400 | void iscsi_free_mgmt_task(struct iscsi_conn *conn, | ||
401 | struct iscsi_mgmt_task *mtask) | ||
402 | { | 429 | { |
403 | list_del_init(&mtask->running); | 430 | struct iscsi_session *session = conn->session; |
404 | if (conn->login_mtask == mtask) | 431 | struct iscsi_hdr *hdr = (struct iscsi_hdr *)task->hdr; |
405 | return; | 432 | struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; |
433 | |||
434 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) | ||
435 | return -ENOTCONN; | ||
436 | |||
437 | if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) && | ||
438 | hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) | ||
439 | nop->exp_statsn = cpu_to_be32(conn->exp_statsn); | ||
440 | /* | ||
441 | * pre-format CmdSN for outgoing PDU. | ||
442 | */ | ||
443 | nop->cmdsn = cpu_to_be32(session->cmdsn); | ||
444 | if (hdr->itt != RESERVED_ITT) { | ||
445 | hdr->itt = build_itt(task->itt, session->age); | ||
446 | /* | ||
447 | * TODO: We always use immediate, so we never hit this. | ||
448 | * If we start to send tmfs or nops as non-immediate then | ||
449 | * we should start checking the cmdsn numbers for mgmt tasks. | ||
450 | */ | ||
451 | if (conn->c_stage == ISCSI_CONN_STARTED && | ||
452 | !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { | ||
453 | session->queued_cmdsn++; | ||
454 | session->cmdsn++; | ||
455 | } | ||
456 | } | ||
406 | 457 | ||
407 | if (conn->ping_mtask == mtask) | 458 | if (session->tt->init_task) |
408 | conn->ping_mtask = NULL; | 459 | session->tt->init_task(task); |
409 | __kfifo_put(conn->session->mgmtpool.queue, | 460 | |
410 | (void*)&mtask, sizeof(void*)); | 461 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) |
462 | session->state = ISCSI_STATE_LOGGING_OUT; | ||
463 | |||
464 | list_move_tail(&task->running, &conn->mgmt_run_list); | ||
465 | debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", | ||
466 | hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt, | ||
467 | task->data_count); | ||
468 | return 0; | ||
411 | } | 469 | } |
412 | EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task); | ||
413 | 470 | ||
414 | static struct iscsi_mgmt_task * | 471 | static struct iscsi_task * |
415 | __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 472 | __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
416 | char *data, uint32_t data_size) | 473 | char *data, uint32_t data_size) |
417 | { | 474 | { |
418 | struct iscsi_session *session = conn->session; | 475 | struct iscsi_session *session = conn->session; |
419 | struct iscsi_mgmt_task *mtask; | 476 | struct iscsi_task *task; |
420 | 477 | ||
421 | if (session->state == ISCSI_STATE_TERMINATE) | 478 | if (session->state == ISCSI_STATE_TERMINATE) |
422 | return NULL; | 479 | return NULL; |
@@ -426,29 +483,56 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
426 | /* | 483 | /* |
427 | * Login and Text are sent serially, in | 484 | * Login and Text are sent serially, in |
428 | * request-followed-by-response sequence. | 485 | * request-followed-by-response sequence. |
429 | * Same mtask can be used. Same ITT must be used. | 486 | * Same task can be used. Same ITT must be used. |
430 | * Note that login_mtask is preallocated at conn_create(). | 487 | * Note that login_task is preallocated at conn_create(). |
431 | */ | 488 | */ |
432 | mtask = conn->login_mtask; | 489 | task = conn->login_task; |
433 | else { | 490 | else { |
434 | BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); | 491 | BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); |
435 | BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); | 492 | BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); |
436 | 493 | ||
437 | if (!__kfifo_get(session->mgmtpool.queue, | 494 | if (!__kfifo_get(session->cmdpool.queue, |
438 | (void*)&mtask, sizeof(void*))) | 495 | (void*)&task, sizeof(void*))) |
439 | return NULL; | 496 | return NULL; |
497 | |||
498 | if ((hdr->opcode == (ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE)) && | ||
499 | hdr->ttt == RESERVED_ITT) { | ||
500 | conn->ping_task = task; | ||
501 | conn->last_ping = jiffies; | ||
502 | } | ||
440 | } | 503 | } |
504 | /* | ||
505 | * released in complete pdu for task we expect a response for, and | ||
506 | * released by the lld when it has transmitted the task for | ||
507 | * pdus we do not expect a response for. | ||
508 | */ | ||
509 | atomic_set(&task->refcount, 1); | ||
510 | task->conn = conn; | ||
511 | task->sc = NULL; | ||
441 | 512 | ||
442 | if (data_size) { | 513 | if (data_size) { |
443 | memcpy(mtask->data, data, data_size); | 514 | memcpy(task->data, data, data_size); |
444 | mtask->data_count = data_size; | 515 | task->data_count = data_size; |
516 | } else | ||
517 | task->data_count = 0; | ||
518 | |||
519 | memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr)); | ||
520 | INIT_LIST_HEAD(&task->running); | ||
521 | list_add_tail(&task->running, &conn->mgmtqueue); | ||
522 | |||
523 | if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) { | ||
524 | if (iscsi_prep_mgmt_task(conn, task)) { | ||
525 | __iscsi_put_task(task); | ||
526 | return NULL; | ||
527 | } | ||
528 | |||
529 | if (session->tt->xmit_task(task)) | ||
530 | task = NULL; | ||
531 | |||
445 | } else | 532 | } else |
446 | mtask->data_count = 0; | 533 | scsi_queue_work(conn->session->host, &conn->xmitwork); |
447 | 534 | ||
448 | memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); | 535 | return task; |
449 | INIT_LIST_HEAD(&mtask->running); | ||
450 | list_add_tail(&mtask->running, &conn->mgmtqueue); | ||
451 | return mtask; | ||
452 | } | 536 | } |
453 | 537 | ||
454 | int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, | 538 | int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, |
@@ -462,7 +546,6 @@ int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, | |||
462 | if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) | 546 | if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) |
463 | err = -EPERM; | 547 | err = -EPERM; |
464 | spin_unlock_bh(&session->lock); | 548 | spin_unlock_bh(&session->lock); |
465 | scsi_queue_work(session->host, &conn->xmitwork); | ||
466 | return err; | 549 | return err; |
467 | } | 550 | } |
468 | EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); | 551 | EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); |
@@ -471,7 +554,7 @@ EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); | |||
471 | * iscsi_cmd_rsp - SCSI Command Response processing | 554 | * iscsi_cmd_rsp - SCSI Command Response processing |
472 | * @conn: iscsi connection | 555 | * @conn: iscsi connection |
473 | * @hdr: iscsi header | 556 | * @hdr: iscsi header |
474 | * @ctask: scsi command task | 557 | * @task: scsi command task |
475 | * @data: cmd data buffer | 558 | * @data: cmd data buffer |
476 | * @datalen: len of buffer | 559 | * @datalen: len of buffer |
477 | * | 560 | * |
@@ -479,12 +562,12 @@ EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); | |||
479 | * then completes the command and task. | 562 | * then completes the command and task. |
480 | **/ | 563 | **/ |
481 | static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 564 | static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
482 | struct iscsi_cmd_task *ctask, char *data, | 565 | struct iscsi_task *task, char *data, |
483 | int datalen) | 566 | int datalen) |
484 | { | 567 | { |
485 | struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; | 568 | struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; |
486 | struct iscsi_session *session = conn->session; | 569 | struct iscsi_session *session = conn->session; |
487 | struct scsi_cmnd *sc = ctask->sc; | 570 | struct scsi_cmnd *sc = task->sc; |
488 | 571 | ||
489 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); | 572 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); |
490 | conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; | 573 | conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; |
@@ -508,7 +591,7 @@ invalid_datalen: | |||
508 | goto out; | 591 | goto out; |
509 | } | 592 | } |
510 | 593 | ||
511 | senselen = be16_to_cpu(get_unaligned((__be16 *) data)); | 594 | senselen = get_unaligned_be16(data); |
512 | if (datalen < senselen) | 595 | if (datalen < senselen) |
513 | goto invalid_datalen; | 596 | goto invalid_datalen; |
514 | 597 | ||
@@ -544,10 +627,10 @@ invalid_datalen: | |||
544 | } | 627 | } |
545 | out: | 628 | out: |
546 | debug_scsi("done [sc %lx res %d itt 0x%x]\n", | 629 | debug_scsi("done [sc %lx res %d itt 0x%x]\n", |
547 | (long)sc, sc->result, ctask->itt); | 630 | (long)sc, sc->result, task->itt); |
548 | conn->scsirsp_pdus_cnt++; | 631 | conn->scsirsp_pdus_cnt++; |
549 | 632 | ||
550 | __iscsi_put_ctask(ctask); | 633 | __iscsi_put_task(task); |
551 | } | 634 | } |
552 | 635 | ||
553 | static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | 636 | static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) |
@@ -572,9 +655,9 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
572 | static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) | 655 | static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) |
573 | { | 656 | { |
574 | struct iscsi_nopout hdr; | 657 | struct iscsi_nopout hdr; |
575 | struct iscsi_mgmt_task *mtask; | 658 | struct iscsi_task *task; |
576 | 659 | ||
577 | if (!rhdr && conn->ping_mtask) | 660 | if (!rhdr && conn->ping_task) |
578 | return; | 661 | return; |
579 | 662 | ||
580 | memset(&hdr, 0, sizeof(struct iscsi_nopout)); | 663 | memset(&hdr, 0, sizeof(struct iscsi_nopout)); |
@@ -588,18 +671,9 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) | |||
588 | } else | 671 | } else |
589 | hdr.ttt = RESERVED_ITT; | 672 | hdr.ttt = RESERVED_ITT; |
590 | 673 | ||
591 | mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); | 674 | task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); |
592 | if (!mtask) { | 675 | if (!task) |
593 | iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); | 676 | iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); |
594 | return; | ||
595 | } | ||
596 | |||
597 | /* only track our nops */ | ||
598 | if (!rhdr) { | ||
599 | conn->ping_mtask = mtask; | ||
600 | conn->last_ping = jiffies; | ||
601 | } | ||
602 | scsi_queue_work(conn->session->host, &conn->xmitwork); | ||
603 | } | 677 | } |
604 | 678 | ||
605 | static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 679 | static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
@@ -628,6 +702,31 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
628 | } | 702 | } |
629 | 703 | ||
630 | /** | 704 | /** |
705 | * iscsi_itt_to_task - look up task by itt | ||
706 | * @conn: iscsi connection | ||
707 | * @itt: itt | ||
708 | * | ||
709 | * This should be used for mgmt tasks like login and nops, or if | ||
710 | * the LDD's itt space does not include the session age. | ||
711 | * | ||
712 | * The session lock must be held. | ||
713 | */ | ||
714 | static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt) | ||
715 | { | ||
716 | struct iscsi_session *session = conn->session; | ||
717 | uint32_t i; | ||
718 | |||
719 | if (itt == RESERVED_ITT) | ||
720 | return NULL; | ||
721 | |||
722 | i = get_itt(itt); | ||
723 | if (i >= session->cmds_max) | ||
724 | return NULL; | ||
725 | |||
726 | return session->cmds[i]; | ||
727 | } | ||
728 | |||
729 | /** | ||
631 | * __iscsi_complete_pdu - complete pdu | 730 | * __iscsi_complete_pdu - complete pdu |
632 | * @conn: iscsi conn | 731 | * @conn: iscsi conn |
633 | * @hdr: iscsi header | 732 | * @hdr: iscsi header |
@@ -638,108 +737,28 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
638 | * queuecommand or send generic. session lock must be held and verify | 737 | * queuecommand or send generic. session lock must be held and verify |
639 | * itt must have been called. | 738 | * itt must have been called. |
640 | */ | 739 | */ |
641 | static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 740 | int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
642 | char *data, int datalen) | 741 | char *data, int datalen) |
643 | { | 742 | { |
644 | struct iscsi_session *session = conn->session; | 743 | struct iscsi_session *session = conn->session; |
645 | int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; | 744 | int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; |
646 | struct iscsi_cmd_task *ctask; | 745 | struct iscsi_task *task; |
647 | struct iscsi_mgmt_task *mtask; | ||
648 | uint32_t itt; | 746 | uint32_t itt; |
649 | 747 | ||
650 | conn->last_recv = jiffies; | 748 | conn->last_recv = jiffies; |
749 | rc = iscsi_verify_itt(conn, hdr->itt); | ||
750 | if (rc) | ||
751 | return rc; | ||
752 | |||
651 | if (hdr->itt != RESERVED_ITT) | 753 | if (hdr->itt != RESERVED_ITT) |
652 | itt = get_itt(hdr->itt); | 754 | itt = get_itt(hdr->itt); |
653 | else | 755 | else |
654 | itt = ~0U; | 756 | itt = ~0U; |
655 | 757 | ||
656 | if (itt < session->cmds_max) { | 758 | debug_scsi("[op 0x%x cid %d itt 0x%x len %d]\n", |
657 | ctask = session->cmds[itt]; | 759 | opcode, conn->id, itt, datalen); |
658 | |||
659 | debug_scsi("cmdrsp [op 0x%x cid %d itt 0x%x len %d]\n", | ||
660 | opcode, conn->id, ctask->itt, datalen); | ||
661 | |||
662 | switch(opcode) { | ||
663 | case ISCSI_OP_SCSI_CMD_RSP: | ||
664 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); | ||
665 | iscsi_scsi_cmd_rsp(conn, hdr, ctask, data, | ||
666 | datalen); | ||
667 | break; | ||
668 | case ISCSI_OP_SCSI_DATA_IN: | ||
669 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); | ||
670 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { | ||
671 | conn->scsirsp_pdus_cnt++; | ||
672 | __iscsi_put_ctask(ctask); | ||
673 | } | ||
674 | break; | ||
675 | case ISCSI_OP_R2T: | ||
676 | /* LLD handles this for now */ | ||
677 | break; | ||
678 | default: | ||
679 | rc = ISCSI_ERR_BAD_OPCODE; | ||
680 | break; | ||
681 | } | ||
682 | } else if (itt >= ISCSI_MGMT_ITT_OFFSET && | ||
683 | itt < ISCSI_MGMT_ITT_OFFSET + session->mgmtpool_max) { | ||
684 | mtask = session->mgmt_cmds[itt - ISCSI_MGMT_ITT_OFFSET]; | ||
685 | |||
686 | debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n", | ||
687 | opcode, conn->id, mtask->itt, datalen); | ||
688 | 760 | ||
689 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | 761 | if (itt == ~0U) { |
690 | switch(opcode) { | ||
691 | case ISCSI_OP_LOGOUT_RSP: | ||
692 | if (datalen) { | ||
693 | rc = ISCSI_ERR_PROTO; | ||
694 | break; | ||
695 | } | ||
696 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | ||
697 | /* fall through */ | ||
698 | case ISCSI_OP_LOGIN_RSP: | ||
699 | case ISCSI_OP_TEXT_RSP: | ||
700 | /* | ||
701 | * login related PDU's exp_statsn is handled in | ||
702 | * userspace | ||
703 | */ | ||
704 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) | ||
705 | rc = ISCSI_ERR_CONN_FAILED; | ||
706 | iscsi_free_mgmt_task(conn, mtask); | ||
707 | break; | ||
708 | case ISCSI_OP_SCSI_TMFUNC_RSP: | ||
709 | if (datalen) { | ||
710 | rc = ISCSI_ERR_PROTO; | ||
711 | break; | ||
712 | } | ||
713 | |||
714 | iscsi_tmf_rsp(conn, hdr); | ||
715 | iscsi_free_mgmt_task(conn, mtask); | ||
716 | break; | ||
717 | case ISCSI_OP_NOOP_IN: | ||
718 | if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || | ||
719 | datalen) { | ||
720 | rc = ISCSI_ERR_PROTO; | ||
721 | break; | ||
722 | } | ||
723 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | ||
724 | |||
725 | if (conn->ping_mtask != mtask) { | ||
726 | /* | ||
727 | * If this is not in response to one of our | ||
728 | * nops then it must be from userspace. | ||
729 | */ | ||
730 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, | ||
731 | datalen)) | ||
732 | rc = ISCSI_ERR_CONN_FAILED; | ||
733 | } else | ||
734 | mod_timer(&conn->transport_timer, | ||
735 | jiffies + conn->recv_timeout); | ||
736 | iscsi_free_mgmt_task(conn, mtask); | ||
737 | break; | ||
738 | default: | ||
739 | rc = ISCSI_ERR_BAD_OPCODE; | ||
740 | break; | ||
741 | } | ||
742 | } else if (itt == ~0U) { | ||
743 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | 762 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); |
744 | 763 | ||
745 | switch(opcode) { | 764 | switch(opcode) { |
@@ -766,11 +785,104 @@ static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
766 | rc = ISCSI_ERR_BAD_OPCODE; | 785 | rc = ISCSI_ERR_BAD_OPCODE; |
767 | break; | 786 | break; |
768 | } | 787 | } |
769 | } else | 788 | goto out; |
770 | rc = ISCSI_ERR_BAD_ITT; | 789 | } |
771 | 790 | ||
791 | switch(opcode) { | ||
792 | case ISCSI_OP_SCSI_CMD_RSP: | ||
793 | case ISCSI_OP_SCSI_DATA_IN: | ||
794 | task = iscsi_itt_to_ctask(conn, hdr->itt); | ||
795 | if (!task) | ||
796 | return ISCSI_ERR_BAD_ITT; | ||
797 | break; | ||
798 | case ISCSI_OP_R2T: | ||
799 | /* | ||
800 | * LLD handles R2Ts if they need to. | ||
801 | */ | ||
802 | return 0; | ||
803 | case ISCSI_OP_LOGOUT_RSP: | ||
804 | case ISCSI_OP_LOGIN_RSP: | ||
805 | case ISCSI_OP_TEXT_RSP: | ||
806 | case ISCSI_OP_SCSI_TMFUNC_RSP: | ||
807 | case ISCSI_OP_NOOP_IN: | ||
808 | task = iscsi_itt_to_task(conn, hdr->itt); | ||
809 | if (!task) | ||
810 | return ISCSI_ERR_BAD_ITT; | ||
811 | break; | ||
812 | default: | ||
813 | return ISCSI_ERR_BAD_OPCODE; | ||
814 | } | ||
815 | |||
816 | switch(opcode) { | ||
817 | case ISCSI_OP_SCSI_CMD_RSP: | ||
818 | iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen); | ||
819 | break; | ||
820 | case ISCSI_OP_SCSI_DATA_IN: | ||
821 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { | ||
822 | conn->scsirsp_pdus_cnt++; | ||
823 | iscsi_update_cmdsn(session, | ||
824 | (struct iscsi_nopin*) hdr); | ||
825 | __iscsi_put_task(task); | ||
826 | } | ||
827 | break; | ||
828 | case ISCSI_OP_LOGOUT_RSP: | ||
829 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | ||
830 | if (datalen) { | ||
831 | rc = ISCSI_ERR_PROTO; | ||
832 | break; | ||
833 | } | ||
834 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | ||
835 | goto recv_pdu; | ||
836 | case ISCSI_OP_LOGIN_RSP: | ||
837 | case ISCSI_OP_TEXT_RSP: | ||
838 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | ||
839 | /* | ||
840 | * login related PDU's exp_statsn is handled in | ||
841 | * userspace | ||
842 | */ | ||
843 | goto recv_pdu; | ||
844 | case ISCSI_OP_SCSI_TMFUNC_RSP: | ||
845 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | ||
846 | if (datalen) { | ||
847 | rc = ISCSI_ERR_PROTO; | ||
848 | break; | ||
849 | } | ||
850 | |||
851 | iscsi_tmf_rsp(conn, hdr); | ||
852 | __iscsi_put_task(task); | ||
853 | break; | ||
854 | case ISCSI_OP_NOOP_IN: | ||
855 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | ||
856 | if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) { | ||
857 | rc = ISCSI_ERR_PROTO; | ||
858 | break; | ||
859 | } | ||
860 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | ||
861 | |||
862 | if (conn->ping_task != task) | ||
863 | /* | ||
864 | * If this is not in response to one of our | ||
865 | * nops then it must be from userspace. | ||
866 | */ | ||
867 | goto recv_pdu; | ||
868 | |||
869 | mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout); | ||
870 | __iscsi_put_task(task); | ||
871 | break; | ||
872 | default: | ||
873 | rc = ISCSI_ERR_BAD_OPCODE; | ||
874 | break; | ||
875 | } | ||
876 | |||
877 | out: | ||
878 | return rc; | ||
879 | recv_pdu: | ||
880 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) | ||
881 | rc = ISCSI_ERR_CONN_FAILED; | ||
882 | __iscsi_put_task(task); | ||
772 | return rc; | 883 | return rc; |
773 | } | 884 | } |
885 | EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); | ||
774 | 886 | ||
775 | int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 887 | int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
776 | char *data, int datalen) | 888 | char *data, int datalen) |
@@ -784,51 +896,63 @@ int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
784 | } | 896 | } |
785 | EXPORT_SYMBOL_GPL(iscsi_complete_pdu); | 897 | EXPORT_SYMBOL_GPL(iscsi_complete_pdu); |
786 | 898 | ||
787 | /* verify itt (itt encoding: age+cid+itt) */ | 899 | int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt) |
788 | int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | ||
789 | uint32_t *ret_itt) | ||
790 | { | 900 | { |
791 | struct iscsi_session *session = conn->session; | 901 | struct iscsi_session *session = conn->session; |
792 | struct iscsi_cmd_task *ctask; | 902 | uint32_t i; |
793 | uint32_t itt; | ||
794 | 903 | ||
795 | if (hdr->itt != RESERVED_ITT) { | 904 | if (itt == RESERVED_ITT) |
796 | if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != | 905 | return 0; |
797 | (session->age << ISCSI_AGE_SHIFT)) { | ||
798 | iscsi_conn_printk(KERN_ERR, conn, | ||
799 | "received itt %x expected session " | ||
800 | "age (%x)\n", (__force u32)hdr->itt, | ||
801 | session->age & ISCSI_AGE_MASK); | ||
802 | return ISCSI_ERR_BAD_ITT; | ||
803 | } | ||
804 | 906 | ||
805 | itt = get_itt(hdr->itt); | 907 | if (((__force u32)itt & ISCSI_AGE_MASK) != |
806 | } else | 908 | (session->age << ISCSI_AGE_SHIFT)) { |
807 | itt = ~0U; | 909 | iscsi_conn_printk(KERN_ERR, conn, |
910 | "received itt %x expected session age (%x)\n", | ||
911 | (__force u32)itt, session->age); | ||
912 | return ISCSI_ERR_BAD_ITT; | ||
913 | } | ||
808 | 914 | ||
809 | if (itt < session->cmds_max) { | 915 | i = get_itt(itt); |
810 | ctask = session->cmds[itt]; | 916 | if (i >= session->cmds_max) { |
917 | iscsi_conn_printk(KERN_ERR, conn, | ||
918 | "received invalid itt index %u (max cmds " | ||
919 | "%u.\n", i, session->cmds_max); | ||
920 | return ISCSI_ERR_BAD_ITT; | ||
921 | } | ||
922 | return 0; | ||
923 | } | ||
924 | EXPORT_SYMBOL_GPL(iscsi_verify_itt); | ||
811 | 925 | ||
812 | if (!ctask->sc) { | 926 | /** |
813 | iscsi_conn_printk(KERN_INFO, conn, "dropping ctask " | 927 | * iscsi_itt_to_ctask - look up ctask by itt |
814 | "with itt 0x%x\n", ctask->itt); | 928 | * @conn: iscsi connection |
815 | /* force drop */ | 929 | * @itt: itt |
816 | return ISCSI_ERR_NO_SCSI_CMD; | 930 | * |
817 | } | 931 | * This should be used for cmd tasks. |
932 | * | ||
933 | * The session lock must be held. | ||
934 | */ | ||
935 | struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt) | ||
936 | { | ||
937 | struct iscsi_task *task; | ||
818 | 938 | ||
819 | if (ctask->sc->SCp.phase != session->age) { | 939 | if (iscsi_verify_itt(conn, itt)) |
820 | iscsi_conn_printk(KERN_ERR, conn, | 940 | return NULL; |
821 | "iscsi: ctask's session age %d, " | 941 | |
822 | "expected %d\n", ctask->sc->SCp.phase, | 942 | task = iscsi_itt_to_task(conn, itt); |
823 | session->age); | 943 | if (!task || !task->sc) |
824 | return ISCSI_ERR_SESSION_FAILED; | 944 | return NULL; |
825 | } | 945 | |
946 | if (task->sc->SCp.phase != conn->session->age) { | ||
947 | iscsi_session_printk(KERN_ERR, conn->session, | ||
948 | "task's session age %d, expected %d\n", | ||
949 | task->sc->SCp.phase, conn->session->age); | ||
950 | return NULL; | ||
826 | } | 951 | } |
827 | 952 | ||
828 | *ret_itt = itt; | 953 | return task; |
829 | return 0; | ||
830 | } | 954 | } |
831 | EXPORT_SYMBOL_GPL(iscsi_verify_itt); | 955 | EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask); |
832 | 956 | ||
833 | void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) | 957 | void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) |
834 | { | 958 | { |
@@ -850,61 +974,6 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) | |||
850 | } | 974 | } |
851 | EXPORT_SYMBOL_GPL(iscsi_conn_failure); | 975 | EXPORT_SYMBOL_GPL(iscsi_conn_failure); |
852 | 976 | ||
853 | static void iscsi_prep_mtask(struct iscsi_conn *conn, | ||
854 | struct iscsi_mgmt_task *mtask) | ||
855 | { | ||
856 | struct iscsi_session *session = conn->session; | ||
857 | struct iscsi_hdr *hdr = mtask->hdr; | ||
858 | struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; | ||
859 | |||
860 | if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) && | ||
861 | hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) | ||
862 | nop->exp_statsn = cpu_to_be32(conn->exp_statsn); | ||
863 | /* | ||
864 | * pre-format CmdSN for outgoing PDU. | ||
865 | */ | ||
866 | nop->cmdsn = cpu_to_be32(session->cmdsn); | ||
867 | if (hdr->itt != RESERVED_ITT) { | ||
868 | hdr->itt = build_itt(mtask->itt, session->age); | ||
869 | /* | ||
870 | * TODO: We always use immediate, so we never hit this. | ||
871 | * If we start to send tmfs or nops as non-immediate then | ||
872 | * we should start checking the cmdsn numbers for mgmt tasks. | ||
873 | */ | ||
874 | if (conn->c_stage == ISCSI_CONN_STARTED && | ||
875 | !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { | ||
876 | session->queued_cmdsn++; | ||
877 | session->cmdsn++; | ||
878 | } | ||
879 | } | ||
880 | |||
881 | if (session->tt->init_mgmt_task) | ||
882 | session->tt->init_mgmt_task(conn, mtask); | ||
883 | |||
884 | debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", | ||
885 | hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt, | ||
886 | mtask->data_count); | ||
887 | } | ||
888 | |||
889 | static int iscsi_xmit_mtask(struct iscsi_conn *conn) | ||
890 | { | ||
891 | struct iscsi_hdr *hdr = conn->mtask->hdr; | ||
892 | int rc; | ||
893 | |||
894 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) | ||
895 | conn->session->state = ISCSI_STATE_LOGGING_OUT; | ||
896 | spin_unlock_bh(&conn->session->lock); | ||
897 | |||
898 | rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); | ||
899 | spin_lock_bh(&conn->session->lock); | ||
900 | if (rc) | ||
901 | return rc; | ||
902 | |||
903 | /* done with this in-progress mtask */ | ||
904 | conn->mtask = NULL; | ||
905 | return 0; | ||
906 | } | ||
907 | |||
908 | static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) | 977 | static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) |
909 | { | 978 | { |
910 | struct iscsi_session *session = conn->session; | 979 | struct iscsi_session *session = conn->session; |
@@ -922,37 +991,38 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) | |||
922 | return 0; | 991 | return 0; |
923 | } | 992 | } |
924 | 993 | ||
925 | static int iscsi_xmit_ctask(struct iscsi_conn *conn) | 994 | static int iscsi_xmit_task(struct iscsi_conn *conn) |
926 | { | 995 | { |
927 | struct iscsi_cmd_task *ctask = conn->ctask; | 996 | struct iscsi_task *task = conn->task; |
928 | int rc; | 997 | int rc; |
929 | 998 | ||
930 | __iscsi_get_ctask(ctask); | 999 | __iscsi_get_task(task); |
931 | spin_unlock_bh(&conn->session->lock); | 1000 | spin_unlock_bh(&conn->session->lock); |
932 | rc = conn->session->tt->xmit_cmd_task(conn, ctask); | 1001 | rc = conn->session->tt->xmit_task(task); |
933 | spin_lock_bh(&conn->session->lock); | 1002 | spin_lock_bh(&conn->session->lock); |
934 | __iscsi_put_ctask(ctask); | 1003 | __iscsi_put_task(task); |
935 | if (!rc) | 1004 | if (!rc) |
936 | /* done with this ctask */ | 1005 | /* done with this task */ |
937 | conn->ctask = NULL; | 1006 | conn->task = NULL; |
938 | return rc; | 1007 | return rc; |
939 | } | 1008 | } |
940 | 1009 | ||
941 | /** | 1010 | /** |
942 | * iscsi_requeue_ctask - requeue ctask to run from session workqueue | 1011 | * iscsi_requeue_task - requeue task to run from session workqueue |
943 | * @ctask: ctask to requeue | 1012 | * @task: task to requeue |
944 | * | 1013 | * |
945 | * LLDs that need to run a ctask from the session workqueue should call | 1014 | * LLDs that need to run a task from the session workqueue should call |
946 | * this. The session lock must be held. | 1015 | * this. The session lock must be held. This should only be called |
1016 | * by software drivers. | ||
947 | */ | 1017 | */ |
948 | void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask) | 1018 | void iscsi_requeue_task(struct iscsi_task *task) |
949 | { | 1019 | { |
950 | struct iscsi_conn *conn = ctask->conn; | 1020 | struct iscsi_conn *conn = task->conn; |
951 | 1021 | ||
952 | list_move_tail(&ctask->running, &conn->requeue); | 1022 | list_move_tail(&task->running, &conn->requeue); |
953 | scsi_queue_work(conn->session->host, &conn->xmitwork); | 1023 | scsi_queue_work(conn->session->host, &conn->xmitwork); |
954 | } | 1024 | } |
955 | EXPORT_SYMBOL_GPL(iscsi_requeue_ctask); | 1025 | EXPORT_SYMBOL_GPL(iscsi_requeue_task); |
956 | 1026 | ||
957 | /** | 1027 | /** |
958 | * iscsi_data_xmit - xmit any command into the scheduled connection | 1028 | * iscsi_data_xmit - xmit any command into the scheduled connection |
@@ -974,14 +1044,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
974 | return -ENODATA; | 1044 | return -ENODATA; |
975 | } | 1045 | } |
976 | 1046 | ||
977 | if (conn->ctask) { | 1047 | if (conn->task) { |
978 | rc = iscsi_xmit_ctask(conn); | 1048 | rc = iscsi_xmit_task(conn); |
979 | if (rc) | ||
980 | goto again; | ||
981 | } | ||
982 | |||
983 | if (conn->mtask) { | ||
984 | rc = iscsi_xmit_mtask(conn); | ||
985 | if (rc) | 1049 | if (rc) |
986 | goto again; | 1050 | goto again; |
987 | } | 1051 | } |
@@ -993,17 +1057,14 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
993 | */ | 1057 | */ |
994 | check_mgmt: | 1058 | check_mgmt: |
995 | while (!list_empty(&conn->mgmtqueue)) { | 1059 | while (!list_empty(&conn->mgmtqueue)) { |
996 | conn->mtask = list_entry(conn->mgmtqueue.next, | 1060 | conn->task = list_entry(conn->mgmtqueue.next, |
997 | struct iscsi_mgmt_task, running); | 1061 | struct iscsi_task, running); |
998 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { | 1062 | if (iscsi_prep_mgmt_task(conn, conn->task)) { |
999 | iscsi_free_mgmt_task(conn, conn->mtask); | 1063 | __iscsi_put_task(conn->task); |
1000 | conn->mtask = NULL; | 1064 | conn->task = NULL; |
1001 | continue; | 1065 | continue; |
1002 | } | 1066 | } |
1003 | 1067 | rc = iscsi_xmit_task(conn); | |
1004 | iscsi_prep_mtask(conn, conn->mtask); | ||
1005 | list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list); | ||
1006 | rc = iscsi_xmit_mtask(conn); | ||
1007 | if (rc) | 1068 | if (rc) |
1008 | goto again; | 1069 | goto again; |
1009 | } | 1070 | } |
@@ -1013,24 +1074,21 @@ check_mgmt: | |||
1013 | if (conn->tmf_state == TMF_QUEUED) | 1074 | if (conn->tmf_state == TMF_QUEUED) |
1014 | break; | 1075 | break; |
1015 | 1076 | ||
1016 | conn->ctask = list_entry(conn->xmitqueue.next, | 1077 | conn->task = list_entry(conn->xmitqueue.next, |
1017 | struct iscsi_cmd_task, running); | 1078 | struct iscsi_task, running); |
1018 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { | 1079 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { |
1019 | fail_command(conn, conn->ctask, DID_IMM_RETRY << 16); | 1080 | fail_command(conn, conn->task, DID_IMM_RETRY << 16); |
1020 | continue; | 1081 | continue; |
1021 | } | 1082 | } |
1022 | if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) { | 1083 | if (iscsi_prep_scsi_cmd_pdu(conn->task)) { |
1023 | fail_command(conn, conn->ctask, DID_ABORT << 16); | 1084 | fail_command(conn, conn->task, DID_ABORT << 16); |
1024 | continue; | 1085 | continue; |
1025 | } | 1086 | } |
1026 | 1087 | rc = iscsi_xmit_task(conn); | |
1027 | conn->ctask->state = ISCSI_TASK_RUNNING; | ||
1028 | list_move_tail(conn->xmitqueue.next, &conn->run_list); | ||
1029 | rc = iscsi_xmit_ctask(conn); | ||
1030 | if (rc) | 1088 | if (rc) |
1031 | goto again; | 1089 | goto again; |
1032 | /* | 1090 | /* |
1033 | * we could continuously get new ctask requests so | 1091 | * we could continuously get new task requests so |
1034 | * we need to check the mgmt queue for nops that need to | 1092 | * we need to check the mgmt queue for nops that need to |
1035 | * be sent to aviod starvation | 1093 | * be sent to aviod starvation |
1036 | */ | 1094 | */ |
@@ -1048,11 +1106,11 @@ check_mgmt: | |||
1048 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) | 1106 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) |
1049 | break; | 1107 | break; |
1050 | 1108 | ||
1051 | conn->ctask = list_entry(conn->requeue.next, | 1109 | conn->task = list_entry(conn->requeue.next, |
1052 | struct iscsi_cmd_task, running); | 1110 | struct iscsi_task, running); |
1053 | conn->ctask->state = ISCSI_TASK_RUNNING; | 1111 | conn->task->state = ISCSI_TASK_RUNNING; |
1054 | list_move_tail(conn->requeue.next, &conn->run_list); | 1112 | list_move_tail(conn->requeue.next, &conn->run_list); |
1055 | rc = iscsi_xmit_ctask(conn); | 1113 | rc = iscsi_xmit_task(conn); |
1056 | if (rc) | 1114 | if (rc) |
1057 | goto again; | 1115 | goto again; |
1058 | if (!list_empty(&conn->mgmtqueue)) | 1116 | if (!list_empty(&conn->mgmtqueue)) |
@@ -1096,11 +1154,12 @@ enum { | |||
1096 | 1154 | ||
1097 | int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | 1155 | int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) |
1098 | { | 1156 | { |
1157 | struct iscsi_cls_session *cls_session; | ||
1099 | struct Scsi_Host *host; | 1158 | struct Scsi_Host *host; |
1100 | int reason = 0; | 1159 | int reason = 0; |
1101 | struct iscsi_session *session; | 1160 | struct iscsi_session *session; |
1102 | struct iscsi_conn *conn; | 1161 | struct iscsi_conn *conn; |
1103 | struct iscsi_cmd_task *ctask = NULL; | 1162 | struct iscsi_task *task = NULL; |
1104 | 1163 | ||
1105 | sc->scsi_done = done; | 1164 | sc->scsi_done = done; |
1106 | sc->result = 0; | 1165 | sc->result = 0; |
@@ -1109,10 +1168,11 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
1109 | host = sc->device->host; | 1168 | host = sc->device->host; |
1110 | spin_unlock(host->host_lock); | 1169 | spin_unlock(host->host_lock); |
1111 | 1170 | ||
1112 | session = iscsi_hostdata(host->hostdata); | 1171 | cls_session = starget_to_session(scsi_target(sc->device)); |
1172 | session = cls_session->dd_data; | ||
1113 | spin_lock(&session->lock); | 1173 | spin_lock(&session->lock); |
1114 | 1174 | ||
1115 | reason = iscsi_session_chkready(session_to_cls(session)); | 1175 | reason = iscsi_session_chkready(cls_session); |
1116 | if (reason) { | 1176 | if (reason) { |
1117 | sc->result = reason; | 1177 | sc->result = reason; |
1118 | goto fault; | 1178 | goto fault; |
@@ -1167,26 +1227,39 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
1167 | goto reject; | 1227 | goto reject; |
1168 | } | 1228 | } |
1169 | 1229 | ||
1170 | if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, | 1230 | if (!__kfifo_get(session->cmdpool.queue, (void*)&task, |
1171 | sizeof(void*))) { | 1231 | sizeof(void*))) { |
1172 | reason = FAILURE_OOM; | 1232 | reason = FAILURE_OOM; |
1173 | goto reject; | 1233 | goto reject; |
1174 | } | 1234 | } |
1175 | session->queued_cmdsn++; | ||
1176 | |||
1177 | sc->SCp.phase = session->age; | 1235 | sc->SCp.phase = session->age; |
1178 | sc->SCp.ptr = (char *)ctask; | 1236 | sc->SCp.ptr = (char *)task; |
1179 | 1237 | ||
1180 | atomic_set(&ctask->refcount, 1); | 1238 | atomic_set(&task->refcount, 1); |
1181 | ctask->state = ISCSI_TASK_PENDING; | 1239 | task->state = ISCSI_TASK_PENDING; |
1182 | ctask->conn = conn; | 1240 | task->conn = conn; |
1183 | ctask->sc = sc; | 1241 | task->sc = sc; |
1184 | INIT_LIST_HEAD(&ctask->running); | 1242 | INIT_LIST_HEAD(&task->running); |
1243 | list_add_tail(&task->running, &conn->xmitqueue); | ||
1244 | |||
1245 | if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) { | ||
1246 | if (iscsi_prep_scsi_cmd_pdu(task)) { | ||
1247 | sc->result = DID_ABORT << 16; | ||
1248 | sc->scsi_done = NULL; | ||
1249 | iscsi_complete_command(task); | ||
1250 | goto fault; | ||
1251 | } | ||
1252 | if (session->tt->xmit_task(task)) { | ||
1253 | sc->scsi_done = NULL; | ||
1254 | iscsi_complete_command(task); | ||
1255 | reason = FAILURE_SESSION_NOT_READY; | ||
1256 | goto reject; | ||
1257 | } | ||
1258 | } else | ||
1259 | scsi_queue_work(session->host, &conn->xmitwork); | ||
1185 | 1260 | ||
1186 | list_add_tail(&ctask->running, &conn->xmitqueue); | 1261 | session->queued_cmdsn++; |
1187 | spin_unlock(&session->lock); | 1262 | spin_unlock(&session->lock); |
1188 | |||
1189 | scsi_queue_work(host, &conn->xmitwork); | ||
1190 | spin_lock(host->host_lock); | 1263 | spin_lock(host->host_lock); |
1191 | return 0; | 1264 | return 0; |
1192 | 1265 | ||
@@ -1205,7 +1278,7 @@ fault: | |||
1205 | scsi_out(sc)->resid = scsi_out(sc)->length; | 1278 | scsi_out(sc)->resid = scsi_out(sc)->length; |
1206 | scsi_in(sc)->resid = scsi_in(sc)->length; | 1279 | scsi_in(sc)->resid = scsi_in(sc)->length; |
1207 | } | 1280 | } |
1208 | sc->scsi_done(sc); | 1281 | done(sc); |
1209 | spin_lock(host->host_lock); | 1282 | spin_lock(host->host_lock); |
1210 | return 0; | 1283 | return 0; |
1211 | } | 1284 | } |
@@ -1222,7 +1295,7 @@ EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); | |||
1222 | 1295 | ||
1223 | void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) | 1296 | void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) |
1224 | { | 1297 | { |
1225 | struct iscsi_session *session = class_to_transport_session(cls_session); | 1298 | struct iscsi_session *session = cls_session->dd_data; |
1226 | 1299 | ||
1227 | spin_lock_bh(&session->lock); | 1300 | spin_lock_bh(&session->lock); |
1228 | if (session->state != ISCSI_STATE_LOGGED_IN) { | 1301 | if (session->state != ISCSI_STATE_LOGGED_IN) { |
@@ -1236,9 +1309,13 @@ EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout); | |||
1236 | 1309 | ||
1237 | int iscsi_eh_host_reset(struct scsi_cmnd *sc) | 1310 | int iscsi_eh_host_reset(struct scsi_cmnd *sc) |
1238 | { | 1311 | { |
1239 | struct Scsi_Host *host = sc->device->host; | 1312 | struct iscsi_cls_session *cls_session; |
1240 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); | 1313 | struct iscsi_session *session; |
1241 | struct iscsi_conn *conn = session->leadconn; | 1314 | struct iscsi_conn *conn; |
1315 | |||
1316 | cls_session = starget_to_session(scsi_target(sc->device)); | ||
1317 | session = cls_session->dd_data; | ||
1318 | conn = session->leadconn; | ||
1242 | 1319 | ||
1243 | mutex_lock(&session->eh_mutex); | 1320 | mutex_lock(&session->eh_mutex); |
1244 | spin_lock_bh(&session->lock); | 1321 | spin_lock_bh(&session->lock); |
@@ -1300,11 +1377,11 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, | |||
1300 | int timeout) | 1377 | int timeout) |
1301 | { | 1378 | { |
1302 | struct iscsi_session *session = conn->session; | 1379 | struct iscsi_session *session = conn->session; |
1303 | struct iscsi_mgmt_task *mtask; | 1380 | struct iscsi_task *task; |
1304 | 1381 | ||
1305 | mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, | 1382 | task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, |
1306 | NULL, 0); | 1383 | NULL, 0); |
1307 | if (!mtask) { | 1384 | if (!task) { |
1308 | spin_unlock_bh(&session->lock); | 1385 | spin_unlock_bh(&session->lock); |
1309 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 1386 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
1310 | spin_lock_bh(&session->lock); | 1387 | spin_lock_bh(&session->lock); |
@@ -1320,7 +1397,6 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, | |||
1320 | 1397 | ||
1321 | spin_unlock_bh(&session->lock); | 1398 | spin_unlock_bh(&session->lock); |
1322 | mutex_unlock(&session->eh_mutex); | 1399 | mutex_unlock(&session->eh_mutex); |
1323 | scsi_queue_work(session->host, &conn->xmitwork); | ||
1324 | 1400 | ||
1325 | /* | 1401 | /* |
1326 | * block eh thread until: | 1402 | * block eh thread until: |
@@ -1339,7 +1415,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, | |||
1339 | 1415 | ||
1340 | mutex_lock(&session->eh_mutex); | 1416 | mutex_lock(&session->eh_mutex); |
1341 | spin_lock_bh(&session->lock); | 1417 | spin_lock_bh(&session->lock); |
1342 | /* if the session drops it will clean up the mtask */ | 1418 | /* if the session drops it will clean up the task */ |
1343 | if (age != session->age || | 1419 | if (age != session->age || |
1344 | session->state != ISCSI_STATE_LOGGED_IN) | 1420 | session->state != ISCSI_STATE_LOGGED_IN) |
1345 | return -ENOTCONN; | 1421 | return -ENOTCONN; |
@@ -1353,48 +1429,51 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, | |||
1353 | static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, | 1429 | static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, |
1354 | int error) | 1430 | int error) |
1355 | { | 1431 | { |
1356 | struct iscsi_cmd_task *ctask, *tmp; | 1432 | struct iscsi_task *task, *tmp; |
1357 | 1433 | ||
1358 | if (conn->ctask && (conn->ctask->sc->device->lun == lun || lun == -1)) | 1434 | if (conn->task && (conn->task->sc->device->lun == lun || lun == -1)) |
1359 | conn->ctask = NULL; | 1435 | conn->task = NULL; |
1360 | 1436 | ||
1361 | /* flush pending */ | 1437 | /* flush pending */ |
1362 | list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) { | 1438 | list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) { |
1363 | if (lun == ctask->sc->device->lun || lun == -1) { | 1439 | if (lun == task->sc->device->lun || lun == -1) { |
1364 | debug_scsi("failing pending sc %p itt 0x%x\n", | 1440 | debug_scsi("failing pending sc %p itt 0x%x\n", |
1365 | ctask->sc, ctask->itt); | 1441 | task->sc, task->itt); |
1366 | fail_command(conn, ctask, error << 16); | 1442 | fail_command(conn, task, error << 16); |
1367 | } | 1443 | } |
1368 | } | 1444 | } |
1369 | 1445 | ||
1370 | list_for_each_entry_safe(ctask, tmp, &conn->requeue, running) { | 1446 | list_for_each_entry_safe(task, tmp, &conn->requeue, running) { |
1371 | if (lun == ctask->sc->device->lun || lun == -1) { | 1447 | if (lun == task->sc->device->lun || lun == -1) { |
1372 | debug_scsi("failing requeued sc %p itt 0x%x\n", | 1448 | debug_scsi("failing requeued sc %p itt 0x%x\n", |
1373 | ctask->sc, ctask->itt); | 1449 | task->sc, task->itt); |
1374 | fail_command(conn, ctask, error << 16); | 1450 | fail_command(conn, task, error << 16); |
1375 | } | 1451 | } |
1376 | } | 1452 | } |
1377 | 1453 | ||
1378 | /* fail all other running */ | 1454 | /* fail all other running */ |
1379 | list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) { | 1455 | list_for_each_entry_safe(task, tmp, &conn->run_list, running) { |
1380 | if (lun == ctask->sc->device->lun || lun == -1) { | 1456 | if (lun == task->sc->device->lun || lun == -1) { |
1381 | debug_scsi("failing in progress sc %p itt 0x%x\n", | 1457 | debug_scsi("failing in progress sc %p itt 0x%x\n", |
1382 | ctask->sc, ctask->itt); | 1458 | task->sc, task->itt); |
1383 | fail_command(conn, ctask, DID_BUS_BUSY << 16); | 1459 | fail_command(conn, task, DID_BUS_BUSY << 16); |
1384 | } | 1460 | } |
1385 | } | 1461 | } |
1386 | } | 1462 | } |
1387 | 1463 | ||
1388 | static void iscsi_suspend_tx(struct iscsi_conn *conn) | 1464 | void iscsi_suspend_tx(struct iscsi_conn *conn) |
1389 | { | 1465 | { |
1390 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | 1466 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); |
1391 | scsi_flush_work(conn->session->host); | 1467 | if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD)) |
1468 | scsi_flush_work(conn->session->host); | ||
1392 | } | 1469 | } |
1470 | EXPORT_SYMBOL_GPL(iscsi_suspend_tx); | ||
1393 | 1471 | ||
1394 | static void iscsi_start_tx(struct iscsi_conn *conn) | 1472 | static void iscsi_start_tx(struct iscsi_conn *conn) |
1395 | { | 1473 | { |
1396 | clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | 1474 | clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); |
1397 | scsi_queue_work(conn->session->host, &conn->xmitwork); | 1475 | if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD)) |
1476 | scsi_queue_work(conn->session->host, &conn->xmitwork); | ||
1398 | } | 1477 | } |
1399 | 1478 | ||
1400 | static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) | 1479 | static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) |
@@ -1405,7 +1484,7 @@ static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) | |||
1405 | enum scsi_eh_timer_return rc = EH_NOT_HANDLED; | 1484 | enum scsi_eh_timer_return rc = EH_NOT_HANDLED; |
1406 | 1485 | ||
1407 | cls_session = starget_to_session(scsi_target(scmd->device)); | 1486 | cls_session = starget_to_session(scsi_target(scmd->device)); |
1408 | session = class_to_transport_session(cls_session); | 1487 | session = cls_session->dd_data; |
1409 | 1488 | ||
1410 | debug_scsi("scsi cmd %p timedout\n", scmd); | 1489 | debug_scsi("scsi cmd %p timedout\n", scmd); |
1411 | 1490 | ||
@@ -1443,7 +1522,7 @@ static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) | |||
1443 | jiffies)) | 1522 | jiffies)) |
1444 | rc = EH_RESET_TIMER; | 1523 | rc = EH_RESET_TIMER; |
1445 | /* if in the middle of checking the transport then give us more time */ | 1524 | /* if in the middle of checking the transport then give us more time */ |
1446 | if (conn->ping_mtask) | 1525 | if (conn->ping_task) |
1447 | rc = EH_RESET_TIMER; | 1526 | rc = EH_RESET_TIMER; |
1448 | done: | 1527 | done: |
1449 | spin_unlock(&session->lock); | 1528 | spin_unlock(&session->lock); |
@@ -1467,7 +1546,7 @@ static void iscsi_check_transport_timeouts(unsigned long data) | |||
1467 | 1546 | ||
1468 | recv_timeout *= HZ; | 1547 | recv_timeout *= HZ; |
1469 | last_recv = conn->last_recv; | 1548 | last_recv = conn->last_recv; |
1470 | if (conn->ping_mtask && | 1549 | if (conn->ping_task && |
1471 | time_before_eq(conn->last_ping + (conn->ping_timeout * HZ), | 1550 | time_before_eq(conn->last_ping + (conn->ping_timeout * HZ), |
1472 | jiffies)) { | 1551 | jiffies)) { |
1473 | iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs " | 1552 | iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs " |
@@ -1493,27 +1572,30 @@ done: | |||
1493 | spin_unlock(&session->lock); | 1572 | spin_unlock(&session->lock); |
1494 | } | 1573 | } |
1495 | 1574 | ||
1496 | static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask, | 1575 | static void iscsi_prep_abort_task_pdu(struct iscsi_task *task, |
1497 | struct iscsi_tm *hdr) | 1576 | struct iscsi_tm *hdr) |
1498 | { | 1577 | { |
1499 | memset(hdr, 0, sizeof(*hdr)); | 1578 | memset(hdr, 0, sizeof(*hdr)); |
1500 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; | 1579 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; |
1501 | hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; | 1580 | hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; |
1502 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 1581 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
1503 | memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); | 1582 | memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun)); |
1504 | hdr->rtt = ctask->hdr->itt; | 1583 | hdr->rtt = task->hdr->itt; |
1505 | hdr->refcmdsn = ctask->hdr->cmdsn; | 1584 | hdr->refcmdsn = task->hdr->cmdsn; |
1506 | } | 1585 | } |
1507 | 1586 | ||
1508 | int iscsi_eh_abort(struct scsi_cmnd *sc) | 1587 | int iscsi_eh_abort(struct scsi_cmnd *sc) |
1509 | { | 1588 | { |
1510 | struct Scsi_Host *host = sc->device->host; | 1589 | struct iscsi_cls_session *cls_session; |
1511 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); | 1590 | struct iscsi_session *session; |
1512 | struct iscsi_conn *conn; | 1591 | struct iscsi_conn *conn; |
1513 | struct iscsi_cmd_task *ctask; | 1592 | struct iscsi_task *task; |
1514 | struct iscsi_tm *hdr; | 1593 | struct iscsi_tm *hdr; |
1515 | int rc, age; | 1594 | int rc, age; |
1516 | 1595 | ||
1596 | cls_session = starget_to_session(scsi_target(sc->device)); | ||
1597 | session = cls_session->dd_data; | ||
1598 | |||
1517 | mutex_lock(&session->eh_mutex); | 1599 | mutex_lock(&session->eh_mutex); |
1518 | spin_lock_bh(&session->lock); | 1600 | spin_lock_bh(&session->lock); |
1519 | /* | 1601 | /* |
@@ -1542,17 +1624,17 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1542 | conn->eh_abort_cnt++; | 1624 | conn->eh_abort_cnt++; |
1543 | age = session->age; | 1625 | age = session->age; |
1544 | 1626 | ||
1545 | ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; | 1627 | task = (struct iscsi_task *)sc->SCp.ptr; |
1546 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); | 1628 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, task->itt); |
1547 | 1629 | ||
1548 | /* ctask completed before time out */ | 1630 | /* task completed before time out */ |
1549 | if (!ctask->sc) { | 1631 | if (!task->sc) { |
1550 | debug_scsi("sc completed while abort in progress\n"); | 1632 | debug_scsi("sc completed while abort in progress\n"); |
1551 | goto success; | 1633 | goto success; |
1552 | } | 1634 | } |
1553 | 1635 | ||
1554 | if (ctask->state == ISCSI_TASK_PENDING) { | 1636 | if (task->state == ISCSI_TASK_PENDING) { |
1555 | fail_command(conn, ctask, DID_ABORT << 16); | 1637 | fail_command(conn, task, DID_ABORT << 16); |
1556 | goto success; | 1638 | goto success; |
1557 | } | 1639 | } |
1558 | 1640 | ||
@@ -1562,7 +1644,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1562 | conn->tmf_state = TMF_QUEUED; | 1644 | conn->tmf_state = TMF_QUEUED; |
1563 | 1645 | ||
1564 | hdr = &conn->tmhdr; | 1646 | hdr = &conn->tmhdr; |
1565 | iscsi_prep_abort_task_pdu(ctask, hdr); | 1647 | iscsi_prep_abort_task_pdu(task, hdr); |
1566 | 1648 | ||
1567 | if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) { | 1649 | if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) { |
1568 | rc = FAILED; | 1650 | rc = FAILED; |
@@ -1572,16 +1654,20 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1572 | switch (conn->tmf_state) { | 1654 | switch (conn->tmf_state) { |
1573 | case TMF_SUCCESS: | 1655 | case TMF_SUCCESS: |
1574 | spin_unlock_bh(&session->lock); | 1656 | spin_unlock_bh(&session->lock); |
1657 | /* | ||
1658 | * stop tx side incase the target had sent a abort rsp but | ||
1659 | * the initiator was still writing out data. | ||
1660 | */ | ||
1575 | iscsi_suspend_tx(conn); | 1661 | iscsi_suspend_tx(conn); |
1576 | /* | 1662 | /* |
1577 | * clean up task if aborted. grab the recv lock as a writer | 1663 | * we do not stop the recv side because targets have been |
1664 | * good and have never sent us a successful tmf response | ||
1665 | * then sent more data for the cmd. | ||
1578 | */ | 1666 | */ |
1579 | write_lock_bh(conn->recv_lock); | ||
1580 | spin_lock(&session->lock); | 1667 | spin_lock(&session->lock); |
1581 | fail_command(conn, ctask, DID_ABORT << 16); | 1668 | fail_command(conn, task, DID_ABORT << 16); |
1582 | conn->tmf_state = TMF_INITIAL; | 1669 | conn->tmf_state = TMF_INITIAL; |
1583 | spin_unlock(&session->lock); | 1670 | spin_unlock(&session->lock); |
1584 | write_unlock_bh(conn->recv_lock); | ||
1585 | iscsi_start_tx(conn); | 1671 | iscsi_start_tx(conn); |
1586 | goto success_unlocked; | 1672 | goto success_unlocked; |
1587 | case TMF_TIMEDOUT: | 1673 | case TMF_TIMEDOUT: |
@@ -1591,7 +1677,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1591 | case TMF_NOT_FOUND: | 1677 | case TMF_NOT_FOUND: |
1592 | if (!sc->SCp.ptr) { | 1678 | if (!sc->SCp.ptr) { |
1593 | conn->tmf_state = TMF_INITIAL; | 1679 | conn->tmf_state = TMF_INITIAL; |
1594 | /* ctask completed before tmf abort response */ | 1680 | /* task completed before tmf abort response */ |
1595 | debug_scsi("sc completed while abort in progress\n"); | 1681 | debug_scsi("sc completed while abort in progress\n"); |
1596 | goto success; | 1682 | goto success; |
1597 | } | 1683 | } |
@@ -1604,7 +1690,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1604 | success: | 1690 | success: |
1605 | spin_unlock_bh(&session->lock); | 1691 | spin_unlock_bh(&session->lock); |
1606 | success_unlocked: | 1692 | success_unlocked: |
1607 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | 1693 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, task->itt); |
1608 | mutex_unlock(&session->eh_mutex); | 1694 | mutex_unlock(&session->eh_mutex); |
1609 | return SUCCESS; | 1695 | return SUCCESS; |
1610 | 1696 | ||
@@ -1612,7 +1698,7 @@ failed: | |||
1612 | spin_unlock_bh(&session->lock); | 1698 | spin_unlock_bh(&session->lock); |
1613 | failed_unlocked: | 1699 | failed_unlocked: |
1614 | debug_scsi("abort failed [sc %p itt 0x%x]\n", sc, | 1700 | debug_scsi("abort failed [sc %p itt 0x%x]\n", sc, |
1615 | ctask ? ctask->itt : 0); | 1701 | task ? task->itt : 0); |
1616 | mutex_unlock(&session->eh_mutex); | 1702 | mutex_unlock(&session->eh_mutex); |
1617 | return FAILED; | 1703 | return FAILED; |
1618 | } | 1704 | } |
@@ -1630,12 +1716,15 @@ static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) | |||
1630 | 1716 | ||
1631 | int iscsi_eh_device_reset(struct scsi_cmnd *sc) | 1717 | int iscsi_eh_device_reset(struct scsi_cmnd *sc) |
1632 | { | 1718 | { |
1633 | struct Scsi_Host *host = sc->device->host; | 1719 | struct iscsi_cls_session *cls_session; |
1634 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); | 1720 | struct iscsi_session *session; |
1635 | struct iscsi_conn *conn; | 1721 | struct iscsi_conn *conn; |
1636 | struct iscsi_tm *hdr; | 1722 | struct iscsi_tm *hdr; |
1637 | int rc = FAILED; | 1723 | int rc = FAILED; |
1638 | 1724 | ||
1725 | cls_session = starget_to_session(scsi_target(sc->device)); | ||
1726 | session = cls_session->dd_data; | ||
1727 | |||
1639 | debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun); | 1728 | debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun); |
1640 | 1729 | ||
1641 | mutex_lock(&session->eh_mutex); | 1730 | mutex_lock(&session->eh_mutex); |
@@ -1678,13 +1767,11 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) | |||
1678 | spin_unlock_bh(&session->lock); | 1767 | spin_unlock_bh(&session->lock); |
1679 | 1768 | ||
1680 | iscsi_suspend_tx(conn); | 1769 | iscsi_suspend_tx(conn); |
1681 | /* need to grab the recv lock then session lock */ | 1770 | |
1682 | write_lock_bh(conn->recv_lock); | ||
1683 | spin_lock(&session->lock); | 1771 | spin_lock(&session->lock); |
1684 | fail_all_commands(conn, sc->device->lun, DID_ERROR); | 1772 | fail_all_commands(conn, sc->device->lun, DID_ERROR); |
1685 | conn->tmf_state = TMF_INITIAL; | 1773 | conn->tmf_state = TMF_INITIAL; |
1686 | spin_unlock(&session->lock); | 1774 | spin_unlock(&session->lock); |
1687 | write_unlock_bh(conn->recv_lock); | ||
1688 | 1775 | ||
1689 | iscsi_start_tx(conn); | 1776 | iscsi_start_tx(conn); |
1690 | goto done; | 1777 | goto done; |
@@ -1760,177 +1847,203 @@ void iscsi_pool_free(struct iscsi_pool *q) | |||
1760 | } | 1847 | } |
1761 | EXPORT_SYMBOL_GPL(iscsi_pool_free); | 1848 | EXPORT_SYMBOL_GPL(iscsi_pool_free); |
1762 | 1849 | ||
1763 | /* | 1850 | /** |
1764 | * iSCSI Session's hostdata organization: | 1851 | * iscsi_host_add - add host to system |
1852 | * @shost: scsi host | ||
1853 | * @pdev: parent device | ||
1854 | * | ||
1855 | * This should be called by partial offload and software iscsi drivers | ||
1856 | * to add a host to the system. | ||
1857 | */ | ||
1858 | int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev) | ||
1859 | { | ||
1860 | if (!shost->can_queue) | ||
1861 | shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX; | ||
1862 | |||
1863 | return scsi_add_host(shost, pdev); | ||
1864 | } | ||
1865 | EXPORT_SYMBOL_GPL(iscsi_host_add); | ||
1866 | |||
1867 | /** | ||
1868 | * iscsi_host_alloc - allocate a host and driver data | ||
1869 | * @sht: scsi host template | ||
1870 | * @dd_data_size: driver host data size | ||
1871 | * @qdepth: default device queue depth | ||
1872 | * | ||
1873 | * This should be called by partial offload and software iscsi drivers. | ||
1874 | * To access the driver specific memory use the iscsi_host_priv() macro. | ||
1875 | */ | ||
1876 | struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht, | ||
1877 | int dd_data_size, uint16_t qdepth) | ||
1878 | { | ||
1879 | struct Scsi_Host *shost; | ||
1880 | |||
1881 | shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size); | ||
1882 | if (!shost) | ||
1883 | return NULL; | ||
1884 | shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out; | ||
1885 | |||
1886 | if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) { | ||
1887 | if (qdepth != 0) | ||
1888 | printk(KERN_ERR "iscsi: invalid queue depth of %d. " | ||
1889 | "Queue depth must be between 1 and %d.\n", | ||
1890 | qdepth, ISCSI_MAX_CMD_PER_LUN); | ||
1891 | qdepth = ISCSI_DEF_CMD_PER_LUN; | ||
1892 | } | ||
1893 | shost->cmd_per_lun = qdepth; | ||
1894 | return shost; | ||
1895 | } | ||
1896 | EXPORT_SYMBOL_GPL(iscsi_host_alloc); | ||
1897 | |||
1898 | /** | ||
1899 | * iscsi_host_remove - remove host and sessions | ||
1900 | * @shost: scsi host | ||
1765 | * | 1901 | * |
1766 | * *------------------* <== hostdata_session(host->hostdata) | 1902 | * This will also remove any sessions attached to the host, but if userspace |
1767 | * | ptr to class sess| | 1903 | * is managing the session at the same time this will break. TODO: add |
1768 | * |------------------| <== iscsi_hostdata(host->hostdata) | 1904 | * refcounting to the netlink iscsi interface so a rmmod or host hot unplug |
1769 | * | iscsi_session | | 1905 | * does not remove the memory from under us. |
1770 | * *------------------* | ||
1771 | */ | 1906 | */ |
1907 | void iscsi_host_remove(struct Scsi_Host *shost) | ||
1908 | { | ||
1909 | iscsi_host_for_each_session(shost, iscsi_session_teardown); | ||
1910 | scsi_remove_host(shost); | ||
1911 | } | ||
1912 | EXPORT_SYMBOL_GPL(iscsi_host_remove); | ||
1772 | 1913 | ||
1773 | #define hostdata_privsize(_sz) (sizeof(unsigned long) + _sz + \ | 1914 | void iscsi_host_free(struct Scsi_Host *shost) |
1774 | _sz % sizeof(unsigned long)) | 1915 | { |
1916 | struct iscsi_host *ihost = shost_priv(shost); | ||
1775 | 1917 | ||
1776 | #define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata)) | 1918 | kfree(ihost->netdev); |
1919 | kfree(ihost->hwaddress); | ||
1920 | kfree(ihost->initiatorname); | ||
1921 | scsi_host_put(shost); | ||
1922 | } | ||
1923 | EXPORT_SYMBOL_GPL(iscsi_host_free); | ||
1777 | 1924 | ||
1778 | /** | 1925 | /** |
1779 | * iscsi_session_setup - create iscsi cls session and host and session | 1926 | * iscsi_session_setup - create iscsi cls session and host and session |
1780 | * @scsit: scsi transport template | ||
1781 | * @iscsit: iscsi transport template | 1927 | * @iscsit: iscsi transport template |
1782 | * @cmds_max: scsi host can queue | 1928 | * @shost: scsi host |
1783 | * @qdepth: scsi host cmds per lun | 1929 | * @cmds_max: session can queue |
1784 | * @cmd_task_size: LLD ctask private data size | 1930 | * @cmd_task_size: LLD task private data size |
1785 | * @mgmt_task_size: LLD mtask private data size | ||
1786 | * @initial_cmdsn: initial CmdSN | 1931 | * @initial_cmdsn: initial CmdSN |
1787 | * @hostno: host no allocated | ||
1788 | * | 1932 | * |
1789 | * This can be used by software iscsi_transports that allocate | 1933 | * This can be used by software iscsi_transports that allocate |
1790 | * a session per scsi host. | 1934 | * a session per scsi host. |
1791 | **/ | 1935 | * |
1936 | * Callers should set cmds_max to the largest total numer (mgmt + scsi) of | ||
1937 | * tasks they support. The iscsi layer reserves ISCSI_MGMT_CMDS_MAX tasks | ||
1938 | * for nop handling and login/logout requests. | ||
1939 | */ | ||
1792 | struct iscsi_cls_session * | 1940 | struct iscsi_cls_session * |
1793 | iscsi_session_setup(struct iscsi_transport *iscsit, | 1941 | iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, |
1794 | struct scsi_transport_template *scsit, | 1942 | uint16_t cmds_max, int cmd_task_size, |
1795 | uint16_t cmds_max, uint16_t qdepth, | 1943 | uint32_t initial_cmdsn, unsigned int id) |
1796 | int cmd_task_size, int mgmt_task_size, | ||
1797 | uint32_t initial_cmdsn, uint32_t *hostno) | ||
1798 | { | 1944 | { |
1799 | struct Scsi_Host *shost; | ||
1800 | struct iscsi_session *session; | 1945 | struct iscsi_session *session; |
1801 | struct iscsi_cls_session *cls_session; | 1946 | struct iscsi_cls_session *cls_session; |
1802 | int cmd_i; | 1947 | int cmd_i, scsi_cmds, total_cmds = cmds_max; |
1803 | 1948 | ||
1804 | if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) { | 1949 | if (!total_cmds) |
1805 | if (qdepth != 0) | 1950 | total_cmds = ISCSI_DEF_XMIT_CMDS_MAX; |
1806 | printk(KERN_ERR "iscsi: invalid queue depth of %d. " | 1951 | /* |
1807 | "Queue depth must be between 1 and %d.\n", | 1952 | * The iscsi layer needs some tasks for nop handling and tmfs, |
1808 | qdepth, ISCSI_MAX_CMD_PER_LUN); | 1953 | * so the cmds_max must at least be greater than ISCSI_MGMT_CMDS_MAX |
1809 | qdepth = ISCSI_DEF_CMD_PER_LUN; | 1954 | * + 1 command for scsi IO. |
1955 | */ | ||
1956 | if (total_cmds < ISCSI_TOTAL_CMDS_MIN) { | ||
1957 | printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue " | ||
1958 | "must be a power of two that is at least %d.\n", | ||
1959 | total_cmds, ISCSI_TOTAL_CMDS_MIN); | ||
1960 | return NULL; | ||
1810 | } | 1961 | } |
1811 | 1962 | ||
1812 | if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET || | 1963 | if (total_cmds > ISCSI_TOTAL_CMDS_MAX) { |
1813 | cmds_max < 2) { | 1964 | printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue " |
1814 | if (cmds_max != 0) | 1965 | "must be a power of 2 less than or equal to %d.\n", |
1815 | printk(KERN_ERR "iscsi: invalid can_queue of %d. " | 1966 | cmds_max, ISCSI_TOTAL_CMDS_MAX); |
1816 | "can_queue must be a power of 2 and between " | 1967 | total_cmds = ISCSI_TOTAL_CMDS_MAX; |
1817 | "2 and %d - setting to %d.\n", cmds_max, | ||
1818 | ISCSI_MGMT_ITT_OFFSET, ISCSI_DEF_XMIT_CMDS_MAX); | ||
1819 | cmds_max = ISCSI_DEF_XMIT_CMDS_MAX; | ||
1820 | } | 1968 | } |
1821 | 1969 | ||
1822 | shost = scsi_host_alloc(iscsit->host_template, | 1970 | if (!is_power_of_2(total_cmds)) { |
1823 | hostdata_privsize(sizeof(*session))); | 1971 | printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue " |
1824 | if (!shost) | 1972 | "must be a power of 2.\n", total_cmds); |
1825 | return NULL; | 1973 | total_cmds = rounddown_pow_of_two(total_cmds); |
1826 | 1974 | if (total_cmds < ISCSI_TOTAL_CMDS_MIN) | |
1827 | /* the iscsi layer takes one task for reserve */ | 1975 | return NULL; |
1828 | shost->can_queue = cmds_max - 1; | 1976 | printk(KERN_INFO "iscsi: Rounding can_queue to %d.\n", |
1829 | shost->cmd_per_lun = qdepth; | 1977 | total_cmds); |
1830 | shost->max_id = 1; | 1978 | } |
1831 | shost->max_channel = 0; | 1979 | scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX; |
1832 | shost->max_lun = iscsit->max_lun; | ||
1833 | shost->max_cmd_len = iscsit->max_cmd_len; | ||
1834 | shost->transportt = scsit; | ||
1835 | shost->transportt->create_work_queue = 1; | ||
1836 | shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out; | ||
1837 | *hostno = shost->host_no; | ||
1838 | 1980 | ||
1839 | session = iscsi_hostdata(shost->hostdata); | 1981 | cls_session = iscsi_alloc_session(shost, iscsit, |
1840 | memset(session, 0, sizeof(struct iscsi_session)); | 1982 | sizeof(struct iscsi_session)); |
1983 | if (!cls_session) | ||
1984 | return NULL; | ||
1985 | session = cls_session->dd_data; | ||
1986 | session->cls_session = cls_session; | ||
1841 | session->host = shost; | 1987 | session->host = shost; |
1842 | session->state = ISCSI_STATE_FREE; | 1988 | session->state = ISCSI_STATE_FREE; |
1843 | session->fast_abort = 1; | 1989 | session->fast_abort = 1; |
1844 | session->lu_reset_timeout = 15; | 1990 | session->lu_reset_timeout = 15; |
1845 | session->abort_timeout = 10; | 1991 | session->abort_timeout = 10; |
1846 | session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; | 1992 | session->scsi_cmds_max = scsi_cmds; |
1847 | session->cmds_max = cmds_max; | 1993 | session->cmds_max = total_cmds; |
1848 | session->queued_cmdsn = session->cmdsn = initial_cmdsn; | 1994 | session->queued_cmdsn = session->cmdsn = initial_cmdsn; |
1849 | session->exp_cmdsn = initial_cmdsn + 1; | 1995 | session->exp_cmdsn = initial_cmdsn + 1; |
1850 | session->max_cmdsn = initial_cmdsn + 1; | 1996 | session->max_cmdsn = initial_cmdsn + 1; |
1851 | session->max_r2t = 1; | 1997 | session->max_r2t = 1; |
1852 | session->tt = iscsit; | 1998 | session->tt = iscsit; |
1853 | mutex_init(&session->eh_mutex); | 1999 | mutex_init(&session->eh_mutex); |
2000 | spin_lock_init(&session->lock); | ||
1854 | 2001 | ||
1855 | /* initialize SCSI PDU commands pool */ | 2002 | /* initialize SCSI PDU commands pool */ |
1856 | if (iscsi_pool_init(&session->cmdpool, session->cmds_max, | 2003 | if (iscsi_pool_init(&session->cmdpool, session->cmds_max, |
1857 | (void***)&session->cmds, | 2004 | (void***)&session->cmds, |
1858 | cmd_task_size + sizeof(struct iscsi_cmd_task))) | 2005 | cmd_task_size + sizeof(struct iscsi_task))) |
1859 | goto cmdpool_alloc_fail; | 2006 | goto cmdpool_alloc_fail; |
1860 | 2007 | ||
1861 | /* pre-format cmds pool with ITT */ | 2008 | /* pre-format cmds pool with ITT */ |
1862 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { | 2009 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { |
1863 | struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; | 2010 | struct iscsi_task *task = session->cmds[cmd_i]; |
1864 | 2011 | ||
1865 | if (cmd_task_size) | 2012 | if (cmd_task_size) |
1866 | ctask->dd_data = &ctask[1]; | 2013 | task->dd_data = &task[1]; |
1867 | ctask->itt = cmd_i; | 2014 | task->itt = cmd_i; |
1868 | INIT_LIST_HEAD(&ctask->running); | 2015 | INIT_LIST_HEAD(&task->running); |
1869 | } | ||
1870 | |||
1871 | spin_lock_init(&session->lock); | ||
1872 | |||
1873 | /* initialize immediate command pool */ | ||
1874 | if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max, | ||
1875 | (void***)&session->mgmt_cmds, | ||
1876 | mgmt_task_size + sizeof(struct iscsi_mgmt_task))) | ||
1877 | goto mgmtpool_alloc_fail; | ||
1878 | |||
1879 | |||
1880 | /* pre-format immediate cmds pool with ITT */ | ||
1881 | for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { | ||
1882 | struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i]; | ||
1883 | |||
1884 | if (mgmt_task_size) | ||
1885 | mtask->dd_data = &mtask[1]; | ||
1886 | mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i; | ||
1887 | INIT_LIST_HEAD(&mtask->running); | ||
1888 | } | 2016 | } |
1889 | 2017 | ||
1890 | if (scsi_add_host(shost, NULL)) | ||
1891 | goto add_host_fail; | ||
1892 | |||
1893 | if (!try_module_get(iscsit->owner)) | 2018 | if (!try_module_get(iscsit->owner)) |
1894 | goto cls_session_fail; | 2019 | goto module_get_fail; |
1895 | |||
1896 | cls_session = iscsi_create_session(shost, iscsit, 0); | ||
1897 | if (!cls_session) | ||
1898 | goto module_put; | ||
1899 | *(unsigned long*)shost->hostdata = (unsigned long)cls_session; | ||
1900 | 2020 | ||
2021 | if (iscsi_add_session(cls_session, id)) | ||
2022 | goto cls_session_fail; | ||
1901 | return cls_session; | 2023 | return cls_session; |
1902 | 2024 | ||
1903 | module_put: | ||
1904 | module_put(iscsit->owner); | ||
1905 | cls_session_fail: | 2025 | cls_session_fail: |
1906 | scsi_remove_host(shost); | 2026 | module_put(iscsit->owner); |
1907 | add_host_fail: | 2027 | module_get_fail: |
1908 | iscsi_pool_free(&session->mgmtpool); | ||
1909 | mgmtpool_alloc_fail: | ||
1910 | iscsi_pool_free(&session->cmdpool); | 2028 | iscsi_pool_free(&session->cmdpool); |
1911 | cmdpool_alloc_fail: | 2029 | cmdpool_alloc_fail: |
1912 | scsi_host_put(shost); | 2030 | iscsi_free_session(cls_session); |
1913 | return NULL; | 2031 | return NULL; |
1914 | } | 2032 | } |
1915 | EXPORT_SYMBOL_GPL(iscsi_session_setup); | 2033 | EXPORT_SYMBOL_GPL(iscsi_session_setup); |
1916 | 2034 | ||
1917 | /** | 2035 | /** |
1918 | * iscsi_session_teardown - destroy session, host, and cls_session | 2036 | * iscsi_session_teardown - destroy session, host, and cls_session |
1919 | * shost: scsi host | 2037 | * @cls_session: iscsi session |
1920 | * | 2038 | * |
1921 | * This can be used by software iscsi_transports that allocate | 2039 | * The driver must have called iscsi_remove_session before |
1922 | * a session per scsi host. | 2040 | * calling this. |
1923 | **/ | 2041 | */ |
1924 | void iscsi_session_teardown(struct iscsi_cls_session *cls_session) | 2042 | void iscsi_session_teardown(struct iscsi_cls_session *cls_session) |
1925 | { | 2043 | { |
1926 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); | 2044 | struct iscsi_session *session = cls_session->dd_data; |
1927 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | ||
1928 | struct module *owner = cls_session->transport->owner; | 2045 | struct module *owner = cls_session->transport->owner; |
1929 | 2046 | ||
1930 | iscsi_remove_session(cls_session); | ||
1931 | scsi_remove_host(shost); | ||
1932 | |||
1933 | iscsi_pool_free(&session->mgmtpool); | ||
1934 | iscsi_pool_free(&session->cmdpool); | 2047 | iscsi_pool_free(&session->cmdpool); |
1935 | 2048 | ||
1936 | kfree(session->password); | 2049 | kfree(session->password); |
@@ -1938,12 +2051,10 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) | |||
1938 | kfree(session->username); | 2051 | kfree(session->username); |
1939 | kfree(session->username_in); | 2052 | kfree(session->username_in); |
1940 | kfree(session->targetname); | 2053 | kfree(session->targetname); |
1941 | kfree(session->netdev); | ||
1942 | kfree(session->hwaddress); | ||
1943 | kfree(session->initiatorname); | 2054 | kfree(session->initiatorname); |
2055 | kfree(session->ifacename); | ||
1944 | 2056 | ||
1945 | iscsi_free_session(cls_session); | 2057 | iscsi_destroy_session(cls_session); |
1946 | scsi_host_put(shost); | ||
1947 | module_put(owner); | 2058 | module_put(owner); |
1948 | } | 2059 | } |
1949 | EXPORT_SYMBOL_GPL(iscsi_session_teardown); | 2060 | EXPORT_SYMBOL_GPL(iscsi_session_teardown); |
@@ -1951,22 +2062,26 @@ EXPORT_SYMBOL_GPL(iscsi_session_teardown); | |||
1951 | /** | 2062 | /** |
1952 | * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn | 2063 | * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn |
1953 | * @cls_session: iscsi_cls_session | 2064 | * @cls_session: iscsi_cls_session |
2065 | * @dd_size: private driver data size | ||
1954 | * @conn_idx: cid | 2066 | * @conn_idx: cid |
1955 | **/ | 2067 | */ |
1956 | struct iscsi_cls_conn * | 2068 | struct iscsi_cls_conn * |
1957 | iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | 2069 | iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size, |
2070 | uint32_t conn_idx) | ||
1958 | { | 2071 | { |
1959 | struct iscsi_session *session = class_to_transport_session(cls_session); | 2072 | struct iscsi_session *session = cls_session->dd_data; |
1960 | struct iscsi_conn *conn; | 2073 | struct iscsi_conn *conn; |
1961 | struct iscsi_cls_conn *cls_conn; | 2074 | struct iscsi_cls_conn *cls_conn; |
1962 | char *data; | 2075 | char *data; |
1963 | 2076 | ||
1964 | cls_conn = iscsi_create_conn(cls_session, conn_idx); | 2077 | cls_conn = iscsi_create_conn(cls_session, sizeof(*conn) + dd_size, |
2078 | conn_idx); | ||
1965 | if (!cls_conn) | 2079 | if (!cls_conn) |
1966 | return NULL; | 2080 | return NULL; |
1967 | conn = cls_conn->dd_data; | 2081 | conn = cls_conn->dd_data; |
1968 | memset(conn, 0, sizeof(*conn)); | 2082 | memset(conn, 0, sizeof(*conn) + dd_size); |
1969 | 2083 | ||
2084 | conn->dd_data = cls_conn->dd_data + sizeof(*conn); | ||
1970 | conn->session = session; | 2085 | conn->session = session; |
1971 | conn->cls_conn = cls_conn; | 2086 | conn->cls_conn = cls_conn; |
1972 | conn->c_stage = ISCSI_CONN_INITIAL_STAGE; | 2087 | conn->c_stage = ISCSI_CONN_INITIAL_STAGE; |
@@ -1985,30 +2100,30 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1985 | INIT_LIST_HEAD(&conn->requeue); | 2100 | INIT_LIST_HEAD(&conn->requeue); |
1986 | INIT_WORK(&conn->xmitwork, iscsi_xmitworker); | 2101 | INIT_WORK(&conn->xmitwork, iscsi_xmitworker); |
1987 | 2102 | ||
1988 | /* allocate login_mtask used for the login/text sequences */ | 2103 | /* allocate login_task used for the login/text sequences */ |
1989 | spin_lock_bh(&session->lock); | 2104 | spin_lock_bh(&session->lock); |
1990 | if (!__kfifo_get(session->mgmtpool.queue, | 2105 | if (!__kfifo_get(session->cmdpool.queue, |
1991 | (void*)&conn->login_mtask, | 2106 | (void*)&conn->login_task, |
1992 | sizeof(void*))) { | 2107 | sizeof(void*))) { |
1993 | spin_unlock_bh(&session->lock); | 2108 | spin_unlock_bh(&session->lock); |
1994 | goto login_mtask_alloc_fail; | 2109 | goto login_task_alloc_fail; |
1995 | } | 2110 | } |
1996 | spin_unlock_bh(&session->lock); | 2111 | spin_unlock_bh(&session->lock); |
1997 | 2112 | ||
1998 | data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL); | 2113 | data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL); |
1999 | if (!data) | 2114 | if (!data) |
2000 | goto login_mtask_data_alloc_fail; | 2115 | goto login_task_data_alloc_fail; |
2001 | conn->login_mtask->data = conn->data = data; | 2116 | conn->login_task->data = conn->data = data; |
2002 | 2117 | ||
2003 | init_timer(&conn->tmf_timer); | 2118 | init_timer(&conn->tmf_timer); |
2004 | init_waitqueue_head(&conn->ehwait); | 2119 | init_waitqueue_head(&conn->ehwait); |
2005 | 2120 | ||
2006 | return cls_conn; | 2121 | return cls_conn; |
2007 | 2122 | ||
2008 | login_mtask_data_alloc_fail: | 2123 | login_task_data_alloc_fail: |
2009 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, | 2124 | __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task, |
2010 | sizeof(void*)); | 2125 | sizeof(void*)); |
2011 | login_mtask_alloc_fail: | 2126 | login_task_alloc_fail: |
2012 | iscsi_destroy_conn(cls_conn); | 2127 | iscsi_destroy_conn(cls_conn); |
2013 | return NULL; | 2128 | return NULL; |
2014 | } | 2129 | } |
@@ -2068,7 +2183,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
2068 | spin_lock_bh(&session->lock); | 2183 | spin_lock_bh(&session->lock); |
2069 | kfree(conn->data); | 2184 | kfree(conn->data); |
2070 | kfree(conn->persistent_address); | 2185 | kfree(conn->persistent_address); |
2071 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, | 2186 | __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task, |
2072 | sizeof(void*)); | 2187 | sizeof(void*)); |
2073 | if (session->leadconn == conn) | 2188 | if (session->leadconn == conn) |
2074 | session->leadconn = NULL; | 2189 | session->leadconn = NULL; |
@@ -2140,7 +2255,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) | |||
2140 | } | 2255 | } |
2141 | spin_unlock_bh(&session->lock); | 2256 | spin_unlock_bh(&session->lock); |
2142 | 2257 | ||
2143 | iscsi_unblock_session(session_to_cls(session)); | 2258 | iscsi_unblock_session(session->cls_session); |
2144 | wake_up(&conn->ehwait); | 2259 | wake_up(&conn->ehwait); |
2145 | return 0; | 2260 | return 0; |
2146 | } | 2261 | } |
@@ -2149,21 +2264,23 @@ EXPORT_SYMBOL_GPL(iscsi_conn_start); | |||
2149 | static void | 2264 | static void |
2150 | flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) | 2265 | flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) |
2151 | { | 2266 | { |
2152 | struct iscsi_mgmt_task *mtask, *tmp; | 2267 | struct iscsi_task *task, *tmp; |
2153 | 2268 | ||
2154 | /* handle pending */ | 2269 | /* handle pending */ |
2155 | list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) { | 2270 | list_for_each_entry_safe(task, tmp, &conn->mgmtqueue, running) { |
2156 | debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); | 2271 | debug_scsi("flushing pending mgmt task itt 0x%x\n", task->itt); |
2157 | iscsi_free_mgmt_task(conn, mtask); | 2272 | /* release ref from prep task */ |
2273 | __iscsi_put_task(task); | ||
2158 | } | 2274 | } |
2159 | 2275 | ||
2160 | /* handle running */ | 2276 | /* handle running */ |
2161 | list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { | 2277 | list_for_each_entry_safe(task, tmp, &conn->mgmt_run_list, running) { |
2162 | debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); | 2278 | debug_scsi("flushing running mgmt task itt 0x%x\n", task->itt); |
2163 | iscsi_free_mgmt_task(conn, mtask); | 2279 | /* release ref from prep task */ |
2280 | __iscsi_put_task(task); | ||
2164 | } | 2281 | } |
2165 | 2282 | ||
2166 | conn->mtask = NULL; | 2283 | conn->task = NULL; |
2167 | } | 2284 | } |
2168 | 2285 | ||
2169 | static void iscsi_start_session_recovery(struct iscsi_session *session, | 2286 | static void iscsi_start_session_recovery(struct iscsi_session *session, |
@@ -2182,17 +2299,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
2182 | } | 2299 | } |
2183 | 2300 | ||
2184 | /* | 2301 | /* |
2185 | * The LLD either freed/unset the lock on us, or userspace called | ||
2186 | * stop but did not create a proper connection (connection was never | ||
2187 | * bound or it was unbound then stop was called). | ||
2188 | */ | ||
2189 | if (!conn->recv_lock) { | ||
2190 | spin_unlock_bh(&session->lock); | ||
2191 | mutex_unlock(&session->eh_mutex); | ||
2192 | return; | ||
2193 | } | ||
2194 | |||
2195 | /* | ||
2196 | * When this is called for the in_login state, we only want to clean | 2302 | * When this is called for the in_login state, we only want to clean |
2197 | * up the login task and connection. We do not need to block and set | 2303 | * up the login task and connection. We do not need to block and set |
2198 | * the recovery state again | 2304 | * the recovery state again |
@@ -2208,11 +2314,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
2208 | spin_unlock_bh(&session->lock); | 2314 | spin_unlock_bh(&session->lock); |
2209 | 2315 | ||
2210 | iscsi_suspend_tx(conn); | 2316 | iscsi_suspend_tx(conn); |
2211 | |||
2212 | write_lock_bh(conn->recv_lock); | ||
2213 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); | ||
2214 | write_unlock_bh(conn->recv_lock); | ||
2215 | |||
2216 | /* | 2317 | /* |
2217 | * for connection level recovery we should not calculate | 2318 | * for connection level recovery we should not calculate |
2218 | * header digest. conn->hdr_size used for optimization | 2319 | * header digest. conn->hdr_size used for optimization |
@@ -2225,7 +2326,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
2225 | if (session->state == ISCSI_STATE_IN_RECOVERY && | 2326 | if (session->state == ISCSI_STATE_IN_RECOVERY && |
2226 | old_stop_stage != STOP_CONN_RECOVER) { | 2327 | old_stop_stage != STOP_CONN_RECOVER) { |
2227 | debug_scsi("blocking session\n"); | 2328 | debug_scsi("blocking session\n"); |
2228 | iscsi_block_session(session_to_cls(session)); | 2329 | iscsi_block_session(session->cls_session); |
2229 | } | 2330 | } |
2230 | } | 2331 | } |
2231 | 2332 | ||
@@ -2260,7 +2361,7 @@ EXPORT_SYMBOL_GPL(iscsi_conn_stop); | |||
2260 | int iscsi_conn_bind(struct iscsi_cls_session *cls_session, | 2361 | int iscsi_conn_bind(struct iscsi_cls_session *cls_session, |
2261 | struct iscsi_cls_conn *cls_conn, int is_leading) | 2362 | struct iscsi_cls_conn *cls_conn, int is_leading) |
2262 | { | 2363 | { |
2263 | struct iscsi_session *session = class_to_transport_session(cls_session); | 2364 | struct iscsi_session *session = cls_session->dd_data; |
2264 | struct iscsi_conn *conn = cls_conn->dd_data; | 2365 | struct iscsi_conn *conn = cls_conn->dd_data; |
2265 | 2366 | ||
2266 | spin_lock_bh(&session->lock); | 2367 | spin_lock_bh(&session->lock); |
@@ -2399,6 +2500,14 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, | |||
2399 | if (!conn->persistent_address) | 2500 | if (!conn->persistent_address) |
2400 | return -ENOMEM; | 2501 | return -ENOMEM; |
2401 | break; | 2502 | break; |
2503 | case ISCSI_PARAM_IFACE_NAME: | ||
2504 | if (!session->ifacename) | ||
2505 | session->ifacename = kstrdup(buf, GFP_KERNEL); | ||
2506 | break; | ||
2507 | case ISCSI_PARAM_INITIATOR_NAME: | ||
2508 | if (!session->initiatorname) | ||
2509 | session->initiatorname = kstrdup(buf, GFP_KERNEL); | ||
2510 | break; | ||
2402 | default: | 2511 | default: |
2403 | return -ENOSYS; | 2512 | return -ENOSYS; |
2404 | } | 2513 | } |
@@ -2410,8 +2519,7 @@ EXPORT_SYMBOL_GPL(iscsi_set_param); | |||
2410 | int iscsi_session_get_param(struct iscsi_cls_session *cls_session, | 2519 | int iscsi_session_get_param(struct iscsi_cls_session *cls_session, |
2411 | enum iscsi_param param, char *buf) | 2520 | enum iscsi_param param, char *buf) |
2412 | { | 2521 | { |
2413 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); | 2522 | struct iscsi_session *session = cls_session->dd_data; |
2414 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | ||
2415 | int len; | 2523 | int len; |
2416 | 2524 | ||
2417 | switch(param) { | 2525 | switch(param) { |
@@ -2466,6 +2574,15 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, | |||
2466 | case ISCSI_PARAM_PASSWORD_IN: | 2574 | case ISCSI_PARAM_PASSWORD_IN: |
2467 | len = sprintf(buf, "%s\n", session->password_in); | 2575 | len = sprintf(buf, "%s\n", session->password_in); |
2468 | break; | 2576 | break; |
2577 | case ISCSI_PARAM_IFACE_NAME: | ||
2578 | len = sprintf(buf, "%s\n", session->ifacename); | ||
2579 | break; | ||
2580 | case ISCSI_PARAM_INITIATOR_NAME: | ||
2581 | if (!session->initiatorname) | ||
2582 | len = sprintf(buf, "%s\n", "unknown"); | ||
2583 | else | ||
2584 | len = sprintf(buf, "%s\n", session->initiatorname); | ||
2585 | break; | ||
2469 | default: | 2586 | default: |
2470 | return -ENOSYS; | 2587 | return -ENOSYS; |
2471 | } | 2588 | } |
@@ -2525,29 +2642,35 @@ EXPORT_SYMBOL_GPL(iscsi_conn_get_param); | |||
2525 | int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, | 2642 | int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, |
2526 | char *buf) | 2643 | char *buf) |
2527 | { | 2644 | { |
2528 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | 2645 | struct iscsi_host *ihost = shost_priv(shost); |
2529 | int len; | 2646 | int len; |
2530 | 2647 | ||
2531 | switch (param) { | 2648 | switch (param) { |
2532 | case ISCSI_HOST_PARAM_NETDEV_NAME: | 2649 | case ISCSI_HOST_PARAM_NETDEV_NAME: |
2533 | if (!session->netdev) | 2650 | if (!ihost->netdev) |
2534 | len = sprintf(buf, "%s\n", "default"); | 2651 | len = sprintf(buf, "%s\n", "default"); |
2535 | else | 2652 | else |
2536 | len = sprintf(buf, "%s\n", session->netdev); | 2653 | len = sprintf(buf, "%s\n", ihost->netdev); |
2537 | break; | 2654 | break; |
2538 | case ISCSI_HOST_PARAM_HWADDRESS: | 2655 | case ISCSI_HOST_PARAM_HWADDRESS: |
2539 | if (!session->hwaddress) | 2656 | if (!ihost->hwaddress) |
2540 | len = sprintf(buf, "%s\n", "default"); | 2657 | len = sprintf(buf, "%s\n", "default"); |
2541 | else | 2658 | else |
2542 | len = sprintf(buf, "%s\n", session->hwaddress); | 2659 | len = sprintf(buf, "%s\n", ihost->hwaddress); |
2543 | break; | 2660 | break; |
2544 | case ISCSI_HOST_PARAM_INITIATOR_NAME: | 2661 | case ISCSI_HOST_PARAM_INITIATOR_NAME: |
2545 | if (!session->initiatorname) | 2662 | if (!ihost->initiatorname) |
2546 | len = sprintf(buf, "%s\n", "unknown"); | 2663 | len = sprintf(buf, "%s\n", "unknown"); |
2547 | else | 2664 | else |
2548 | len = sprintf(buf, "%s\n", session->initiatorname); | 2665 | len = sprintf(buf, "%s\n", ihost->initiatorname); |
2666 | break; | ||
2667 | case ISCSI_HOST_PARAM_IPADDRESS: | ||
2668 | if (!strlen(ihost->local_address)) | ||
2669 | len = sprintf(buf, "%s\n", "unknown"); | ||
2670 | else | ||
2671 | len = sprintf(buf, "%s\n", | ||
2672 | ihost->local_address); | ||
2549 | break; | 2673 | break; |
2550 | |||
2551 | default: | 2674 | default: |
2552 | return -ENOSYS; | 2675 | return -ENOSYS; |
2553 | } | 2676 | } |
@@ -2559,20 +2682,20 @@ EXPORT_SYMBOL_GPL(iscsi_host_get_param); | |||
2559 | int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param, | 2682 | int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param, |
2560 | char *buf, int buflen) | 2683 | char *buf, int buflen) |
2561 | { | 2684 | { |
2562 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | 2685 | struct iscsi_host *ihost = shost_priv(shost); |
2563 | 2686 | ||
2564 | switch (param) { | 2687 | switch (param) { |
2565 | case ISCSI_HOST_PARAM_NETDEV_NAME: | 2688 | case ISCSI_HOST_PARAM_NETDEV_NAME: |
2566 | if (!session->netdev) | 2689 | if (!ihost->netdev) |
2567 | session->netdev = kstrdup(buf, GFP_KERNEL); | 2690 | ihost->netdev = kstrdup(buf, GFP_KERNEL); |
2568 | break; | 2691 | break; |
2569 | case ISCSI_HOST_PARAM_HWADDRESS: | 2692 | case ISCSI_HOST_PARAM_HWADDRESS: |
2570 | if (!session->hwaddress) | 2693 | if (!ihost->hwaddress) |
2571 | session->hwaddress = kstrdup(buf, GFP_KERNEL); | 2694 | ihost->hwaddress = kstrdup(buf, GFP_KERNEL); |
2572 | break; | 2695 | break; |
2573 | case ISCSI_HOST_PARAM_INITIATOR_NAME: | 2696 | case ISCSI_HOST_PARAM_INITIATOR_NAME: |
2574 | if (!session->initiatorname) | 2697 | if (!ihost->initiatorname) |
2575 | session->initiatorname = kstrdup(buf, GFP_KERNEL); | 2698 | ihost->initiatorname = kstrdup(buf, GFP_KERNEL); |
2576 | break; | 2699 | break; |
2577 | default: | 2700 | default: |
2578 | return -ENOSYS; | 2701 | return -ENOSYS; |
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index ec0b0f6e5e1a..e0e018d12653 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -33,6 +33,7 @@ struct lpfc_sli2_slim; | |||
33 | #define LPFC_MAX_SG_SEG_CNT 256 /* sg element count per scsi cmnd */ | 33 | #define LPFC_MAX_SG_SEG_CNT 256 /* sg element count per scsi cmnd */ |
34 | #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ | 34 | #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ |
35 | #define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ | 35 | #define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ |
36 | #define LPFC_VNAME_LEN 100 /* vport symbolic name length */ | ||
36 | 37 | ||
37 | /* | 38 | /* |
38 | * Following time intervals are used of adjusting SCSI device | 39 | * Following time intervals are used of adjusting SCSI device |
@@ -59,6 +60,9 @@ struct lpfc_sli2_slim; | |||
59 | 60 | ||
60 | #define MAX_HBAEVT 32 | 61 | #define MAX_HBAEVT 32 |
61 | 62 | ||
63 | /* lpfc wait event data ready flag */ | ||
64 | #define LPFC_DATA_READY (1<<0) | ||
65 | |||
62 | enum lpfc_polling_flags { | 66 | enum lpfc_polling_flags { |
63 | ENABLE_FCP_RING_POLLING = 0x1, | 67 | ENABLE_FCP_RING_POLLING = 0x1, |
64 | DISABLE_FCP_RING_INT = 0x2 | 68 | DISABLE_FCP_RING_INT = 0x2 |
@@ -425,9 +429,6 @@ struct lpfc_hba { | |||
425 | 429 | ||
426 | uint16_t pci_cfg_value; | 430 | uint16_t pci_cfg_value; |
427 | 431 | ||
428 | uint8_t work_found; | ||
429 | #define LPFC_MAX_WORKER_ITERATION 4 | ||
430 | |||
431 | uint8_t fc_linkspeed; /* Link speed after last READ_LA */ | 432 | uint8_t fc_linkspeed; /* Link speed after last READ_LA */ |
432 | 433 | ||
433 | uint32_t fc_eventTag; /* event tag for link attention */ | 434 | uint32_t fc_eventTag; /* event tag for link attention */ |
@@ -489,8 +490,9 @@ struct lpfc_hba { | |||
489 | uint32_t work_hs; /* HS stored in case of ERRAT */ | 490 | uint32_t work_hs; /* HS stored in case of ERRAT */ |
490 | uint32_t work_status[2]; /* Extra status from SLIM */ | 491 | uint32_t work_status[2]; /* Extra status from SLIM */ |
491 | 492 | ||
492 | wait_queue_head_t *work_wait; | 493 | wait_queue_head_t work_waitq; |
493 | struct task_struct *worker_thread; | 494 | struct task_struct *worker_thread; |
495 | long data_flags; | ||
494 | 496 | ||
495 | uint32_t hbq_in_use; /* HBQs in use flag */ | 497 | uint32_t hbq_in_use; /* HBQs in use flag */ |
496 | struct list_head hbqbuf_in_list; /* in-fly hbq buffer list */ | 498 | struct list_head hbqbuf_in_list; /* in-fly hbq buffer list */ |
@@ -637,6 +639,17 @@ lpfc_is_link_up(struct lpfc_hba *phba) | |||
637 | phba->link_state == LPFC_HBA_READY; | 639 | phba->link_state == LPFC_HBA_READY; |
638 | } | 640 | } |
639 | 641 | ||
642 | static inline void | ||
643 | lpfc_worker_wake_up(struct lpfc_hba *phba) | ||
644 | { | ||
645 | /* Set the lpfc data pending flag */ | ||
646 | set_bit(LPFC_DATA_READY, &phba->data_flags); | ||
647 | |||
648 | /* Wake up worker thread */ | ||
649 | wake_up(&phba->work_waitq); | ||
650 | return; | ||
651 | } | ||
652 | |||
640 | #define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */ | 653 | #define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */ |
641 | #define FC_REG_TEMPERATURE_EVENT 0x20 /* Register for temperature | 654 | #define FC_REG_TEMPERATURE_EVENT 0x20 /* Register for temperature |
642 | event */ | 655 | event */ |
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 960baaf11fb1..37bfa0bd1dae 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -1995,8 +1995,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, | |||
1995 | /* Don't allow mailbox commands to be sent when blocked | 1995 | /* Don't allow mailbox commands to be sent when blocked |
1996 | * or when in the middle of discovery | 1996 | * or when in the middle of discovery |
1997 | */ | 1997 | */ |
1998 | if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO || | 1998 | if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { |
1999 | vport->fc_flag & FC_NDISC_ACTIVE) { | ||
2000 | sysfs_mbox_idle(phba); | 1999 | sysfs_mbox_idle(phba); |
2001 | spin_unlock_irq(&phba->hbalock); | 2000 | spin_unlock_irq(&phba->hbalock); |
2002 | return -EAGAIN; | 2001 | return -EAGAIN; |
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 7c9f8317d972..1b8245213b83 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -142,7 +142,7 @@ int lpfc_config_port_post(struct lpfc_hba *); | |||
142 | int lpfc_hba_down_prep(struct lpfc_hba *); | 142 | int lpfc_hba_down_prep(struct lpfc_hba *); |
143 | int lpfc_hba_down_post(struct lpfc_hba *); | 143 | int lpfc_hba_down_post(struct lpfc_hba *); |
144 | void lpfc_hba_init(struct lpfc_hba *, uint32_t *); | 144 | void lpfc_hba_init(struct lpfc_hba *, uint32_t *); |
145 | int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int); | 145 | int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int); |
146 | void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int); | 146 | void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int); |
147 | int lpfc_online(struct lpfc_hba *); | 147 | int lpfc_online(struct lpfc_hba *); |
148 | void lpfc_unblock_mgmt_io(struct lpfc_hba *); | 148 | void lpfc_unblock_mgmt_io(struct lpfc_hba *); |
@@ -263,6 +263,7 @@ extern int lpfc_sli_mode; | |||
263 | extern int lpfc_enable_npiv; | 263 | extern int lpfc_enable_npiv; |
264 | 264 | ||
265 | int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); | 265 | int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); |
266 | int lpfc_vport_symbolic_port_name(struct lpfc_vport *, char *, size_t); | ||
266 | void lpfc_terminate_rport_io(struct fc_rport *); | 267 | void lpfc_terminate_rport_io(struct fc_rport *); |
267 | void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport); | 268 | void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport); |
268 | 269 | ||
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 153afae567b5..7fc74cf5823b 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c | |||
@@ -101,7 +101,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
101 | /* Not enough posted buffers; Try posting more buffers */ | 101 | /* Not enough posted buffers; Try posting more buffers */ |
102 | phba->fc_stat.NoRcvBuf++; | 102 | phba->fc_stat.NoRcvBuf++; |
103 | if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) | 103 | if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) |
104 | lpfc_post_buffer(phba, pring, 2, 1); | 104 | lpfc_post_buffer(phba, pring, 2); |
105 | return; | 105 | return; |
106 | } | 106 | } |
107 | 107 | ||
@@ -151,7 +151,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
151 | } | 151 | } |
152 | list_del(&iocbq->list); | 152 | list_del(&iocbq->list); |
153 | lpfc_sli_release_iocbq(phba, iocbq); | 153 | lpfc_sli_release_iocbq(phba, iocbq); |
154 | lpfc_post_buffer(phba, pring, i, 1); | 154 | lpfc_post_buffer(phba, pring, i); |
155 | } | 155 | } |
156 | } | 156 | } |
157 | } | 157 | } |
@@ -990,7 +990,7 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
990 | return; | 990 | return; |
991 | } | 991 | } |
992 | 992 | ||
993 | static int | 993 | int |
994 | lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol, | 994 | lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol, |
995 | size_t size) | 995 | size_t size) |
996 | { | 996 | { |
@@ -1679,20 +1679,18 @@ lpfc_fdmi_tmo(unsigned long ptr) | |||
1679 | { | 1679 | { |
1680 | struct lpfc_vport *vport = (struct lpfc_vport *)ptr; | 1680 | struct lpfc_vport *vport = (struct lpfc_vport *)ptr; |
1681 | struct lpfc_hba *phba = vport->phba; | 1681 | struct lpfc_hba *phba = vport->phba; |
1682 | uint32_t tmo_posted; | ||
1682 | unsigned long iflag; | 1683 | unsigned long iflag; |
1683 | 1684 | ||
1684 | spin_lock_irqsave(&vport->work_port_lock, iflag); | 1685 | spin_lock_irqsave(&vport->work_port_lock, iflag); |
1685 | if (!(vport->work_port_events & WORKER_FDMI_TMO)) { | 1686 | tmo_posted = vport->work_port_events & WORKER_FDMI_TMO; |
1687 | if (!tmo_posted) | ||
1686 | vport->work_port_events |= WORKER_FDMI_TMO; | 1688 | vport->work_port_events |= WORKER_FDMI_TMO; |
1687 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); | 1689 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); |
1688 | 1690 | ||
1689 | spin_lock_irqsave(&phba->hbalock, iflag); | 1691 | if (!tmo_posted) |
1690 | if (phba->work_wait) | 1692 | lpfc_worker_wake_up(phba); |
1691 | lpfc_worker_wake_up(phba); | 1693 | return; |
1692 | spin_unlock_irqrestore(&phba->hbalock, iflag); | ||
1693 | } | ||
1694 | else | ||
1695 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); | ||
1696 | } | 1694 | } |
1697 | 1695 | ||
1698 | void | 1696 | void |
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 886c5f1b11d2..f54e0f7eaee3 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -1754,29 +1754,34 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) | |||
1754 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 1754 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
1755 | struct lpfc_work_evt *evtp; | 1755 | struct lpfc_work_evt *evtp; |
1756 | 1756 | ||
1757 | if (!(nlp->nlp_flag & NLP_DELAY_TMO)) | ||
1758 | return; | ||
1757 | spin_lock_irq(shost->host_lock); | 1759 | spin_lock_irq(shost->host_lock); |
1758 | nlp->nlp_flag &= ~NLP_DELAY_TMO; | 1760 | nlp->nlp_flag &= ~NLP_DELAY_TMO; |
1759 | spin_unlock_irq(shost->host_lock); | 1761 | spin_unlock_irq(shost->host_lock); |
1760 | del_timer_sync(&nlp->nlp_delayfunc); | 1762 | del_timer_sync(&nlp->nlp_delayfunc); |
1761 | nlp->nlp_last_elscmd = 0; | 1763 | nlp->nlp_last_elscmd = 0; |
1762 | |||
1763 | if (!list_empty(&nlp->els_retry_evt.evt_listp)) { | 1764 | if (!list_empty(&nlp->els_retry_evt.evt_listp)) { |
1764 | list_del_init(&nlp->els_retry_evt.evt_listp); | 1765 | list_del_init(&nlp->els_retry_evt.evt_listp); |
1765 | /* Decrement nlp reference count held for the delayed retry */ | 1766 | /* Decrement nlp reference count held for the delayed retry */ |
1766 | evtp = &nlp->els_retry_evt; | 1767 | evtp = &nlp->els_retry_evt; |
1767 | lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); | 1768 | lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); |
1768 | } | 1769 | } |
1769 | |||
1770 | if (nlp->nlp_flag & NLP_NPR_2B_DISC) { | 1770 | if (nlp->nlp_flag & NLP_NPR_2B_DISC) { |
1771 | spin_lock_irq(shost->host_lock); | 1771 | spin_lock_irq(shost->host_lock); |
1772 | nlp->nlp_flag &= ~NLP_NPR_2B_DISC; | 1772 | nlp->nlp_flag &= ~NLP_NPR_2B_DISC; |
1773 | spin_unlock_irq(shost->host_lock); | 1773 | spin_unlock_irq(shost->host_lock); |
1774 | if (vport->num_disc_nodes) { | 1774 | if (vport->num_disc_nodes) { |
1775 | /* Check to see if there are more | 1775 | if (vport->port_state < LPFC_VPORT_READY) { |
1776 | * PLOGIs to be sent | 1776 | /* Check if there are more ADISCs to be sent */ |
1777 | */ | 1777 | lpfc_more_adisc(vport); |
1778 | lpfc_more_plogi(vport); | 1778 | if ((vport->num_disc_nodes == 0) && |
1779 | 1779 | (vport->fc_npr_cnt)) | |
1780 | lpfc_els_disc_plogi(vport); | ||
1781 | } else { | ||
1782 | /* Check if there are more PLOGIs to be sent */ | ||
1783 | lpfc_more_plogi(vport); | ||
1784 | } | ||
1780 | if (vport->num_disc_nodes == 0) { | 1785 | if (vport->num_disc_nodes == 0) { |
1781 | spin_lock_irq(shost->host_lock); | 1786 | spin_lock_irq(shost->host_lock); |
1782 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | 1787 | vport->fc_flag &= ~FC_NDISC_ACTIVE; |
@@ -1798,10 +1803,6 @@ lpfc_els_retry_delay(unsigned long ptr) | |||
1798 | unsigned long flags; | 1803 | unsigned long flags; |
1799 | struct lpfc_work_evt *evtp = &ndlp->els_retry_evt; | 1804 | struct lpfc_work_evt *evtp = &ndlp->els_retry_evt; |
1800 | 1805 | ||
1801 | ndlp = (struct lpfc_nodelist *) ptr; | ||
1802 | phba = ndlp->vport->phba; | ||
1803 | evtp = &ndlp->els_retry_evt; | ||
1804 | |||
1805 | spin_lock_irqsave(&phba->hbalock, flags); | 1806 | spin_lock_irqsave(&phba->hbalock, flags); |
1806 | if (!list_empty(&evtp->evt_listp)) { | 1807 | if (!list_empty(&evtp->evt_listp)) { |
1807 | spin_unlock_irqrestore(&phba->hbalock, flags); | 1808 | spin_unlock_irqrestore(&phba->hbalock, flags); |
@@ -1812,11 +1813,11 @@ lpfc_els_retry_delay(unsigned long ptr) | |||
1812 | * count until the queued work is done | 1813 | * count until the queued work is done |
1813 | */ | 1814 | */ |
1814 | evtp->evt_arg1 = lpfc_nlp_get(ndlp); | 1815 | evtp->evt_arg1 = lpfc_nlp_get(ndlp); |
1815 | evtp->evt = LPFC_EVT_ELS_RETRY; | 1816 | if (evtp->evt_arg1) { |
1816 | list_add_tail(&evtp->evt_listp, &phba->work_list); | 1817 | evtp->evt = LPFC_EVT_ELS_RETRY; |
1817 | if (phba->work_wait) | 1818 | list_add_tail(&evtp->evt_listp, &phba->work_list); |
1818 | lpfc_worker_wake_up(phba); | 1819 | lpfc_worker_wake_up(phba); |
1819 | 1820 | } | |
1820 | spin_unlock_irqrestore(&phba->hbalock, flags); | 1821 | spin_unlock_irqrestore(&phba->hbalock, flags); |
1821 | return; | 1822 | return; |
1822 | } | 1823 | } |
@@ -2761,10 +2762,11 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, | |||
2761 | npr = (PRLI *) pcmd; | 2762 | npr = (PRLI *) pcmd; |
2762 | vpd = &phba->vpd; | 2763 | vpd = &phba->vpd; |
2763 | /* | 2764 | /* |
2764 | * If our firmware version is 3.20 or later, | 2765 | * If the remote port is a target and our firmware version is 3.20 or |
2765 | * set the following bits for FC-TAPE support. | 2766 | * later, set the following bits for FC-TAPE support. |
2766 | */ | 2767 | */ |
2767 | if (vpd->rev.feaLevelHigh >= 0x02) { | 2768 | if ((ndlp->nlp_type & NLP_FCP_TARGET) && |
2769 | (vpd->rev.feaLevelHigh >= 0x02)) { | ||
2768 | npr->ConfmComplAllowed = 1; | 2770 | npr->ConfmComplAllowed = 1; |
2769 | npr->Retry = 1; | 2771 | npr->Retry = 1; |
2770 | npr->TaskRetryIdReq = 1; | 2772 | npr->TaskRetryIdReq = 1; |
@@ -3056,27 +3058,16 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) | |||
3056 | { | 3058 | { |
3057 | struct lpfc_nodelist *ndlp = NULL; | 3059 | struct lpfc_nodelist *ndlp = NULL; |
3058 | 3060 | ||
3059 | /* Look at all nodes effected by pending RSCNs and move | 3061 | /* Move all affected nodes by pending RSCNs to NPR state. */ |
3060 | * them to NPR state. | ||
3061 | */ | ||
3062 | |||
3063 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { | 3062 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { |
3064 | if (!NLP_CHK_NODE_ACT(ndlp) || | 3063 | if (!NLP_CHK_NODE_ACT(ndlp) || |
3065 | ndlp->nlp_state == NLP_STE_UNUSED_NODE || | 3064 | (ndlp->nlp_state == NLP_STE_UNUSED_NODE) || |
3066 | lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0) | 3065 | !lpfc_rscn_payload_check(vport, ndlp->nlp_DID)) |
3067 | continue; | 3066 | continue; |
3068 | |||
3069 | lpfc_disc_state_machine(vport, ndlp, NULL, | 3067 | lpfc_disc_state_machine(vport, ndlp, NULL, |
3070 | NLP_EVT_DEVICE_RECOVERY); | 3068 | NLP_EVT_DEVICE_RECOVERY); |
3071 | 3069 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | |
3072 | /* | ||
3073 | * Make sure NLP_DELAY_TMO is NOT running after a device | ||
3074 | * recovery event. | ||
3075 | */ | ||
3076 | if (ndlp->nlp_flag & NLP_DELAY_TMO) | ||
3077 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
3078 | } | 3070 | } |
3079 | |||
3080 | return 0; | 3071 | return 0; |
3081 | } | 3072 | } |
3082 | 3073 | ||
@@ -3781,91 +3772,27 @@ static int | |||
3781 | lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | 3772 | lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, |
3782 | struct lpfc_nodelist *fan_ndlp) | 3773 | struct lpfc_nodelist *fan_ndlp) |
3783 | { | 3774 | { |
3784 | struct lpfc_dmabuf *pcmd; | 3775 | struct lpfc_hba *phba = vport->phba; |
3785 | uint32_t *lp; | 3776 | uint32_t *lp; |
3786 | IOCB_t *icmd; | ||
3787 | uint32_t cmd, did; | ||
3788 | FAN *fp; | 3777 | FAN *fp; |
3789 | struct lpfc_nodelist *ndlp, *next_ndlp; | ||
3790 | struct lpfc_hba *phba = vport->phba; | ||
3791 | |||
3792 | /* FAN received */ | ||
3793 | lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, | ||
3794 | "0265 FAN received\n"); | ||
3795 | icmd = &cmdiocb->iocb; | ||
3796 | did = icmd->un.elsreq64.remoteID; | ||
3797 | pcmd = (struct lpfc_dmabuf *)cmdiocb->context2; | ||
3798 | lp = (uint32_t *)pcmd->virt; | ||
3799 | |||
3800 | cmd = *lp++; | ||
3801 | fp = (FAN *) lp; | ||
3802 | 3778 | ||
3779 | lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0265 FAN received\n"); | ||
3780 | lp = (uint32_t *)((struct lpfc_dmabuf *)cmdiocb->context2)->virt; | ||
3781 | fp = (FAN *) ++lp; | ||
3803 | /* FAN received; Fan does not have a reply sequence */ | 3782 | /* FAN received; Fan does not have a reply sequence */ |
3804 | 3783 | if ((vport == phba->pport) && | |
3805 | if (phba->pport->port_state == LPFC_LOCAL_CFG_LINK) { | 3784 | (vport->port_state == LPFC_LOCAL_CFG_LINK)) { |
3806 | if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName, | 3785 | if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName, |
3807 | sizeof(struct lpfc_name)) != 0) || | 3786 | sizeof(struct lpfc_name))) || |
3808 | (memcmp(&phba->fc_fabparam.portName, &fp->FportName, | 3787 | (memcmp(&phba->fc_fabparam.portName, &fp->FportName, |
3809 | sizeof(struct lpfc_name)) != 0)) { | 3788 | sizeof(struct lpfc_name)))) { |
3810 | /* | 3789 | /* This port has switched fabrics. FLOGI is required */ |
3811 | * This node has switched fabrics. FLOGI is required | ||
3812 | * Clean up the old rpi's | ||
3813 | */ | ||
3814 | |||
3815 | list_for_each_entry_safe(ndlp, next_ndlp, | ||
3816 | &vport->fc_nodes, nlp_listp) { | ||
3817 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
3818 | continue; | ||
3819 | if (ndlp->nlp_state != NLP_STE_NPR_NODE) | ||
3820 | continue; | ||
3821 | if (ndlp->nlp_type & NLP_FABRIC) { | ||
3822 | /* | ||
3823 | * Clean up old Fabric, Nameserver and | ||
3824 | * other NLP_FABRIC logins | ||
3825 | */ | ||
3826 | lpfc_drop_node(vport, ndlp); | ||
3827 | |||
3828 | } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { | ||
3829 | /* Fail outstanding I/O now since this | ||
3830 | * device is marked for PLOGI | ||
3831 | */ | ||
3832 | lpfc_unreg_rpi(vport, ndlp); | ||
3833 | } | ||
3834 | } | ||
3835 | |||
3836 | lpfc_initial_flogi(vport); | 3790 | lpfc_initial_flogi(vport); |
3837 | return 0; | 3791 | } else { |
3838 | } | 3792 | /* FAN verified - skip FLOGI */ |
3839 | /* Discovery not needed, | 3793 | vport->fc_myDID = vport->fc_prevDID; |
3840 | * move the nodes to their original state. | 3794 | lpfc_issue_fabric_reglogin(vport); |
3841 | */ | ||
3842 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, | ||
3843 | nlp_listp) { | ||
3844 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
3845 | continue; | ||
3846 | if (ndlp->nlp_state != NLP_STE_NPR_NODE) | ||
3847 | continue; | ||
3848 | |||
3849 | switch (ndlp->nlp_prev_state) { | ||
3850 | case NLP_STE_UNMAPPED_NODE: | ||
3851 | ndlp->nlp_prev_state = NLP_STE_NPR_NODE; | ||
3852 | lpfc_nlp_set_state(vport, ndlp, | ||
3853 | NLP_STE_UNMAPPED_NODE); | ||
3854 | break; | ||
3855 | |||
3856 | case NLP_STE_MAPPED_NODE: | ||
3857 | ndlp->nlp_prev_state = NLP_STE_NPR_NODE; | ||
3858 | lpfc_nlp_set_state(vport, ndlp, | ||
3859 | NLP_STE_MAPPED_NODE); | ||
3860 | break; | ||
3861 | |||
3862 | default: | ||
3863 | break; | ||
3864 | } | ||
3865 | } | 3795 | } |
3866 | |||
3867 | /* Start discovery - this should just do CLEAR_LA */ | ||
3868 | lpfc_disc_start(vport); | ||
3869 | } | 3796 | } |
3870 | return 0; | 3797 | return 0; |
3871 | } | 3798 | } |
@@ -3875,20 +3802,17 @@ lpfc_els_timeout(unsigned long ptr) | |||
3875 | { | 3802 | { |
3876 | struct lpfc_vport *vport = (struct lpfc_vport *) ptr; | 3803 | struct lpfc_vport *vport = (struct lpfc_vport *) ptr; |
3877 | struct lpfc_hba *phba = vport->phba; | 3804 | struct lpfc_hba *phba = vport->phba; |
3805 | uint32_t tmo_posted; | ||
3878 | unsigned long iflag; | 3806 | unsigned long iflag; |
3879 | 3807 | ||
3880 | spin_lock_irqsave(&vport->work_port_lock, iflag); | 3808 | spin_lock_irqsave(&vport->work_port_lock, iflag); |
3881 | if ((vport->work_port_events & WORKER_ELS_TMO) == 0) { | 3809 | tmo_posted = vport->work_port_events & WORKER_ELS_TMO; |
3810 | if (!tmo_posted) | ||
3882 | vport->work_port_events |= WORKER_ELS_TMO; | 3811 | vport->work_port_events |= WORKER_ELS_TMO; |
3883 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); | 3812 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); |
3884 | 3813 | ||
3885 | spin_lock_irqsave(&phba->hbalock, iflag); | 3814 | if (!tmo_posted) |
3886 | if (phba->work_wait) | 3815 | lpfc_worker_wake_up(phba); |
3887 | lpfc_worker_wake_up(phba); | ||
3888 | spin_unlock_irqrestore(&phba->hbalock, iflag); | ||
3889 | } | ||
3890 | else | ||
3891 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); | ||
3892 | return; | 3816 | return; |
3893 | } | 3817 | } |
3894 | 3818 | ||
@@ -3933,9 +3857,6 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) | |||
3933 | els_command == ELS_CMD_FDISC) | 3857 | els_command == ELS_CMD_FDISC) |
3934 | continue; | 3858 | continue; |
3935 | 3859 | ||
3936 | if (vport != piocb->vport) | ||
3937 | continue; | ||
3938 | |||
3939 | if (piocb->drvrTimeout > 0) { | 3860 | if (piocb->drvrTimeout > 0) { |
3940 | if (piocb->drvrTimeout >= timeout) | 3861 | if (piocb->drvrTimeout >= timeout) |
3941 | piocb->drvrTimeout -= timeout; | 3862 | piocb->drvrTimeout -= timeout; |
@@ -4089,7 +4010,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
4089 | payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; | 4010 | payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; |
4090 | cmd = *payload; | 4011 | cmd = *payload; |
4091 | if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0) | 4012 | if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0) |
4092 | lpfc_post_buffer(phba, pring, 1, 1); | 4013 | lpfc_post_buffer(phba, pring, 1); |
4093 | 4014 | ||
4094 | did = icmd->un.rcvels.remoteID; | 4015 | did = icmd->un.rcvels.remoteID; |
4095 | if (icmd->ulpStatus) { | 4016 | if (icmd->ulpStatus) { |
@@ -4398,7 +4319,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
4398 | phba->fc_stat.NoRcvBuf++; | 4319 | phba->fc_stat.NoRcvBuf++; |
4399 | /* Not enough posted buffers; Try posting more buffers */ | 4320 | /* Not enough posted buffers; Try posting more buffers */ |
4400 | if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) | 4321 | if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) |
4401 | lpfc_post_buffer(phba, pring, 0, 1); | 4322 | lpfc_post_buffer(phba, pring, 0); |
4402 | return; | 4323 | return; |
4403 | } | 4324 | } |
4404 | 4325 | ||
@@ -4842,18 +4763,16 @@ lpfc_fabric_block_timeout(unsigned long ptr) | |||
4842 | struct lpfc_hba *phba = (struct lpfc_hba *) ptr; | 4763 | struct lpfc_hba *phba = (struct lpfc_hba *) ptr; |
4843 | unsigned long iflags; | 4764 | unsigned long iflags; |
4844 | uint32_t tmo_posted; | 4765 | uint32_t tmo_posted; |
4766 | |||
4845 | spin_lock_irqsave(&phba->pport->work_port_lock, iflags); | 4767 | spin_lock_irqsave(&phba->pport->work_port_lock, iflags); |
4846 | tmo_posted = phba->pport->work_port_events & WORKER_FABRIC_BLOCK_TMO; | 4768 | tmo_posted = phba->pport->work_port_events & WORKER_FABRIC_BLOCK_TMO; |
4847 | if (!tmo_posted) | 4769 | if (!tmo_posted) |
4848 | phba->pport->work_port_events |= WORKER_FABRIC_BLOCK_TMO; | 4770 | phba->pport->work_port_events |= WORKER_FABRIC_BLOCK_TMO; |
4849 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags); | 4771 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags); |
4850 | 4772 | ||
4851 | if (!tmo_posted) { | 4773 | if (!tmo_posted) |
4852 | spin_lock_irqsave(&phba->hbalock, iflags); | 4774 | lpfc_worker_wake_up(phba); |
4853 | if (phba->work_wait) | 4775 | return; |
4854 | lpfc_worker_wake_up(phba); | ||
4855 | spin_unlock_irqrestore(&phba->hbalock, iflags); | ||
4856 | } | ||
4857 | } | 4776 | } |
4858 | 4777 | ||
4859 | static void | 4778 | static void |
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 7cb68feb04fd..a98d11bf3576 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -153,11 +153,11 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) | |||
153 | * count until this queued work is done | 153 | * count until this queued work is done |
154 | */ | 154 | */ |
155 | evtp->evt_arg1 = lpfc_nlp_get(ndlp); | 155 | evtp->evt_arg1 = lpfc_nlp_get(ndlp); |
156 | evtp->evt = LPFC_EVT_DEV_LOSS; | 156 | if (evtp->evt_arg1) { |
157 | list_add_tail(&evtp->evt_listp, &phba->work_list); | 157 | evtp->evt = LPFC_EVT_DEV_LOSS; |
158 | if (phba->work_wait) | 158 | list_add_tail(&evtp->evt_listp, &phba->work_list); |
159 | wake_up(phba->work_wait); | 159 | lpfc_worker_wake_up(phba); |
160 | 160 | } | |
161 | spin_unlock_irq(&phba->hbalock); | 161 | spin_unlock_irq(&phba->hbalock); |
162 | 162 | ||
163 | return; | 163 | return; |
@@ -276,14 +276,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) | |||
276 | lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); | 276 | lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); |
277 | } | 277 | } |
278 | 278 | ||
279 | |||
280 | void | ||
281 | lpfc_worker_wake_up(struct lpfc_hba *phba) | ||
282 | { | ||
283 | wake_up(phba->work_wait); | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | static void | 279 | static void |
288 | lpfc_work_list_done(struct lpfc_hba *phba) | 280 | lpfc_work_list_done(struct lpfc_hba *phba) |
289 | { | 281 | { |
@@ -429,6 +421,8 @@ lpfc_work_done(struct lpfc_hba *phba) | |||
429 | || (pring->flag & LPFC_DEFERRED_RING_EVENT)) { | 421 | || (pring->flag & LPFC_DEFERRED_RING_EVENT)) { |
430 | if (pring->flag & LPFC_STOP_IOCB_EVENT) { | 422 | if (pring->flag & LPFC_STOP_IOCB_EVENT) { |
431 | pring->flag |= LPFC_DEFERRED_RING_EVENT; | 423 | pring->flag |= LPFC_DEFERRED_RING_EVENT; |
424 | /* Set the lpfc data pending flag */ | ||
425 | set_bit(LPFC_DATA_READY, &phba->data_flags); | ||
432 | } else { | 426 | } else { |
433 | pring->flag &= ~LPFC_DEFERRED_RING_EVENT; | 427 | pring->flag &= ~LPFC_DEFERRED_RING_EVENT; |
434 | lpfc_sli_handle_slow_ring_event(phba, pring, | 428 | lpfc_sli_handle_slow_ring_event(phba, pring, |
@@ -459,69 +453,29 @@ lpfc_work_done(struct lpfc_hba *phba) | |||
459 | lpfc_work_list_done(phba); | 453 | lpfc_work_list_done(phba); |
460 | } | 454 | } |
461 | 455 | ||
462 | static int | ||
463 | check_work_wait_done(struct lpfc_hba *phba) | ||
464 | { | ||
465 | struct lpfc_vport *vport; | ||
466 | struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; | ||
467 | int rc = 0; | ||
468 | |||
469 | spin_lock_irq(&phba->hbalock); | ||
470 | list_for_each_entry(vport, &phba->port_list, listentry) { | ||
471 | if (vport->work_port_events) { | ||
472 | rc = 1; | ||
473 | break; | ||
474 | } | ||
475 | } | ||
476 | if (rc || phba->work_ha || (!list_empty(&phba->work_list)) || | ||
477 | kthread_should_stop() || pring->flag & LPFC_DEFERRED_RING_EVENT) { | ||
478 | rc = 1; | ||
479 | phba->work_found++; | ||
480 | } else | ||
481 | phba->work_found = 0; | ||
482 | spin_unlock_irq(&phba->hbalock); | ||
483 | return rc; | ||
484 | } | ||
485 | |||
486 | |||
487 | int | 456 | int |
488 | lpfc_do_work(void *p) | 457 | lpfc_do_work(void *p) |
489 | { | 458 | { |
490 | struct lpfc_hba *phba = p; | 459 | struct lpfc_hba *phba = p; |
491 | int rc; | 460 | int rc; |
492 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(work_waitq); | ||
493 | 461 | ||
494 | set_user_nice(current, -20); | 462 | set_user_nice(current, -20); |
495 | phba->work_wait = &work_waitq; | 463 | phba->data_flags = 0; |
496 | phba->work_found = 0; | ||
497 | 464 | ||
498 | while (1) { | 465 | while (1) { |
499 | 466 | /* wait and check worker queue activities */ | |
500 | rc = wait_event_interruptible(work_waitq, | 467 | rc = wait_event_interruptible(phba->work_waitq, |
501 | check_work_wait_done(phba)); | 468 | (test_and_clear_bit(LPFC_DATA_READY, |
502 | 469 | &phba->data_flags) | |
470 | || kthread_should_stop())); | ||
503 | BUG_ON(rc); | 471 | BUG_ON(rc); |
504 | 472 | ||
505 | if (kthread_should_stop()) | 473 | if (kthread_should_stop()) |
506 | break; | 474 | break; |
507 | 475 | ||
476 | /* Attend pending lpfc data processing */ | ||
508 | lpfc_work_done(phba); | 477 | lpfc_work_done(phba); |
509 | |||
510 | /* If there is alot of slow ring work, like during link up | ||
511 | * check_work_wait_done() may cause this thread to not give | ||
512 | * up the CPU for very long periods of time. This may cause | ||
513 | * soft lockups or other problems. To avoid these situations | ||
514 | * give up the CPU here after LPFC_MAX_WORKER_ITERATION | ||
515 | * consecutive iterations. | ||
516 | */ | ||
517 | if (phba->work_found >= LPFC_MAX_WORKER_ITERATION) { | ||
518 | phba->work_found = 0; | ||
519 | schedule(); | ||
520 | } | ||
521 | } | 478 | } |
522 | spin_lock_irq(&phba->hbalock); | ||
523 | phba->work_wait = NULL; | ||
524 | spin_unlock_irq(&phba->hbalock); | ||
525 | return 0; | 479 | return 0; |
526 | } | 480 | } |
527 | 481 | ||
@@ -551,10 +505,10 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, | |||
551 | 505 | ||
552 | spin_lock_irqsave(&phba->hbalock, flags); | 506 | spin_lock_irqsave(&phba->hbalock, flags); |
553 | list_add_tail(&evtp->evt_listp, &phba->work_list); | 507 | list_add_tail(&evtp->evt_listp, &phba->work_list); |
554 | if (phba->work_wait) | ||
555 | lpfc_worker_wake_up(phba); | ||
556 | spin_unlock_irqrestore(&phba->hbalock, flags); | 508 | spin_unlock_irqrestore(&phba->hbalock, flags); |
557 | 509 | ||
510 | lpfc_worker_wake_up(phba); | ||
511 | |||
558 | return 1; | 512 | return 1; |
559 | } | 513 | } |
560 | 514 | ||
@@ -963,6 +917,10 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) | |||
963 | if (phba->fc_topology == TOPOLOGY_LOOP) { | 917 | if (phba->fc_topology == TOPOLOGY_LOOP) { |
964 | phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; | 918 | phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; |
965 | 919 | ||
920 | if (phba->cfg_enable_npiv) | ||
921 | lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, | ||
922 | "1309 Link Up Event npiv not supported in loop " | ||
923 | "topology\n"); | ||
966 | /* Get Loop Map information */ | 924 | /* Get Loop Map information */ |
967 | if (la->il) | 925 | if (la->il) |
968 | vport->fc_flag |= FC_LBIT; | 926 | vport->fc_flag |= FC_LBIT; |
@@ -1087,6 +1045,8 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1087 | MAILBOX_t *mb = &pmb->mb; | 1045 | MAILBOX_t *mb = &pmb->mb; |
1088 | struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); | 1046 | struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); |
1089 | 1047 | ||
1048 | /* Unblock ELS traffic */ | ||
1049 | phba->sli.ring[LPFC_ELS_RING].flag &= ~LPFC_STOP_IOCB_EVENT; | ||
1090 | /* Check for error */ | 1050 | /* Check for error */ |
1091 | if (mb->mbxStatus) { | 1051 | if (mb->mbxStatus) { |
1092 | lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, | 1052 | lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, |
@@ -1650,7 +1610,6 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1650 | ndlp->nlp_DID, old_state, state); | 1610 | ndlp->nlp_DID, old_state, state); |
1651 | 1611 | ||
1652 | if (old_state == NLP_STE_NPR_NODE && | 1612 | if (old_state == NLP_STE_NPR_NODE && |
1653 | (ndlp->nlp_flag & NLP_DELAY_TMO) != 0 && | ||
1654 | state != NLP_STE_NPR_NODE) | 1613 | state != NLP_STE_NPR_NODE) |
1655 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | 1614 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
1656 | if (old_state == NLP_STE_UNMAPPED_NODE) { | 1615 | if (old_state == NLP_STE_UNMAPPED_NODE) { |
@@ -1687,8 +1646,7 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1687 | { | 1646 | { |
1688 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 1647 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
1689 | 1648 | ||
1690 | if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) | 1649 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
1691 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
1692 | if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) | 1650 | if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) |
1693 | lpfc_nlp_counters(vport, ndlp->nlp_state, -1); | 1651 | lpfc_nlp_counters(vport, ndlp->nlp_state, -1); |
1694 | spin_lock_irq(shost->host_lock); | 1652 | spin_lock_irq(shost->host_lock); |
@@ -1701,8 +1659,7 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1701 | static void | 1659 | static void |
1702 | lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | 1660 | lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) |
1703 | { | 1661 | { |
1704 | if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) | 1662 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
1705 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
1706 | if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) | 1663 | if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) |
1707 | lpfc_nlp_counters(vport, ndlp->nlp_state, -1); | 1664 | lpfc_nlp_counters(vport, ndlp->nlp_state, -1); |
1708 | lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, | 1665 | lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, |
@@ -2121,10 +2078,8 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
2121 | ndlp->nlp_last_elscmd = 0; | 2078 | ndlp->nlp_last_elscmd = 0; |
2122 | del_timer_sync(&ndlp->nlp_delayfunc); | 2079 | del_timer_sync(&ndlp->nlp_delayfunc); |
2123 | 2080 | ||
2124 | if (!list_empty(&ndlp->els_retry_evt.evt_listp)) | 2081 | list_del_init(&ndlp->els_retry_evt.evt_listp); |
2125 | list_del_init(&ndlp->els_retry_evt.evt_listp); | 2082 | list_del_init(&ndlp->dev_loss_evt.evt_listp); |
2126 | if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) | ||
2127 | list_del_init(&ndlp->dev_loss_evt.evt_listp); | ||
2128 | 2083 | ||
2129 | lpfc_unreg_rpi(vport, ndlp); | 2084 | lpfc_unreg_rpi(vport, ndlp); |
2130 | 2085 | ||
@@ -2144,10 +2099,7 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
2144 | LPFC_MBOXQ_t *mbox; | 2099 | LPFC_MBOXQ_t *mbox; |
2145 | int rc; | 2100 | int rc; |
2146 | 2101 | ||
2147 | if (ndlp->nlp_flag & NLP_DELAY_TMO) { | 2102 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
2148 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
2149 | } | ||
2150 | |||
2151 | if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) { | 2103 | if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) { |
2152 | /* For this case we need to cleanup the default rpi | 2104 | /* For this case we need to cleanup the default rpi |
2153 | * allocated by the firmware. | 2105 | * allocated by the firmware. |
@@ -2317,8 +2269,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) | |||
2317 | /* Since this node is marked for discovery, | 2269 | /* Since this node is marked for discovery, |
2318 | * delay timeout is not needed. | 2270 | * delay timeout is not needed. |
2319 | */ | 2271 | */ |
2320 | if (ndlp->nlp_flag & NLP_DELAY_TMO) | 2272 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
2321 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
2322 | } else | 2273 | } else |
2323 | ndlp = NULL; | 2274 | ndlp = NULL; |
2324 | } else { | 2275 | } else { |
@@ -2643,21 +2594,20 @@ lpfc_disc_timeout(unsigned long ptr) | |||
2643 | { | 2594 | { |
2644 | struct lpfc_vport *vport = (struct lpfc_vport *) ptr; | 2595 | struct lpfc_vport *vport = (struct lpfc_vport *) ptr; |
2645 | struct lpfc_hba *phba = vport->phba; | 2596 | struct lpfc_hba *phba = vport->phba; |
2597 | uint32_t tmo_posted; | ||
2646 | unsigned long flags = 0; | 2598 | unsigned long flags = 0; |
2647 | 2599 | ||
2648 | if (unlikely(!phba)) | 2600 | if (unlikely(!phba)) |
2649 | return; | 2601 | return; |
2650 | 2602 | ||
2651 | if ((vport->work_port_events & WORKER_DISC_TMO) == 0) { | 2603 | spin_lock_irqsave(&vport->work_port_lock, flags); |
2652 | spin_lock_irqsave(&vport->work_port_lock, flags); | 2604 | tmo_posted = vport->work_port_events & WORKER_DISC_TMO; |
2605 | if (!tmo_posted) | ||
2653 | vport->work_port_events |= WORKER_DISC_TMO; | 2606 | vport->work_port_events |= WORKER_DISC_TMO; |
2654 | spin_unlock_irqrestore(&vport->work_port_lock, flags); | 2607 | spin_unlock_irqrestore(&vport->work_port_lock, flags); |
2655 | 2608 | ||
2656 | spin_lock_irqsave(&phba->hbalock, flags); | 2609 | if (!tmo_posted) |
2657 | if (phba->work_wait) | 2610 | lpfc_worker_wake_up(phba); |
2658 | lpfc_worker_wake_up(phba); | ||
2659 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
2660 | } | ||
2661 | return; | 2611 | return; |
2662 | } | 2612 | } |
2663 | 2613 | ||
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index fa757b251f82..5b6e5395c8eb 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -145,8 +145,10 @@ lpfc_config_port_prep(struct lpfc_hba *phba) | |||
145 | return -ERESTART; | 145 | return -ERESTART; |
146 | } | 146 | } |
147 | 147 | ||
148 | if (phba->sli_rev == 3 && !mb->un.varRdRev.v3rsp) | 148 | if (phba->sli_rev == 3 && !mb->un.varRdRev.v3rsp) { |
149 | mempool_free(pmb, phba->mbox_mem_pool); | ||
149 | return -EINVAL; | 150 | return -EINVAL; |
151 | } | ||
150 | 152 | ||
151 | /* Save information as VPD data */ | 153 | /* Save information as VPD data */ |
152 | vp->rev.rBit = 1; | 154 | vp->rev.rBit = 1; |
@@ -551,18 +553,18 @@ static void | |||
551 | lpfc_hb_timeout(unsigned long ptr) | 553 | lpfc_hb_timeout(unsigned long ptr) |
552 | { | 554 | { |
553 | struct lpfc_hba *phba; | 555 | struct lpfc_hba *phba; |
556 | uint32_t tmo_posted; | ||
554 | unsigned long iflag; | 557 | unsigned long iflag; |
555 | 558 | ||
556 | phba = (struct lpfc_hba *)ptr; | 559 | phba = (struct lpfc_hba *)ptr; |
557 | spin_lock_irqsave(&phba->pport->work_port_lock, iflag); | 560 | spin_lock_irqsave(&phba->pport->work_port_lock, iflag); |
558 | if (!(phba->pport->work_port_events & WORKER_HB_TMO)) | 561 | tmo_posted = phba->pport->work_port_events & WORKER_HB_TMO; |
562 | if (!tmo_posted) | ||
559 | phba->pport->work_port_events |= WORKER_HB_TMO; | 563 | phba->pport->work_port_events |= WORKER_HB_TMO; |
560 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); | 564 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); |
561 | 565 | ||
562 | spin_lock_irqsave(&phba->hbalock, iflag); | 566 | if (!tmo_posted) |
563 | if (phba->work_wait) | 567 | lpfc_worker_wake_up(phba); |
564 | wake_up(phba->work_wait); | ||
565 | spin_unlock_irqrestore(&phba->hbalock, iflag); | ||
566 | return; | 568 | return; |
567 | } | 569 | } |
568 | 570 | ||
@@ -851,6 +853,8 @@ lpfc_handle_latt(struct lpfc_hba *phba) | |||
851 | lpfc_read_la(phba, pmb, mp); | 853 | lpfc_read_la(phba, pmb, mp); |
852 | pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la; | 854 | pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la; |
853 | pmb->vport = vport; | 855 | pmb->vport = vport; |
856 | /* Block ELS IOCBs until we have processed this mbox command */ | ||
857 | phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT; | ||
854 | rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT); | 858 | rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT); |
855 | if (rc == MBX_NOT_FINISHED) { | 859 | if (rc == MBX_NOT_FINISHED) { |
856 | rc = 4; | 860 | rc = 4; |
@@ -866,6 +870,7 @@ lpfc_handle_latt(struct lpfc_hba *phba) | |||
866 | return; | 870 | return; |
867 | 871 | ||
868 | lpfc_handle_latt_free_mbuf: | 872 | lpfc_handle_latt_free_mbuf: |
873 | phba->sli.ring[LPFC_ELS_RING].flag &= ~LPFC_STOP_IOCB_EVENT; | ||
869 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 874 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
870 | lpfc_handle_latt_free_mp: | 875 | lpfc_handle_latt_free_mp: |
871 | kfree(mp); | 876 | kfree(mp); |
@@ -1194,8 +1199,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) | |||
1194 | /* Returns the number of buffers NOT posted. */ | 1199 | /* Returns the number of buffers NOT posted. */ |
1195 | /**************************************************/ | 1200 | /**************************************************/ |
1196 | int | 1201 | int |
1197 | lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt, | 1202 | lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt) |
1198 | int type) | ||
1199 | { | 1203 | { |
1200 | IOCB_t *icmd; | 1204 | IOCB_t *icmd; |
1201 | struct lpfc_iocbq *iocb; | 1205 | struct lpfc_iocbq *iocb; |
@@ -1295,7 +1299,7 @@ lpfc_post_rcv_buf(struct lpfc_hba *phba) | |||
1295 | struct lpfc_sli *psli = &phba->sli; | 1299 | struct lpfc_sli *psli = &phba->sli; |
1296 | 1300 | ||
1297 | /* Ring 0, ELS / CT buffers */ | 1301 | /* Ring 0, ELS / CT buffers */ |
1298 | lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], LPFC_BUF_RING0, 1); | 1302 | lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], LPFC_BUF_RING0); |
1299 | /* Ring 2 - FCP no buffers needed */ | 1303 | /* Ring 2 - FCP no buffers needed */ |
1300 | 1304 | ||
1301 | return 0; | 1305 | return 0; |
@@ -1454,6 +1458,15 @@ lpfc_cleanup(struct lpfc_vport *vport) | |||
1454 | 1458 | ||
1455 | lpfc_disc_state_machine(vport, ndlp, NULL, | 1459 | lpfc_disc_state_machine(vport, ndlp, NULL, |
1456 | NLP_EVT_DEVICE_RM); | 1460 | NLP_EVT_DEVICE_RM); |
1461 | |||
1462 | /* nlp_type zero is not defined, nlp_flag zero also not defined, | ||
1463 | * nlp_state is unused, this happens when | ||
1464 | * an initiator has logged | ||
1465 | * into us so cleanup this ndlp. | ||
1466 | */ | ||
1467 | if ((ndlp->nlp_type == 0) && (ndlp->nlp_flag == 0) && | ||
1468 | (ndlp->nlp_state == 0)) | ||
1469 | lpfc_nlp_put(ndlp); | ||
1457 | } | 1470 | } |
1458 | 1471 | ||
1459 | /* At this point, ALL ndlp's should be gone | 1472 | /* At this point, ALL ndlp's should be gone |
@@ -2101,6 +2114,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
2101 | phba->work_ha_mask = (HA_ERATT|HA_MBATT|HA_LATT); | 2114 | phba->work_ha_mask = (HA_ERATT|HA_MBATT|HA_LATT); |
2102 | phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4)); | 2115 | phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4)); |
2103 | 2116 | ||
2117 | /* Initialize the wait queue head for the kernel thread */ | ||
2118 | init_waitqueue_head(&phba->work_waitq); | ||
2119 | |||
2104 | /* Startup the kernel thread for this host adapter. */ | 2120 | /* Startup the kernel thread for this host adapter. */ |
2105 | phba->worker_thread = kthread_run(lpfc_do_work, phba, | 2121 | phba->worker_thread = kthread_run(lpfc_do_work, phba, |
2106 | "lpfc_worker_%d", phba->brd_no); | 2122 | "lpfc_worker_%d", phba->brd_no); |
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index d08c4c890744..6688a8689b56 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c | |||
@@ -235,10 +235,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) | |||
235 | (iocb->iocb_cmpl) (phba, iocb, iocb); | 235 | (iocb->iocb_cmpl) (phba, iocb, iocb); |
236 | } | 236 | } |
237 | } | 237 | } |
238 | 238 | lpfc_cancel_retry_delay_tmo(phba->pport, ndlp); | |
239 | /* If we are delaying issuing an ELS command, cancel it */ | ||
240 | if (ndlp->nlp_flag & NLP_DELAY_TMO) | ||
241 | lpfc_cancel_retry_delay_tmo(phba->pport, ndlp); | ||
242 | return 0; | 239 | return 0; |
243 | } | 240 | } |
244 | 241 | ||
@@ -249,7 +246,6 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
249 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 246 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
250 | struct lpfc_hba *phba = vport->phba; | 247 | struct lpfc_hba *phba = vport->phba; |
251 | struct lpfc_dmabuf *pcmd; | 248 | struct lpfc_dmabuf *pcmd; |
252 | struct lpfc_work_evt *evtp; | ||
253 | uint32_t *lp; | 249 | uint32_t *lp; |
254 | IOCB_t *icmd; | 250 | IOCB_t *icmd; |
255 | struct serv_parm *sp; | 251 | struct serv_parm *sp; |
@@ -425,73 +421,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
425 | ndlp, mbox); | 421 | ndlp, mbox); |
426 | return 1; | 422 | return 1; |
427 | } | 423 | } |
428 | |||
429 | /* If the remote NPort logs into us, before we can initiate | ||
430 | * discovery to them, cleanup the NPort from discovery accordingly. | ||
431 | */ | ||
432 | if (ndlp->nlp_state == NLP_STE_NPR_NODE) { | ||
433 | spin_lock_irq(shost->host_lock); | ||
434 | ndlp->nlp_flag &= ~NLP_DELAY_TMO; | ||
435 | spin_unlock_irq(shost->host_lock); | ||
436 | del_timer_sync(&ndlp->nlp_delayfunc); | ||
437 | ndlp->nlp_last_elscmd = 0; | ||
438 | |||
439 | if (!list_empty(&ndlp->els_retry_evt.evt_listp)) { | ||
440 | list_del_init(&ndlp->els_retry_evt.evt_listp); | ||
441 | /* Decrement ndlp reference count held for the | ||
442 | * delayed retry | ||
443 | */ | ||
444 | evtp = &ndlp->els_retry_evt; | ||
445 | lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); | ||
446 | } | ||
447 | |||
448 | if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { | ||
449 | spin_lock_irq(shost->host_lock); | ||
450 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
451 | spin_unlock_irq(shost->host_lock); | ||
452 | |||
453 | if ((ndlp->nlp_flag & NLP_ADISC_SND) && | ||
454 | (vport->num_disc_nodes)) { | ||
455 | /* Check to see if there are more | ||
456 | * ADISCs to be sent | ||
457 | */ | ||
458 | lpfc_more_adisc(vport); | ||
459 | |||
460 | if ((vport->num_disc_nodes == 0) && | ||
461 | (vport->fc_npr_cnt)) | ||
462 | lpfc_els_disc_plogi(vport); | ||
463 | |||
464 | if (vport->num_disc_nodes == 0) { | ||
465 | spin_lock_irq(shost->host_lock); | ||
466 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
467 | spin_unlock_irq(shost->host_lock); | ||
468 | lpfc_can_disctmo(vport); | ||
469 | lpfc_end_rscn(vport); | ||
470 | } | ||
471 | } | ||
472 | } | ||
473 | } else if ((ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) && | ||
474 | (ndlp->nlp_flag & NLP_NPR_2B_DISC) && | ||
475 | (vport->num_disc_nodes)) { | ||
476 | spin_lock_irq(shost->host_lock); | ||
477 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
478 | spin_unlock_irq(shost->host_lock); | ||
479 | /* Check to see if there are more | ||
480 | * PLOGIs to be sent | ||
481 | */ | ||
482 | lpfc_more_plogi(vport); | ||
483 | if (vport->num_disc_nodes == 0) { | ||
484 | spin_lock_irq(shost->host_lock); | ||
485 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
486 | spin_unlock_irq(shost->host_lock); | ||
487 | lpfc_can_disctmo(vport); | ||
488 | lpfc_end_rscn(vport); | ||
489 | } | ||
490 | } | ||
491 | |||
492 | lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); | 424 | lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); |
493 | return 1; | 425 | return 1; |
494 | |||
495 | out: | 426 | out: |
496 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | 427 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; |
497 | stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE; | 428 | stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE; |
@@ -574,7 +505,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
574 | else | 505 | else |
575 | lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); | 506 | lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); |
576 | 507 | ||
577 | if (!(ndlp->nlp_type & NLP_FABRIC) || | 508 | if ((!(ndlp->nlp_type & NLP_FABRIC) && |
509 | ((ndlp->nlp_type & NLP_FCP_TARGET) || | ||
510 | !(ndlp->nlp_type & NLP_FCP_INITIATOR))) || | ||
578 | (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { | 511 | (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { |
579 | /* Only try to re-login if this is NOT a Fabric Node */ | 512 | /* Only try to re-login if this is NOT a Fabric Node */ |
580 | mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); | 513 | mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); |
@@ -751,6 +684,7 @@ static uint32_t | |||
751 | lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | 684 | lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, |
752 | void *arg, uint32_t evt) | 685 | void *arg, uint32_t evt) |
753 | { | 686 | { |
687 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
754 | struct lpfc_hba *phba = vport->phba; | 688 | struct lpfc_hba *phba = vport->phba; |
755 | struct lpfc_iocbq *cmdiocb = arg; | 689 | struct lpfc_iocbq *cmdiocb = arg; |
756 | struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | 690 | struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; |
@@ -776,7 +710,22 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
776 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, | 710 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, |
777 | NULL); | 711 | NULL); |
778 | } else { | 712 | } else { |
779 | lpfc_rcv_plogi(vport, ndlp, cmdiocb); | 713 | if (lpfc_rcv_plogi(vport, ndlp, cmdiocb) && |
714 | (ndlp->nlp_flag & NLP_NPR_2B_DISC) && | ||
715 | (vport->num_disc_nodes)) { | ||
716 | spin_lock_irq(shost->host_lock); | ||
717 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
718 | spin_unlock_irq(shost->host_lock); | ||
719 | /* Check if there are more PLOGIs to be sent */ | ||
720 | lpfc_more_plogi(vport); | ||
721 | if (vport->num_disc_nodes == 0) { | ||
722 | spin_lock_irq(shost->host_lock); | ||
723 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
724 | spin_unlock_irq(shost->host_lock); | ||
725 | lpfc_can_disctmo(vport); | ||
726 | lpfc_end_rscn(vport); | ||
727 | } | ||
728 | } | ||
780 | } /* If our portname was less */ | 729 | } /* If our portname was less */ |
781 | 730 | ||
782 | return ndlp->nlp_state; | 731 | return ndlp->nlp_state; |
@@ -1040,6 +989,7 @@ static uint32_t | |||
1040 | lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | 989 | lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, |
1041 | void *arg, uint32_t evt) | 990 | void *arg, uint32_t evt) |
1042 | { | 991 | { |
992 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
1043 | struct lpfc_hba *phba = vport->phba; | 993 | struct lpfc_hba *phba = vport->phba; |
1044 | struct lpfc_iocbq *cmdiocb; | 994 | struct lpfc_iocbq *cmdiocb; |
1045 | 995 | ||
@@ -1048,9 +998,28 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1048 | 998 | ||
1049 | cmdiocb = (struct lpfc_iocbq *) arg; | 999 | cmdiocb = (struct lpfc_iocbq *) arg; |
1050 | 1000 | ||
1051 | if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) | 1001 | if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { |
1052 | return ndlp->nlp_state; | 1002 | if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { |
1003 | spin_lock_irq(shost->host_lock); | ||
1004 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
1005 | spin_unlock_irq(shost->host_lock); | ||
1053 | 1006 | ||
1007 | if (vport->num_disc_nodes) { | ||
1008 | lpfc_more_adisc(vport); | ||
1009 | if ((vport->num_disc_nodes == 0) && | ||
1010 | (vport->fc_npr_cnt)) | ||
1011 | lpfc_els_disc_plogi(vport); | ||
1012 | if (vport->num_disc_nodes == 0) { | ||
1013 | spin_lock_irq(shost->host_lock); | ||
1014 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
1015 | spin_unlock_irq(shost->host_lock); | ||
1016 | lpfc_can_disctmo(vport); | ||
1017 | lpfc_end_rscn(vport); | ||
1018 | } | ||
1019 | } | ||
1020 | } | ||
1021 | return ndlp->nlp_state; | ||
1022 | } | ||
1054 | ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; | 1023 | ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; |
1055 | lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); | 1024 | lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); |
1056 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); | 1025 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); |
@@ -1742,24 +1711,21 @@ lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1742 | struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; | 1711 | struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; |
1743 | 1712 | ||
1744 | /* Ignore PLOGI if we have an outstanding LOGO */ | 1713 | /* Ignore PLOGI if we have an outstanding LOGO */ |
1745 | if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC)) { | 1714 | if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC)) |
1746 | return ndlp->nlp_state; | 1715 | return ndlp->nlp_state; |
1747 | } | ||
1748 | |||
1749 | if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { | 1716 | if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { |
1717 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
1750 | spin_lock_irq(shost->host_lock); | 1718 | spin_lock_irq(shost->host_lock); |
1751 | ndlp->nlp_flag &= ~NLP_NPR_ADISC; | 1719 | ndlp->nlp_flag &= ~(NLP_NPR_ADISC | NLP_NPR_2B_DISC); |
1752 | spin_unlock_irq(shost->host_lock); | 1720 | spin_unlock_irq(shost->host_lock); |
1753 | return ndlp->nlp_state; | 1721 | } else if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { |
1754 | } | 1722 | /* send PLOGI immediately, move to PLOGI issue state */ |
1755 | 1723 | if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { | |
1756 | /* send PLOGI immediately, move to PLOGI issue state */ | 1724 | ndlp->nlp_prev_state = NLP_STE_NPR_NODE; |
1757 | if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { | 1725 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); |
1758 | ndlp->nlp_prev_state = NLP_STE_NPR_NODE; | 1726 | lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); |
1759 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); | 1727 | } |
1760 | lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); | ||
1761 | } | 1728 | } |
1762 | |||
1763 | return ndlp->nlp_state; | 1729 | return ndlp->nlp_state; |
1764 | } | 1730 | } |
1765 | 1731 | ||
@@ -1810,7 +1776,6 @@ lpfc_rcv_padisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1810 | struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; | 1776 | struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; |
1811 | 1777 | ||
1812 | lpfc_rcv_padisc(vport, ndlp, cmdiocb); | 1778 | lpfc_rcv_padisc(vport, ndlp, cmdiocb); |
1813 | |||
1814 | /* | 1779 | /* |
1815 | * Do not start discovery if discovery is about to start | 1780 | * Do not start discovery if discovery is about to start |
1816 | * or discovery in progress for this node. Starting discovery | 1781 | * or discovery in progress for this node. Starting discovery |
@@ -1973,9 +1938,7 @@ lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1973 | spin_lock_irq(shost->host_lock); | 1938 | spin_lock_irq(shost->host_lock); |
1974 | ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); | 1939 | ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); |
1975 | spin_unlock_irq(shost->host_lock); | 1940 | spin_unlock_irq(shost->host_lock); |
1976 | if (ndlp->nlp_flag & NLP_DELAY_TMO) { | 1941 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
1977 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
1978 | } | ||
1979 | return ndlp->nlp_state; | 1942 | return ndlp->nlp_state; |
1980 | } | 1943 | } |
1981 | 1944 | ||
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 0910a9ab76a5..c94da4f2b8a6 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
@@ -50,6 +50,7 @@ void | |||
50 | lpfc_adjust_queue_depth(struct lpfc_hba *phba) | 50 | lpfc_adjust_queue_depth(struct lpfc_hba *phba) |
51 | { | 51 | { |
52 | unsigned long flags; | 52 | unsigned long flags; |
53 | uint32_t evt_posted; | ||
53 | 54 | ||
54 | spin_lock_irqsave(&phba->hbalock, flags); | 55 | spin_lock_irqsave(&phba->hbalock, flags); |
55 | atomic_inc(&phba->num_rsrc_err); | 56 | atomic_inc(&phba->num_rsrc_err); |
@@ -65,17 +66,13 @@ lpfc_adjust_queue_depth(struct lpfc_hba *phba) | |||
65 | spin_unlock_irqrestore(&phba->hbalock, flags); | 66 | spin_unlock_irqrestore(&phba->hbalock, flags); |
66 | 67 | ||
67 | spin_lock_irqsave(&phba->pport->work_port_lock, flags); | 68 | spin_lock_irqsave(&phba->pport->work_port_lock, flags); |
68 | if ((phba->pport->work_port_events & | 69 | evt_posted = phba->pport->work_port_events & WORKER_RAMP_DOWN_QUEUE; |
69 | WORKER_RAMP_DOWN_QUEUE) == 0) { | 70 | if (!evt_posted) |
70 | phba->pport->work_port_events |= WORKER_RAMP_DOWN_QUEUE; | 71 | phba->pport->work_port_events |= WORKER_RAMP_DOWN_QUEUE; |
71 | } | ||
72 | spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); | 72 | spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); |
73 | 73 | ||
74 | spin_lock_irqsave(&phba->hbalock, flags); | 74 | if (!evt_posted) |
75 | if (phba->work_wait) | 75 | lpfc_worker_wake_up(phba); |
76 | wake_up(phba->work_wait); | ||
77 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
78 | |||
79 | return; | 76 | return; |
80 | } | 77 | } |
81 | 78 | ||
@@ -89,6 +86,7 @@ lpfc_rampup_queue_depth(struct lpfc_vport *vport, | |||
89 | { | 86 | { |
90 | unsigned long flags; | 87 | unsigned long flags; |
91 | struct lpfc_hba *phba = vport->phba; | 88 | struct lpfc_hba *phba = vport->phba; |
89 | uint32_t evt_posted; | ||
92 | atomic_inc(&phba->num_cmd_success); | 90 | atomic_inc(&phba->num_cmd_success); |
93 | 91 | ||
94 | if (vport->cfg_lun_queue_depth <= sdev->queue_depth) | 92 | if (vport->cfg_lun_queue_depth <= sdev->queue_depth) |
@@ -103,16 +101,14 @@ lpfc_rampup_queue_depth(struct lpfc_vport *vport, | |||
103 | spin_unlock_irqrestore(&phba->hbalock, flags); | 101 | spin_unlock_irqrestore(&phba->hbalock, flags); |
104 | 102 | ||
105 | spin_lock_irqsave(&phba->pport->work_port_lock, flags); | 103 | spin_lock_irqsave(&phba->pport->work_port_lock, flags); |
106 | if ((phba->pport->work_port_events & | 104 | evt_posted = phba->pport->work_port_events & WORKER_RAMP_UP_QUEUE; |
107 | WORKER_RAMP_UP_QUEUE) == 0) { | 105 | if (!evt_posted) |
108 | phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE; | 106 | phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE; |
109 | } | ||
110 | spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); | 107 | spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); |
111 | 108 | ||
112 | spin_lock_irqsave(&phba->hbalock, flags); | 109 | if (!evt_posted) |
113 | if (phba->work_wait) | 110 | lpfc_worker_wake_up(phba); |
114 | wake_up(phba->work_wait); | 111 | return; |
115 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
116 | } | 112 | } |
117 | 113 | ||
118 | void | 114 | void |
@@ -609,9 +605,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | |||
609 | result = cmd->result; | 605 | result = cmd->result; |
610 | sdev = cmd->device; | 606 | sdev = cmd->device; |
611 | lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); | 607 | lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); |
612 | spin_lock_irqsave(sdev->host->host_lock, flags); | ||
613 | lpfc_cmd->pCmd = NULL; /* This must be done before scsi_done */ | ||
614 | spin_unlock_irqrestore(sdev->host->host_lock, flags); | ||
615 | cmd->scsi_done(cmd); | 608 | cmd->scsi_done(cmd); |
616 | 609 | ||
617 | if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { | 610 | if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { |
@@ -620,6 +613,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | |||
620 | * wake up the thread. | 613 | * wake up the thread. |
621 | */ | 614 | */ |
622 | spin_lock_irqsave(sdev->host->host_lock, flags); | 615 | spin_lock_irqsave(sdev->host->host_lock, flags); |
616 | lpfc_cmd->pCmd = NULL; | ||
623 | if (lpfc_cmd->waitq) | 617 | if (lpfc_cmd->waitq) |
624 | wake_up(lpfc_cmd->waitq); | 618 | wake_up(lpfc_cmd->waitq); |
625 | spin_unlock_irqrestore(sdev->host->host_lock, flags); | 619 | spin_unlock_irqrestore(sdev->host->host_lock, flags); |
@@ -690,6 +684,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | |||
690 | * wake up the thread. | 684 | * wake up the thread. |
691 | */ | 685 | */ |
692 | spin_lock_irqsave(sdev->host->host_lock, flags); | 686 | spin_lock_irqsave(sdev->host->host_lock, flags); |
687 | lpfc_cmd->pCmd = NULL; | ||
693 | if (lpfc_cmd->waitq) | 688 | if (lpfc_cmd->waitq) |
694 | wake_up(lpfc_cmd->waitq); | 689 | wake_up(lpfc_cmd->waitq); |
695 | spin_unlock_irqrestore(sdev->host->host_lock, flags); | 690 | spin_unlock_irqrestore(sdev->host->host_lock, flags); |
@@ -849,14 +844,15 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport, | |||
849 | struct lpfc_iocbq *iocbq; | 844 | struct lpfc_iocbq *iocbq; |
850 | struct lpfc_iocbq *iocbqrsp; | 845 | struct lpfc_iocbq *iocbqrsp; |
851 | int ret; | 846 | int ret; |
847 | int status; | ||
852 | 848 | ||
853 | if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) | 849 | if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) |
854 | return FAILED; | 850 | return FAILED; |
855 | 851 | ||
856 | lpfc_cmd->rdata = rdata; | 852 | lpfc_cmd->rdata = rdata; |
857 | ret = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun, | 853 | status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun, |
858 | FCP_TARGET_RESET); | 854 | FCP_TARGET_RESET); |
859 | if (!ret) | 855 | if (!status) |
860 | return FAILED; | 856 | return FAILED; |
861 | 857 | ||
862 | iocbq = &lpfc_cmd->cur_iocbq; | 858 | iocbq = &lpfc_cmd->cur_iocbq; |
@@ -869,12 +865,15 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport, | |||
869 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, | 865 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, |
870 | "0702 Issue Target Reset to TGT %d Data: x%x x%x\n", | 866 | "0702 Issue Target Reset to TGT %d Data: x%x x%x\n", |
871 | tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag); | 867 | tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag); |
872 | ret = lpfc_sli_issue_iocb_wait(phba, | 868 | status = lpfc_sli_issue_iocb_wait(phba, |
873 | &phba->sli.ring[phba->sli.fcp_ring], | 869 | &phba->sli.ring[phba->sli.fcp_ring], |
874 | iocbq, iocbqrsp, lpfc_cmd->timeout); | 870 | iocbq, iocbqrsp, lpfc_cmd->timeout); |
875 | if (ret != IOCB_SUCCESS) { | 871 | if (status != IOCB_SUCCESS) { |
876 | if (ret == IOCB_TIMEDOUT) | 872 | if (status == IOCB_TIMEDOUT) { |
877 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; | 873 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; |
874 | ret = TIMEOUT_ERROR; | ||
875 | } else | ||
876 | ret = FAILED; | ||
878 | lpfc_cmd->status = IOSTAT_DRIVER_REJECT; | 877 | lpfc_cmd->status = IOSTAT_DRIVER_REJECT; |
879 | } else { | 878 | } else { |
880 | ret = SUCCESS; | 879 | ret = SUCCESS; |
@@ -1142,121 +1141,96 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) | |||
1142 | struct lpfc_iocbq *iocbq, *iocbqrsp; | 1141 | struct lpfc_iocbq *iocbq, *iocbqrsp; |
1143 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; | 1142 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; |
1144 | struct lpfc_nodelist *pnode = rdata->pnode; | 1143 | struct lpfc_nodelist *pnode = rdata->pnode; |
1145 | uint32_t cmd_result = 0, cmd_status = 0; | 1144 | unsigned long later; |
1146 | int ret = FAILED; | 1145 | int ret = SUCCESS; |
1147 | int iocb_status = IOCB_SUCCESS; | 1146 | int status; |
1148 | int cnt, loopcnt; | 1147 | int cnt; |
1149 | 1148 | ||
1150 | lpfc_block_error_handler(cmnd); | 1149 | lpfc_block_error_handler(cmnd); |
1151 | loopcnt = 0; | ||
1152 | /* | 1150 | /* |
1153 | * If target is not in a MAPPED state, delay the reset until | 1151 | * If target is not in a MAPPED state, delay the reset until |
1154 | * target is rediscovered or devloss timeout expires. | 1152 | * target is rediscovered or devloss timeout expires. |
1155 | */ | 1153 | */ |
1156 | while (1) { | 1154 | later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; |
1155 | while (time_after(later, jiffies)) { | ||
1157 | if (!pnode || !NLP_CHK_NODE_ACT(pnode)) | 1156 | if (!pnode || !NLP_CHK_NODE_ACT(pnode)) |
1158 | goto out; | 1157 | return FAILED; |
1159 | |||
1160 | if (pnode->nlp_state != NLP_STE_MAPPED_NODE) { | ||
1161 | schedule_timeout_uninterruptible(msecs_to_jiffies(500)); | ||
1162 | loopcnt++; | ||
1163 | rdata = cmnd->device->hostdata; | ||
1164 | if (!rdata || | ||
1165 | (loopcnt > ((vport->cfg_devloss_tmo * 2) + 1))){ | ||
1166 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
1167 | "0721 LUN Reset rport " | ||
1168 | "failure: cnt x%x rdata x%p\n", | ||
1169 | loopcnt, rdata); | ||
1170 | goto out; | ||
1171 | } | ||
1172 | pnode = rdata->pnode; | ||
1173 | if (!pnode || !NLP_CHK_NODE_ACT(pnode)) | ||
1174 | goto out; | ||
1175 | } | ||
1176 | if (pnode->nlp_state == NLP_STE_MAPPED_NODE) | 1158 | if (pnode->nlp_state == NLP_STE_MAPPED_NODE) |
1177 | break; | 1159 | break; |
1160 | schedule_timeout_uninterruptible(msecs_to_jiffies(500)); | ||
1161 | rdata = cmnd->device->hostdata; | ||
1162 | if (!rdata) | ||
1163 | break; | ||
1164 | pnode = rdata->pnode; | ||
1165 | } | ||
1166 | if (!rdata || pnode->nlp_state != NLP_STE_MAPPED_NODE) { | ||
1167 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
1168 | "0721 LUN Reset rport " | ||
1169 | "failure: msec x%x rdata x%p\n", | ||
1170 | jiffies_to_msecs(jiffies - later), rdata); | ||
1171 | return FAILED; | ||
1178 | } | 1172 | } |
1179 | |||
1180 | lpfc_cmd = lpfc_get_scsi_buf(phba); | 1173 | lpfc_cmd = lpfc_get_scsi_buf(phba); |
1181 | if (lpfc_cmd == NULL) | 1174 | if (lpfc_cmd == NULL) |
1182 | goto out; | 1175 | return FAILED; |
1183 | |||
1184 | lpfc_cmd->timeout = 60; | 1176 | lpfc_cmd->timeout = 60; |
1185 | lpfc_cmd->rdata = rdata; | 1177 | lpfc_cmd->rdata = rdata; |
1186 | 1178 | ||
1187 | ret = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, cmnd->device->lun, | 1179 | status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, |
1188 | FCP_TARGET_RESET); | 1180 | cmnd->device->lun, |
1189 | if (!ret) | 1181 | FCP_TARGET_RESET); |
1190 | goto out_free_scsi_buf; | 1182 | if (!status) { |
1191 | 1183 | lpfc_release_scsi_buf(phba, lpfc_cmd); | |
1184 | return FAILED; | ||
1185 | } | ||
1192 | iocbq = &lpfc_cmd->cur_iocbq; | 1186 | iocbq = &lpfc_cmd->cur_iocbq; |
1193 | 1187 | ||
1194 | /* get a buffer for this IOCB command response */ | 1188 | /* get a buffer for this IOCB command response */ |
1195 | iocbqrsp = lpfc_sli_get_iocbq(phba); | 1189 | iocbqrsp = lpfc_sli_get_iocbq(phba); |
1196 | if (iocbqrsp == NULL) | 1190 | if (iocbqrsp == NULL) { |
1197 | goto out_free_scsi_buf; | 1191 | lpfc_release_scsi_buf(phba, lpfc_cmd); |
1198 | 1192 | return FAILED; | |
1193 | } | ||
1199 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, | 1194 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, |
1200 | "0703 Issue target reset to TGT %d LUN %d " | 1195 | "0703 Issue target reset to TGT %d LUN %d " |
1201 | "rpi x%x nlp_flag x%x\n", cmnd->device->id, | 1196 | "rpi x%x nlp_flag x%x\n", cmnd->device->id, |
1202 | cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); | 1197 | cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); |
1203 | iocb_status = lpfc_sli_issue_iocb_wait(phba, | 1198 | status = lpfc_sli_issue_iocb_wait(phba, |
1204 | &phba->sli.ring[phba->sli.fcp_ring], | 1199 | &phba->sli.ring[phba->sli.fcp_ring], |
1205 | iocbq, iocbqrsp, lpfc_cmd->timeout); | 1200 | iocbq, iocbqrsp, lpfc_cmd->timeout); |
1206 | 1201 | if (status == IOCB_TIMEDOUT) { | |
1207 | if (iocb_status == IOCB_TIMEDOUT) | ||
1208 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; | 1202 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; |
1209 | 1203 | ret = TIMEOUT_ERROR; | |
1210 | if (iocb_status == IOCB_SUCCESS) | 1204 | } else { |
1211 | ret = SUCCESS; | 1205 | if (status != IOCB_SUCCESS) |
1212 | else | 1206 | ret = FAILED; |
1213 | ret = iocb_status; | 1207 | lpfc_release_scsi_buf(phba, lpfc_cmd); |
1214 | 1208 | } | |
1215 | cmd_result = iocbqrsp->iocb.un.ulpWord[4]; | 1209 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
1216 | cmd_status = iocbqrsp->iocb.ulpStatus; | 1210 | "0713 SCSI layer issued device reset (%d, %d) " |
1217 | 1211 | "return x%x status x%x result x%x\n", | |
1212 | cmnd->device->id, cmnd->device->lun, ret, | ||
1213 | iocbqrsp->iocb.ulpStatus, | ||
1214 | iocbqrsp->iocb.un.ulpWord[4]); | ||
1218 | lpfc_sli_release_iocbq(phba, iocbqrsp); | 1215 | lpfc_sli_release_iocbq(phba, iocbqrsp); |
1219 | |||
1220 | /* | ||
1221 | * All outstanding txcmplq I/Os should have been aborted by the device. | ||
1222 | * Unfortunately, some targets do not abide by this forcing the driver | ||
1223 | * to double check. | ||
1224 | */ | ||
1225 | cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, cmnd->device->lun, | 1216 | cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, cmnd->device->lun, |
1226 | LPFC_CTX_LUN); | 1217 | LPFC_CTX_TGT); |
1227 | if (cnt) | 1218 | if (cnt) |
1228 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], | 1219 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], |
1229 | cmnd->device->id, cmnd->device->lun, | 1220 | cmnd->device->id, cmnd->device->lun, |
1230 | LPFC_CTX_LUN); | 1221 | LPFC_CTX_TGT); |
1231 | loopcnt = 0; | 1222 | later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; |
1232 | while(cnt) { | 1223 | while (time_after(later, jiffies) && cnt) { |
1233 | schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ); | 1224 | schedule_timeout_uninterruptible(msecs_to_jiffies(20)); |
1234 | |||
1235 | if (++loopcnt | ||
1236 | > (2 * vport->cfg_devloss_tmo)/LPFC_RESET_WAIT) | ||
1237 | break; | ||
1238 | |||
1239 | cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, | 1225 | cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, |
1240 | cmnd->device->lun, LPFC_CTX_LUN); | 1226 | cmnd->device->lun, LPFC_CTX_TGT); |
1241 | } | 1227 | } |
1242 | |||
1243 | if (cnt) { | 1228 | if (cnt) { |
1244 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 1229 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
1245 | "0719 device reset I/O flush failure: " | 1230 | "0719 device reset I/O flush failure: " |
1246 | "cnt x%x\n", cnt); | 1231 | "cnt x%x\n", cnt); |
1247 | ret = FAILED; | 1232 | ret = FAILED; |
1248 | } | 1233 | } |
1249 | |||
1250 | out_free_scsi_buf: | ||
1251 | if (iocb_status != IOCB_TIMEDOUT) { | ||
1252 | lpfc_release_scsi_buf(phba, lpfc_cmd); | ||
1253 | } | ||
1254 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
1255 | "0713 SCSI layer issued device reset (%d, %d) " | ||
1256 | "return x%x status x%x result x%x\n", | ||
1257 | cmnd->device->id, cmnd->device->lun, ret, | ||
1258 | cmd_status, cmd_result); | ||
1259 | out: | ||
1260 | return ret; | 1234 | return ret; |
1261 | } | 1235 | } |
1262 | 1236 | ||
@@ -1268,19 +1242,12 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | |||
1268 | struct lpfc_hba *phba = vport->phba; | 1242 | struct lpfc_hba *phba = vport->phba; |
1269 | struct lpfc_nodelist *ndlp = NULL; | 1243 | struct lpfc_nodelist *ndlp = NULL; |
1270 | int match; | 1244 | int match; |
1271 | int ret = FAILED, i, err_count = 0; | 1245 | int ret = SUCCESS, status, i; |
1272 | int cnt, loopcnt; | 1246 | int cnt; |
1273 | struct lpfc_scsi_buf * lpfc_cmd; | 1247 | struct lpfc_scsi_buf * lpfc_cmd; |
1248 | unsigned long later; | ||
1274 | 1249 | ||
1275 | lpfc_block_error_handler(cmnd); | 1250 | lpfc_block_error_handler(cmnd); |
1276 | |||
1277 | lpfc_cmd = lpfc_get_scsi_buf(phba); | ||
1278 | if (lpfc_cmd == NULL) | ||
1279 | goto out; | ||
1280 | |||
1281 | /* The lpfc_cmd storage is reused. Set all loop invariants. */ | ||
1282 | lpfc_cmd->timeout = 60; | ||
1283 | |||
1284 | /* | 1251 | /* |
1285 | * Since the driver manages a single bus device, reset all | 1252 | * Since the driver manages a single bus device, reset all |
1286 | * targets known to the driver. Should any target reset | 1253 | * targets known to the driver. Should any target reset |
@@ -1294,7 +1261,7 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | |||
1294 | if (!NLP_CHK_NODE_ACT(ndlp)) | 1261 | if (!NLP_CHK_NODE_ACT(ndlp)) |
1295 | continue; | 1262 | continue; |
1296 | if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && | 1263 | if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && |
1297 | i == ndlp->nlp_sid && | 1264 | ndlp->nlp_sid == i && |
1298 | ndlp->rport) { | 1265 | ndlp->rport) { |
1299 | match = 1; | 1266 | match = 1; |
1300 | break; | 1267 | break; |
@@ -1303,27 +1270,22 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | |||
1303 | spin_unlock_irq(shost->host_lock); | 1270 | spin_unlock_irq(shost->host_lock); |
1304 | if (!match) | 1271 | if (!match) |
1305 | continue; | 1272 | continue; |
1306 | 1273 | lpfc_cmd = lpfc_get_scsi_buf(phba); | |
1307 | ret = lpfc_scsi_tgt_reset(lpfc_cmd, vport, i, | 1274 | if (lpfc_cmd) { |
1308 | cmnd->device->lun, | 1275 | lpfc_cmd->timeout = 60; |
1309 | ndlp->rport->dd_data); | 1276 | status = lpfc_scsi_tgt_reset(lpfc_cmd, vport, i, |
1310 | if (ret != SUCCESS) { | 1277 | cmnd->device->lun, |
1278 | ndlp->rport->dd_data); | ||
1279 | if (status != TIMEOUT_ERROR) | ||
1280 | lpfc_release_scsi_buf(phba, lpfc_cmd); | ||
1281 | } | ||
1282 | if (!lpfc_cmd || status != SUCCESS) { | ||
1311 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 1283 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
1312 | "0700 Bus Reset on target %d failed\n", | 1284 | "0700 Bus Reset on target %d failed\n", |
1313 | i); | 1285 | i); |
1314 | err_count++; | 1286 | ret = FAILED; |
1315 | break; | ||
1316 | } | 1287 | } |
1317 | } | 1288 | } |
1318 | |||
1319 | if (ret != IOCB_TIMEDOUT) | ||
1320 | lpfc_release_scsi_buf(phba, lpfc_cmd); | ||
1321 | |||
1322 | if (err_count == 0) | ||
1323 | ret = SUCCESS; | ||
1324 | else | ||
1325 | ret = FAILED; | ||
1326 | |||
1327 | /* | 1289 | /* |
1328 | * All outstanding txcmplq I/Os should have been aborted by | 1290 | * All outstanding txcmplq I/Os should have been aborted by |
1329 | * the targets. Unfortunately, some targets do not abide by | 1291 | * the targets. Unfortunately, some targets do not abide by |
@@ -1333,27 +1295,19 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | |||
1333 | if (cnt) | 1295 | if (cnt) |
1334 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], | 1296 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], |
1335 | 0, 0, LPFC_CTX_HOST); | 1297 | 0, 0, LPFC_CTX_HOST); |
1336 | loopcnt = 0; | 1298 | later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; |
1337 | while(cnt) { | 1299 | while (time_after(later, jiffies) && cnt) { |
1338 | schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ); | 1300 | schedule_timeout_uninterruptible(msecs_to_jiffies(20)); |
1339 | |||
1340 | if (++loopcnt | ||
1341 | > (2 * vport->cfg_devloss_tmo)/LPFC_RESET_WAIT) | ||
1342 | break; | ||
1343 | |||
1344 | cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST); | 1301 | cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST); |
1345 | } | 1302 | } |
1346 | |||
1347 | if (cnt) { | 1303 | if (cnt) { |
1348 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 1304 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
1349 | "0715 Bus Reset I/O flush failure: " | 1305 | "0715 Bus Reset I/O flush failure: " |
1350 | "cnt x%x left x%x\n", cnt, i); | 1306 | "cnt x%x left x%x\n", cnt, i); |
1351 | ret = FAILED; | 1307 | ret = FAILED; |
1352 | } | 1308 | } |
1353 | |||
1354 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 1309 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
1355 | "0714 SCSI layer issued Bus Reset Data: x%x\n", ret); | 1310 | "0714 SCSI layer issued Bus Reset Data: x%x\n", ret); |
1356 | out: | ||
1357 | return ret; | 1311 | return ret; |
1358 | } | 1312 | } |
1359 | 1313 | ||
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 70a0a9eab211..f40aa7b905f7 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -324,9 +324,7 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) | |||
324 | phba->work_ha |= HA_ERATT; | 324 | phba->work_ha |= HA_ERATT; |
325 | phba->work_hs = HS_FFER3; | 325 | phba->work_hs = HS_FFER3; |
326 | 326 | ||
327 | /* hbalock should already be held */ | 327 | lpfc_worker_wake_up(phba); |
328 | if (phba->work_wait) | ||
329 | lpfc_worker_wake_up(phba); | ||
330 | 328 | ||
331 | return NULL; | 329 | return NULL; |
332 | } | 330 | } |
@@ -1309,9 +1307,7 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) | |||
1309 | phba->work_ha |= HA_ERATT; | 1307 | phba->work_ha |= HA_ERATT; |
1310 | phba->work_hs = HS_FFER3; | 1308 | phba->work_hs = HS_FFER3; |
1311 | 1309 | ||
1312 | /* hbalock should already be held */ | 1310 | lpfc_worker_wake_up(phba); |
1313 | if (phba->work_wait) | ||
1314 | lpfc_worker_wake_up(phba); | ||
1315 | 1311 | ||
1316 | return; | 1312 | return; |
1317 | } | 1313 | } |
@@ -2611,12 +2607,9 @@ lpfc_mbox_timeout(unsigned long ptr) | |||
2611 | phba->pport->work_port_events |= WORKER_MBOX_TMO; | 2607 | phba->pport->work_port_events |= WORKER_MBOX_TMO; |
2612 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); | 2608 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); |
2613 | 2609 | ||
2614 | if (!tmo_posted) { | 2610 | if (!tmo_posted) |
2615 | spin_lock_irqsave(&phba->hbalock, iflag); | 2611 | lpfc_worker_wake_up(phba); |
2616 | if (phba->work_wait) | 2612 | return; |
2617 | lpfc_worker_wake_up(phba); | ||
2618 | spin_unlock_irqrestore(&phba->hbalock, iflag); | ||
2619 | } | ||
2620 | } | 2613 | } |
2621 | 2614 | ||
2622 | void | 2615 | void |
@@ -3374,8 +3367,12 @@ lpfc_sli_host_down(struct lpfc_vport *vport) | |||
3374 | for (i = 0; i < psli->num_rings; i++) { | 3367 | for (i = 0; i < psli->num_rings; i++) { |
3375 | pring = &psli->ring[i]; | 3368 | pring = &psli->ring[i]; |
3376 | prev_pring_flag = pring->flag; | 3369 | prev_pring_flag = pring->flag; |
3377 | if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */ | 3370 | /* Only slow rings */ |
3371 | if (pring->ringno == LPFC_ELS_RING) { | ||
3378 | pring->flag |= LPFC_DEFERRED_RING_EVENT; | 3372 | pring->flag |= LPFC_DEFERRED_RING_EVENT; |
3373 | /* Set the lpfc data pending flag */ | ||
3374 | set_bit(LPFC_DATA_READY, &phba->data_flags); | ||
3375 | } | ||
3379 | /* | 3376 | /* |
3380 | * Error everything on the txq since these iocbs have not been | 3377 | * Error everything on the txq since these iocbs have not been |
3381 | * given to the FW yet. | 3378 | * given to the FW yet. |
@@ -3434,8 +3431,12 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) | |||
3434 | spin_lock_irqsave(&phba->hbalock, flags); | 3431 | spin_lock_irqsave(&phba->hbalock, flags); |
3435 | for (i = 0; i < psli->num_rings; i++) { | 3432 | for (i = 0; i < psli->num_rings; i++) { |
3436 | pring = &psli->ring[i]; | 3433 | pring = &psli->ring[i]; |
3437 | if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */ | 3434 | /* Only slow rings */ |
3435 | if (pring->ringno == LPFC_ELS_RING) { | ||
3438 | pring->flag |= LPFC_DEFERRED_RING_EVENT; | 3436 | pring->flag |= LPFC_DEFERRED_RING_EVENT; |
3437 | /* Set the lpfc data pending flag */ | ||
3438 | set_bit(LPFC_DATA_READY, &phba->data_flags); | ||
3439 | } | ||
3439 | 3440 | ||
3440 | /* | 3441 | /* |
3441 | * Error everything on the txq since these iocbs have not been | 3442 | * Error everything on the txq since these iocbs have not been |
@@ -3762,7 +3763,6 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport, | |||
3762 | lpfc_ctx_cmd ctx_cmd) | 3763 | lpfc_ctx_cmd ctx_cmd) |
3763 | { | 3764 | { |
3764 | struct lpfc_scsi_buf *lpfc_cmd; | 3765 | struct lpfc_scsi_buf *lpfc_cmd; |
3765 | struct scsi_cmnd *cmnd; | ||
3766 | int rc = 1; | 3766 | int rc = 1; |
3767 | 3767 | ||
3768 | if (!(iocbq->iocb_flag & LPFC_IO_FCP)) | 3768 | if (!(iocbq->iocb_flag & LPFC_IO_FCP)) |
@@ -3772,19 +3772,20 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport, | |||
3772 | return rc; | 3772 | return rc; |
3773 | 3773 | ||
3774 | lpfc_cmd = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq); | 3774 | lpfc_cmd = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq); |
3775 | cmnd = lpfc_cmd->pCmd; | ||
3776 | 3775 | ||
3777 | if (cmnd == NULL) | 3776 | if (lpfc_cmd->pCmd == NULL) |
3778 | return rc; | 3777 | return rc; |
3779 | 3778 | ||
3780 | switch (ctx_cmd) { | 3779 | switch (ctx_cmd) { |
3781 | case LPFC_CTX_LUN: | 3780 | case LPFC_CTX_LUN: |
3782 | if ((cmnd->device->id == tgt_id) && | 3781 | if ((lpfc_cmd->rdata->pnode) && |
3783 | (cmnd->device->lun == lun_id)) | 3782 | (lpfc_cmd->rdata->pnode->nlp_sid == tgt_id) && |
3783 | (scsilun_to_int(&lpfc_cmd->fcp_cmnd->fcp_lun) == lun_id)) | ||
3784 | rc = 0; | 3784 | rc = 0; |
3785 | break; | 3785 | break; |
3786 | case LPFC_CTX_TGT: | 3786 | case LPFC_CTX_TGT: |
3787 | if (cmnd->device->id == tgt_id) | 3787 | if ((lpfc_cmd->rdata->pnode) && |
3788 | (lpfc_cmd->rdata->pnode->nlp_sid == tgt_id)) | ||
3788 | rc = 0; | 3789 | rc = 0; |
3789 | break; | 3790 | break; |
3790 | case LPFC_CTX_HOST: | 3791 | case LPFC_CTX_HOST: |
@@ -3994,6 +3995,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, | |||
3994 | if (pmboxq->context1) | 3995 | if (pmboxq->context1) |
3995 | return MBX_NOT_FINISHED; | 3996 | return MBX_NOT_FINISHED; |
3996 | 3997 | ||
3998 | pmboxq->mbox_flag &= ~LPFC_MBX_WAKE; | ||
3997 | /* setup wake call as IOCB callback */ | 3999 | /* setup wake call as IOCB callback */ |
3998 | pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait; | 4000 | pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait; |
3999 | /* setup context field to pass wait_queue pointer to wake function */ | 4001 | /* setup context field to pass wait_queue pointer to wake function */ |
@@ -4159,7 +4161,7 @@ lpfc_intr_handler(int irq, void *dev_id) | |||
4159 | "pwork:x%x hawork:x%x wait:x%x", | 4161 | "pwork:x%x hawork:x%x wait:x%x", |
4160 | phba->work_ha, work_ha_copy, | 4162 | phba->work_ha, work_ha_copy, |
4161 | (uint32_t)((unsigned long) | 4163 | (uint32_t)((unsigned long) |
4162 | phba->work_wait)); | 4164 | &phba->work_waitq)); |
4163 | 4165 | ||
4164 | control &= | 4166 | control &= |
4165 | ~(HC_R0INT_ENA << LPFC_ELS_RING); | 4167 | ~(HC_R0INT_ENA << LPFC_ELS_RING); |
@@ -4172,7 +4174,7 @@ lpfc_intr_handler(int irq, void *dev_id) | |||
4172 | "x%x hawork:x%x wait:x%x", | 4174 | "x%x hawork:x%x wait:x%x", |
4173 | phba->work_ha, work_ha_copy, | 4175 | phba->work_ha, work_ha_copy, |
4174 | (uint32_t)((unsigned long) | 4176 | (uint32_t)((unsigned long) |
4175 | phba->work_wait)); | 4177 | &phba->work_waitq)); |
4176 | } | 4178 | } |
4177 | spin_unlock(&phba->hbalock); | 4179 | spin_unlock(&phba->hbalock); |
4178 | } | 4180 | } |
@@ -4297,9 +4299,8 @@ send_current_mbox: | |||
4297 | 4299 | ||
4298 | spin_lock(&phba->hbalock); | 4300 | spin_lock(&phba->hbalock); |
4299 | phba->work_ha |= work_ha_copy; | 4301 | phba->work_ha |= work_ha_copy; |
4300 | if (phba->work_wait) | ||
4301 | lpfc_worker_wake_up(phba); | ||
4302 | spin_unlock(&phba->hbalock); | 4302 | spin_unlock(&phba->hbalock); |
4303 | lpfc_worker_wake_up(phba); | ||
4303 | } | 4304 | } |
4304 | 4305 | ||
4305 | ha_copy &= ~(phba->work_ha_mask); | 4306 | ha_copy &= ~(phba->work_ha_mask); |
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index b22b893019f4..ad24cacfbe10 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h | |||
@@ -18,7 +18,7 @@ | |||
18 | * included with this package. * | 18 | * included with this package. * |
19 | *******************************************************************/ | 19 | *******************************************************************/ |
20 | 20 | ||
21 | #define LPFC_DRIVER_VERSION "8.2.6" | 21 | #define LPFC_DRIVER_VERSION "8.2.7" |
22 | 22 | ||
23 | #define LPFC_DRIVER_NAME "lpfc" | 23 | #define LPFC_DRIVER_NAME "lpfc" |
24 | 24 | ||
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 6feaf59b0b1b..109f89d98830 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c | |||
@@ -216,6 +216,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) | |||
216 | int vpi; | 216 | int vpi; |
217 | int rc = VPORT_ERROR; | 217 | int rc = VPORT_ERROR; |
218 | int status; | 218 | int status; |
219 | int size; | ||
219 | 220 | ||
220 | if ((phba->sli_rev < 3) || | 221 | if ((phba->sli_rev < 3) || |
221 | !(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { | 222 | !(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { |
@@ -278,7 +279,20 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) | |||
278 | 279 | ||
279 | memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8); | 280 | memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8); |
280 | memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8); | 281 | memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8); |
281 | 282 | size = strnlen(fc_vport->symbolic_name, LPFC_VNAME_LEN); | |
283 | if (size) { | ||
284 | vport->vname = kzalloc(size+1, GFP_KERNEL); | ||
285 | if (!vport->vname) { | ||
286 | lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, | ||
287 | "1814 Create VPORT failed. " | ||
288 | "vname allocation failed.\n"); | ||
289 | rc = VPORT_ERROR; | ||
290 | lpfc_free_vpi(phba, vpi); | ||
291 | destroy_port(vport); | ||
292 | goto error_out; | ||
293 | } | ||
294 | memcpy(vport->vname, fc_vport->symbolic_name, size+1); | ||
295 | } | ||
282 | if (fc_vport->node_name != 0) | 296 | if (fc_vport->node_name != 0) |
283 | u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn); | 297 | u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn); |
284 | if (fc_vport->port_name != 0) | 298 | if (fc_vport->port_name != 0) |
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index fd63b06d9ef1..11aa917629ac 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c | |||
@@ -1765,7 +1765,7 @@ static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg) | |||
1765 | default: | 1765 | default: |
1766 | return 0; | 1766 | return 0; |
1767 | } | 1767 | } |
1768 | if (mesg.event == mdev->ofdev.dev.power.power_state.event) | 1768 | if (ms->phase == sleeping) |
1769 | return 0; | 1769 | return 0; |
1770 | 1770 | ||
1771 | scsi_block_requests(ms->host); | 1771 | scsi_block_requests(ms->host); |
@@ -1780,8 +1780,6 @@ static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg) | |||
1780 | disable_irq(ms->meshintr); | 1780 | disable_irq(ms->meshintr); |
1781 | set_mesh_power(ms, 0); | 1781 | set_mesh_power(ms, 0); |
1782 | 1782 | ||
1783 | mdev->ofdev.dev.power.power_state = mesg; | ||
1784 | |||
1785 | return 0; | 1783 | return 0; |
1786 | } | 1784 | } |
1787 | 1785 | ||
@@ -1790,7 +1788,7 @@ static int mesh_resume(struct macio_dev *mdev) | |||
1790 | struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); | 1788 | struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); |
1791 | unsigned long flags; | 1789 | unsigned long flags; |
1792 | 1790 | ||
1793 | if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON) | 1791 | if (ms->phase != sleeping) |
1794 | return 0; | 1792 | return 0; |
1795 | 1793 | ||
1796 | set_mesh_power(ms, 1); | 1794 | set_mesh_power(ms, 1); |
@@ -1801,8 +1799,6 @@ static int mesh_resume(struct macio_dev *mdev) | |||
1801 | enable_irq(ms->meshintr); | 1799 | enable_irq(ms->meshintr); |
1802 | scsi_unblock_requests(ms->host); | 1800 | scsi_unblock_requests(ms->host); |
1803 | 1801 | ||
1804 | mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON; | ||
1805 | |||
1806 | return 0; | 1802 | return 0; |
1807 | } | 1803 | } |
1808 | 1804 | ||
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 0c786944d2c2..5822dd595826 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
@@ -113,9 +113,6 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { | |||
113 | .host_param_mask = ISCSI_HOST_HWADDRESS | | 113 | .host_param_mask = ISCSI_HOST_HWADDRESS | |
114 | ISCSI_HOST_IPADDRESS | | 114 | ISCSI_HOST_IPADDRESS | |
115 | ISCSI_HOST_INITIATOR_NAME, | 115 | ISCSI_HOST_INITIATOR_NAME, |
116 | .sessiondata_size = sizeof(struct ddb_entry), | ||
117 | .host_template = &qla4xxx_driver_template, | ||
118 | |||
119 | .tgt_dscvr = qla4xxx_tgt_dscvr, | 116 | .tgt_dscvr = qla4xxx_tgt_dscvr, |
120 | .get_conn_param = qla4xxx_conn_get_param, | 117 | .get_conn_param = qla4xxx_conn_get_param, |
121 | .get_session_param = qla4xxx_sess_get_param, | 118 | .get_session_param = qla4xxx_sess_get_param, |
@@ -275,7 +272,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) | |||
275 | return err; | 272 | return err; |
276 | } | 273 | } |
277 | 274 | ||
278 | ddb_entry->conn = iscsi_create_conn(ddb_entry->sess, 0); | 275 | ddb_entry->conn = iscsi_create_conn(ddb_entry->sess, 0, 0); |
279 | if (!ddb_entry->conn) { | 276 | if (!ddb_entry->conn) { |
280 | iscsi_remove_session(ddb_entry->sess); | 277 | iscsi_remove_session(ddb_entry->sess); |
281 | DEBUG2(printk(KERN_ERR "Could not add connection.\n")); | 278 | DEBUG2(printk(KERN_ERR "Could not add connection.\n")); |
@@ -292,7 +289,8 @@ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha) | |||
292 | struct ddb_entry *ddb_entry; | 289 | struct ddb_entry *ddb_entry; |
293 | struct iscsi_cls_session *sess; | 290 | struct iscsi_cls_session *sess; |
294 | 291 | ||
295 | sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport); | 292 | sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport, |
293 | sizeof(struct ddb_entry)); | ||
296 | if (!sess) | 294 | if (!sess) |
297 | return NULL; | 295 | return NULL; |
298 | 296 | ||
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 110e776d1a07..36c92f961e15 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
@@ -855,9 +855,18 @@ void scsi_finish_command(struct scsi_cmnd *cmd) | |||
855 | 855 | ||
856 | good_bytes = scsi_bufflen(cmd); | 856 | good_bytes = scsi_bufflen(cmd); |
857 | if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { | 857 | if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { |
858 | int old_good_bytes = good_bytes; | ||
858 | drv = scsi_cmd_to_driver(cmd); | 859 | drv = scsi_cmd_to_driver(cmd); |
859 | if (drv->done) | 860 | if (drv->done) |
860 | good_bytes = drv->done(cmd); | 861 | good_bytes = drv->done(cmd); |
862 | /* | ||
863 | * USB may not give sense identifying bad sector and | ||
864 | * simply return a residue instead, so subtract off the | ||
865 | * residue if drv->done() error processing indicates no | ||
866 | * change to the completion length. | ||
867 | */ | ||
868 | if (good_bytes == old_good_bytes) | ||
869 | good_bytes -= scsi_get_resid(cmd); | ||
861 | } | 870 | } |
862 | scsi_io_completion(cmd, good_bytes); | 871 | scsi_io_completion(cmd, good_bytes); |
863 | } | 872 | } |
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index f6600bfb5bde..01d11a01ffbf 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -94,6 +94,7 @@ static const char * scsi_debug_version_date = "20070104"; | |||
94 | #define DEF_VIRTUAL_GB 0 | 94 | #define DEF_VIRTUAL_GB 0 |
95 | #define DEF_FAKE_RW 0 | 95 | #define DEF_FAKE_RW 0 |
96 | #define DEF_VPD_USE_HOSTNO 1 | 96 | #define DEF_VPD_USE_HOSTNO 1 |
97 | #define DEF_SECTOR_SIZE 512 | ||
97 | 98 | ||
98 | /* bit mask values for scsi_debug_opts */ | 99 | /* bit mask values for scsi_debug_opts */ |
99 | #define SCSI_DEBUG_OPT_NOISE 1 | 100 | #define SCSI_DEBUG_OPT_NOISE 1 |
@@ -142,6 +143,7 @@ static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; | |||
142 | static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; | 143 | static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; |
143 | static int scsi_debug_fake_rw = DEF_FAKE_RW; | 144 | static int scsi_debug_fake_rw = DEF_FAKE_RW; |
144 | static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; | 145 | static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; |
146 | static int scsi_debug_sector_size = DEF_SECTOR_SIZE; | ||
145 | 147 | ||
146 | static int scsi_debug_cmnd_count = 0; | 148 | static int scsi_debug_cmnd_count = 0; |
147 | 149 | ||
@@ -157,11 +159,6 @@ static int sdebug_heads; /* heads per disk */ | |||
157 | static int sdebug_cylinders_per; /* cylinders per surface */ | 159 | static int sdebug_cylinders_per; /* cylinders per surface */ |
158 | static int sdebug_sectors_per; /* sectors per cylinder */ | 160 | static int sdebug_sectors_per; /* sectors per cylinder */ |
159 | 161 | ||
160 | /* default sector size is 512 bytes, 2**9 bytes */ | ||
161 | #define POW2_SECT_SIZE 9 | ||
162 | #define SECT_SIZE (1 << POW2_SECT_SIZE) | ||
163 | #define SECT_SIZE_PER(TGT) SECT_SIZE | ||
164 | |||
165 | #define SDEBUG_MAX_PARTS 4 | 162 | #define SDEBUG_MAX_PARTS 4 |
166 | 163 | ||
167 | #define SDEBUG_SENSE_LEN 32 | 164 | #define SDEBUG_SENSE_LEN 32 |
@@ -646,6 +643,14 @@ static int inquiry_evpd_b0(unsigned char * arr) | |||
646 | return sizeof(vpdb0_data); | 643 | return sizeof(vpdb0_data); |
647 | } | 644 | } |
648 | 645 | ||
646 | static int inquiry_evpd_b1(unsigned char *arr) | ||
647 | { | ||
648 | memset(arr, 0, 0x3c); | ||
649 | arr[0] = 0; | ||
650 | arr[1] = 1; | ||
651 | |||
652 | return 0x3c; | ||
653 | } | ||
649 | 654 | ||
650 | #define SDEBUG_LONG_INQ_SZ 96 | 655 | #define SDEBUG_LONG_INQ_SZ 96 |
651 | #define SDEBUG_MAX_INQ_ARR_SZ 584 | 656 | #define SDEBUG_MAX_INQ_ARR_SZ 584 |
@@ -701,6 +706,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
701 | arr[n++] = 0x88; /* SCSI ports */ | 706 | arr[n++] = 0x88; /* SCSI ports */ |
702 | arr[n++] = 0x89; /* ATA information */ | 707 | arr[n++] = 0x89; /* ATA information */ |
703 | arr[n++] = 0xb0; /* Block limits (SBC) */ | 708 | arr[n++] = 0xb0; /* Block limits (SBC) */ |
709 | arr[n++] = 0xb1; /* Block characteristics (SBC) */ | ||
704 | arr[3] = n - 4; /* number of supported VPD pages */ | 710 | arr[3] = n - 4; /* number of supported VPD pages */ |
705 | } else if (0x80 == cmd[2]) { /* unit serial number */ | 711 | } else if (0x80 == cmd[2]) { /* unit serial number */ |
706 | arr[1] = cmd[2]; /*sanity */ | 712 | arr[1] = cmd[2]; /*sanity */ |
@@ -740,6 +746,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
740 | } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ | 746 | } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ |
741 | arr[1] = cmd[2]; /*sanity */ | 747 | arr[1] = cmd[2]; /*sanity */ |
742 | arr[3] = inquiry_evpd_b0(&arr[4]); | 748 | arr[3] = inquiry_evpd_b0(&arr[4]); |
749 | } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ | ||
750 | arr[1] = cmd[2]; /*sanity */ | ||
751 | arr[3] = inquiry_evpd_b1(&arr[4]); | ||
743 | } else { | 752 | } else { |
744 | /* Illegal request, invalid field in cdb */ | 753 | /* Illegal request, invalid field in cdb */ |
745 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | 754 | mk_sense_buffer(devip, ILLEGAL_REQUEST, |
@@ -878,8 +887,8 @@ static int resp_readcap(struct scsi_cmnd * scp, | |||
878 | arr[2] = 0xff; | 887 | arr[2] = 0xff; |
879 | arr[3] = 0xff; | 888 | arr[3] = 0xff; |
880 | } | 889 | } |
881 | arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; | 890 | arr[6] = (scsi_debug_sector_size >> 8) & 0xff; |
882 | arr[7] = SECT_SIZE_PER(target) & 0xff; | 891 | arr[7] = scsi_debug_sector_size & 0xff; |
883 | return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); | 892 | return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); |
884 | } | 893 | } |
885 | 894 | ||
@@ -902,10 +911,10 @@ static int resp_readcap16(struct scsi_cmnd * scp, | |||
902 | capac = sdebug_capacity - 1; | 911 | capac = sdebug_capacity - 1; |
903 | for (k = 0; k < 8; ++k, capac >>= 8) | 912 | for (k = 0; k < 8; ++k, capac >>= 8) |
904 | arr[7 - k] = capac & 0xff; | 913 | arr[7 - k] = capac & 0xff; |
905 | arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff; | 914 | arr[8] = (scsi_debug_sector_size >> 24) & 0xff; |
906 | arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff; | 915 | arr[9] = (scsi_debug_sector_size >> 16) & 0xff; |
907 | arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff; | 916 | arr[10] = (scsi_debug_sector_size >> 8) & 0xff; |
908 | arr[11] = SECT_SIZE_PER(target) & 0xff; | 917 | arr[11] = scsi_debug_sector_size & 0xff; |
909 | return fill_from_dev_buffer(scp, arr, | 918 | return fill_from_dev_buffer(scp, arr, |
910 | min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); | 919 | min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); |
911 | } | 920 | } |
@@ -1019,20 +1028,20 @@ static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) | |||
1019 | 1028 | ||
1020 | static int resp_format_pg(unsigned char * p, int pcontrol, int target) | 1029 | static int resp_format_pg(unsigned char * p, int pcontrol, int target) |
1021 | { /* Format device page for mode_sense */ | 1030 | { /* Format device page for mode_sense */ |
1022 | unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, | 1031 | unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, |
1023 | 0, 0, 0, 0, 0, 0, 0, 0, | 1032 | 0, 0, 0, 0, 0, 0, 0, 0, |
1024 | 0, 0, 0, 0, 0x40, 0, 0, 0}; | 1033 | 0, 0, 0, 0, 0x40, 0, 0, 0}; |
1025 | 1034 | ||
1026 | memcpy(p, format_pg, sizeof(format_pg)); | 1035 | memcpy(p, format_pg, sizeof(format_pg)); |
1027 | p[10] = (sdebug_sectors_per >> 8) & 0xff; | 1036 | p[10] = (sdebug_sectors_per >> 8) & 0xff; |
1028 | p[11] = sdebug_sectors_per & 0xff; | 1037 | p[11] = sdebug_sectors_per & 0xff; |
1029 | p[12] = (SECT_SIZE >> 8) & 0xff; | 1038 | p[12] = (scsi_debug_sector_size >> 8) & 0xff; |
1030 | p[13] = SECT_SIZE & 0xff; | 1039 | p[13] = scsi_debug_sector_size & 0xff; |
1031 | if (DEV_REMOVEABLE(target)) | 1040 | if (DEV_REMOVEABLE(target)) |
1032 | p[20] |= 0x20; /* should agree with INQUIRY */ | 1041 | p[20] |= 0x20; /* should agree with INQUIRY */ |
1033 | if (1 == pcontrol) | 1042 | if (1 == pcontrol) |
1034 | memset(p + 2, 0, sizeof(format_pg) - 2); | 1043 | memset(p + 2, 0, sizeof(format_pg) - 2); |
1035 | return sizeof(format_pg); | 1044 | return sizeof(format_pg); |
1036 | } | 1045 | } |
1037 | 1046 | ||
1038 | static int resp_caching_pg(unsigned char * p, int pcontrol, int target) | 1047 | static int resp_caching_pg(unsigned char * p, int pcontrol, int target) |
@@ -1206,8 +1215,8 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, | |||
1206 | ap[2] = (sdebug_capacity >> 8) & 0xff; | 1215 | ap[2] = (sdebug_capacity >> 8) & 0xff; |
1207 | ap[3] = sdebug_capacity & 0xff; | 1216 | ap[3] = sdebug_capacity & 0xff; |
1208 | } | 1217 | } |
1209 | ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; | 1218 | ap[6] = (scsi_debug_sector_size >> 8) & 0xff; |
1210 | ap[7] = SECT_SIZE_PER(target) & 0xff; | 1219 | ap[7] = scsi_debug_sector_size & 0xff; |
1211 | offset += bd_len; | 1220 | offset += bd_len; |
1212 | ap = arr + offset; | 1221 | ap = arr + offset; |
1213 | } else if (16 == bd_len) { | 1222 | } else if (16 == bd_len) { |
@@ -1215,10 +1224,10 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, | |||
1215 | 1224 | ||
1216 | for (k = 0; k < 8; ++k, capac >>= 8) | 1225 | for (k = 0; k < 8; ++k, capac >>= 8) |
1217 | ap[7 - k] = capac & 0xff; | 1226 | ap[7 - k] = capac & 0xff; |
1218 | ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff; | 1227 | ap[12] = (scsi_debug_sector_size >> 24) & 0xff; |
1219 | ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff; | 1228 | ap[13] = (scsi_debug_sector_size >> 16) & 0xff; |
1220 | ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff; | 1229 | ap[14] = (scsi_debug_sector_size >> 8) & 0xff; |
1221 | ap[15] = SECT_SIZE_PER(target) & 0xff; | 1230 | ap[15] = scsi_debug_sector_size & 0xff; |
1222 | offset += bd_len; | 1231 | offset += bd_len; |
1223 | ap = arr + offset; | 1232 | ap = arr + offset; |
1224 | } | 1233 | } |
@@ -1519,10 +1528,10 @@ static int do_device_access(struct scsi_cmnd *scmd, | |||
1519 | if (block + num > sdebug_store_sectors) | 1528 | if (block + num > sdebug_store_sectors) |
1520 | rest = block + num - sdebug_store_sectors; | 1529 | rest = block + num - sdebug_store_sectors; |
1521 | 1530 | ||
1522 | ret = func(scmd, fake_storep + (block * SECT_SIZE), | 1531 | ret = func(scmd, fake_storep + (block * scsi_debug_sector_size), |
1523 | (num - rest) * SECT_SIZE); | 1532 | (num - rest) * scsi_debug_sector_size); |
1524 | if (!ret && rest) | 1533 | if (!ret && rest) |
1525 | ret = func(scmd, fake_storep, rest * SECT_SIZE); | 1534 | ret = func(scmd, fake_storep, rest * scsi_debug_sector_size); |
1526 | 1535 | ||
1527 | return ret; | 1536 | return ret; |
1528 | } | 1537 | } |
@@ -1575,10 +1584,10 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, | |||
1575 | write_unlock_irqrestore(&atomic_rw, iflags); | 1584 | write_unlock_irqrestore(&atomic_rw, iflags); |
1576 | if (-1 == ret) | 1585 | if (-1 == ret) |
1577 | return (DID_ERROR << 16); | 1586 | return (DID_ERROR << 16); |
1578 | else if ((ret < (num * SECT_SIZE)) && | 1587 | else if ((ret < (num * scsi_debug_sector_size)) && |
1579 | (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) | 1588 | (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) |
1580 | printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " | 1589 | printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " |
1581 | " IO sent=%d bytes\n", num * SECT_SIZE, ret); | 1590 | " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); |
1582 | return 0; | 1591 | return 0; |
1583 | } | 1592 | } |
1584 | 1593 | ||
@@ -2085,6 +2094,7 @@ module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); | |||
2085 | module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); | 2094 | module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); |
2086 | module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, | 2095 | module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, |
2087 | S_IRUGO | S_IWUSR); | 2096 | S_IRUGO | S_IWUSR); |
2097 | module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); | ||
2088 | 2098 | ||
2089 | MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); | 2099 | MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); |
2090 | MODULE_DESCRIPTION("SCSI debug adapter driver"); | 2100 | MODULE_DESCRIPTION("SCSI debug adapter driver"); |
@@ -2106,6 +2116,7 @@ MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); | |||
2106 | MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); | 2116 | MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); |
2107 | MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); | 2117 | MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); |
2108 | MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); | 2118 | MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); |
2119 | MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)"); | ||
2109 | 2120 | ||
2110 | 2121 | ||
2111 | static char sdebug_info[256]; | 2122 | static char sdebug_info[256]; |
@@ -2158,8 +2169,9 @@ static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **sta | |||
2158 | scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, | 2169 | scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, |
2159 | scsi_debug_cmnd_count, scsi_debug_delay, | 2170 | scsi_debug_cmnd_count, scsi_debug_delay, |
2160 | scsi_debug_max_luns, scsi_debug_scsi_level, | 2171 | scsi_debug_max_luns, scsi_debug_scsi_level, |
2161 | SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, | 2172 | scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, |
2162 | num_aborts, num_dev_resets, num_bus_resets, num_host_resets); | 2173 | sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets, |
2174 | num_host_resets); | ||
2163 | if (pos < offset) { | 2175 | if (pos < offset) { |
2164 | len = 0; | 2176 | len = 0; |
2165 | begin = pos; | 2177 | begin = pos; |
@@ -2434,6 +2446,12 @@ static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp, | |||
2434 | DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, | 2446 | DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, |
2435 | sdebug_vpd_use_hostno_store); | 2447 | sdebug_vpd_use_hostno_store); |
2436 | 2448 | ||
2449 | static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf) | ||
2450 | { | ||
2451 | return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size); | ||
2452 | } | ||
2453 | DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL); | ||
2454 | |||
2437 | /* Note: The following function creates attribute files in the | 2455 | /* Note: The following function creates attribute files in the |
2438 | /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these | 2456 | /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these |
2439 | files (over those found in the /sys/module/scsi_debug/parameters | 2457 | files (over those found in the /sys/module/scsi_debug/parameters |
@@ -2459,11 +2477,13 @@ static int do_create_driverfs_files(void) | |||
2459 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); | 2477 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); |
2460 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); | 2478 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); |
2461 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); | 2479 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); |
2480 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size); | ||
2462 | return ret; | 2481 | return ret; |
2463 | } | 2482 | } |
2464 | 2483 | ||
2465 | static void do_remove_driverfs_files(void) | 2484 | static void do_remove_driverfs_files(void) |
2466 | { | 2485 | { |
2486 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size); | ||
2467 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); | 2487 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); |
2468 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); | 2488 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); |
2469 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); | 2489 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); |
@@ -2499,10 +2519,22 @@ static int __init scsi_debug_init(void) | |||
2499 | int k; | 2519 | int k; |
2500 | int ret; | 2520 | int ret; |
2501 | 2521 | ||
2522 | switch (scsi_debug_sector_size) { | ||
2523 | case 512: | ||
2524 | case 1024: | ||
2525 | case 2048: | ||
2526 | case 4096: | ||
2527 | break; | ||
2528 | default: | ||
2529 | printk(KERN_ERR "scsi_debug_init: invalid sector_size %u\n", | ||
2530 | scsi_debug_sector_size); | ||
2531 | return -EINVAL; | ||
2532 | } | ||
2533 | |||
2502 | if (scsi_debug_dev_size_mb < 1) | 2534 | if (scsi_debug_dev_size_mb < 1) |
2503 | scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ | 2535 | scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ |
2504 | sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; | 2536 | sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; |
2505 | sdebug_store_sectors = sz / SECT_SIZE; | 2537 | sdebug_store_sectors = sz / scsi_debug_sector_size; |
2506 | sdebug_capacity = get_sdebug_capacity(); | 2538 | sdebug_capacity = get_sdebug_capacity(); |
2507 | 2539 | ||
2508 | /* play around with geometry, don't waste too much on track 0 */ | 2540 | /* play around with geometry, don't waste too much on track 0 */ |
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index eaf5a8add1ba..006a95916f72 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c | |||
@@ -298,6 +298,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost, | |||
298 | */ | 298 | */ |
299 | static int scsi_check_sense(struct scsi_cmnd *scmd) | 299 | static int scsi_check_sense(struct scsi_cmnd *scmd) |
300 | { | 300 | { |
301 | struct scsi_device *sdev = scmd->device; | ||
301 | struct scsi_sense_hdr sshdr; | 302 | struct scsi_sense_hdr sshdr; |
302 | 303 | ||
303 | if (! scsi_command_normalize_sense(scmd, &sshdr)) | 304 | if (! scsi_command_normalize_sense(scmd, &sshdr)) |
@@ -306,6 +307,16 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) | |||
306 | if (scsi_sense_is_deferred(&sshdr)) | 307 | if (scsi_sense_is_deferred(&sshdr)) |
307 | return NEEDS_RETRY; | 308 | return NEEDS_RETRY; |
308 | 309 | ||
310 | if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh && | ||
311 | sdev->scsi_dh_data->scsi_dh->check_sense) { | ||
312 | int rc; | ||
313 | |||
314 | rc = sdev->scsi_dh_data->scsi_dh->check_sense(sdev, &sshdr); | ||
315 | if (rc != SCSI_RETURN_NOT_HANDLED) | ||
316 | return rc; | ||
317 | /* handler does not care. Drop down to default handling */ | ||
318 | } | ||
319 | |||
309 | /* | 320 | /* |
310 | * Previous logic looked for FILEMARK, EOM or ILI which are | 321 | * Previous logic looked for FILEMARK, EOM or ILI which are |
311 | * mainly associated with tapes and returned SUCCESS. | 322 | * mainly associated with tapes and returned SUCCESS. |
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index cbf55d59a54c..88d1b5f44e59 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -65,7 +65,7 @@ static struct scsi_host_sg_pool scsi_sg_pools[] = { | |||
65 | }; | 65 | }; |
66 | #undef SP | 66 | #undef SP |
67 | 67 | ||
68 | static struct kmem_cache *scsi_bidi_sdb_cache; | 68 | static struct kmem_cache *scsi_sdb_cache; |
69 | 69 | ||
70 | static void scsi_run_queue(struct request_queue *q); | 70 | static void scsi_run_queue(struct request_queue *q); |
71 | 71 | ||
@@ -784,7 +784,7 @@ void scsi_release_buffers(struct scsi_cmnd *cmd) | |||
784 | struct scsi_data_buffer *bidi_sdb = | 784 | struct scsi_data_buffer *bidi_sdb = |
785 | cmd->request->next_rq->special; | 785 | cmd->request->next_rq->special; |
786 | scsi_free_sgtable(bidi_sdb); | 786 | scsi_free_sgtable(bidi_sdb); |
787 | kmem_cache_free(scsi_bidi_sdb_cache, bidi_sdb); | 787 | kmem_cache_free(scsi_sdb_cache, bidi_sdb); |
788 | cmd->request->next_rq->special = NULL; | 788 | cmd->request->next_rq->special = NULL; |
789 | } | 789 | } |
790 | } | 790 | } |
@@ -1059,7 +1059,7 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) | |||
1059 | 1059 | ||
1060 | if (blk_bidi_rq(cmd->request)) { | 1060 | if (blk_bidi_rq(cmd->request)) { |
1061 | struct scsi_data_buffer *bidi_sdb = kmem_cache_zalloc( | 1061 | struct scsi_data_buffer *bidi_sdb = kmem_cache_zalloc( |
1062 | scsi_bidi_sdb_cache, GFP_ATOMIC); | 1062 | scsi_sdb_cache, GFP_ATOMIC); |
1063 | if (!bidi_sdb) { | 1063 | if (!bidi_sdb) { |
1064 | error = BLKPREP_DEFER; | 1064 | error = BLKPREP_DEFER; |
1065 | goto err_exit; | 1065 | goto err_exit; |
@@ -1169,6 +1169,14 @@ int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) | |||
1169 | 1169 | ||
1170 | if (ret != BLKPREP_OK) | 1170 | if (ret != BLKPREP_OK) |
1171 | return ret; | 1171 | return ret; |
1172 | |||
1173 | if (unlikely(sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh | ||
1174 | && sdev->scsi_dh_data->scsi_dh->prep_fn)) { | ||
1175 | ret = sdev->scsi_dh_data->scsi_dh->prep_fn(sdev, req); | ||
1176 | if (ret != BLKPREP_OK) | ||
1177 | return ret; | ||
1178 | } | ||
1179 | |||
1172 | /* | 1180 | /* |
1173 | * Filesystem requests must transfer data. | 1181 | * Filesystem requests must transfer data. |
1174 | */ | 1182 | */ |
@@ -1329,7 +1337,6 @@ static inline int scsi_host_queue_ready(struct request_queue *q, | |||
1329 | printk("scsi%d unblocking host at zero depth\n", | 1337 | printk("scsi%d unblocking host at zero depth\n", |
1330 | shost->host_no)); | 1338 | shost->host_no)); |
1331 | } else { | 1339 | } else { |
1332 | blk_plug_device(q); | ||
1333 | return 0; | 1340 | return 0; |
1334 | } | 1341 | } |
1335 | } | 1342 | } |
@@ -1693,11 +1700,11 @@ int __init scsi_init_queue(void) | |||
1693 | return -ENOMEM; | 1700 | return -ENOMEM; |
1694 | } | 1701 | } |
1695 | 1702 | ||
1696 | scsi_bidi_sdb_cache = kmem_cache_create("scsi_bidi_sdb", | 1703 | scsi_sdb_cache = kmem_cache_create("scsi_data_buffer", |
1697 | sizeof(struct scsi_data_buffer), | 1704 | sizeof(struct scsi_data_buffer), |
1698 | 0, 0, NULL); | 1705 | 0, 0, NULL); |
1699 | if (!scsi_bidi_sdb_cache) { | 1706 | if (!scsi_sdb_cache) { |
1700 | printk(KERN_ERR "SCSI: can't init scsi bidi sdb cache\n"); | 1707 | printk(KERN_ERR "SCSI: can't init scsi sdb cache\n"); |
1701 | goto cleanup_io_context; | 1708 | goto cleanup_io_context; |
1702 | } | 1709 | } |
1703 | 1710 | ||
@@ -1710,7 +1717,7 @@ int __init scsi_init_queue(void) | |||
1710 | if (!sgp->slab) { | 1717 | if (!sgp->slab) { |
1711 | printk(KERN_ERR "SCSI: can't init sg slab %s\n", | 1718 | printk(KERN_ERR "SCSI: can't init sg slab %s\n", |
1712 | sgp->name); | 1719 | sgp->name); |
1713 | goto cleanup_bidi_sdb; | 1720 | goto cleanup_sdb; |
1714 | } | 1721 | } |
1715 | 1722 | ||
1716 | sgp->pool = mempool_create_slab_pool(SG_MEMPOOL_SIZE, | 1723 | sgp->pool = mempool_create_slab_pool(SG_MEMPOOL_SIZE, |
@@ -1718,13 +1725,13 @@ int __init scsi_init_queue(void) | |||
1718 | if (!sgp->pool) { | 1725 | if (!sgp->pool) { |
1719 | printk(KERN_ERR "SCSI: can't init sg mempool %s\n", | 1726 | printk(KERN_ERR "SCSI: can't init sg mempool %s\n", |
1720 | sgp->name); | 1727 | sgp->name); |
1721 | goto cleanup_bidi_sdb; | 1728 | goto cleanup_sdb; |
1722 | } | 1729 | } |
1723 | } | 1730 | } |
1724 | 1731 | ||
1725 | return 0; | 1732 | return 0; |
1726 | 1733 | ||
1727 | cleanup_bidi_sdb: | 1734 | cleanup_sdb: |
1728 | for (i = 0; i < SG_MEMPOOL_NR; i++) { | 1735 | for (i = 0; i < SG_MEMPOOL_NR; i++) { |
1729 | struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; | 1736 | struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; |
1730 | if (sgp->pool) | 1737 | if (sgp->pool) |
@@ -1732,7 +1739,7 @@ cleanup_bidi_sdb: | |||
1732 | if (sgp->slab) | 1739 | if (sgp->slab) |
1733 | kmem_cache_destroy(sgp->slab); | 1740 | kmem_cache_destroy(sgp->slab); |
1734 | } | 1741 | } |
1735 | kmem_cache_destroy(scsi_bidi_sdb_cache); | 1742 | kmem_cache_destroy(scsi_sdb_cache); |
1736 | cleanup_io_context: | 1743 | cleanup_io_context: |
1737 | kmem_cache_destroy(scsi_io_context_cache); | 1744 | kmem_cache_destroy(scsi_io_context_cache); |
1738 | 1745 | ||
@@ -1744,7 +1751,7 @@ void scsi_exit_queue(void) | |||
1744 | int i; | 1751 | int i; |
1745 | 1752 | ||
1746 | kmem_cache_destroy(scsi_io_context_cache); | 1753 | kmem_cache_destroy(scsi_io_context_cache); |
1747 | kmem_cache_destroy(scsi_bidi_sdb_cache); | 1754 | kmem_cache_destroy(scsi_sdb_cache); |
1748 | 1755 | ||
1749 | for (i = 0; i < SG_MEMPOOL_NR; i++) { | 1756 | for (i = 0; i < SG_MEMPOOL_NR; i++) { |
1750 | struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; | 1757 | struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; |
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index a00eee6f7be9..196fe3af0d5e 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -346,7 +346,7 @@ static void scsi_target_dev_release(struct device *dev) | |||
346 | put_device(parent); | 346 | put_device(parent); |
347 | } | 347 | } |
348 | 348 | ||
349 | struct device_type scsi_target_type = { | 349 | static struct device_type scsi_target_type = { |
350 | .name = "scsi_target", | 350 | .name = "scsi_target", |
351 | .release = scsi_target_dev_release, | 351 | .release = scsi_target_dev_release, |
352 | }; | 352 | }; |
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 93d2b6714453..b6e561059779 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
@@ -439,6 +439,7 @@ struct bus_type scsi_bus_type = { | |||
439 | .resume = scsi_bus_resume, | 439 | .resume = scsi_bus_resume, |
440 | .remove = scsi_bus_remove, | 440 | .remove = scsi_bus_remove, |
441 | }; | 441 | }; |
442 | EXPORT_SYMBOL_GPL(scsi_bus_type); | ||
442 | 443 | ||
443 | int scsi_sysfs_register(void) | 444 | int scsi_sysfs_register(void) |
444 | { | 445 | { |
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 65d1737eb664..3af7cbcc5c5d 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c | |||
@@ -30,10 +30,11 @@ | |||
30 | #include <scsi/scsi_transport_iscsi.h> | 30 | #include <scsi/scsi_transport_iscsi.h> |
31 | #include <scsi/iscsi_if.h> | 31 | #include <scsi/iscsi_if.h> |
32 | 32 | ||
33 | #define ISCSI_SESSION_ATTRS 19 | 33 | #define ISCSI_SESSION_ATTRS 21 |
34 | #define ISCSI_CONN_ATTRS 13 | 34 | #define ISCSI_CONN_ATTRS 13 |
35 | #define ISCSI_HOST_ATTRS 4 | 35 | #define ISCSI_HOST_ATTRS 4 |
36 | #define ISCSI_TRANSPORT_VERSION "2.0-869" | 36 | |
37 | #define ISCSI_TRANSPORT_VERSION "2.0-870" | ||
37 | 38 | ||
38 | struct iscsi_internal { | 39 | struct iscsi_internal { |
39 | int daemon_pid; | 40 | int daemon_pid; |
@@ -101,16 +102,10 @@ show_transport_##name(struct device *dev, \ | |||
101 | static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL); | 102 | static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL); |
102 | 103 | ||
103 | show_transport_attr(caps, "0x%x"); | 104 | show_transport_attr(caps, "0x%x"); |
104 | show_transport_attr(max_lun, "%d"); | ||
105 | show_transport_attr(max_conn, "%d"); | ||
106 | show_transport_attr(max_cmd_len, "%d"); | ||
107 | 105 | ||
108 | static struct attribute *iscsi_transport_attrs[] = { | 106 | static struct attribute *iscsi_transport_attrs[] = { |
109 | &dev_attr_handle.attr, | 107 | &dev_attr_handle.attr, |
110 | &dev_attr_caps.attr, | 108 | &dev_attr_caps.attr, |
111 | &dev_attr_max_lun.attr, | ||
112 | &dev_attr_max_conn.attr, | ||
113 | &dev_attr_max_cmd_len.attr, | ||
114 | NULL, | 109 | NULL, |
115 | }; | 110 | }; |
116 | 111 | ||
@@ -118,18 +113,139 @@ static struct attribute_group iscsi_transport_group = { | |||
118 | .attrs = iscsi_transport_attrs, | 113 | .attrs = iscsi_transport_attrs, |
119 | }; | 114 | }; |
120 | 115 | ||
116 | /* | ||
117 | * iSCSI endpoint attrs | ||
118 | */ | ||
119 | #define iscsi_dev_to_endpoint(_dev) \ | ||
120 | container_of(_dev, struct iscsi_endpoint, dev) | ||
121 | |||
122 | #define ISCSI_ATTR(_prefix,_name,_mode,_show,_store) \ | ||
123 | struct device_attribute dev_attr_##_prefix##_##_name = \ | ||
124 | __ATTR(_name,_mode,_show,_store) | ||
125 | |||
126 | static void iscsi_endpoint_release(struct device *dev) | ||
127 | { | ||
128 | struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); | ||
129 | kfree(ep); | ||
130 | } | ||
131 | |||
132 | static struct class iscsi_endpoint_class = { | ||
133 | .name = "iscsi_endpoint", | ||
134 | .dev_release = iscsi_endpoint_release, | ||
135 | }; | ||
136 | |||
137 | static ssize_t | ||
138 | show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf) | ||
139 | { | ||
140 | struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); | ||
141 | return sprintf(buf, "%u\n", ep->id); | ||
142 | } | ||
143 | static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL); | ||
144 | |||
145 | static struct attribute *iscsi_endpoint_attrs[] = { | ||
146 | &dev_attr_ep_handle.attr, | ||
147 | NULL, | ||
148 | }; | ||
149 | |||
150 | static struct attribute_group iscsi_endpoint_group = { | ||
151 | .attrs = iscsi_endpoint_attrs, | ||
152 | }; | ||
121 | 153 | ||
154 | #define ISCSI_MAX_EPID -1 | ||
155 | |||
156 | static int iscsi_match_epid(struct device *dev, void *data) | ||
157 | { | ||
158 | struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); | ||
159 | unsigned int *epid = (unsigned int *) data; | ||
160 | |||
161 | return *epid == ep->id; | ||
162 | } | ||
163 | |||
164 | struct iscsi_endpoint * | ||
165 | iscsi_create_endpoint(int dd_size) | ||
166 | { | ||
167 | struct device *dev; | ||
168 | struct iscsi_endpoint *ep; | ||
169 | unsigned int id; | ||
170 | int err; | ||
171 | |||
172 | for (id = 1; id < ISCSI_MAX_EPID; id++) { | ||
173 | dev = class_find_device(&iscsi_endpoint_class, &id, | ||
174 | iscsi_match_epid); | ||
175 | if (!dev) | ||
176 | break; | ||
177 | } | ||
178 | if (id == ISCSI_MAX_EPID) { | ||
179 | printk(KERN_ERR "Too many connections. Max supported %u\n", | ||
180 | ISCSI_MAX_EPID - 1); | ||
181 | return NULL; | ||
182 | } | ||
183 | |||
184 | ep = kzalloc(sizeof(*ep) + dd_size, GFP_KERNEL); | ||
185 | if (!ep) | ||
186 | return NULL; | ||
187 | |||
188 | ep->id = id; | ||
189 | ep->dev.class = &iscsi_endpoint_class; | ||
190 | snprintf(ep->dev.bus_id, BUS_ID_SIZE, "ep-%u", id); | ||
191 | err = device_register(&ep->dev); | ||
192 | if (err) | ||
193 | goto free_ep; | ||
194 | |||
195 | err = sysfs_create_group(&ep->dev.kobj, &iscsi_endpoint_group); | ||
196 | if (err) | ||
197 | goto unregister_dev; | ||
198 | |||
199 | if (dd_size) | ||
200 | ep->dd_data = &ep[1]; | ||
201 | return ep; | ||
202 | |||
203 | unregister_dev: | ||
204 | device_unregister(&ep->dev); | ||
205 | return NULL; | ||
206 | |||
207 | free_ep: | ||
208 | kfree(ep); | ||
209 | return NULL; | ||
210 | } | ||
211 | EXPORT_SYMBOL_GPL(iscsi_create_endpoint); | ||
212 | |||
213 | void iscsi_destroy_endpoint(struct iscsi_endpoint *ep) | ||
214 | { | ||
215 | sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group); | ||
216 | device_unregister(&ep->dev); | ||
217 | } | ||
218 | EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint); | ||
219 | |||
220 | struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle) | ||
221 | { | ||
222 | struct iscsi_endpoint *ep; | ||
223 | struct device *dev; | ||
224 | |||
225 | dev = class_find_device(&iscsi_endpoint_class, &handle, | ||
226 | iscsi_match_epid); | ||
227 | if (!dev) | ||
228 | return NULL; | ||
229 | |||
230 | ep = iscsi_dev_to_endpoint(dev); | ||
231 | /* | ||
232 | * we can drop this now because the interface will prevent | ||
233 | * removals and lookups from racing. | ||
234 | */ | ||
235 | put_device(dev); | ||
236 | return ep; | ||
237 | } | ||
238 | EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint); | ||
122 | 239 | ||
123 | static int iscsi_setup_host(struct transport_container *tc, struct device *dev, | 240 | static int iscsi_setup_host(struct transport_container *tc, struct device *dev, |
124 | struct device *cdev) | 241 | struct device *cdev) |
125 | { | 242 | { |
126 | struct Scsi_Host *shost = dev_to_shost(dev); | 243 | struct Scsi_Host *shost = dev_to_shost(dev); |
127 | struct iscsi_host *ihost = shost->shost_data; | 244 | struct iscsi_cls_host *ihost = shost->shost_data; |
128 | 245 | ||
129 | memset(ihost, 0, sizeof(*ihost)); | 246 | memset(ihost, 0, sizeof(*ihost)); |
130 | INIT_LIST_HEAD(&ihost->sessions); | ||
131 | mutex_init(&ihost->mutex); | ||
132 | atomic_set(&ihost->nr_scans, 0); | 247 | atomic_set(&ihost->nr_scans, 0); |
248 | mutex_init(&ihost->mutex); | ||
133 | 249 | ||
134 | snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", | 250 | snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", |
135 | shost->host_no); | 251 | shost->host_no); |
@@ -144,7 +260,7 @@ static int iscsi_remove_host(struct transport_container *tc, struct device *dev, | |||
144 | struct device *cdev) | 260 | struct device *cdev) |
145 | { | 261 | { |
146 | struct Scsi_Host *shost = dev_to_shost(dev); | 262 | struct Scsi_Host *shost = dev_to_shost(dev); |
147 | struct iscsi_host *ihost = shost->shost_data; | 263 | struct iscsi_cls_host *ihost = shost->shost_data; |
148 | 264 | ||
149 | destroy_workqueue(ihost->scan_workq); | 265 | destroy_workqueue(ihost->scan_workq); |
150 | return 0; | 266 | return 0; |
@@ -287,6 +403,24 @@ static int iscsi_is_session_dev(const struct device *dev) | |||
287 | return dev->release == iscsi_session_release; | 403 | return dev->release == iscsi_session_release; |
288 | } | 404 | } |
289 | 405 | ||
406 | static int iscsi_iter_session_fn(struct device *dev, void *data) | ||
407 | { | ||
408 | void (* fn) (struct iscsi_cls_session *) = data; | ||
409 | |||
410 | if (!iscsi_is_session_dev(dev)) | ||
411 | return 0; | ||
412 | fn(iscsi_dev_to_session(dev)); | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | void iscsi_host_for_each_session(struct Scsi_Host *shost, | ||
417 | void (*fn)(struct iscsi_cls_session *)) | ||
418 | { | ||
419 | device_for_each_child(&shost->shost_gendev, fn, | ||
420 | iscsi_iter_session_fn); | ||
421 | } | ||
422 | EXPORT_SYMBOL_GPL(iscsi_host_for_each_session); | ||
423 | |||
290 | /** | 424 | /** |
291 | * iscsi_scan_finished - helper to report when running scans are done | 425 | * iscsi_scan_finished - helper to report when running scans are done |
292 | * @shost: scsi host | 426 | * @shost: scsi host |
@@ -297,7 +431,7 @@ static int iscsi_is_session_dev(const struct device *dev) | |||
297 | */ | 431 | */ |
298 | int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) | 432 | int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) |
299 | { | 433 | { |
300 | struct iscsi_host *ihost = shost->shost_data; | 434 | struct iscsi_cls_host *ihost = shost->shost_data; |
301 | /* | 435 | /* |
302 | * qla4xxx will have kicked off some session unblocks before calling | 436 | * qla4xxx will have kicked off some session unblocks before calling |
303 | * scsi_scan_host, so just wait for them to complete. | 437 | * scsi_scan_host, so just wait for them to complete. |
@@ -306,42 +440,76 @@ int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) | |||
306 | } | 440 | } |
307 | EXPORT_SYMBOL_GPL(iscsi_scan_finished); | 441 | EXPORT_SYMBOL_GPL(iscsi_scan_finished); |
308 | 442 | ||
309 | static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, | 443 | struct iscsi_scan_data { |
310 | uint id, uint lun) | 444 | unsigned int channel; |
445 | unsigned int id; | ||
446 | unsigned int lun; | ||
447 | }; | ||
448 | |||
449 | static int iscsi_user_scan_session(struct device *dev, void *data) | ||
311 | { | 450 | { |
312 | struct iscsi_host *ihost = shost->shost_data; | 451 | struct iscsi_scan_data *scan_data = data; |
313 | struct iscsi_cls_session *session; | 452 | struct iscsi_cls_session *session; |
453 | struct Scsi_Host *shost; | ||
454 | struct iscsi_cls_host *ihost; | ||
455 | unsigned long flags; | ||
456 | unsigned int id; | ||
457 | |||
458 | if (!iscsi_is_session_dev(dev)) | ||
459 | return 0; | ||
460 | |||
461 | session = iscsi_dev_to_session(dev); | ||
462 | shost = iscsi_session_to_shost(session); | ||
463 | ihost = shost->shost_data; | ||
314 | 464 | ||
315 | mutex_lock(&ihost->mutex); | 465 | mutex_lock(&ihost->mutex); |
316 | list_for_each_entry(session, &ihost->sessions, host_list) { | 466 | spin_lock_irqsave(&session->lock, flags); |
317 | if ((channel == SCAN_WILD_CARD || channel == 0) && | 467 | if (session->state != ISCSI_SESSION_LOGGED_IN) { |
318 | (id == SCAN_WILD_CARD || id == session->target_id)) | 468 | spin_unlock_irqrestore(&session->lock, flags); |
319 | scsi_scan_target(&session->dev, 0, | 469 | mutex_unlock(&ihost->mutex); |
320 | session->target_id, lun, 1); | 470 | return 0; |
321 | } | 471 | } |
322 | mutex_unlock(&ihost->mutex); | 472 | id = session->target_id; |
473 | spin_unlock_irqrestore(&session->lock, flags); | ||
323 | 474 | ||
475 | if (id != ISCSI_MAX_TARGET) { | ||
476 | if ((scan_data->channel == SCAN_WILD_CARD || | ||
477 | scan_data->channel == 0) && | ||
478 | (scan_data->id == SCAN_WILD_CARD || | ||
479 | scan_data->id == id)) | ||
480 | scsi_scan_target(&session->dev, 0, id, | ||
481 | scan_data->lun, 1); | ||
482 | } | ||
483 | mutex_unlock(&ihost->mutex); | ||
324 | return 0; | 484 | return 0; |
325 | } | 485 | } |
326 | 486 | ||
487 | static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, | ||
488 | uint id, uint lun) | ||
489 | { | ||
490 | struct iscsi_scan_data scan_data; | ||
491 | |||
492 | scan_data.channel = channel; | ||
493 | scan_data.id = id; | ||
494 | scan_data.lun = lun; | ||
495 | |||
496 | return device_for_each_child(&shost->shost_gendev, &scan_data, | ||
497 | iscsi_user_scan_session); | ||
498 | } | ||
499 | |||
327 | static void iscsi_scan_session(struct work_struct *work) | 500 | static void iscsi_scan_session(struct work_struct *work) |
328 | { | 501 | { |
329 | struct iscsi_cls_session *session = | 502 | struct iscsi_cls_session *session = |
330 | container_of(work, struct iscsi_cls_session, scan_work); | 503 | container_of(work, struct iscsi_cls_session, scan_work); |
331 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 504 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
332 | struct iscsi_host *ihost = shost->shost_data; | 505 | struct iscsi_cls_host *ihost = shost->shost_data; |
333 | unsigned long flags; | 506 | struct iscsi_scan_data scan_data; |
334 | 507 | ||
335 | spin_lock_irqsave(&session->lock, flags); | 508 | scan_data.channel = 0; |
336 | if (session->state != ISCSI_SESSION_LOGGED_IN) { | 509 | scan_data.id = SCAN_WILD_CARD; |
337 | spin_unlock_irqrestore(&session->lock, flags); | 510 | scan_data.lun = SCAN_WILD_CARD; |
338 | goto done; | ||
339 | } | ||
340 | spin_unlock_irqrestore(&session->lock, flags); | ||
341 | 511 | ||
342 | scsi_scan_target(&session->dev, 0, session->target_id, | 512 | iscsi_user_scan_session(&session->dev, &scan_data); |
343 | SCAN_WILD_CARD, 1); | ||
344 | done: | ||
345 | atomic_dec(&ihost->nr_scans); | 513 | atomic_dec(&ihost->nr_scans); |
346 | } | 514 | } |
347 | 515 | ||
@@ -381,7 +549,7 @@ static void __iscsi_unblock_session(struct work_struct *work) | |||
381 | container_of(work, struct iscsi_cls_session, | 549 | container_of(work, struct iscsi_cls_session, |
382 | unblock_work); | 550 | unblock_work); |
383 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 551 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
384 | struct iscsi_host *ihost = shost->shost_data; | 552 | struct iscsi_cls_host *ihost = shost->shost_data; |
385 | unsigned long flags; | 553 | unsigned long flags; |
386 | 554 | ||
387 | /* | 555 | /* |
@@ -449,15 +617,19 @@ static void __iscsi_unbind_session(struct work_struct *work) | |||
449 | container_of(work, struct iscsi_cls_session, | 617 | container_of(work, struct iscsi_cls_session, |
450 | unbind_work); | 618 | unbind_work); |
451 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 619 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
452 | struct iscsi_host *ihost = shost->shost_data; | 620 | struct iscsi_cls_host *ihost = shost->shost_data; |
621 | unsigned long flags; | ||
453 | 622 | ||
454 | /* Prevent new scans and make sure scanning is not in progress */ | 623 | /* Prevent new scans and make sure scanning is not in progress */ |
455 | mutex_lock(&ihost->mutex); | 624 | mutex_lock(&ihost->mutex); |
456 | if (list_empty(&session->host_list)) { | 625 | spin_lock_irqsave(&session->lock, flags); |
626 | if (session->target_id == ISCSI_MAX_TARGET) { | ||
627 | spin_unlock_irqrestore(&session->lock, flags); | ||
457 | mutex_unlock(&ihost->mutex); | 628 | mutex_unlock(&ihost->mutex); |
458 | return; | 629 | return; |
459 | } | 630 | } |
460 | list_del_init(&session->host_list); | 631 | session->target_id = ISCSI_MAX_TARGET; |
632 | spin_unlock_irqrestore(&session->lock, flags); | ||
461 | mutex_unlock(&ihost->mutex); | 633 | mutex_unlock(&ihost->mutex); |
462 | 634 | ||
463 | scsi_remove_target(&session->dev); | 635 | scsi_remove_target(&session->dev); |
@@ -467,18 +639,18 @@ static void __iscsi_unbind_session(struct work_struct *work) | |||
467 | static int iscsi_unbind_session(struct iscsi_cls_session *session) | 639 | static int iscsi_unbind_session(struct iscsi_cls_session *session) |
468 | { | 640 | { |
469 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 641 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
470 | struct iscsi_host *ihost = shost->shost_data; | 642 | struct iscsi_cls_host *ihost = shost->shost_data; |
471 | 643 | ||
472 | return queue_work(ihost->scan_workq, &session->unbind_work); | 644 | return queue_work(ihost->scan_workq, &session->unbind_work); |
473 | } | 645 | } |
474 | 646 | ||
475 | struct iscsi_cls_session * | 647 | struct iscsi_cls_session * |
476 | iscsi_alloc_session(struct Scsi_Host *shost, | 648 | iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport, |
477 | struct iscsi_transport *transport) | 649 | int dd_size) |
478 | { | 650 | { |
479 | struct iscsi_cls_session *session; | 651 | struct iscsi_cls_session *session; |
480 | 652 | ||
481 | session = kzalloc(sizeof(*session) + transport->sessiondata_size, | 653 | session = kzalloc(sizeof(*session) + dd_size, |
482 | GFP_KERNEL); | 654 | GFP_KERNEL); |
483 | if (!session) | 655 | if (!session) |
484 | return NULL; | 656 | return NULL; |
@@ -487,7 +659,6 @@ iscsi_alloc_session(struct Scsi_Host *shost, | |||
487 | session->recovery_tmo = 120; | 659 | session->recovery_tmo = 120; |
488 | session->state = ISCSI_SESSION_FREE; | 660 | session->state = ISCSI_SESSION_FREE; |
489 | INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); | 661 | INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); |
490 | INIT_LIST_HEAD(&session->host_list); | ||
491 | INIT_LIST_HEAD(&session->sess_list); | 662 | INIT_LIST_HEAD(&session->sess_list); |
492 | INIT_WORK(&session->unblock_work, __iscsi_unblock_session); | 663 | INIT_WORK(&session->unblock_work, __iscsi_unblock_session); |
493 | INIT_WORK(&session->block_work, __iscsi_block_session); | 664 | INIT_WORK(&session->block_work, __iscsi_block_session); |
@@ -500,22 +671,57 @@ iscsi_alloc_session(struct Scsi_Host *shost, | |||
500 | session->dev.parent = &shost->shost_gendev; | 671 | session->dev.parent = &shost->shost_gendev; |
501 | session->dev.release = iscsi_session_release; | 672 | session->dev.release = iscsi_session_release; |
502 | device_initialize(&session->dev); | 673 | device_initialize(&session->dev); |
503 | if (transport->sessiondata_size) | 674 | if (dd_size) |
504 | session->dd_data = &session[1]; | 675 | session->dd_data = &session[1]; |
505 | return session; | 676 | return session; |
506 | } | 677 | } |
507 | EXPORT_SYMBOL_GPL(iscsi_alloc_session); | 678 | EXPORT_SYMBOL_GPL(iscsi_alloc_session); |
508 | 679 | ||
680 | static int iscsi_get_next_target_id(struct device *dev, void *data) | ||
681 | { | ||
682 | struct iscsi_cls_session *session; | ||
683 | unsigned long flags; | ||
684 | int err = 0; | ||
685 | |||
686 | if (!iscsi_is_session_dev(dev)) | ||
687 | return 0; | ||
688 | |||
689 | session = iscsi_dev_to_session(dev); | ||
690 | spin_lock_irqsave(&session->lock, flags); | ||
691 | if (*((unsigned int *) data) == session->target_id) | ||
692 | err = -EEXIST; | ||
693 | spin_unlock_irqrestore(&session->lock, flags); | ||
694 | return err; | ||
695 | } | ||
696 | |||
509 | int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) | 697 | int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) |
510 | { | 698 | { |
511 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 699 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
512 | struct iscsi_host *ihost; | 700 | struct iscsi_cls_host *ihost; |
513 | unsigned long flags; | 701 | unsigned long flags; |
702 | unsigned int id = target_id; | ||
514 | int err; | 703 | int err; |
515 | 704 | ||
516 | ihost = shost->shost_data; | 705 | ihost = shost->shost_data; |
517 | session->sid = atomic_add_return(1, &iscsi_session_nr); | 706 | session->sid = atomic_add_return(1, &iscsi_session_nr); |
518 | session->target_id = target_id; | 707 | |
708 | if (id == ISCSI_MAX_TARGET) { | ||
709 | for (id = 0; id < ISCSI_MAX_TARGET; id++) { | ||
710 | err = device_for_each_child(&shost->shost_gendev, &id, | ||
711 | iscsi_get_next_target_id); | ||
712 | if (!err) | ||
713 | break; | ||
714 | } | ||
715 | |||
716 | if (id == ISCSI_MAX_TARGET) { | ||
717 | iscsi_cls_session_printk(KERN_ERR, session, | ||
718 | "Too many iscsi targets. Max " | ||
719 | "number of targets is %d.\n", | ||
720 | ISCSI_MAX_TARGET - 1); | ||
721 | goto release_host; | ||
722 | } | ||
723 | } | ||
724 | session->target_id = id; | ||
519 | 725 | ||
520 | snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", | 726 | snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", |
521 | session->sid); | 727 | session->sid); |
@@ -531,10 +737,6 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) | |||
531 | list_add(&session->sess_list, &sesslist); | 737 | list_add(&session->sess_list, &sesslist); |
532 | spin_unlock_irqrestore(&sesslock, flags); | 738 | spin_unlock_irqrestore(&sesslock, flags); |
533 | 739 | ||
534 | mutex_lock(&ihost->mutex); | ||
535 | list_add(&session->host_list, &ihost->sessions); | ||
536 | mutex_unlock(&ihost->mutex); | ||
537 | |||
538 | iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION); | 740 | iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION); |
539 | return 0; | 741 | return 0; |
540 | 742 | ||
@@ -548,18 +750,18 @@ EXPORT_SYMBOL_GPL(iscsi_add_session); | |||
548 | * iscsi_create_session - create iscsi class session | 750 | * iscsi_create_session - create iscsi class session |
549 | * @shost: scsi host | 751 | * @shost: scsi host |
550 | * @transport: iscsi transport | 752 | * @transport: iscsi transport |
753 | * @dd_size: private driver data size | ||
551 | * @target_id: which target | 754 | * @target_id: which target |
552 | * | 755 | * |
553 | * This can be called from a LLD or iscsi_transport. | 756 | * This can be called from a LLD or iscsi_transport. |
554 | */ | 757 | */ |
555 | struct iscsi_cls_session * | 758 | struct iscsi_cls_session * |
556 | iscsi_create_session(struct Scsi_Host *shost, | 759 | iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport, |
557 | struct iscsi_transport *transport, | 760 | int dd_size, unsigned int target_id) |
558 | unsigned int target_id) | ||
559 | { | 761 | { |
560 | struct iscsi_cls_session *session; | 762 | struct iscsi_cls_session *session; |
561 | 763 | ||
562 | session = iscsi_alloc_session(shost, transport); | 764 | session = iscsi_alloc_session(shost, transport, dd_size); |
563 | if (!session) | 765 | if (!session) |
564 | return NULL; | 766 | return NULL; |
565 | 767 | ||
@@ -595,7 +797,7 @@ static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data) | |||
595 | void iscsi_remove_session(struct iscsi_cls_session *session) | 797 | void iscsi_remove_session(struct iscsi_cls_session *session) |
596 | { | 798 | { |
597 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 799 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
598 | struct iscsi_host *ihost = shost->shost_data; | 800 | struct iscsi_cls_host *ihost = shost->shost_data; |
599 | unsigned long flags; | 801 | unsigned long flags; |
600 | int err; | 802 | int err; |
601 | 803 | ||
@@ -661,6 +863,7 @@ EXPORT_SYMBOL_GPL(iscsi_destroy_session); | |||
661 | /** | 863 | /** |
662 | * iscsi_create_conn - create iscsi class connection | 864 | * iscsi_create_conn - create iscsi class connection |
663 | * @session: iscsi cls session | 865 | * @session: iscsi cls session |
866 | * @dd_size: private driver data size | ||
664 | * @cid: connection id | 867 | * @cid: connection id |
665 | * | 868 | * |
666 | * This can be called from a LLD or iscsi_transport. The connection | 869 | * This can be called from a LLD or iscsi_transport. The connection |
@@ -673,18 +876,17 @@ EXPORT_SYMBOL_GPL(iscsi_destroy_session); | |||
673 | * non-zero. | 876 | * non-zero. |
674 | */ | 877 | */ |
675 | struct iscsi_cls_conn * | 878 | struct iscsi_cls_conn * |
676 | iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) | 879 | iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) |
677 | { | 880 | { |
678 | struct iscsi_transport *transport = session->transport; | 881 | struct iscsi_transport *transport = session->transport; |
679 | struct iscsi_cls_conn *conn; | 882 | struct iscsi_cls_conn *conn; |
680 | unsigned long flags; | 883 | unsigned long flags; |
681 | int err; | 884 | int err; |
682 | 885 | ||
683 | conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL); | 886 | conn = kzalloc(sizeof(*conn) + dd_size, GFP_KERNEL); |
684 | if (!conn) | 887 | if (!conn) |
685 | return NULL; | 888 | return NULL; |
686 | 889 | if (dd_size) | |
687 | if (transport->conndata_size) | ||
688 | conn->dd_data = &conn[1]; | 890 | conn->dd_data = &conn[1]; |
689 | 891 | ||
690 | INIT_LIST_HEAD(&conn->conn_list); | 892 | INIT_LIST_HEAD(&conn->conn_list); |
@@ -1017,21 +1219,20 @@ int iscsi_session_event(struct iscsi_cls_session *session, | |||
1017 | EXPORT_SYMBOL_GPL(iscsi_session_event); | 1219 | EXPORT_SYMBOL_GPL(iscsi_session_event); |
1018 | 1220 | ||
1019 | static int | 1221 | static int |
1020 | iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) | 1222 | iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep, |
1223 | struct iscsi_uevent *ev, uint32_t initial_cmdsn, | ||
1224 | uint16_t cmds_max, uint16_t queue_depth) | ||
1021 | { | 1225 | { |
1022 | struct iscsi_transport *transport = priv->iscsi_transport; | 1226 | struct iscsi_transport *transport = priv->iscsi_transport; |
1023 | struct iscsi_cls_session *session; | 1227 | struct iscsi_cls_session *session; |
1024 | uint32_t hostno; | 1228 | uint32_t host_no; |
1025 | 1229 | ||
1026 | session = transport->create_session(transport, &priv->t, | 1230 | session = transport->create_session(ep, cmds_max, queue_depth, |
1027 | ev->u.c_session.cmds_max, | 1231 | initial_cmdsn, &host_no); |
1028 | ev->u.c_session.queue_depth, | ||
1029 | ev->u.c_session.initial_cmdsn, | ||
1030 | &hostno); | ||
1031 | if (!session) | 1232 | if (!session) |
1032 | return -ENOMEM; | 1233 | return -ENOMEM; |
1033 | 1234 | ||
1034 | ev->r.c_session_ret.host_no = hostno; | 1235 | ev->r.c_session_ret.host_no = host_no; |
1035 | ev->r.c_session_ret.sid = session->sid; | 1236 | ev->r.c_session_ret.sid = session->sid; |
1036 | return 0; | 1237 | return 0; |
1037 | } | 1238 | } |
@@ -1106,6 +1307,7 @@ static int | |||
1106 | iscsi_if_transport_ep(struct iscsi_transport *transport, | 1307 | iscsi_if_transport_ep(struct iscsi_transport *transport, |
1107 | struct iscsi_uevent *ev, int msg_type) | 1308 | struct iscsi_uevent *ev, int msg_type) |
1108 | { | 1309 | { |
1310 | struct iscsi_endpoint *ep; | ||
1109 | struct sockaddr *dst_addr; | 1311 | struct sockaddr *dst_addr; |
1110 | int rc = 0; | 1312 | int rc = 0; |
1111 | 1313 | ||
@@ -1115,22 +1317,33 @@ iscsi_if_transport_ep(struct iscsi_transport *transport, | |||
1115 | return -EINVAL; | 1317 | return -EINVAL; |
1116 | 1318 | ||
1117 | dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); | 1319 | dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); |
1118 | rc = transport->ep_connect(dst_addr, | 1320 | ep = transport->ep_connect(dst_addr, |
1119 | ev->u.ep_connect.non_blocking, | 1321 | ev->u.ep_connect.non_blocking); |
1120 | &ev->r.ep_connect_ret.handle); | 1322 | if (IS_ERR(ep)) |
1323 | return PTR_ERR(ep); | ||
1324 | |||
1325 | ev->r.ep_connect_ret.handle = ep->id; | ||
1121 | break; | 1326 | break; |
1122 | case ISCSI_UEVENT_TRANSPORT_EP_POLL: | 1327 | case ISCSI_UEVENT_TRANSPORT_EP_POLL: |
1123 | if (!transport->ep_poll) | 1328 | if (!transport->ep_poll) |
1124 | return -EINVAL; | 1329 | return -EINVAL; |
1125 | 1330 | ||
1126 | ev->r.retcode = transport->ep_poll(ev->u.ep_poll.ep_handle, | 1331 | ep = iscsi_lookup_endpoint(ev->u.ep_poll.ep_handle); |
1332 | if (!ep) | ||
1333 | return -EINVAL; | ||
1334 | |||
1335 | ev->r.retcode = transport->ep_poll(ep, | ||
1127 | ev->u.ep_poll.timeout_ms); | 1336 | ev->u.ep_poll.timeout_ms); |
1128 | break; | 1337 | break; |
1129 | case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: | 1338 | case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: |
1130 | if (!transport->ep_disconnect) | 1339 | if (!transport->ep_disconnect) |
1131 | return -EINVAL; | 1340 | return -EINVAL; |
1132 | 1341 | ||
1133 | transport->ep_disconnect(ev->u.ep_disconnect.ep_handle); | 1342 | ep = iscsi_lookup_endpoint(ev->u.ep_disconnect.ep_handle); |
1343 | if (!ep) | ||
1344 | return -EINVAL; | ||
1345 | |||
1346 | transport->ep_disconnect(ep); | ||
1134 | break; | 1347 | break; |
1135 | } | 1348 | } |
1136 | return rc; | 1349 | return rc; |
@@ -1195,6 +1408,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1195 | struct iscsi_internal *priv; | 1408 | struct iscsi_internal *priv; |
1196 | struct iscsi_cls_session *session; | 1409 | struct iscsi_cls_session *session; |
1197 | struct iscsi_cls_conn *conn; | 1410 | struct iscsi_cls_conn *conn; |
1411 | struct iscsi_endpoint *ep = NULL; | ||
1198 | 1412 | ||
1199 | priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); | 1413 | priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); |
1200 | if (!priv) | 1414 | if (!priv) |
@@ -1208,7 +1422,22 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1208 | 1422 | ||
1209 | switch (nlh->nlmsg_type) { | 1423 | switch (nlh->nlmsg_type) { |
1210 | case ISCSI_UEVENT_CREATE_SESSION: | 1424 | case ISCSI_UEVENT_CREATE_SESSION: |
1211 | err = iscsi_if_create_session(priv, ev); | 1425 | err = iscsi_if_create_session(priv, ep, ev, |
1426 | ev->u.c_session.initial_cmdsn, | ||
1427 | ev->u.c_session.cmds_max, | ||
1428 | ev->u.c_session.queue_depth); | ||
1429 | break; | ||
1430 | case ISCSI_UEVENT_CREATE_BOUND_SESSION: | ||
1431 | ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle); | ||
1432 | if (!ep) { | ||
1433 | err = -EINVAL; | ||
1434 | break; | ||
1435 | } | ||
1436 | |||
1437 | err = iscsi_if_create_session(priv, ep, ev, | ||
1438 | ev->u.c_bound_session.initial_cmdsn, | ||
1439 | ev->u.c_bound_session.cmds_max, | ||
1440 | ev->u.c_bound_session.queue_depth); | ||
1212 | break; | 1441 | break; |
1213 | case ISCSI_UEVENT_DESTROY_SESSION: | 1442 | case ISCSI_UEVENT_DESTROY_SESSION: |
1214 | session = iscsi_session_lookup(ev->u.d_session.sid); | 1443 | session = iscsi_session_lookup(ev->u.d_session.sid); |
@@ -1414,6 +1643,8 @@ iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1); | |||
1414 | iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0); | 1643 | iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0); |
1415 | iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); | 1644 | iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); |
1416 | iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); | 1645 | iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); |
1646 | iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0); | ||
1647 | iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0) | ||
1417 | 1648 | ||
1418 | static ssize_t | 1649 | static ssize_t |
1419 | show_priv_session_state(struct device *dev, struct device_attribute *attr, | 1650 | show_priv_session_state(struct device *dev, struct device_attribute *attr, |
@@ -1580,6 +1811,8 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1580 | priv->daemon_pid = -1; | 1811 | priv->daemon_pid = -1; |
1581 | priv->iscsi_transport = tt; | 1812 | priv->iscsi_transport = tt; |
1582 | priv->t.user_scan = iscsi_user_scan; | 1813 | priv->t.user_scan = iscsi_user_scan; |
1814 | if (!(tt->caps & CAP_DATA_PATH_OFFLOAD)) | ||
1815 | priv->t.create_work_queue = 1; | ||
1583 | 1816 | ||
1584 | priv->dev.class = &iscsi_transport_class; | 1817 | priv->dev.class = &iscsi_transport_class; |
1585 | snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name); | 1818 | snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name); |
@@ -1595,7 +1828,7 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1595 | priv->t.host_attrs.ac.attrs = &priv->host_attrs[0]; | 1828 | priv->t.host_attrs.ac.attrs = &priv->host_attrs[0]; |
1596 | priv->t.host_attrs.ac.class = &iscsi_host_class.class; | 1829 | priv->t.host_attrs.ac.class = &iscsi_host_class.class; |
1597 | priv->t.host_attrs.ac.match = iscsi_host_match; | 1830 | priv->t.host_attrs.ac.match = iscsi_host_match; |
1598 | priv->t.host_size = sizeof(struct iscsi_host); | 1831 | priv->t.host_size = sizeof(struct iscsi_cls_host); |
1599 | transport_container_register(&priv->t.host_attrs); | 1832 | transport_container_register(&priv->t.host_attrs); |
1600 | 1833 | ||
1601 | SETUP_HOST_RD_ATTR(netdev, ISCSI_HOST_NETDEV_NAME); | 1834 | SETUP_HOST_RD_ATTR(netdev, ISCSI_HOST_NETDEV_NAME); |
@@ -1653,6 +1886,8 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1653 | SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT); | 1886 | SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT); |
1654 | SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); | 1887 | SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); |
1655 | SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); | 1888 | SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); |
1889 | SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME); | ||
1890 | SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME); | ||
1656 | SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); | 1891 | SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); |
1657 | SETUP_PRIV_SESSION_RD_ATTR(state); | 1892 | SETUP_PRIV_SESSION_RD_ATTR(state); |
1658 | 1893 | ||
@@ -1668,6 +1903,7 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1668 | 1903 | ||
1669 | unregister_dev: | 1904 | unregister_dev: |
1670 | device_unregister(&priv->dev); | 1905 | device_unregister(&priv->dev); |
1906 | return NULL; | ||
1671 | free_priv: | 1907 | free_priv: |
1672 | kfree(priv); | 1908 | kfree(priv); |
1673 | return NULL; | 1909 | return NULL; |
@@ -1715,10 +1951,14 @@ static __init int iscsi_transport_init(void) | |||
1715 | if (err) | 1951 | if (err) |
1716 | return err; | 1952 | return err; |
1717 | 1953 | ||
1718 | err = transport_class_register(&iscsi_host_class); | 1954 | err = class_register(&iscsi_endpoint_class); |
1719 | if (err) | 1955 | if (err) |
1720 | goto unregister_transport_class; | 1956 | goto unregister_transport_class; |
1721 | 1957 | ||
1958 | err = transport_class_register(&iscsi_host_class); | ||
1959 | if (err) | ||
1960 | goto unregister_endpoint_class; | ||
1961 | |||
1722 | err = transport_class_register(&iscsi_connection_class); | 1962 | err = transport_class_register(&iscsi_connection_class); |
1723 | if (err) | 1963 | if (err) |
1724 | goto unregister_host_class; | 1964 | goto unregister_host_class; |
@@ -1727,8 +1967,8 @@ static __init int iscsi_transport_init(void) | |||
1727 | if (err) | 1967 | if (err) |
1728 | goto unregister_conn_class; | 1968 | goto unregister_conn_class; |
1729 | 1969 | ||
1730 | nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, NULL, | 1970 | nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, |
1731 | THIS_MODULE); | 1971 | NULL, THIS_MODULE); |
1732 | if (!nls) { | 1972 | if (!nls) { |
1733 | err = -ENOBUFS; | 1973 | err = -ENOBUFS; |
1734 | goto unregister_session_class; | 1974 | goto unregister_session_class; |
@@ -1748,6 +1988,8 @@ unregister_conn_class: | |||
1748 | transport_class_unregister(&iscsi_connection_class); | 1988 | transport_class_unregister(&iscsi_connection_class); |
1749 | unregister_host_class: | 1989 | unregister_host_class: |
1750 | transport_class_unregister(&iscsi_host_class); | 1990 | transport_class_unregister(&iscsi_host_class); |
1991 | unregister_endpoint_class: | ||
1992 | class_unregister(&iscsi_endpoint_class); | ||
1751 | unregister_transport_class: | 1993 | unregister_transport_class: |
1752 | class_unregister(&iscsi_transport_class); | 1994 | class_unregister(&iscsi_transport_class); |
1753 | return err; | 1995 | return err; |
@@ -1760,6 +2002,7 @@ static void __exit iscsi_transport_exit(void) | |||
1760 | transport_class_unregister(&iscsi_connection_class); | 2002 | transport_class_unregister(&iscsi_connection_class); |
1761 | transport_class_unregister(&iscsi_session_class); | 2003 | transport_class_unregister(&iscsi_session_class); |
1762 | transport_class_unregister(&iscsi_host_class); | 2004 | transport_class_unregister(&iscsi_host_class); |
2005 | class_unregister(&iscsi_endpoint_class); | ||
1763 | class_unregister(&iscsi_transport_class); | 2006 | class_unregister(&iscsi_transport_class); |
1764 | } | 2007 | } |
1765 | 2008 | ||
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index d53312c42547..0c63947d8a9d 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -58,8 +58,8 @@ | |||
58 | #include <scsi/scsi_host.h> | 58 | #include <scsi/scsi_host.h> |
59 | #include <scsi/scsi_ioctl.h> | 59 | #include <scsi/scsi_ioctl.h> |
60 | #include <scsi/scsicam.h> | 60 | #include <scsi/scsicam.h> |
61 | #include <scsi/sd.h> | ||
62 | 61 | ||
62 | #include "sd.h" | ||
63 | #include "scsi_logging.h" | 63 | #include "scsi_logging.h" |
64 | 64 | ||
65 | MODULE_AUTHOR("Eric Youngdale"); | 65 | MODULE_AUTHOR("Eric Youngdale"); |
@@ -295,11 +295,6 @@ static int sd_major(int major_idx) | |||
295 | } | 295 | } |
296 | } | 296 | } |
297 | 297 | ||
298 | static inline struct scsi_disk *scsi_disk(struct gendisk *disk) | ||
299 | { | ||
300 | return container_of(disk->private_data, struct scsi_disk, driver); | ||
301 | } | ||
302 | |||
303 | static struct scsi_disk *__scsi_disk_get(struct gendisk *disk) | 298 | static struct scsi_disk *__scsi_disk_get(struct gendisk *disk) |
304 | { | 299 | { |
305 | struct scsi_disk *sdkp = NULL; | 300 | struct scsi_disk *sdkp = NULL; |
diff --git a/include/scsi/sd.h b/drivers/scsi/sd.h index 4f032d48cb6e..03a3d45cfa42 100644 --- a/include/scsi/sd.h +++ b/drivers/scsi/sd.h | |||
@@ -48,6 +48,11 @@ struct scsi_disk { | |||
48 | }; | 48 | }; |
49 | #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) | 49 | #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) |
50 | 50 | ||
51 | static inline struct scsi_disk *scsi_disk(struct gendisk *disk) | ||
52 | { | ||
53 | return container_of(disk->private_data, struct scsi_disk, driver); | ||
54 | } | ||
55 | |||
51 | #define sd_printk(prefix, sdsk, fmt, a...) \ | 56 | #define sd_printk(prefix, sdsk, fmt, a...) \ |
52 | (sdsk)->disk ? \ | 57 | (sdsk)->disk ? \ |
53 | sdev_printk(prefix, (sdsk)->device, "[%s] " fmt, \ | 58 | sdev_printk(prefix, (sdsk)->device, "[%s] " fmt, \ |
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index fccd2e88d600..d3b8ebb83776 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c | |||
@@ -1036,6 +1036,9 @@ sg_ioctl(struct inode *inode, struct file *filp, | |||
1036 | case SG_SCSI_RESET_DEVICE: | 1036 | case SG_SCSI_RESET_DEVICE: |
1037 | val = SCSI_TRY_RESET_DEVICE; | 1037 | val = SCSI_TRY_RESET_DEVICE; |
1038 | break; | 1038 | break; |
1039 | case SG_SCSI_RESET_TARGET: | ||
1040 | val = SCSI_TRY_RESET_TARGET; | ||
1041 | break; | ||
1039 | case SG_SCSI_RESET_BUS: | 1042 | case SG_SCSI_RESET_BUS: |
1040 | val = SCSI_TRY_RESET_BUS; | 1043 | val = SCSI_TRY_RESET_BUS; |
1041 | break; | 1044 | break; |
diff --git a/drivers/scsi/sym53c8xx_2/sym_misc.h b/drivers/scsi/sym53c8xx_2/sym_misc.h index 0433d5d0caf3..430537183c18 100644 --- a/drivers/scsi/sym53c8xx_2/sym_misc.h +++ b/drivers/scsi/sym53c8xx_2/sym_misc.h | |||
@@ -121,9 +121,7 @@ static __inline void sym_que_move(struct sym_quehead *orig, | |||
121 | } | 121 | } |
122 | } | 122 | } |
123 | 123 | ||
124 | #define sym_que_entry(ptr, type, member) \ | 124 | #define sym_que_entry(ptr, type, member) container_of(ptr, type, member) |
125 | ((type *)((char *)(ptr)-(unsigned int)(&((type *)0)->member))) | ||
126 | |||
127 | 125 | ||
128 | #define sym_insque(new, pos) __sym_que_add(new, pos, (pos)->flink) | 126 | #define sym_insque(new, pos) __sym_que_add(new, pos, (pos)->flink) |
129 | 127 | ||
diff --git a/include/linux/crc-t10dif.h b/include/linux/crc-t10dif.h new file mode 100644 index 000000000000..a9c96d865ee7 --- /dev/null +++ b/include/linux/crc-t10dif.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef _LINUX_CRC_T10DIF_H | ||
2 | #define _LINUX_CRC_T10DIF_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | |||
6 | __u16 crc_t10dif(unsigned char const *, size_t); | ||
7 | |||
8 | #endif | ||
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index e19e58423166..16be12f1cbe8 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h | |||
@@ -50,6 +50,7 @@ enum iscsi_uevent_e { | |||
50 | ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15, | 50 | ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15, |
51 | ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16, | 51 | ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16, |
52 | ISCSI_UEVENT_UNBIND_SESSION = UEVENT_BASE + 17, | 52 | ISCSI_UEVENT_UNBIND_SESSION = UEVENT_BASE + 17, |
53 | ISCSI_UEVENT_CREATE_BOUND_SESSION = UEVENT_BASE + 18, | ||
53 | 54 | ||
54 | /* up events */ | 55 | /* up events */ |
55 | ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, | 56 | ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, |
@@ -78,6 +79,12 @@ struct iscsi_uevent { | |||
78 | uint16_t cmds_max; | 79 | uint16_t cmds_max; |
79 | uint16_t queue_depth; | 80 | uint16_t queue_depth; |
80 | } c_session; | 81 | } c_session; |
82 | struct msg_create_bound_session { | ||
83 | uint64_t ep_handle; | ||
84 | uint32_t initial_cmdsn; | ||
85 | uint16_t cmds_max; | ||
86 | uint16_t queue_depth; | ||
87 | } c_bound_session; | ||
81 | struct msg_destroy_session { | 88 | struct msg_destroy_session { |
82 | uint32_t sid; | 89 | uint32_t sid; |
83 | } d_session; | 90 | } d_session; |
@@ -250,42 +257,49 @@ enum iscsi_param { | |||
250 | 257 | ||
251 | ISCSI_PARAM_PING_TMO, | 258 | ISCSI_PARAM_PING_TMO, |
252 | ISCSI_PARAM_RECV_TMO, | 259 | ISCSI_PARAM_RECV_TMO, |
260 | |||
261 | ISCSI_PARAM_IFACE_NAME, | ||
262 | ISCSI_PARAM_ISID, | ||
263 | ISCSI_PARAM_INITIATOR_NAME, | ||
253 | /* must always be last */ | 264 | /* must always be last */ |
254 | ISCSI_PARAM_MAX, | 265 | ISCSI_PARAM_MAX, |
255 | }; | 266 | }; |
256 | 267 | ||
257 | #define ISCSI_MAX_RECV_DLENGTH (1 << ISCSI_PARAM_MAX_RECV_DLENGTH) | 268 | #define ISCSI_MAX_RECV_DLENGTH (1ULL << ISCSI_PARAM_MAX_RECV_DLENGTH) |
258 | #define ISCSI_MAX_XMIT_DLENGTH (1 << ISCSI_PARAM_MAX_XMIT_DLENGTH) | 269 | #define ISCSI_MAX_XMIT_DLENGTH (1ULL << ISCSI_PARAM_MAX_XMIT_DLENGTH) |
259 | #define ISCSI_HDRDGST_EN (1 << ISCSI_PARAM_HDRDGST_EN) | 270 | #define ISCSI_HDRDGST_EN (1ULL << ISCSI_PARAM_HDRDGST_EN) |
260 | #define ISCSI_DATADGST_EN (1 << ISCSI_PARAM_DATADGST_EN) | 271 | #define ISCSI_DATADGST_EN (1ULL << ISCSI_PARAM_DATADGST_EN) |
261 | #define ISCSI_INITIAL_R2T_EN (1 << ISCSI_PARAM_INITIAL_R2T_EN) | 272 | #define ISCSI_INITIAL_R2T_EN (1ULL << ISCSI_PARAM_INITIAL_R2T_EN) |
262 | #define ISCSI_MAX_R2T (1 << ISCSI_PARAM_MAX_R2T) | 273 | #define ISCSI_MAX_R2T (1ULL << ISCSI_PARAM_MAX_R2T) |
263 | #define ISCSI_IMM_DATA_EN (1 << ISCSI_PARAM_IMM_DATA_EN) | 274 | #define ISCSI_IMM_DATA_EN (1ULL << ISCSI_PARAM_IMM_DATA_EN) |
264 | #define ISCSI_FIRST_BURST (1 << ISCSI_PARAM_FIRST_BURST) | 275 | #define ISCSI_FIRST_BURST (1ULL << ISCSI_PARAM_FIRST_BURST) |
265 | #define ISCSI_MAX_BURST (1 << ISCSI_PARAM_MAX_BURST) | 276 | #define ISCSI_MAX_BURST (1ULL << ISCSI_PARAM_MAX_BURST) |
266 | #define ISCSI_PDU_INORDER_EN (1 << ISCSI_PARAM_PDU_INORDER_EN) | 277 | #define ISCSI_PDU_INORDER_EN (1ULL << ISCSI_PARAM_PDU_INORDER_EN) |
267 | #define ISCSI_DATASEQ_INORDER_EN (1 << ISCSI_PARAM_DATASEQ_INORDER_EN) | 278 | #define ISCSI_DATASEQ_INORDER_EN (1ULL << ISCSI_PARAM_DATASEQ_INORDER_EN) |
268 | #define ISCSI_ERL (1 << ISCSI_PARAM_ERL) | 279 | #define ISCSI_ERL (1ULL << ISCSI_PARAM_ERL) |
269 | #define ISCSI_IFMARKER_EN (1 << ISCSI_PARAM_IFMARKER_EN) | 280 | #define ISCSI_IFMARKER_EN (1ULL << ISCSI_PARAM_IFMARKER_EN) |
270 | #define ISCSI_OFMARKER_EN (1 << ISCSI_PARAM_OFMARKER_EN) | 281 | #define ISCSI_OFMARKER_EN (1ULL << ISCSI_PARAM_OFMARKER_EN) |
271 | #define ISCSI_EXP_STATSN (1 << ISCSI_PARAM_EXP_STATSN) | 282 | #define ISCSI_EXP_STATSN (1ULL << ISCSI_PARAM_EXP_STATSN) |
272 | #define ISCSI_TARGET_NAME (1 << ISCSI_PARAM_TARGET_NAME) | 283 | #define ISCSI_TARGET_NAME (1ULL << ISCSI_PARAM_TARGET_NAME) |
273 | #define ISCSI_TPGT (1 << ISCSI_PARAM_TPGT) | 284 | #define ISCSI_TPGT (1ULL << ISCSI_PARAM_TPGT) |
274 | #define ISCSI_PERSISTENT_ADDRESS (1 << ISCSI_PARAM_PERSISTENT_ADDRESS) | 285 | #define ISCSI_PERSISTENT_ADDRESS (1ULL << ISCSI_PARAM_PERSISTENT_ADDRESS) |
275 | #define ISCSI_PERSISTENT_PORT (1 << ISCSI_PARAM_PERSISTENT_PORT) | 286 | #define ISCSI_PERSISTENT_PORT (1ULL << ISCSI_PARAM_PERSISTENT_PORT) |
276 | #define ISCSI_SESS_RECOVERY_TMO (1 << ISCSI_PARAM_SESS_RECOVERY_TMO) | 287 | #define ISCSI_SESS_RECOVERY_TMO (1ULL << ISCSI_PARAM_SESS_RECOVERY_TMO) |
277 | #define ISCSI_CONN_PORT (1 << ISCSI_PARAM_CONN_PORT) | 288 | #define ISCSI_CONN_PORT (1ULL << ISCSI_PARAM_CONN_PORT) |
278 | #define ISCSI_CONN_ADDRESS (1 << ISCSI_PARAM_CONN_ADDRESS) | 289 | #define ISCSI_CONN_ADDRESS (1ULL << ISCSI_PARAM_CONN_ADDRESS) |
279 | #define ISCSI_USERNAME (1 << ISCSI_PARAM_USERNAME) | 290 | #define ISCSI_USERNAME (1ULL << ISCSI_PARAM_USERNAME) |
280 | #define ISCSI_USERNAME_IN (1 << ISCSI_PARAM_USERNAME_IN) | 291 | #define ISCSI_USERNAME_IN (1ULL << ISCSI_PARAM_USERNAME_IN) |
281 | #define ISCSI_PASSWORD (1 << ISCSI_PARAM_PASSWORD) | 292 | #define ISCSI_PASSWORD (1ULL << ISCSI_PARAM_PASSWORD) |
282 | #define ISCSI_PASSWORD_IN (1 << ISCSI_PARAM_PASSWORD_IN) | 293 | #define ISCSI_PASSWORD_IN (1ULL << ISCSI_PARAM_PASSWORD_IN) |
283 | #define ISCSI_FAST_ABORT (1 << ISCSI_PARAM_FAST_ABORT) | 294 | #define ISCSI_FAST_ABORT (1ULL << ISCSI_PARAM_FAST_ABORT) |
284 | #define ISCSI_ABORT_TMO (1 << ISCSI_PARAM_ABORT_TMO) | 295 | #define ISCSI_ABORT_TMO (1ULL << ISCSI_PARAM_ABORT_TMO) |
285 | #define ISCSI_LU_RESET_TMO (1 << ISCSI_PARAM_LU_RESET_TMO) | 296 | #define ISCSI_LU_RESET_TMO (1ULL << ISCSI_PARAM_LU_RESET_TMO) |
286 | #define ISCSI_HOST_RESET_TMO (1 << ISCSI_PARAM_HOST_RESET_TMO) | 297 | #define ISCSI_HOST_RESET_TMO (1ULL << ISCSI_PARAM_HOST_RESET_TMO) |
287 | #define ISCSI_PING_TMO (1 << ISCSI_PARAM_PING_TMO) | 298 | #define ISCSI_PING_TMO (1ULL << ISCSI_PARAM_PING_TMO) |
288 | #define ISCSI_RECV_TMO (1 << ISCSI_PARAM_RECV_TMO) | 299 | #define ISCSI_RECV_TMO (1ULL << ISCSI_PARAM_RECV_TMO) |
300 | #define ISCSI_IFACE_NAME (1ULL << ISCSI_PARAM_IFACE_NAME) | ||
301 | #define ISCSI_ISID (1ULL << ISCSI_PARAM_ISID) | ||
302 | #define ISCSI_INITIATOR_NAME (1ULL << ISCSI_PARAM_INITIATOR_NAME) | ||
289 | 303 | ||
290 | /* iSCSI HBA params */ | 304 | /* iSCSI HBA params */ |
291 | enum iscsi_host_param { | 305 | enum iscsi_host_param { |
@@ -296,20 +310,13 @@ enum iscsi_host_param { | |||
296 | ISCSI_HOST_PARAM_MAX, | 310 | ISCSI_HOST_PARAM_MAX, |
297 | }; | 311 | }; |
298 | 312 | ||
299 | #define ISCSI_HOST_HWADDRESS (1 << ISCSI_HOST_PARAM_HWADDRESS) | 313 | #define ISCSI_HOST_HWADDRESS (1ULL << ISCSI_HOST_PARAM_HWADDRESS) |
300 | #define ISCSI_HOST_INITIATOR_NAME (1 << ISCSI_HOST_PARAM_INITIATOR_NAME) | 314 | #define ISCSI_HOST_INITIATOR_NAME (1ULL << ISCSI_HOST_PARAM_INITIATOR_NAME) |
301 | #define ISCSI_HOST_NETDEV_NAME (1 << ISCSI_HOST_PARAM_NETDEV_NAME) | 315 | #define ISCSI_HOST_NETDEV_NAME (1ULL << ISCSI_HOST_PARAM_NETDEV_NAME) |
302 | #define ISCSI_HOST_IPADDRESS (1 << ISCSI_HOST_PARAM_IPADDRESS) | 316 | #define ISCSI_HOST_IPADDRESS (1ULL << ISCSI_HOST_PARAM_IPADDRESS) |
303 | 317 | ||
304 | #define iscsi_ptr(_handle) ((void*)(unsigned long)_handle) | 318 | #define iscsi_ptr(_handle) ((void*)(unsigned long)_handle) |
305 | #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr) | 319 | #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr) |
306 | #define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata)) | ||
307 | |||
308 | /** | ||
309 | * iscsi_hostdata - get LLD hostdata from scsi_host | ||
310 | * @_hostdata: pointer to scsi host's hostdata | ||
311 | **/ | ||
312 | #define iscsi_hostdata(_hostdata) ((void*)_hostdata + sizeof(unsigned long)) | ||
313 | 320 | ||
314 | /* | 321 | /* |
315 | * These flags presents iSCSI Data-Path capabilities. | 322 | * These flags presents iSCSI Data-Path capabilities. |
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h index e0593bfae622..f2a2c1169486 100644 --- a/include/scsi/iscsi_proto.h +++ b/include/scsi/iscsi_proto.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #define ISCSI_PROTO_H | 22 | #define ISCSI_PROTO_H |
23 | 23 | ||
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | #include <scsi/scsi.h> | ||
25 | 26 | ||
26 | #define ISCSI_DRAFT20_VERSION 0x00 | 27 | #define ISCSI_DRAFT20_VERSION 0x00 |
27 | 28 | ||
@@ -156,7 +157,7 @@ struct iscsi_ecdb_ahdr { | |||
156 | uint8_t ahstype; | 157 | uint8_t ahstype; |
157 | uint8_t reserved; | 158 | uint8_t reserved; |
158 | /* 4-byte aligned extended CDB spillover */ | 159 | /* 4-byte aligned extended CDB spillover */ |
159 | uint8_t ecdb[260 - ISCSI_CDB_SIZE]; | 160 | uint8_t ecdb[SCSI_MAX_VARLEN_CDB_SIZE - ISCSI_CDB_SIZE]; |
160 | }; | 161 | }; |
161 | 162 | ||
162 | /* SCSI Response Header */ | 163 | /* SCSI Response Header */ |
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index cd3ca63d4fb1..5e75bb7f311c 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h | |||
@@ -24,6 +24,7 @@ | |||
24 | #define LIBISCSI_H | 24 | #define LIBISCSI_H |
25 | 25 | ||
26 | #include <linux/types.h> | 26 | #include <linux/types.h> |
27 | #include <linux/wait.h> | ||
27 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
28 | #include <linux/timer.h> | 29 | #include <linux/timer.h> |
29 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
@@ -31,6 +32,7 @@ | |||
31 | #include <scsi/iscsi_if.h> | 32 | #include <scsi/iscsi_if.h> |
32 | 33 | ||
33 | struct scsi_transport_template; | 34 | struct scsi_transport_template; |
35 | struct scsi_host_template; | ||
34 | struct scsi_device; | 36 | struct scsi_device; |
35 | struct Scsi_Host; | 37 | struct Scsi_Host; |
36 | struct scsi_cmnd; | 38 | struct scsi_cmnd; |
@@ -40,6 +42,7 @@ struct iscsi_cls_session; | |||
40 | struct iscsi_cls_conn; | 42 | struct iscsi_cls_conn; |
41 | struct iscsi_session; | 43 | struct iscsi_session; |
42 | struct iscsi_nopin; | 44 | struct iscsi_nopin; |
45 | struct device; | ||
43 | 46 | ||
44 | /* #define DEBUG_SCSI */ | 47 | /* #define DEBUG_SCSI */ |
45 | #ifdef DEBUG_SCSI | 48 | #ifdef DEBUG_SCSI |
@@ -49,9 +52,7 @@ struct iscsi_nopin; | |||
49 | #endif | 52 | #endif |
50 | 53 | ||
51 | #define ISCSI_DEF_XMIT_CMDS_MAX 128 /* must be power of 2 */ | 54 | #define ISCSI_DEF_XMIT_CMDS_MAX 128 /* must be power of 2 */ |
52 | #define ISCSI_MGMT_CMDS_MAX 16 /* must be power of 2 */ | 55 | #define ISCSI_MGMT_CMDS_MAX 15 |
53 | |||
54 | #define ISCSI_MGMT_ITT_OFFSET 0xa00 | ||
55 | 56 | ||
56 | #define ISCSI_DEF_CMD_PER_LUN 32 | 57 | #define ISCSI_DEF_CMD_PER_LUN 32 |
57 | #define ISCSI_MAX_CMD_PER_LUN 128 | 58 | #define ISCSI_MAX_CMD_PER_LUN 128 |
@@ -69,7 +70,10 @@ enum { | |||
69 | /* Connection suspend "bit" */ | 70 | /* Connection suspend "bit" */ |
70 | #define ISCSI_SUSPEND_BIT 1 | 71 | #define ISCSI_SUSPEND_BIT 1 |
71 | 72 | ||
72 | #define ISCSI_ITT_MASK (0xfff) | 73 | #define ISCSI_ITT_MASK (0x1fff) |
74 | #define ISCSI_TOTAL_CMDS_MAX 4096 | ||
75 | /* this must be a power of two greater than ISCSI_MGMT_CMDS_MAX */ | ||
76 | #define ISCSI_TOTAL_CMDS_MIN 16 | ||
73 | #define ISCSI_AGE_SHIFT 28 | 77 | #define ISCSI_AGE_SHIFT 28 |
74 | #define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT) | 78 | #define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT) |
75 | 79 | ||
@@ -82,18 +86,6 @@ enum { | |||
82 | ISCSI_DIGEST_SIZE = sizeof(__u32), | 86 | ISCSI_DIGEST_SIZE = sizeof(__u32), |
83 | }; | 87 | }; |
84 | 88 | ||
85 | struct iscsi_mgmt_task { | ||
86 | /* | ||
87 | * Becuae LLDs allocate their hdr differently, this is a pointer to | ||
88 | * that storage. It must be setup at session creation time. | ||
89 | */ | ||
90 | struct iscsi_hdr *hdr; | ||
91 | char *data; /* mgmt payload */ | ||
92 | unsigned data_count; /* counts data to be sent */ | ||
93 | uint32_t itt; /* this ITT */ | ||
94 | void *dd_data; /* driver/transport data */ | ||
95 | struct list_head running; | ||
96 | }; | ||
97 | 89 | ||
98 | enum { | 90 | enum { |
99 | ISCSI_TASK_COMPLETED, | 91 | ISCSI_TASK_COMPLETED, |
@@ -101,7 +93,7 @@ enum { | |||
101 | ISCSI_TASK_RUNNING, | 93 | ISCSI_TASK_RUNNING, |
102 | }; | 94 | }; |
103 | 95 | ||
104 | struct iscsi_cmd_task { | 96 | struct iscsi_task { |
105 | /* | 97 | /* |
106 | * Because LLDs allocate their hdr differently, this is a pointer | 98 | * Because LLDs allocate their hdr differently, this is a pointer |
107 | * and length to that storage. It must be setup at session | 99 | * and length to that storage. It must be setup at session |
@@ -118,6 +110,7 @@ struct iscsi_cmd_task { | |||
118 | /* offset in unsolicited stream (bytes); */ | 110 | /* offset in unsolicited stream (bytes); */ |
119 | unsigned unsol_offset; | 111 | unsigned unsol_offset; |
120 | unsigned data_count; /* remaining Data-Out */ | 112 | unsigned data_count; /* remaining Data-Out */ |
113 | char *data; /* mgmt payload */ | ||
121 | struct scsi_cmnd *sc; /* associated SCSI cmd*/ | 114 | struct scsi_cmnd *sc; /* associated SCSI cmd*/ |
122 | struct iscsi_conn *conn; /* used connection */ | 115 | struct iscsi_conn *conn; /* used connection */ |
123 | 116 | ||
@@ -128,9 +121,9 @@ struct iscsi_cmd_task { | |||
128 | void *dd_data; /* driver/transport data */ | 121 | void *dd_data; /* driver/transport data */ |
129 | }; | 122 | }; |
130 | 123 | ||
131 | static inline void* iscsi_next_hdr(struct iscsi_cmd_task *ctask) | 124 | static inline void* iscsi_next_hdr(struct iscsi_task *task) |
132 | { | 125 | { |
133 | return (void*)ctask->hdr + ctask->hdr_len; | 126 | return (void*)task->hdr + task->hdr_len; |
134 | } | 127 | } |
135 | 128 | ||
136 | /* Connection's states */ | 129 | /* Connection's states */ |
@@ -146,11 +139,6 @@ struct iscsi_conn { | |||
146 | void *dd_data; /* iscsi_transport data */ | 139 | void *dd_data; /* iscsi_transport data */ |
147 | struct iscsi_session *session; /* parent session */ | 140 | struct iscsi_session *session; /* parent session */ |
148 | /* | 141 | /* |
149 | * LLDs should set this lock. It protects the transport recv | ||
150 | * code | ||
151 | */ | ||
152 | rwlock_t *recv_lock; | ||
153 | /* | ||
154 | * conn_stop() flag: stop to recover, stop to terminate | 142 | * conn_stop() flag: stop to recover, stop to terminate |
155 | */ | 143 | */ |
156 | int stop_stage; | 144 | int stop_stage; |
@@ -159,7 +147,7 @@ struct iscsi_conn { | |||
159 | unsigned long last_ping; | 147 | unsigned long last_ping; |
160 | int ping_timeout; | 148 | int ping_timeout; |
161 | int recv_timeout; | 149 | int recv_timeout; |
162 | struct iscsi_mgmt_task *ping_mtask; | 150 | struct iscsi_task *ping_task; |
163 | 151 | ||
164 | /* iSCSI connection-wide sequencing */ | 152 | /* iSCSI connection-wide sequencing */ |
165 | uint32_t exp_statsn; | 153 | uint32_t exp_statsn; |
@@ -175,9 +163,8 @@ struct iscsi_conn { | |||
175 | * should always fit in this buffer | 163 | * should always fit in this buffer |
176 | */ | 164 | */ |
177 | char *data; | 165 | char *data; |
178 | struct iscsi_mgmt_task *login_mtask; /* mtask used for login/text */ | 166 | struct iscsi_task *login_task; /* mtask used for login/text */ |
179 | struct iscsi_mgmt_task *mtask; /* xmit mtask in progress */ | 167 | struct iscsi_task *task; /* xmit task in progress */ |
180 | struct iscsi_cmd_task *ctask; /* xmit ctask in progress */ | ||
181 | 168 | ||
182 | /* xmit */ | 169 | /* xmit */ |
183 | struct list_head mgmtqueue; /* mgmt (control) xmit queue */ | 170 | struct list_head mgmtqueue; /* mgmt (control) xmit queue */ |
@@ -208,9 +195,6 @@ struct iscsi_conn { | |||
208 | /* remote portal currently connected to */ | 195 | /* remote portal currently connected to */ |
209 | int portal_port; | 196 | int portal_port; |
210 | char portal_address[ISCSI_ADDRESS_BUF_LEN]; | 197 | char portal_address[ISCSI_ADDRESS_BUF_LEN]; |
211 | /* local address */ | ||
212 | int local_port; | ||
213 | char local_address[ISCSI_ADDRESS_BUF_LEN]; | ||
214 | 198 | ||
215 | /* MIB-statistics */ | 199 | /* MIB-statistics */ |
216 | uint64_t txdata_octets; | 200 | uint64_t txdata_octets; |
@@ -246,6 +230,7 @@ enum { | |||
246 | }; | 230 | }; |
247 | 231 | ||
248 | struct iscsi_session { | 232 | struct iscsi_session { |
233 | struct iscsi_cls_session *cls_session; | ||
249 | /* | 234 | /* |
250 | * Syncs up the scsi eh thread with the iscsi eh thread when sending | 235 | * Syncs up the scsi eh thread with the iscsi eh thread when sending |
251 | * task management functions. This must be taken before the session | 236 | * task management functions. This must be taken before the session |
@@ -281,10 +266,8 @@ struct iscsi_session { | |||
281 | char *password; | 266 | char *password; |
282 | char *password_in; | 267 | char *password_in; |
283 | char *targetname; | 268 | char *targetname; |
269 | char *ifacename; | ||
284 | char *initiatorname; | 270 | char *initiatorname; |
285 | /* hw address or netdev iscsi connection is bound to */ | ||
286 | char *hwaddress; | ||
287 | char *netdev; | ||
288 | /* control data */ | 271 | /* control data */ |
289 | struct iscsi_transport *tt; | 272 | struct iscsi_transport *tt; |
290 | struct Scsi_Host *host; | 273 | struct Scsi_Host *host; |
@@ -298,12 +281,20 @@ struct iscsi_session { | |||
298 | int state; /* session state */ | 281 | int state; /* session state */ |
299 | int age; /* counts session re-opens */ | 282 | int age; /* counts session re-opens */ |
300 | 283 | ||
284 | int scsi_cmds_max; /* max scsi commands */ | ||
301 | int cmds_max; /* size of cmds array */ | 285 | int cmds_max; /* size of cmds array */ |
302 | struct iscsi_cmd_task **cmds; /* Original Cmds arr */ | 286 | struct iscsi_task **cmds; /* Original Cmds arr */ |
303 | struct iscsi_pool cmdpool; /* PDU's pool */ | 287 | struct iscsi_pool cmdpool; /* PDU's pool */ |
304 | int mgmtpool_max; /* size of mgmt array */ | 288 | }; |
305 | struct iscsi_mgmt_task **mgmt_cmds; /* Original mgmt arr */ | 289 | |
306 | struct iscsi_pool mgmtpool; /* Mgmt PDU's pool */ | 290 | struct iscsi_host { |
291 | char *initiatorname; | ||
292 | /* hw address or netdev iscsi connection is bound to */ | ||
293 | char *hwaddress; | ||
294 | char *netdev; | ||
295 | /* local address */ | ||
296 | int local_port; | ||
297 | char local_address[ISCSI_ADDRESS_BUF_LEN]; | ||
307 | }; | 298 | }; |
308 | 299 | ||
309 | /* | 300 | /* |
@@ -316,42 +307,44 @@ extern int iscsi_eh_device_reset(struct scsi_cmnd *sc); | |||
316 | extern int iscsi_queuecommand(struct scsi_cmnd *sc, | 307 | extern int iscsi_queuecommand(struct scsi_cmnd *sc, |
317 | void (*done)(struct scsi_cmnd *)); | 308 | void (*done)(struct scsi_cmnd *)); |
318 | 309 | ||
319 | |||
320 | /* | 310 | /* |
321 | * iSCSI host helpers. | 311 | * iSCSI host helpers. |
322 | */ | 312 | */ |
313 | #define iscsi_host_priv(_shost) \ | ||
314 | (shost_priv(_shost) + sizeof(struct iscsi_host)) | ||
315 | |||
323 | extern int iscsi_host_set_param(struct Scsi_Host *shost, | 316 | extern int iscsi_host_set_param(struct Scsi_Host *shost, |
324 | enum iscsi_host_param param, char *buf, | 317 | enum iscsi_host_param param, char *buf, |
325 | int buflen); | 318 | int buflen); |
326 | extern int iscsi_host_get_param(struct Scsi_Host *shost, | 319 | extern int iscsi_host_get_param(struct Scsi_Host *shost, |
327 | enum iscsi_host_param param, char *buf); | 320 | enum iscsi_host_param param, char *buf); |
321 | extern int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev); | ||
322 | extern struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht, | ||
323 | int dd_data_size, uint16_t qdepth); | ||
324 | extern void iscsi_host_remove(struct Scsi_Host *shost); | ||
325 | extern void iscsi_host_free(struct Scsi_Host *shost); | ||
328 | 326 | ||
329 | /* | 327 | /* |
330 | * session management | 328 | * session management |
331 | */ | 329 | */ |
332 | extern struct iscsi_cls_session * | 330 | extern struct iscsi_cls_session * |
333 | iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *, | 331 | iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost, |
334 | uint16_t, uint16_t, int, int, uint32_t, uint32_t *); | 332 | uint16_t, int, uint32_t, unsigned int); |
335 | extern void iscsi_session_teardown(struct iscsi_cls_session *); | 333 | extern void iscsi_session_teardown(struct iscsi_cls_session *); |
336 | extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *); | ||
337 | extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *); | 334 | extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *); |
338 | extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn, | 335 | extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn, |
339 | enum iscsi_param param, char *buf, int buflen); | 336 | enum iscsi_param param, char *buf, int buflen); |
340 | extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session, | 337 | extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session, |
341 | enum iscsi_param param, char *buf); | 338 | enum iscsi_param param, char *buf); |
342 | 339 | ||
343 | #define session_to_cls(_sess) \ | ||
344 | hostdata_session(_sess->host->hostdata) | ||
345 | |||
346 | #define iscsi_session_printk(prefix, _sess, fmt, a...) \ | 340 | #define iscsi_session_printk(prefix, _sess, fmt, a...) \ |
347 | iscsi_cls_session_printk(prefix, \ | 341 | iscsi_cls_session_printk(prefix, _sess->cls_session, fmt, ##a) |
348 | (struct iscsi_cls_session *)session_to_cls(_sess), fmt, ##a) | ||
349 | 342 | ||
350 | /* | 343 | /* |
351 | * connection management | 344 | * connection management |
352 | */ | 345 | */ |
353 | extern struct iscsi_cls_conn *iscsi_conn_setup(struct iscsi_cls_session *, | 346 | extern struct iscsi_cls_conn *iscsi_conn_setup(struct iscsi_cls_session *, |
354 | uint32_t); | 347 | int, uint32_t); |
355 | extern void iscsi_conn_teardown(struct iscsi_cls_conn *); | 348 | extern void iscsi_conn_teardown(struct iscsi_cls_conn *); |
356 | extern int iscsi_conn_start(struct iscsi_cls_conn *); | 349 | extern int iscsi_conn_start(struct iscsi_cls_conn *); |
357 | extern void iscsi_conn_stop(struct iscsi_cls_conn *, int); | 350 | extern void iscsi_conn_stop(struct iscsi_cls_conn *, int); |
@@ -360,25 +353,29 @@ extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *, | |||
360 | extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err); | 353 | extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err); |
361 | extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, | 354 | extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, |
362 | enum iscsi_param param, char *buf); | 355 | enum iscsi_param param, char *buf); |
356 | extern void iscsi_suspend_tx(struct iscsi_conn *conn); | ||
363 | 357 | ||
364 | #define iscsi_conn_printk(prefix, _c, fmt, a...) \ | 358 | #define iscsi_conn_printk(prefix, _c, fmt, a...) \ |
365 | iscsi_cls_conn_printk(prefix, _c->cls_conn, fmt, ##a) | 359 | iscsi_cls_conn_printk(prefix, ((struct iscsi_conn *)_c)->cls_conn, \ |
360 | fmt, ##a) | ||
366 | 361 | ||
367 | /* | 362 | /* |
368 | * pdu and task processing | 363 | * pdu and task processing |
369 | */ | 364 | */ |
370 | extern void iscsi_update_cmdsn(struct iscsi_session *, struct iscsi_nopin *); | 365 | extern void iscsi_update_cmdsn(struct iscsi_session *, struct iscsi_nopin *); |
371 | extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *, | 366 | extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_task *, |
372 | struct iscsi_data *hdr); | 367 | struct iscsi_data *hdr); |
373 | extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *, | 368 | extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *, |
374 | char *, uint32_t); | 369 | char *, uint32_t); |
375 | extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, | 370 | extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, |
376 | char *, int); | 371 | char *, int); |
377 | extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *, | 372 | extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, |
378 | uint32_t *); | 373 | char *, int); |
379 | extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask); | 374 | extern int iscsi_verify_itt(struct iscsi_conn *, itt_t); |
380 | extern void iscsi_free_mgmt_task(struct iscsi_conn *conn, | 375 | extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t); |
381 | struct iscsi_mgmt_task *mtask); | 376 | extern void iscsi_requeue_task(struct iscsi_task *task); |
377 | extern void iscsi_put_task(struct iscsi_task *task); | ||
378 | extern void __iscsi_get_task(struct iscsi_task *task); | ||
382 | 379 | ||
383 | /* | 380 | /* |
384 | * generic helpers | 381 | * generic helpers |
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 32742c4563de..00137a7769ee 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #define _SCSI_SCSI_H | 9 | #define _SCSI_SCSI_H |
10 | 10 | ||
11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
12 | #include <scsi/scsi_cmnd.h> | ||
12 | 13 | ||
13 | /* | 14 | /* |
14 | * The maximum number of SG segments that we will put inside a | 15 | * The maximum number of SG segments that we will put inside a |
@@ -400,6 +401,7 @@ struct scsi_lun { | |||
400 | #define SOFT_ERROR 0x2005 | 401 | #define SOFT_ERROR 0x2005 |
401 | #define ADD_TO_MLQUEUE 0x2006 | 402 | #define ADD_TO_MLQUEUE 0x2006 |
402 | #define TIMEOUT_ERROR 0x2007 | 403 | #define TIMEOUT_ERROR 0x2007 |
404 | #define SCSI_RETURN_NOT_HANDLED 0x2008 | ||
403 | 405 | ||
404 | /* | 406 | /* |
405 | * Midlevel queue return values. | 407 | * Midlevel queue return values. |
@@ -424,6 +426,22 @@ struct scsi_lun { | |||
424 | #define driver_byte(result) (((result) >> 24) & 0xff) | 426 | #define driver_byte(result) (((result) >> 24) & 0xff) |
425 | #define suggestion(result) (driver_byte(result) & SUGGEST_MASK) | 427 | #define suggestion(result) (driver_byte(result) & SUGGEST_MASK) |
426 | 428 | ||
429 | static inline void set_msg_byte(struct scsi_cmnd *cmd, char status) | ||
430 | { | ||
431 | cmd->result |= status << 8; | ||
432 | } | ||
433 | |||
434 | static inline void set_host_byte(struct scsi_cmnd *cmd, char status) | ||
435 | { | ||
436 | cmd->result |= status << 16; | ||
437 | } | ||
438 | |||
439 | static inline void set_driver_byte(struct scsi_cmnd *cmd, char status) | ||
440 | { | ||
441 | cmd->result |= status << 24; | ||
442 | } | ||
443 | |||
444 | |||
427 | #define sense_class(sense) (((sense) >> 4) & 0x7) | 445 | #define sense_class(sense) (((sense) >> 4) & 0x7) |
428 | #define sense_error(sense) ((sense) & 0xf) | 446 | #define sense_error(sense) ((sense) & 0xf) |
429 | #define sense_valid(sense) ((sense) & 0x80); | 447 | #define sense_valid(sense) ((sense) & 0x80); |
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 3e46dfae8194..66c944849d6b 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
8 | #include <linux/timer.h> | 8 | #include <linux/timer.h> |
9 | #include <linux/scatterlist.h> | 9 | #include <linux/scatterlist.h> |
10 | #include <linux/blkdev.h> | ||
11 | 10 | ||
12 | struct Scsi_Host; | 11 | struct Scsi_Host; |
13 | struct scsi_device; | 12 | struct scsi_device; |
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 00b78763a1bf..6467f78b191f 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h | |||
@@ -162,9 +162,29 @@ struct scsi_device { | |||
162 | 162 | ||
163 | struct execute_work ew; /* used to get process context on put */ | 163 | struct execute_work ew; /* used to get process context on put */ |
164 | 164 | ||
165 | struct scsi_dh_data *scsi_dh_data; | ||
165 | enum scsi_device_state sdev_state; | 166 | enum scsi_device_state sdev_state; |
166 | unsigned long sdev_data[0]; | 167 | unsigned long sdev_data[0]; |
167 | } __attribute__((aligned(sizeof(unsigned long)))); | 168 | } __attribute__((aligned(sizeof(unsigned long)))); |
169 | |||
170 | struct scsi_device_handler { | ||
171 | /* Used by the infrastructure */ | ||
172 | struct list_head list; /* list of scsi_device_handlers */ | ||
173 | struct notifier_block nb; | ||
174 | |||
175 | /* Filled by the hardware handler */ | ||
176 | struct module *module; | ||
177 | const char *name; | ||
178 | int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *); | ||
179 | int (*activate)(struct scsi_device *); | ||
180 | int (*prep_fn)(struct scsi_device *, struct request *); | ||
181 | }; | ||
182 | |||
183 | struct scsi_dh_data { | ||
184 | struct scsi_device_handler *scsi_dh; | ||
185 | char buf[0]; | ||
186 | }; | ||
187 | |||
168 | #define to_scsi_device(d) \ | 188 | #define to_scsi_device(d) \ |
169 | container_of(d, struct scsi_device, sdev_gendev) | 189 | container_of(d, struct scsi_device, sdev_gendev) |
170 | #define class_to_sdev(d) \ | 190 | #define class_to_sdev(d) \ |
@@ -231,7 +251,9 @@ extern struct scsi_device *__scsi_add_device(struct Scsi_Host *, | |||
231 | uint, uint, uint, void *hostdata); | 251 | uint, uint, uint, void *hostdata); |
232 | extern int scsi_add_device(struct Scsi_Host *host, uint channel, | 252 | extern int scsi_add_device(struct Scsi_Host *host, uint channel, |
233 | uint target, uint lun); | 253 | uint target, uint lun); |
254 | extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh); | ||
234 | extern void scsi_remove_device(struct scsi_device *); | 255 | extern void scsi_remove_device(struct scsi_device *); |
256 | extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh); | ||
235 | 257 | ||
236 | extern int scsi_device_get(struct scsi_device *); | 258 | extern int scsi_device_get(struct scsi_device *); |
237 | extern void scsi_device_put(struct scsi_device *); | 259 | extern void scsi_device_put(struct scsi_device *); |
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h new file mode 100644 index 000000000000..3ad2303d1a16 --- /dev/null +++ b/include/scsi/scsi_dh.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Header file for SCSI device handler infrastruture. | ||
3 | * | ||
4 | * Modified version of patches posted by Mike Christie <michaelc@cs.wisc.edu> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | * | ||
20 | * Copyright IBM Corporation, 2007 | ||
21 | * Authors: | ||
22 | * Chandra Seetharaman <sekharan@us.ibm.com> | ||
23 | * Mike Anderson <andmike@linux.vnet.ibm.com> | ||
24 | */ | ||
25 | |||
26 | #include <scsi/scsi_device.h> | ||
27 | |||
28 | enum { | ||
29 | SCSI_DH_OK = 0, | ||
30 | /* | ||
31 | * device errors | ||
32 | */ | ||
33 | SCSI_DH_DEV_FAILED, /* generic device error */ | ||
34 | SCSI_DH_DEV_TEMP_BUSY, | ||
35 | SCSI_DH_DEVICE_MAX, /* max device blkerr definition */ | ||
36 | |||
37 | /* | ||
38 | * transport errors | ||
39 | */ | ||
40 | SCSI_DH_NOTCONN = SCSI_DH_DEVICE_MAX + 1, | ||
41 | SCSI_DH_CONN_FAILURE, | ||
42 | SCSI_DH_TRANSPORT_MAX, /* max transport blkerr definition */ | ||
43 | |||
44 | /* | ||
45 | * driver and generic errors | ||
46 | */ | ||
47 | SCSI_DH_IO = SCSI_DH_TRANSPORT_MAX + 1, /* generic error */ | ||
48 | SCSI_DH_INVALID_IO, | ||
49 | SCSI_DH_RETRY, /* retry the req, but not immediately */ | ||
50 | SCSI_DH_IMM_RETRY, /* immediately retry the req */ | ||
51 | SCSI_DH_TIMED_OUT, | ||
52 | SCSI_DH_RES_TEMP_UNAVAIL, | ||
53 | SCSI_DH_DEV_OFFLINED, | ||
54 | SCSI_DH_NOSYS, | ||
55 | SCSI_DH_DRIVER_MAX, | ||
56 | }; | ||
57 | #if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE) | ||
58 | extern int scsi_dh_activate(struct request_queue *); | ||
59 | extern int scsi_dh_handler_exist(const char *); | ||
60 | #else | ||
61 | static inline int scsi_dh_activate(struct request_queue *req) | ||
62 | { | ||
63 | return 0; | ||
64 | } | ||
65 | static inline int scsi_dh_handler_exist(const char *name) | ||
66 | { | ||
67 | return 0; | ||
68 | } | ||
69 | #endif | ||
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index aab1eae2ec4c..f5444e033cc9 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h | |||
@@ -30,11 +30,11 @@ | |||
30 | 30 | ||
31 | struct scsi_transport_template; | 31 | struct scsi_transport_template; |
32 | struct iscsi_transport; | 32 | struct iscsi_transport; |
33 | struct iscsi_endpoint; | ||
33 | struct Scsi_Host; | 34 | struct Scsi_Host; |
34 | struct iscsi_cls_conn; | 35 | struct iscsi_cls_conn; |
35 | struct iscsi_conn; | 36 | struct iscsi_conn; |
36 | struct iscsi_cmd_task; | 37 | struct iscsi_task; |
37 | struct iscsi_mgmt_task; | ||
38 | struct sockaddr; | 38 | struct sockaddr; |
39 | 39 | ||
40 | /** | 40 | /** |
@@ -58,19 +58,22 @@ struct sockaddr; | |||
58 | * @stop_conn: suspend/recover/terminate connection | 58 | * @stop_conn: suspend/recover/terminate connection |
59 | * @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text. | 59 | * @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text. |
60 | * @session_recovery_timedout: notify LLD a block during recovery timed out | 60 | * @session_recovery_timedout: notify LLD a block during recovery timed out |
61 | * @init_cmd_task: Initialize a iscsi_cmd_task and any internal structs. | 61 | * @init_task: Initialize a iscsi_task and any internal structs. |
62 | * Called from queuecommand with session lock held. | 62 | * When offloading the data path, this is called from |
63 | * @init_mgmt_task: Initialize a iscsi_mgmt_task and any internal structs. | 63 | * queuecommand with the session lock, or from the |
64 | * Called from iscsi_conn_send_generic with xmitmutex. | 64 | * iscsi_conn_send_pdu context with the session lock. |
65 | * @xmit_cmd_task: Requests LLD to transfer cmd task. Returns 0 or the | 65 | * When not offloading the data path, this is called |
66 | * from the scsi work queue without the session lock. | ||
67 | * @xmit_task Requests LLD to transfer cmd task. Returns 0 or the | ||
66 | * the number of bytes transferred on success, and -Exyz | 68 | * the number of bytes transferred on success, and -Exyz |
67 | * value on error. | 69 | * value on error. When offloading the data path, this |
68 | * @xmit_mgmt_task: Requests LLD to transfer mgmt task. Returns 0 or the | 70 | * is called from queuecommand with the session lock, or |
69 | * the number of bytes transferred on success, and -Exyz | 71 | * from the iscsi_conn_send_pdu context with the session |
70 | * value on error. | 72 | * lock. When not offloading the data path, this is called |
71 | * @cleanup_cmd_task: requests LLD to fail cmd task. Called with xmitmutex | 73 | * from the scsi work queue without the session lock. |
72 | * and session->lock after the connection has been | 74 | * @cleanup_task: requests LLD to fail task. Called with session lock |
73 | * suspended and terminated during recovery. If called | 75 | * and after the connection has been suspended and |
76 | * terminated during recovery. If called | ||
74 | * from abort task then connection is not suspended | 77 | * from abort task then connection is not suspended |
75 | * or terminated but sk_callback_lock is held | 78 | * or terminated but sk_callback_lock is held |
76 | * | 79 | * |
@@ -83,17 +86,9 @@ struct iscsi_transport { | |||
83 | /* LLD sets this to indicate what values it can export to sysfs */ | 86 | /* LLD sets this to indicate what values it can export to sysfs */ |
84 | uint64_t param_mask; | 87 | uint64_t param_mask; |
85 | uint64_t host_param_mask; | 88 | uint64_t host_param_mask; |
86 | struct scsi_host_template *host_template; | 89 | struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep, |
87 | /* LLD connection data size */ | 90 | uint16_t cmds_max, uint16_t qdepth, |
88 | int conndata_size; | 91 | uint32_t sn, uint32_t *hn); |
89 | /* LLD session data size */ | ||
90 | int sessiondata_size; | ||
91 | int max_lun; | ||
92 | unsigned int max_conn; | ||
93 | unsigned int max_cmd_len; | ||
94 | struct iscsi_cls_session *(*create_session) (struct iscsi_transport *it, | ||
95 | struct scsi_transport_template *t, uint16_t, uint16_t, | ||
96 | uint32_t sn, uint32_t *hn); | ||
97 | void (*destroy_session) (struct iscsi_cls_session *session); | 92 | void (*destroy_session) (struct iscsi_cls_session *session); |
98 | struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess, | 93 | struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess, |
99 | uint32_t cid); | 94 | uint32_t cid); |
@@ -118,20 +113,15 @@ struct iscsi_transport { | |||
118 | char *data, uint32_t data_size); | 113 | char *data, uint32_t data_size); |
119 | void (*get_stats) (struct iscsi_cls_conn *conn, | 114 | void (*get_stats) (struct iscsi_cls_conn *conn, |
120 | struct iscsi_stats *stats); | 115 | struct iscsi_stats *stats); |
121 | int (*init_cmd_task) (struct iscsi_cmd_task *ctask); | 116 | int (*init_task) (struct iscsi_task *task); |
122 | void (*init_mgmt_task) (struct iscsi_conn *conn, | 117 | int (*xmit_task) (struct iscsi_task *task); |
123 | struct iscsi_mgmt_task *mtask); | 118 | void (*cleanup_task) (struct iscsi_conn *conn, |
124 | int (*xmit_cmd_task) (struct iscsi_conn *conn, | 119 | struct iscsi_task *task); |
125 | struct iscsi_cmd_task *ctask); | ||
126 | void (*cleanup_cmd_task) (struct iscsi_conn *conn, | ||
127 | struct iscsi_cmd_task *ctask); | ||
128 | int (*xmit_mgmt_task) (struct iscsi_conn *conn, | ||
129 | struct iscsi_mgmt_task *mtask); | ||
130 | void (*session_recovery_timedout) (struct iscsi_cls_session *session); | 120 | void (*session_recovery_timedout) (struct iscsi_cls_session *session); |
131 | int (*ep_connect) (struct sockaddr *dst_addr, int non_blocking, | 121 | struct iscsi_endpoint *(*ep_connect) (struct sockaddr *dst_addr, |
132 | uint64_t *ep_handle); | 122 | int non_blocking); |
133 | int (*ep_poll) (uint64_t ep_handle, int timeout_ms); | 123 | int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms); |
134 | void (*ep_disconnect) (uint64_t ep_handle); | 124 | void (*ep_disconnect) (struct iscsi_endpoint *ep); |
135 | int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type, | 125 | int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type, |
136 | uint32_t enable, struct sockaddr *dst_addr); | 126 | uint32_t enable, struct sockaddr *dst_addr); |
137 | }; | 127 | }; |
@@ -172,9 +162,10 @@ enum { | |||
172 | ISCSI_SESSION_FREE, | 162 | ISCSI_SESSION_FREE, |
173 | }; | 163 | }; |
174 | 164 | ||
165 | #define ISCSI_MAX_TARGET -1 | ||
166 | |||
175 | struct iscsi_cls_session { | 167 | struct iscsi_cls_session { |
176 | struct list_head sess_list; /* item in session_list */ | 168 | struct list_head sess_list; /* item in session_list */ |
177 | struct list_head host_list; | ||
178 | struct iscsi_transport *transport; | 169 | struct iscsi_transport *transport; |
179 | spinlock_t lock; | 170 | spinlock_t lock; |
180 | struct work_struct block_work; | 171 | struct work_struct block_work; |
@@ -186,7 +177,7 @@ struct iscsi_cls_session { | |||
186 | int recovery_tmo; | 177 | int recovery_tmo; |
187 | struct delayed_work recovery_work; | 178 | struct delayed_work recovery_work; |
188 | 179 | ||
189 | int target_id; | 180 | unsigned int target_id; |
190 | 181 | ||
191 | int state; | 182 | int state; |
192 | int sid; /* session id */ | 183 | int sid; /* session id */ |
@@ -203,14 +194,22 @@ struct iscsi_cls_session { | |||
203 | #define starget_to_session(_stgt) \ | 194 | #define starget_to_session(_stgt) \ |
204 | iscsi_dev_to_session(_stgt->dev.parent) | 195 | iscsi_dev_to_session(_stgt->dev.parent) |
205 | 196 | ||
206 | struct iscsi_host { | 197 | struct iscsi_cls_host { |
207 | struct list_head sessions; | ||
208 | atomic_t nr_scans; | 198 | atomic_t nr_scans; |
209 | struct mutex mutex; | 199 | struct mutex mutex; |
210 | struct workqueue_struct *scan_workq; | 200 | struct workqueue_struct *scan_workq; |
211 | char scan_workq_name[KOBJ_NAME_LEN]; | 201 | char scan_workq_name[KOBJ_NAME_LEN]; |
212 | }; | 202 | }; |
213 | 203 | ||
204 | extern void iscsi_host_for_each_session(struct Scsi_Host *shost, | ||
205 | void (*fn)(struct iscsi_cls_session *)); | ||
206 | |||
207 | struct iscsi_endpoint { | ||
208 | void *dd_data; /* LLD private data */ | ||
209 | struct device dev; | ||
210 | unsigned int id; | ||
211 | }; | ||
212 | |||
214 | /* | 213 | /* |
215 | * session and connection functions that can be used by HW iSCSI LLDs | 214 | * session and connection functions that can be used by HW iSCSI LLDs |
216 | */ | 215 | */ |
@@ -222,22 +221,26 @@ struct iscsi_host { | |||
222 | 221 | ||
223 | extern int iscsi_session_chkready(struct iscsi_cls_session *session); | 222 | extern int iscsi_session_chkready(struct iscsi_cls_session *session); |
224 | extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost, | 223 | extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost, |
225 | struct iscsi_transport *transport); | 224 | struct iscsi_transport *transport, int dd_size); |
226 | extern int iscsi_add_session(struct iscsi_cls_session *session, | 225 | extern int iscsi_add_session(struct iscsi_cls_session *session, |
227 | unsigned int target_id); | 226 | unsigned int target_id); |
228 | extern int iscsi_session_event(struct iscsi_cls_session *session, | 227 | extern int iscsi_session_event(struct iscsi_cls_session *session, |
229 | enum iscsi_uevent_e event); | 228 | enum iscsi_uevent_e event); |
230 | extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, | 229 | extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, |
231 | struct iscsi_transport *t, | 230 | struct iscsi_transport *t, |
231 | int dd_size, | ||
232 | unsigned int target_id); | 232 | unsigned int target_id); |
233 | extern void iscsi_remove_session(struct iscsi_cls_session *session); | 233 | extern void iscsi_remove_session(struct iscsi_cls_session *session); |
234 | extern void iscsi_free_session(struct iscsi_cls_session *session); | 234 | extern void iscsi_free_session(struct iscsi_cls_session *session); |
235 | extern int iscsi_destroy_session(struct iscsi_cls_session *session); | 235 | extern int iscsi_destroy_session(struct iscsi_cls_session *session); |
236 | extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, | 236 | extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, |
237 | uint32_t cid); | 237 | int dd_size, uint32_t cid); |
238 | extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); | 238 | extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); |
239 | extern void iscsi_unblock_session(struct iscsi_cls_session *session); | 239 | extern void iscsi_unblock_session(struct iscsi_cls_session *session); |
240 | extern void iscsi_block_session(struct iscsi_cls_session *session); | 240 | extern void iscsi_block_session(struct iscsi_cls_session *session); |
241 | extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time); | 241 | extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time); |
242 | extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size); | ||
243 | extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep); | ||
244 | extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle); | ||
242 | 245 | ||
243 | #endif | 246 | #endif |
diff --git a/include/scsi/sg.h b/include/scsi/sg.h index 519c49a0fc11..934ae389671d 100644 --- a/include/scsi/sg.h +++ b/include/scsi/sg.h | |||
@@ -206,6 +206,7 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ | |||
206 | #define SG_SCSI_RESET_DEVICE 1 | 206 | #define SG_SCSI_RESET_DEVICE 1 |
207 | #define SG_SCSI_RESET_BUS 2 | 207 | #define SG_SCSI_RESET_BUS 2 |
208 | #define SG_SCSI_RESET_HOST 3 | 208 | #define SG_SCSI_RESET_HOST 3 |
209 | #define SG_SCSI_RESET_TARGET 4 | ||
209 | 210 | ||
210 | /* synchronous SCSI command ioctl, (only in version 3 interface) */ | 211 | /* synchronous SCSI command ioctl, (only in version 3 interface) */ |
211 | #define SG_IO 0x2285 /* similar effect as write() followed by read() */ | 212 | #define SG_IO 0x2285 /* similar effect as write() followed by read() */ |
diff --git a/lib/Kconfig b/lib/Kconfig index 8cc8e8722a3f..c7ad7a5b3535 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
@@ -29,6 +29,13 @@ config CRC16 | |||
29 | the kernel tree does. Such modules that use library CRC16 | 29 | the kernel tree does. Such modules that use library CRC16 |
30 | functions require M here. | 30 | functions require M here. |
31 | 31 | ||
32 | config CRC_T10DIF | ||
33 | tristate "CRC calculation for the T10 Data Integrity Field" | ||
34 | help | ||
35 | This option is only needed if a module that's not in the | ||
36 | kernel tree needs to calculate CRC checks for use with the | ||
37 | SCSI data integrity subsystem. | ||
38 | |||
32 | config CRC_ITU_T | 39 | config CRC_ITU_T |
33 | tristate "CRC ITU-T V.41 functions" | 40 | tristate "CRC ITU-T V.41 functions" |
34 | help | 41 | help |
diff --git a/lib/Makefile b/lib/Makefile index 4b836a53c08f..2c62a9c06fbe 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
@@ -54,6 +54,7 @@ endif | |||
54 | obj-$(CONFIG_BITREVERSE) += bitrev.o | 54 | obj-$(CONFIG_BITREVERSE) += bitrev.o |
55 | obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o | 55 | obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o |
56 | obj-$(CONFIG_CRC16) += crc16.o | 56 | obj-$(CONFIG_CRC16) += crc16.o |
57 | obj-$(CONFIG_CRC_T10DIF)+= crc-t10dif.o | ||
57 | obj-$(CONFIG_CRC_ITU_T) += crc-itu-t.o | 58 | obj-$(CONFIG_CRC_ITU_T) += crc-itu-t.o |
58 | obj-$(CONFIG_CRC32) += crc32.o | 59 | obj-$(CONFIG_CRC32) += crc32.o |
59 | obj-$(CONFIG_CRC7) += crc7.o | 60 | obj-$(CONFIG_CRC7) += crc7.o |
diff --git a/lib/crc-t10dif.c b/lib/crc-t10dif.c new file mode 100644 index 000000000000..fbbd66ed86cd --- /dev/null +++ b/lib/crc-t10dif.c | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * T10 Data Integrity Field CRC16 calculation | ||
3 | * | ||
4 | * Copyright (c) 2007 Oracle Corporation. All rights reserved. | ||
5 | * Written by Martin K. Petersen <martin.petersen@oracle.com> | ||
6 | * | ||
7 | * This source code is licensed under the GNU General Public License, | ||
8 | * Version 2. See the file COPYING for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/types.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/crc-t10dif.h> | ||
14 | |||
15 | /* Table generated using the following polynomium: | ||
16 | * x^16 + x^15 + x^11 + x^9 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 | ||
17 | * gt: 0x8bb7 | ||
18 | */ | ||
19 | static const __u16 t10_dif_crc_table[256] = { | ||
20 | 0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B, | ||
21 | 0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6, | ||
22 | 0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6, | ||
23 | 0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B, | ||
24 | 0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1, | ||
25 | 0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C, | ||
26 | 0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C, | ||
27 | 0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781, | ||
28 | 0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8, | ||
29 | 0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255, | ||
30 | 0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925, | ||
31 | 0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698, | ||
32 | 0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472, | ||
33 | 0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF, | ||
34 | 0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF, | ||
35 | 0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02, | ||
36 | 0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA, | ||
37 | 0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067, | ||
38 | 0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17, | ||
39 | 0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA, | ||
40 | 0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640, | ||
41 | 0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD, | ||
42 | 0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D, | ||
43 | 0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30, | ||
44 | 0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759, | ||
45 | 0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4, | ||
46 | 0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394, | ||
47 | 0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29, | ||
48 | 0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3, | ||
49 | 0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E, | ||
50 | 0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E, | ||
51 | 0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3 | ||
52 | }; | ||
53 | |||
54 | __u16 crc_t10dif(const unsigned char *buffer, size_t len) | ||
55 | { | ||
56 | __u16 crc = 0; | ||
57 | unsigned int i; | ||
58 | |||
59 | for (i = 0 ; i < len ; i++) | ||
60 | crc = (crc << 8) ^ t10_dif_crc_table[((crc >> 8) ^ buffer[i]) & 0xff]; | ||
61 | |||
62 | return crc; | ||
63 | } | ||
64 | EXPORT_SYMBOL(crc_t10dif); | ||
65 | |||
66 | MODULE_DESCRIPTION("T10 DIF CRC calculation"); | ||
67 | MODULE_LICENSE("GPL"); | ||