1 | /* |
2 | * This file is part of the Emulex Linux Device Driver for Enterprise iSCSI |
3 | * Host Bus Adapters. Refer to the README file included with this package |
4 | * for driver version and adapter compatibility. |
5 | * |
6 | * Copyright (c) 2018 Broadcom. All Rights Reserved. |
7 | * The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify it |
10 | * under the terms of version 2 of the GNU General Public License as published |
11 | * by the Free Software Foundation. |
12 | * |
13 | * This program is distributed in the hope that it will be useful. ALL EXPRESS |
14 | * OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY |
15 | * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, |
16 | * OR NON-INFRINGEMENT, ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH |
17 | * DISCLAIMERS ARE HELD TO BE LEGALLY INVALID. |
18 | * See the GNU General Public License for more details, a copy of which |
19 | * can be found in the file COPYING included with this package. |
20 | * |
21 | * Contact Information: |
22 | * linux-drivers@broadcom.com |
23 | * |
24 | */ |
25 | |
26 | #include <linux/bsg-lib.h> |
27 | #include <scsi/scsi_transport_iscsi.h> |
28 | #include <scsi/scsi_bsg_iscsi.h> |
29 | #include "be_mgmt.h" |
30 | #include "be_iscsi.h" |
31 | #include "be_main.h" |
32 | |
33 | unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, |
34 | struct beiscsi_hba *phba, |
35 | struct bsg_job *job, |
36 | struct be_dma_mem *nonemb_cmd) |
37 | { |
38 | struct be_mcc_wrb *wrb; |
39 | struct be_sge *mcc_sge; |
40 | unsigned int tag = 0; |
41 | struct iscsi_bsg_request *bsg_req = job->request; |
42 | struct be_bsg_vendor_cmd *req = nonemb_cmd->va; |
43 | unsigned short region, sector_size, sector, offset; |
44 | |
45 | nonemb_cmd->size = job->request_payload.payload_len; |
46 | memset(nonemb_cmd->va, 0, nonemb_cmd->size); |
47 | region = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; |
48 | sector_size = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; |
49 | sector = bsg_req->rqst_data.h_vendor.vendor_cmd[3]; |
50 | offset = bsg_req->rqst_data.h_vendor.vendor_cmd[4]; |
51 | req->region = region; |
52 | req->sector = sector; |
53 | req->offset = offset; |
54 | |
55 | if (mutex_lock_interruptible(&ctrl->mbox_lock)) |
56 | return 0; |
57 | switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) { |
58 | case BEISCSI_WRITE_FLASH: |
59 | offset = sector * sector_size + offset; |
60 | be_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ISCSI, |
61 | OPCODE_COMMON_WRITE_FLASH, cmd_len: sizeof(*req)); |
62 | sg_copy_to_buffer(sgl: job->request_payload.sg_list, |
63 | nents: job->request_payload.sg_cnt, |
64 | buf: nonemb_cmd->va + offset, buflen: job->request_len); |
65 | break; |
66 | case BEISCSI_READ_FLASH: |
67 | be_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ISCSI, |
68 | OPCODE_COMMON_READ_FLASH, cmd_len: sizeof(*req)); |
69 | break; |
70 | default: |
71 | beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, |
72 | "BG_%d : Unsupported cmd = 0x%x\n\n" , |
73 | bsg_req->rqst_data.h_vendor.vendor_cmd[0]); |
74 | |
75 | mutex_unlock(lock: &ctrl->mbox_lock); |
76 | return -EPERM; |
77 | } |
78 | |
79 | wrb = alloc_mcc_wrb(phba, ref_tag: &tag); |
80 | if (!wrb) { |
81 | mutex_unlock(lock: &ctrl->mbox_lock); |
82 | return 0; |
83 | } |
84 | |
85 | mcc_sge = nonembedded_sgl(wrb); |
86 | be_wrb_hdr_prepare(wrb, payload_len: nonemb_cmd->size, embedded: false, |
87 | sge_cnt: job->request_payload.sg_cnt); |
88 | mcc_sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); |
89 | mcc_sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); |
90 | mcc_sge->len = cpu_to_le32(nonemb_cmd->size); |
91 | |
92 | be_mcc_notify(phba, tag); |
93 | |
94 | mutex_unlock(lock: &ctrl->mbox_lock); |
95 | return tag; |
96 | } |
97 | |
98 | /** |
99 | * mgmt_open_connection()- Establish a TCP CXN |
100 | * @phba: driver priv structure |
101 | * @dst_addr: Destination Address |
102 | * @beiscsi_ep: ptr to device endpoint struct |
103 | * @nonemb_cmd: ptr to memory allocated for command |
104 | * |
105 | * return |
106 | * Success: Tag number of the MBX Command issued |
107 | * Failure: Error code |
108 | **/ |
109 | int mgmt_open_connection(struct beiscsi_hba *phba, |
110 | struct sockaddr *dst_addr, |
111 | struct beiscsi_endpoint *beiscsi_ep, |
112 | struct be_dma_mem *nonemb_cmd) |
113 | { |
114 | struct hwi_controller *phwi_ctrlr; |
115 | struct hwi_context_memory *phwi_context; |
116 | struct sockaddr_in *daddr_in = (struct sockaddr_in *)dst_addr; |
117 | struct sockaddr_in6 *daddr_in6 = (struct sockaddr_in6 *)dst_addr; |
118 | struct be_ctrl_info *ctrl = &phba->ctrl; |
119 | struct be_mcc_wrb *wrb; |
120 | struct tcp_connect_and_offload_in_v1 *req; |
121 | unsigned short def_hdr_id; |
122 | unsigned short def_data_id; |
123 | struct phys_addr template_address = { 0, 0 }; |
124 | struct phys_addr *ptemplate_address; |
125 | unsigned int tag = 0; |
126 | unsigned int i, ulp_num; |
127 | unsigned short cid = beiscsi_ep->ep_cid; |
128 | struct be_sge *sge; |
129 | |
130 | if (dst_addr->sa_family != PF_INET && dst_addr->sa_family != PF_INET6) { |
131 | beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, |
132 | "BG_%d : unknown addr family %d\n" , |
133 | dst_addr->sa_family); |
134 | return 0; |
135 | } |
136 | |
137 | phwi_ctrlr = phba->phwi_ctrlr; |
138 | phwi_context = phwi_ctrlr->phwi_ctxt; |
139 | |
140 | ulp_num = phwi_ctrlr->wrb_context[BE_GET_CRI_FROM_CID(cid)].ulp_num; |
141 | |
142 | def_hdr_id = (unsigned short)HWI_GET_DEF_HDRQ_ID(phba, ulp_num); |
143 | def_data_id = (unsigned short)HWI_GET_DEF_BUFQ_ID(phba, ulp_num); |
144 | |
145 | ptemplate_address = &template_address; |
146 | ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address); |
147 | if (mutex_lock_interruptible(&ctrl->mbox_lock)) |
148 | return 0; |
149 | wrb = alloc_mcc_wrb(phba, ref_tag: &tag); |
150 | if (!wrb) { |
151 | mutex_unlock(lock: &ctrl->mbox_lock); |
152 | return 0; |
153 | } |
154 | |
155 | sge = nonembedded_sgl(wrb); |
156 | req = nonemb_cmd->va; |
157 | memset(req, 0, sizeof(*req)); |
158 | |
159 | be_wrb_hdr_prepare(wrb, payload_len: nonemb_cmd->size, embedded: false, sge_cnt: 1); |
160 | be_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ISCSI, |
161 | OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD, |
162 | cmd_len: nonemb_cmd->size); |
163 | if (dst_addr->sa_family == PF_INET) { |
164 | __be32 s_addr = daddr_in->sin_addr.s_addr; |
165 | req->ip_address.ip_type = BEISCSI_IP_TYPE_V4; |
166 | req->ip_address.addr[0] = s_addr & 0x000000ff; |
167 | req->ip_address.addr[1] = (s_addr & 0x0000ff00) >> 8; |
168 | req->ip_address.addr[2] = (s_addr & 0x00ff0000) >> 16; |
169 | req->ip_address.addr[3] = (s_addr & 0xff000000) >> 24; |
170 | req->tcp_port = ntohs(daddr_in->sin_port); |
171 | beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr; |
172 | beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port); |
173 | beiscsi_ep->ip_type = BEISCSI_IP_TYPE_V4; |
174 | } else { |
175 | /* else its PF_INET6 family */ |
176 | req->ip_address.ip_type = BEISCSI_IP_TYPE_V6; |
177 | memcpy(&req->ip_address.addr, |
178 | &daddr_in6->sin6_addr.in6_u.u6_addr8, 16); |
179 | req->tcp_port = ntohs(daddr_in6->sin6_port); |
180 | beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port); |
181 | memcpy(&beiscsi_ep->dst6_addr, |
182 | &daddr_in6->sin6_addr.in6_u.u6_addr8, 16); |
183 | beiscsi_ep->ip_type = BEISCSI_IP_TYPE_V6; |
184 | } |
185 | req->cid = cid; |
186 | i = phba->nxt_cqid++; |
187 | if (phba->nxt_cqid == phba->num_cpus) |
188 | phba->nxt_cqid = 0; |
189 | req->cq_id = phwi_context->be_cq[i].id; |
190 | beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, |
191 | "BG_%d : i=%d cq_id=%d\n" , i, req->cq_id); |
192 | req->defq_id = def_hdr_id; |
193 | req->hdr_ring_id = def_hdr_id; |
194 | req->data_ring_id = def_data_id; |
195 | req->do_offload = 1; |
196 | req->dataout_template_pa.lo = ptemplate_address->lo; |
197 | req->dataout_template_pa.hi = ptemplate_address->hi; |
198 | sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); |
199 | sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); |
200 | sge->len = cpu_to_le32(nonemb_cmd->size); |
201 | |
202 | if (!is_chip_be2_be3r(phba)) { |
203 | req->hdr.version = MBX_CMD_VER1; |
204 | req->tcp_window_size = 0x8000; |
205 | req->tcp_window_scale_count = 2; |
206 | } |
207 | |
208 | be_mcc_notify(phba, tag); |
209 | mutex_unlock(lock: &ctrl->mbox_lock); |
210 | return tag; |
211 | } |
212 | |
213 | /** |
214 | * beiscsi_exec_nemb_cmd()- execute non-embedded MBX cmd |
215 | * @phba: driver priv structure |
216 | * @nonemb_cmd: DMA address of the MBX command to be issued |
217 | * @cbfn: callback func on MCC completion |
218 | * @resp_buf: buffer to copy the MBX cmd response |
219 | * @resp_buf_len: response length to be copied |
220 | * |
221 | **/ |
222 | static int beiscsi_exec_nemb_cmd(struct beiscsi_hba *phba, |
223 | struct be_dma_mem *nonemb_cmd, |
224 | void (*cbfn)(struct beiscsi_hba *, |
225 | unsigned int), |
226 | void *resp_buf, u32 resp_buf_len) |
227 | { |
228 | struct be_ctrl_info *ctrl = &phba->ctrl; |
229 | struct be_mcc_wrb *wrb; |
230 | struct be_sge *sge; |
231 | unsigned int tag; |
232 | int rc = 0; |
233 | |
234 | mutex_lock(&ctrl->mbox_lock); |
235 | wrb = alloc_mcc_wrb(phba, ref_tag: &tag); |
236 | if (!wrb) { |
237 | mutex_unlock(lock: &ctrl->mbox_lock); |
238 | return -ENOMEM; |
239 | } |
240 | |
241 | sge = nonembedded_sgl(wrb); |
242 | be_wrb_hdr_prepare(wrb, payload_len: nonemb_cmd->size, embedded: false, sge_cnt: 1); |
243 | sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); |
244 | sge->pa_lo = cpu_to_le32(lower_32_bits(nonemb_cmd->dma)); |
245 | sge->len = cpu_to_le32(nonemb_cmd->size); |
246 | |
247 | if (cbfn) { |
248 | struct be_dma_mem *tag_mem; |
249 | |
250 | set_bit(MCC_TAG_STATE_ASYNC, addr: &ctrl->ptag_state[tag].tag_state); |
251 | ctrl->ptag_state[tag].cbfn = cbfn; |
252 | tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state; |
253 | |
254 | /* store DMA mem to be freed in callback */ |
255 | tag_mem->size = nonemb_cmd->size; |
256 | tag_mem->va = nonemb_cmd->va; |
257 | tag_mem->dma = nonemb_cmd->dma; |
258 | } |
259 | be_mcc_notify(phba, tag); |
260 | mutex_unlock(lock: &ctrl->mbox_lock); |
261 | |
262 | /* with cbfn set, its async cmd, don't wait */ |
263 | if (cbfn) |
264 | return 0; |
265 | |
266 | rc = beiscsi_mccq_compl_wait(phba, tag, NULL, mbx_cmd_mem: nonemb_cmd); |
267 | |
268 | /* copy the response, if any */ |
269 | if (resp_buf) |
270 | memcpy(resp_buf, nonemb_cmd->va, resp_buf_len); |
271 | return rc; |
272 | } |
273 | |
274 | static int beiscsi_prep_nemb_cmd(struct beiscsi_hba *phba, |
275 | struct be_dma_mem *cmd, |
276 | u8 subsystem, u8 opcode, u32 size) |
277 | { |
278 | cmd->va = dma_alloc_coherent(dev: &phba->ctrl.pdev->dev, size, dma_handle: &cmd->dma, |
279 | GFP_KERNEL); |
280 | if (!cmd->va) { |
281 | beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, |
282 | "BG_%d : Failed to allocate memory for if info\n" ); |
283 | return -ENOMEM; |
284 | } |
285 | cmd->size = size; |
286 | be_cmd_hdr_prepare(req_hdr: cmd->va, subsystem, opcode, cmd_len: size); |
287 | beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, |
288 | "BG_%d : subsystem %u cmd %u size %u\n" , |
289 | subsystem, opcode, size); |
290 | return 0; |
291 | } |
292 | |
293 | static void beiscsi_free_nemb_cmd(struct beiscsi_hba *phba, |
294 | struct be_dma_mem *cmd, int rc) |
295 | { |
296 | /* |
297 | * If FW is busy the DMA buffer is saved with the tag. When the cmd |
298 | * completes this buffer is freed. |
299 | */ |
300 | if (rc == -EBUSY) |
301 | return; |
302 | |
303 | dma_free_coherent(dev: &phba->ctrl.pdev->dev, size: cmd->size, cpu_addr: cmd->va, dma_handle: cmd->dma); |
304 | } |
305 | |
306 | static void __beiscsi_eq_delay_compl(struct beiscsi_hba *phba, unsigned int tag) |
307 | { |
308 | struct be_dma_mem *tag_mem; |
309 | |
310 | /* status is ignored */ |
311 | __beiscsi_mcc_compl_status(phba, tag, NULL, NULL); |
312 | tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state; |
313 | if (tag_mem->size) { |
314 | dma_free_coherent(dev: &phba->pcidev->dev, size: tag_mem->size, |
315 | cpu_addr: tag_mem->va, dma_handle: tag_mem->dma); |
316 | tag_mem->size = 0; |
317 | } |
318 | } |
319 | |
320 | int beiscsi_modify_eq_delay(struct beiscsi_hba *phba, |
321 | struct be_set_eqd *set_eqd, int num) |
322 | { |
323 | struct be_cmd_req_modify_eq_delay *req; |
324 | struct be_dma_mem nonemb_cmd; |
325 | int i, rc; |
326 | |
327 | rc = beiscsi_prep_nemb_cmd(phba, cmd: &nonemb_cmd, CMD_SUBSYSTEM_COMMON, |
328 | OPCODE_COMMON_MODIFY_EQ_DELAY, size: sizeof(*req)); |
329 | if (rc) |
330 | return rc; |
331 | |
332 | req = nonemb_cmd.va; |
333 | req->num_eq = cpu_to_le32(num); |
334 | for (i = 0; i < num; i++) { |
335 | req->delay[i].eq_id = cpu_to_le32(set_eqd[i].eq_id); |
336 | req->delay[i].phase = 0; |
337 | req->delay[i].delay_multiplier = |
338 | cpu_to_le32(set_eqd[i].delay_multiplier); |
339 | } |
340 | |
341 | rc = beiscsi_exec_nemb_cmd(phba, nonemb_cmd: &nonemb_cmd, cbfn: __beiscsi_eq_delay_compl, |
342 | NULL, resp_buf_len: 0); |
343 | if (rc) { |
344 | /* |
345 | * Only free on failure. Async cmds are handled like -EBUSY |
346 | * where it's handled for us. |
347 | */ |
348 | beiscsi_free_nemb_cmd(phba, cmd: &nonemb_cmd, rc); |
349 | } |
350 | return rc; |
351 | } |
352 | |
353 | /** |
354 | * beiscsi_get_initiator_name - read initiator name from flash |
355 | * @phba: device priv structure |
356 | * @name: buffer pointer |
357 | * @cfg: fetch user configured |
358 | * |
359 | */ |
360 | int beiscsi_get_initiator_name(struct beiscsi_hba *phba, char *name, bool cfg) |
361 | { |
362 | struct be_dma_mem nonemb_cmd; |
363 | struct be_cmd_hba_name resp; |
364 | struct be_cmd_hba_name *req; |
365 | int rc; |
366 | |
367 | rc = beiscsi_prep_nemb_cmd(phba, cmd: &nonemb_cmd, CMD_SUBSYSTEM_ISCSI_INI, |
368 | OPCODE_ISCSI_INI_CFG_GET_HBA_NAME, size: sizeof(resp)); |
369 | if (rc) |
370 | return rc; |
371 | |
372 | req = nonemb_cmd.va; |
373 | if (cfg) |
374 | req->hdr.version = 1; |
375 | rc = beiscsi_exec_nemb_cmd(phba, nonemb_cmd: &nonemb_cmd, NULL, |
376 | resp_buf: &resp, resp_buf_len: sizeof(resp)); |
377 | beiscsi_free_nemb_cmd(phba, cmd: &nonemb_cmd, rc); |
378 | if (rc) { |
379 | beiscsi_log(phba, KERN_ERR, |
380 | BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, |
381 | "BS_%d : Initiator Name MBX Failed\n" ); |
382 | return rc; |
383 | } |
384 | rc = sprintf(buf: name, fmt: "%s\n" , resp.initiator_name); |
385 | return rc; |
386 | } |
387 | |
388 | unsigned int beiscsi_if_get_handle(struct beiscsi_hba *phba) |
389 | { |
390 | struct be_ctrl_info *ctrl = &phba->ctrl; |
391 | struct be_mcc_wrb *wrb; |
392 | struct be_cmd_get_all_if_id_req *req; |
393 | struct be_cmd_get_all_if_id_req *pbe_allid; |
394 | unsigned int tag; |
395 | int status = 0; |
396 | |
397 | if (mutex_lock_interruptible(&ctrl->mbox_lock)) |
398 | return -EINTR; |
399 | wrb = alloc_mcc_wrb(phba, ref_tag: &tag); |
400 | if (!wrb) { |
401 | mutex_unlock(lock: &ctrl->mbox_lock); |
402 | return -ENOMEM; |
403 | } |
404 | |
405 | req = embedded_payload(wrb); |
406 | be_wrb_hdr_prepare(wrb, payload_len: sizeof(*req), embedded: true, sge_cnt: 0); |
407 | be_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ISCSI, |
408 | OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID, |
409 | cmd_len: sizeof(*req)); |
410 | be_mcc_notify(phba, tag); |
411 | mutex_unlock(lock: &ctrl->mbox_lock); |
412 | |
413 | status = beiscsi_mccq_compl_wait(phba, tag, wrb: &wrb, NULL); |
414 | if (status) { |
415 | beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, |
416 | "BG_%d : %s failed: %d\n" , __func__, status); |
417 | return -EBUSY; |
418 | } |
419 | |
420 | pbe_allid = embedded_payload(wrb); |
421 | /* we now support only one interface per function */ |
422 | phba->interface_handle = pbe_allid->if_hndl_list[0]; |
423 | |
424 | return status; |
425 | } |
426 | |
427 | static inline bool beiscsi_if_zero_ip(u8 *ip, u32 ip_type) |
428 | { |
429 | u32 len; |
430 | |
431 | len = (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN; |
432 | while (len && !ip[len - 1]) |
433 | len--; |
434 | return (len == 0); |
435 | } |
436 | |
437 | static int beiscsi_if_mod_gw(struct beiscsi_hba *phba, |
438 | u32 action, u32 ip_type, u8 *gw) |
439 | { |
440 | struct be_cmd_set_def_gateway_req *req; |
441 | struct be_dma_mem nonemb_cmd; |
442 | int rt_val; |
443 | |
444 | rt_val = beiscsi_prep_nemb_cmd(phba, cmd: &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, |
445 | OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY, |
446 | size: sizeof(*req)); |
447 | if (rt_val) |
448 | return rt_val; |
449 | |
450 | req = nonemb_cmd.va; |
451 | req->action = action; |
452 | req->ip_addr.ip_type = ip_type; |
453 | memcpy(req->ip_addr.addr, gw, |
454 | (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN); |
455 | rt_val = beiscsi_exec_nemb_cmd(phba, nonemb_cmd: &nonemb_cmd, NULL, NULL, resp_buf_len: 0); |
456 | beiscsi_free_nemb_cmd(phba, cmd: &nonemb_cmd, rc: rt_val); |
457 | return rt_val; |
458 | } |
459 | |
460 | int beiscsi_if_set_gw(struct beiscsi_hba *phba, u32 ip_type, u8 *gw) |
461 | { |
462 | struct be_cmd_get_def_gateway_resp gw_resp; |
463 | int rt_val; |
464 | |
465 | memset(&gw_resp, 0, sizeof(gw_resp)); |
466 | rt_val = beiscsi_if_get_gw(phba, ip_type, resp: &gw_resp); |
467 | if (rt_val) { |
468 | beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, |
469 | "BG_%d : Failed to Get Gateway Addr\n" ); |
470 | return rt_val; |
471 | } |
472 | |
473 | if (!beiscsi_if_zero_ip(ip: gw_resp.ip_addr.addr, ip_type)) { |
474 | rt_val = beiscsi_if_mod_gw(phba, IP_ACTION_DEL, ip_type, |
475 | gw: gw_resp.ip_addr.addr); |
476 | if (rt_val) { |
477 | beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, |
478 | "BG_%d : Failed to clear Gateway Addr Set\n" ); |
479 | return rt_val; |
480 | } |
481 | } |
482 | |
483 | rt_val = beiscsi_if_mod_gw(phba, IP_ACTION_ADD, ip_type, gw); |
484 | if (rt_val) |
485 | beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, |
486 | "BG_%d : Failed to Set Gateway Addr\n" ); |
487 | |
488 | return rt_val; |
489 | } |
490 | |
491 | int beiscsi_if_get_gw(struct beiscsi_hba *phba, u32 ip_type, |
492 | struct be_cmd_get_def_gateway_resp *resp) |
493 | { |
494 | struct be_cmd_get_def_gateway_req *req; |
495 | struct be_dma_mem nonemb_cmd; |
496 | int rc; |
497 | |
498 | rc = beiscsi_prep_nemb_cmd(phba, cmd: &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, |
499 | OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY, |
500 | size: sizeof(*resp)); |
501 | if (rc) |
502 | return rc; |
503 | |
504 | req = nonemb_cmd.va; |
505 | req->ip_type = ip_type; |
506 | |
507 | rc = beiscsi_exec_nemb_cmd(phba, nonemb_cmd: &nonemb_cmd, NULL, resp_buf: resp, |
508 | resp_buf_len: sizeof(*resp)); |
509 | beiscsi_free_nemb_cmd(phba, cmd: &nonemb_cmd, rc); |
510 | return rc; |
511 | } |
512 | |
513 | static int |
514 | beiscsi_if_clr_ip(struct beiscsi_hba *phba, |
515 | struct be_cmd_get_if_info_resp *if_info) |
516 | { |
517 | struct be_cmd_set_ip_addr_req *req; |
518 | struct be_dma_mem nonemb_cmd; |
519 | int rc; |
520 | |
521 | rc = beiscsi_prep_nemb_cmd(phba, cmd: &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, |
522 | OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR, |
523 | size: sizeof(*req)); |
524 | if (rc) |
525 | return rc; |
526 | |
527 | req = nonemb_cmd.va; |
528 | req->ip_params.record_entry_count = 1; |
529 | req->ip_params.ip_record.action = IP_ACTION_DEL; |
530 | req->ip_params.ip_record.interface_hndl = |
531 | phba->interface_handle; |
532 | req->ip_params.ip_record.ip_addr.size_of_structure = |
533 | sizeof(struct be_ip_addr_subnet_format); |
534 | req->ip_params.ip_record.ip_addr.ip_type = if_info->ip_addr.ip_type; |
535 | memcpy(req->ip_params.ip_record.ip_addr.addr, |
536 | if_info->ip_addr.addr, |
537 | sizeof(if_info->ip_addr.addr)); |
538 | memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, |
539 | if_info->ip_addr.subnet_mask, |
540 | sizeof(if_info->ip_addr.subnet_mask)); |
541 | rc = beiscsi_exec_nemb_cmd(phba, nonemb_cmd: &nonemb_cmd, NULL, NULL, resp_buf_len: 0); |
542 | if (rc < 0 || req->ip_params.ip_record.status) { |
543 | beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, |
544 | "BG_%d : failed to clear IP: rc %d status %d\n" , |
545 | rc, req->ip_params.ip_record.status); |
546 | } |
547 | beiscsi_free_nemb_cmd(phba, cmd: &nonemb_cmd, rc); |
548 | return rc; |
549 | } |
550 | |
551 | static int |
552 | beiscsi_if_set_ip(struct beiscsi_hba *phba, u8 *ip, |
553 | u8 *subnet, u32 ip_type) |
554 | { |
555 | struct be_cmd_set_ip_addr_req *req; |
556 | struct be_dma_mem nonemb_cmd; |
557 | uint32_t ip_len; |
558 | int rc; |
559 | |
560 | rc = beiscsi_prep_nemb_cmd(phba, cmd: &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, |
561 | OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR, |
562 | size: sizeof(*req)); |
563 | if (rc) |
564 | return rc; |
565 | |
566 | req = nonemb_cmd.va; |
567 | req->ip_params.record_entry_count = 1; |
568 | req->ip_params.ip_record.action = IP_ACTION_ADD; |
569 | req->ip_params.ip_record.interface_hndl = |
570 | phba->interface_handle; |
571 | req->ip_params.ip_record.ip_addr.size_of_structure = |
572 | sizeof(struct be_ip_addr_subnet_format); |
573 | req->ip_params.ip_record.ip_addr.ip_type = ip_type; |
574 | ip_len = (ip_type < BEISCSI_IP_TYPE_V6) ? IP_V4_LEN : IP_V6_LEN; |
575 | memcpy(req->ip_params.ip_record.ip_addr.addr, ip, ip_len); |
576 | if (subnet) |
577 | memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, |
578 | subnet, ip_len); |
579 | |
580 | rc = beiscsi_exec_nemb_cmd(phba, nonemb_cmd: &nonemb_cmd, NULL, NULL, resp_buf_len: 0); |
581 | /** |
582 | * In some cases, host needs to look into individual record status |
583 | * even though FW reported success for that IOCTL. |
584 | */ |
585 | if (rc < 0 || req->ip_params.ip_record.status) { |
586 | __beiscsi_log(phba, KERN_ERR, |
587 | "BG_%d : failed to set IP: rc %d status %d\n" , |
588 | rc, req->ip_params.ip_record.status); |
589 | if (req->ip_params.ip_record.status) |
590 | rc = -EINVAL; |
591 | } |
592 | beiscsi_free_nemb_cmd(phba, cmd: &nonemb_cmd, rc); |
593 | return rc; |
594 | } |
595 | |
596 | int beiscsi_if_en_static(struct beiscsi_hba *phba, u32 ip_type, |
597 | u8 *ip, u8 *subnet) |
598 | { |
599 | struct be_cmd_get_if_info_resp *if_info; |
600 | struct be_cmd_rel_dhcp_req *reldhcp; |
601 | struct be_dma_mem nonemb_cmd; |
602 | int rc; |
603 | |
604 | rc = beiscsi_if_get_info(phba, ip_type, if_info: &if_info); |
605 | if (rc) |
606 | return rc; |
607 | |
608 | if (if_info->dhcp_state) { |
609 | rc = beiscsi_prep_nemb_cmd(phba, cmd: &nonemb_cmd, |
610 | CMD_SUBSYSTEM_ISCSI, |
611 | OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR, |
612 | size: sizeof(*reldhcp)); |
613 | if (rc) |
614 | goto exit; |
615 | |
616 | reldhcp = nonemb_cmd.va; |
617 | reldhcp->interface_hndl = phba->interface_handle; |
618 | reldhcp->ip_type = ip_type; |
619 | rc = beiscsi_exec_nemb_cmd(phba, nonemb_cmd: &nonemb_cmd, NULL, NULL, resp_buf_len: 0); |
620 | beiscsi_free_nemb_cmd(phba, cmd: &nonemb_cmd, rc); |
621 | if (rc < 0) { |
622 | beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, |
623 | "BG_%d : failed to release existing DHCP: %d\n" , |
624 | rc); |
625 | goto exit; |
626 | } |
627 | } |
628 | |
629 | /* first delete any IP set */ |
630 | if (!beiscsi_if_zero_ip(ip: if_info->ip_addr.addr, ip_type)) { |
631 | rc = beiscsi_if_clr_ip(phba, if_info); |
632 | if (rc) |
633 | goto exit; |
634 | } |
635 | |
636 | /* if ip == NULL then this is called just to release DHCP IP */ |
637 | if (ip) |
638 | rc = beiscsi_if_set_ip(phba, ip, subnet, ip_type); |
639 | exit: |
640 | kfree(objp: if_info); |
641 | return rc; |
642 | } |
643 | |
644 | int beiscsi_if_en_dhcp(struct beiscsi_hba *phba, u32 ip_type) |
645 | { |
646 | struct be_cmd_get_def_gateway_resp gw_resp; |
647 | struct be_cmd_get_if_info_resp *if_info; |
648 | struct be_cmd_set_dhcp_req *dhcpreq; |
649 | struct be_dma_mem nonemb_cmd; |
650 | u8 *gw; |
651 | int rc; |
652 | |
653 | rc = beiscsi_if_get_info(phba, ip_type, if_info: &if_info); |
654 | if (rc) |
655 | return rc; |
656 | |
657 | if (if_info->dhcp_state) { |
658 | beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, |
659 | "BG_%d : DHCP Already Enabled\n" ); |
660 | goto exit; |
661 | } |
662 | |
663 | /* first delete any IP set */ |
664 | if (!beiscsi_if_zero_ip(ip: if_info->ip_addr.addr, ip_type)) { |
665 | rc = beiscsi_if_clr_ip(phba, if_info); |
666 | if (rc) |
667 | goto exit; |
668 | } |
669 | |
670 | /* delete gateway settings if mode change is to DHCP */ |
671 | memset(&gw_resp, 0, sizeof(gw_resp)); |
672 | /* use ip_type provided in if_info */ |
673 | rc = beiscsi_if_get_gw(phba, ip_type: if_info->ip_addr.ip_type, resp: &gw_resp); |
674 | if (rc) { |
675 | beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, |
676 | "BG_%d : Failed to Get Gateway Addr\n" ); |
677 | goto exit; |
678 | } |
679 | gw = (u8 *)&gw_resp.ip_addr.addr; |
680 | if (!beiscsi_if_zero_ip(ip: gw, ip_type: if_info->ip_addr.ip_type)) { |
681 | rc = beiscsi_if_mod_gw(phba, IP_ACTION_DEL, |
682 | ip_type: if_info->ip_addr.ip_type, gw); |
683 | if (rc) { |
684 | beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG, |
685 | "BG_%d : Failed to clear Gateway Addr Set\n" ); |
686 | goto exit; |
687 | } |
688 | } |
689 | |
690 | rc = beiscsi_prep_nemb_cmd(phba, cmd: &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, |
691 | OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR, |
692 | size: sizeof(*dhcpreq)); |
693 | if (rc) |
694 | goto exit; |
695 | |
696 | dhcpreq = nonemb_cmd.va; |
697 | dhcpreq->flags = 1; /* 1 - blocking; 0 - non-blocking */ |
698 | dhcpreq->retry_count = 1; |
699 | dhcpreq->interface_hndl = phba->interface_handle; |
700 | dhcpreq->ip_type = ip_type; |
701 | rc = beiscsi_exec_nemb_cmd(phba, nonemb_cmd: &nonemb_cmd, NULL, NULL, resp_buf_len: 0); |
702 | beiscsi_free_nemb_cmd(phba, cmd: &nonemb_cmd, rc); |
703 | exit: |
704 | kfree(objp: if_info); |
705 | return rc; |
706 | } |
707 | |
708 | /** |
709 | * beiscsi_if_set_vlan()- Issue and wait for CMD completion |
710 | * @phba: device private structure instance |
711 | * @vlan_tag: VLAN tag |
712 | * |
713 | * Issue the MBX Cmd and wait for the completion of the |
714 | * command. |
715 | * |
716 | * returns |
717 | * Success: 0 |
718 | * Failure: Non-Xero Value |
719 | **/ |
720 | int beiscsi_if_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag) |
721 | { |
722 | int rc; |
723 | unsigned int tag; |
724 | |
725 | tag = be_cmd_set_vlan(phba, vlan_tag); |
726 | if (!tag) { |
727 | beiscsi_log(phba, KERN_ERR, |
728 | (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX), |
729 | "BG_%d : VLAN Setting Failed\n" ); |
730 | return -EBUSY; |
731 | } |
732 | |
733 | rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL); |
734 | if (rc) { |
735 | beiscsi_log(phba, KERN_ERR, |
736 | (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX), |
737 | "BS_%d : VLAN MBX Cmd Failed\n" ); |
738 | return rc; |
739 | } |
740 | return rc; |
741 | } |
742 | |
743 | |
744 | int beiscsi_if_get_info(struct beiscsi_hba *phba, int ip_type, |
745 | struct be_cmd_get_if_info_resp **if_info) |
746 | { |
747 | struct be_cmd_get_if_info_req *req; |
748 | struct be_dma_mem nonemb_cmd; |
749 | uint32_t ioctl_size = sizeof(struct be_cmd_get_if_info_resp); |
750 | int rc; |
751 | |
752 | rc = beiscsi_if_get_handle(phba); |
753 | if (rc) |
754 | return rc; |
755 | |
756 | do { |
757 | rc = beiscsi_prep_nemb_cmd(phba, cmd: &nonemb_cmd, |
758 | CMD_SUBSYSTEM_ISCSI, |
759 | OPCODE_COMMON_ISCSI_NTWK_GET_IF_INFO, |
760 | size: ioctl_size); |
761 | if (rc) |
762 | return rc; |
763 | |
764 | req = nonemb_cmd.va; |
765 | req->interface_hndl = phba->interface_handle; |
766 | req->ip_type = ip_type; |
767 | |
768 | /* Allocate memory for if_info */ |
769 | *if_info = kzalloc(size: ioctl_size, GFP_KERNEL); |
770 | if (!*if_info) { |
771 | beiscsi_log(phba, KERN_ERR, |
772 | BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, |
773 | "BG_%d : Memory Allocation Failure\n" ); |
774 | |
775 | beiscsi_free_nemb_cmd(phba, cmd: &nonemb_cmd, |
776 | rc: -ENOMEM); |
777 | return -ENOMEM; |
778 | } |
779 | |
780 | rc = beiscsi_exec_nemb_cmd(phba, nonemb_cmd: &nonemb_cmd, NULL, resp_buf: *if_info, |
781 | resp_buf_len: ioctl_size); |
782 | |
783 | /* Check if the error is because of Insufficent_Buffer */ |
784 | if (rc == -EAGAIN) { |
785 | |
786 | /* Get the new memory size */ |
787 | ioctl_size = ((struct be_cmd_resp_hdr *) |
788 | nonemb_cmd.va)->actual_resp_len; |
789 | ioctl_size += sizeof(struct be_cmd_req_hdr); |
790 | |
791 | beiscsi_free_nemb_cmd(phba, cmd: &nonemb_cmd, rc); |
792 | /* Free the virtual memory */ |
793 | kfree(objp: *if_info); |
794 | } else { |
795 | beiscsi_free_nemb_cmd(phba, cmd: &nonemb_cmd, rc); |
796 | break; |
797 | } |
798 | } while (true); |
799 | return rc; |
800 | } |
801 | |
802 | int mgmt_get_nic_conf(struct beiscsi_hba *phba, |
803 | struct be_cmd_get_nic_conf_resp *nic) |
804 | { |
805 | struct be_dma_mem nonemb_cmd; |
806 | int rc; |
807 | |
808 | rc = beiscsi_prep_nemb_cmd(phba, cmd: &nonemb_cmd, CMD_SUBSYSTEM_ISCSI, |
809 | OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, |
810 | size: sizeof(*nic)); |
811 | if (rc) |
812 | return rc; |
813 | |
814 | rc = beiscsi_exec_nemb_cmd(phba, nonemb_cmd: &nonemb_cmd, NULL, resp_buf: nic, resp_buf_len: sizeof(*nic)); |
815 | beiscsi_free_nemb_cmd(phba, cmd: &nonemb_cmd, rc); |
816 | return rc; |
817 | } |
818 | |
819 | static void beiscsi_boot_process_compl(struct beiscsi_hba *phba, |
820 | unsigned int tag) |
821 | { |
822 | struct be_cmd_get_boot_target_resp *boot_resp; |
823 | struct be_cmd_resp_logout_fw_sess *logo_resp; |
824 | struct be_cmd_get_session_resp *sess_resp; |
825 | struct be_mcc_wrb *wrb; |
826 | struct boot_struct *bs; |
827 | int boot_work, status; |
828 | |
829 | if (!test_bit(BEISCSI_HBA_BOOT_WORK, &phba->state)) { |
830 | __beiscsi_log(phba, KERN_ERR, |
831 | "BG_%d : %s no boot work %lx\n" , |
832 | __func__, phba->state); |
833 | return; |
834 | } |
835 | |
836 | if (phba->boot_struct.tag != tag) { |
837 | __beiscsi_log(phba, KERN_ERR, |
838 | "BG_%d : %s tag mismatch %d:%d\n" , |
839 | __func__, tag, phba->boot_struct.tag); |
840 | return; |
841 | } |
842 | bs = &phba->boot_struct; |
843 | boot_work = 1; |
844 | status = 0; |
845 | switch (bs->action) { |
846 | case BEISCSI_BOOT_REOPEN_SESS: |
847 | status = __beiscsi_mcc_compl_status(phba, tag, NULL, NULL); |
848 | if (!status) |
849 | bs->action = BEISCSI_BOOT_GET_SHANDLE; |
850 | else |
851 | bs->retry--; |
852 | break; |
853 | case BEISCSI_BOOT_GET_SHANDLE: |
854 | status = __beiscsi_mcc_compl_status(phba, tag, wrb: &wrb, NULL); |
855 | if (!status) { |
856 | boot_resp = embedded_payload(wrb); |
857 | bs->s_handle = boot_resp->boot_session_handle; |
858 | } |
859 | if (bs->s_handle == BE_BOOT_INVALID_SHANDLE) { |
860 | bs->action = BEISCSI_BOOT_REOPEN_SESS; |
861 | bs->retry--; |
862 | } else { |
863 | bs->action = BEISCSI_BOOT_GET_SINFO; |
864 | } |
865 | break; |
866 | case BEISCSI_BOOT_GET_SINFO: |
867 | status = __beiscsi_mcc_compl_status(phba, tag, NULL, |
868 | mbx_cmd_mem: &bs->nonemb_cmd); |
869 | if (!status) { |
870 | sess_resp = bs->nonemb_cmd.va; |
871 | memcpy(&bs->boot_sess, &sess_resp->session_info, |
872 | sizeof(struct mgmt_session_info)); |
873 | bs->action = BEISCSI_BOOT_LOGOUT_SESS; |
874 | } else { |
875 | __beiscsi_log(phba, KERN_ERR, |
876 | "BG_%d : get boot session info error : 0x%x\n" , |
877 | status); |
878 | boot_work = 0; |
879 | } |
880 | dma_free_coherent(dev: &phba->ctrl.pdev->dev, size: bs->nonemb_cmd.size, |
881 | cpu_addr: bs->nonemb_cmd.va, dma_handle: bs->nonemb_cmd.dma); |
882 | bs->nonemb_cmd.va = NULL; |
883 | break; |
884 | case BEISCSI_BOOT_LOGOUT_SESS: |
885 | status = __beiscsi_mcc_compl_status(phba, tag, wrb: &wrb, NULL); |
886 | if (!status) { |
887 | logo_resp = embedded_payload(wrb); |
888 | if (logo_resp->session_status != BE_SESS_STATUS_CLOSE) { |
889 | __beiscsi_log(phba, KERN_ERR, |
890 | "BG_%d : FW boot session logout error : 0x%x\n" , |
891 | logo_resp->session_status); |
892 | } |
893 | } |
894 | /* continue to create boot_kset even if logout failed? */ |
895 | bs->action = BEISCSI_BOOT_CREATE_KSET; |
896 | break; |
897 | default: |
898 | break; |
899 | } |
900 | |
901 | /* clear the tag so no other completion matches this tag */ |
902 | bs->tag = 0; |
903 | if (!bs->retry) { |
904 | boot_work = 0; |
905 | __beiscsi_log(phba, KERN_ERR, |
906 | "BG_%d : failed to setup boot target: status %d action %d\n" , |
907 | status, bs->action); |
908 | } |
909 | if (!boot_work) { |
910 | /* wait for next event to start boot_work */ |
911 | clear_bit(BEISCSI_HBA_BOOT_WORK, addr: &phba->state); |
912 | return; |
913 | } |
914 | schedule_work(work: &phba->boot_work); |
915 | } |
916 | |
917 | /** |
918 | * beiscsi_boot_logout_sess()- Logout from boot FW session |
919 | * @phba: Device priv structure instance |
920 | * |
921 | * return |
922 | * the TAG used for MBOX Command |
923 | * |
924 | */ |
925 | unsigned int beiscsi_boot_logout_sess(struct beiscsi_hba *phba) |
926 | { |
927 | struct be_ctrl_info *ctrl = &phba->ctrl; |
928 | struct be_mcc_wrb *wrb; |
929 | struct be_cmd_req_logout_fw_sess *req; |
930 | unsigned int tag; |
931 | |
932 | mutex_lock(&ctrl->mbox_lock); |
933 | wrb = alloc_mcc_wrb(phba, ref_tag: &tag); |
934 | if (!wrb) { |
935 | mutex_unlock(lock: &ctrl->mbox_lock); |
936 | return 0; |
937 | } |
938 | |
939 | req = embedded_payload(wrb); |
940 | be_wrb_hdr_prepare(wrb, payload_len: sizeof(*req), embedded: true, sge_cnt: 0); |
941 | be_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ISCSI_INI, |
942 | OPCODE_ISCSI_INI_SESSION_LOGOUT_TARGET, |
943 | cmd_len: sizeof(struct be_cmd_req_logout_fw_sess)); |
944 | /* Use the session handle copied into boot_sess */ |
945 | req->session_handle = phba->boot_struct.boot_sess.session_handle; |
946 | |
947 | phba->boot_struct.tag = tag; |
948 | set_bit(MCC_TAG_STATE_ASYNC, addr: &ctrl->ptag_state[tag].tag_state); |
949 | ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl; |
950 | |
951 | be_mcc_notify(phba, tag); |
952 | mutex_unlock(lock: &ctrl->mbox_lock); |
953 | |
954 | return tag; |
955 | } |
956 | /** |
957 | * beiscsi_boot_reopen_sess()- Reopen boot session |
958 | * @phba: Device priv structure instance |
959 | * |
960 | * return |
961 | * the TAG used for MBOX Command |
962 | * |
963 | **/ |
964 | unsigned int beiscsi_boot_reopen_sess(struct beiscsi_hba *phba) |
965 | { |
966 | struct be_ctrl_info *ctrl = &phba->ctrl; |
967 | struct be_mcc_wrb *wrb; |
968 | struct be_cmd_reopen_session_req *req; |
969 | unsigned int tag; |
970 | |
971 | mutex_lock(&ctrl->mbox_lock); |
972 | wrb = alloc_mcc_wrb(phba, ref_tag: &tag); |
973 | if (!wrb) { |
974 | mutex_unlock(lock: &ctrl->mbox_lock); |
975 | return 0; |
976 | } |
977 | |
978 | req = embedded_payload(wrb); |
979 | be_wrb_hdr_prepare(wrb, payload_len: sizeof(*req), embedded: true, sge_cnt: 0); |
980 | be_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ISCSI_INI, |
981 | OPCODE_ISCSI_INI_DRIVER_REOPEN_ALL_SESSIONS, |
982 | cmd_len: sizeof(struct be_cmd_reopen_session_resp)); |
983 | req->reopen_type = BE_REOPEN_BOOT_SESSIONS; |
984 | req->session_handle = BE_BOOT_INVALID_SHANDLE; |
985 | |
986 | phba->boot_struct.tag = tag; |
987 | set_bit(MCC_TAG_STATE_ASYNC, addr: &ctrl->ptag_state[tag].tag_state); |
988 | ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl; |
989 | |
990 | be_mcc_notify(phba, tag); |
991 | mutex_unlock(lock: &ctrl->mbox_lock); |
992 | return tag; |
993 | } |
994 | |
995 | |
996 | /** |
997 | * beiscsi_boot_get_sinfo()- Get boot session info |
998 | * @phba: device priv structure instance |
999 | * |
1000 | * Fetches the boot_struct.s_handle info from FW. |
1001 | * return |
1002 | * the TAG used for MBOX Command |
1003 | * |
1004 | **/ |
1005 | unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba) |
1006 | { |
1007 | struct be_ctrl_info *ctrl = &phba->ctrl; |
1008 | struct be_cmd_get_session_req *req; |
1009 | struct be_dma_mem *nonemb_cmd; |
1010 | struct be_mcc_wrb *wrb; |
1011 | struct be_sge *sge; |
1012 | unsigned int tag; |
1013 | |
1014 | mutex_lock(&ctrl->mbox_lock); |
1015 | wrb = alloc_mcc_wrb(phba, ref_tag: &tag); |
1016 | if (!wrb) { |
1017 | mutex_unlock(lock: &ctrl->mbox_lock); |
1018 | return 0; |
1019 | } |
1020 | |
1021 | nonemb_cmd = &phba->boot_struct.nonemb_cmd; |
1022 | nonemb_cmd->size = sizeof(struct be_cmd_get_session_resp); |
1023 | nonemb_cmd->va = dma_alloc_coherent(dev: &phba->ctrl.pdev->dev, |
1024 | size: nonemb_cmd->size, |
1025 | dma_handle: &nonemb_cmd->dma, |
1026 | GFP_KERNEL); |
1027 | if (!nonemb_cmd->va) { |
1028 | mutex_unlock(lock: &ctrl->mbox_lock); |
1029 | return 0; |
1030 | } |
1031 | |
1032 | req = nonemb_cmd->va; |
1033 | memset(req, 0, sizeof(*req)); |
1034 | sge = nonembedded_sgl(wrb); |
1035 | be_wrb_hdr_prepare(wrb, payload_len: sizeof(*req), embedded: false, sge_cnt: 1); |
1036 | be_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ISCSI_INI, |
1037 | OPCODE_ISCSI_INI_SESSION_GET_A_SESSION, |
1038 | cmd_len: sizeof(struct be_cmd_get_session_resp)); |
1039 | req->session_handle = phba->boot_struct.s_handle; |
1040 | sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); |
1041 | sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); |
1042 | sge->len = cpu_to_le32(nonemb_cmd->size); |
1043 | |
1044 | phba->boot_struct.tag = tag; |
1045 | set_bit(MCC_TAG_STATE_ASYNC, addr: &ctrl->ptag_state[tag].tag_state); |
1046 | ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl; |
1047 | |
1048 | be_mcc_notify(phba, tag); |
1049 | mutex_unlock(lock: &ctrl->mbox_lock); |
1050 | return tag; |
1051 | } |
1052 | |
1053 | unsigned int __beiscsi_boot_get_shandle(struct beiscsi_hba *phba, int async) |
1054 | { |
1055 | struct be_ctrl_info *ctrl = &phba->ctrl; |
1056 | struct be_mcc_wrb *wrb; |
1057 | struct be_cmd_get_boot_target_req *req; |
1058 | unsigned int tag; |
1059 | |
1060 | mutex_lock(&ctrl->mbox_lock); |
1061 | wrb = alloc_mcc_wrb(phba, ref_tag: &tag); |
1062 | if (!wrb) { |
1063 | mutex_unlock(lock: &ctrl->mbox_lock); |
1064 | return 0; |
1065 | } |
1066 | |
1067 | req = embedded_payload(wrb); |
1068 | be_wrb_hdr_prepare(wrb, payload_len: sizeof(*req), embedded: true, sge_cnt: 0); |
1069 | be_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ISCSI_INI, |
1070 | OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET, |
1071 | cmd_len: sizeof(struct be_cmd_get_boot_target_resp)); |
1072 | |
1073 | if (async) { |
1074 | phba->boot_struct.tag = tag; |
1075 | set_bit(MCC_TAG_STATE_ASYNC, addr: &ctrl->ptag_state[tag].tag_state); |
1076 | ctrl->ptag_state[tag].cbfn = beiscsi_boot_process_compl; |
1077 | } |
1078 | |
1079 | be_mcc_notify(phba, tag); |
1080 | mutex_unlock(lock: &ctrl->mbox_lock); |
1081 | return tag; |
1082 | } |
1083 | |
1084 | /** |
1085 | * beiscsi_boot_get_shandle()- Get boot session handle |
1086 | * @phba: device priv structure instance |
1087 | * @s_handle: session handle returned for boot session. |
1088 | * |
1089 | * return |
1090 | * Success: 1 |
1091 | * Failure: negative |
1092 | * |
1093 | **/ |
1094 | int beiscsi_boot_get_shandle(struct beiscsi_hba *phba, unsigned int *s_handle) |
1095 | { |
1096 | struct be_cmd_get_boot_target_resp *boot_resp; |
1097 | struct be_mcc_wrb *wrb; |
1098 | unsigned int tag; |
1099 | int rc; |
1100 | |
1101 | *s_handle = BE_BOOT_INVALID_SHANDLE; |
1102 | /* get configured boot session count and handle */ |
1103 | tag = __beiscsi_boot_get_shandle(phba, async: 0); |
1104 | if (!tag) { |
1105 | beiscsi_log(phba, KERN_ERR, |
1106 | BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT, |
1107 | "BG_%d : Getting Boot Target Info Failed\n" ); |
1108 | return -EAGAIN; |
1109 | } |
1110 | |
1111 | rc = beiscsi_mccq_compl_wait(phba, tag, wrb: &wrb, NULL); |
1112 | if (rc) { |
1113 | beiscsi_log(phba, KERN_ERR, |
1114 | BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG, |
1115 | "BG_%d : MBX CMD get_boot_target Failed\n" ); |
1116 | return -EBUSY; |
1117 | } |
1118 | |
1119 | boot_resp = embedded_payload(wrb); |
1120 | /* check if there are any boot targets configured */ |
1121 | if (!boot_resp->boot_session_count) { |
1122 | __beiscsi_log(phba, KERN_INFO, |
1123 | "BG_%d : No boot targets configured\n" ); |
1124 | return -ENXIO; |
1125 | } |
1126 | |
1127 | /* only if FW has logged in to the boot target, s_handle is valid */ |
1128 | *s_handle = boot_resp->boot_session_handle; |
1129 | return 1; |
1130 | } |
1131 | |
1132 | /** |
1133 | * beiscsi_drvr_ver_disp()- Display the driver Name and Version |
1134 | * @dev: ptr to device not used. |
1135 | * @attr: device attribute, not used. |
1136 | * @buf: contains formatted text driver name and version |
1137 | * |
1138 | * return |
1139 | * size of the formatted string |
1140 | **/ |
1141 | ssize_t |
1142 | beiscsi_drvr_ver_disp(struct device *dev, struct device_attribute *attr, |
1143 | char *buf) |
1144 | { |
1145 | return snprintf(buf, PAGE_SIZE, BE_NAME "\n" ); |
1146 | } |
1147 | |
1148 | /** |
1149 | * beiscsi_fw_ver_disp()- Display Firmware Version |
1150 | * @dev: ptr to device not used. |
1151 | * @attr: device attribute, not used. |
1152 | * @buf: contains formatted text Firmware version |
1153 | * |
1154 | * return |
1155 | * size of the formatted string |
1156 | **/ |
1157 | ssize_t |
1158 | beiscsi_fw_ver_disp(struct device *dev, struct device_attribute *attr, |
1159 | char *buf) |
1160 | { |
1161 | struct Scsi_Host *shost = class_to_shost(dev); |
1162 | struct beiscsi_hba *phba = iscsi_host_priv(shost); |
1163 | |
1164 | return snprintf(buf, PAGE_SIZE, fmt: "%s\n" , phba->fw_ver_str); |
1165 | } |
1166 | |
1167 | /** |
1168 | * beiscsi_active_session_disp()- Display Sessions Active |
1169 | * @dev: ptr to device not used. |
1170 | * @attr: device attribute, not used. |
1171 | * @buf: contains formatted text Session Count |
1172 | * |
1173 | * return |
1174 | * size of the formatted string |
1175 | **/ |
1176 | ssize_t |
1177 | beiscsi_active_session_disp(struct device *dev, struct device_attribute *attr, |
1178 | char *buf) |
1179 | { |
1180 | struct Scsi_Host *shost = class_to_shost(dev); |
1181 | struct beiscsi_hba *phba = iscsi_host_priv(shost); |
1182 | uint16_t avlbl_cids = 0, ulp_num, len = 0, total_cids = 0; |
1183 | |
1184 | for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { |
1185 | if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) { |
1186 | avlbl_cids = BEISCSI_ULP_AVLBL_CID(phba, ulp_num); |
1187 | total_cids = BEISCSI_GET_CID_COUNT(phba, ulp_num); |
1188 | len += scnprintf(buf: buf+len, PAGE_SIZE - len, |
1189 | fmt: "ULP%d : %d\n" , ulp_num, |
1190 | (total_cids - avlbl_cids)); |
1191 | } else |
1192 | len += scnprintf(buf: buf+len, PAGE_SIZE - len, |
1193 | fmt: "ULP%d : %d\n" , ulp_num, 0); |
1194 | } |
1195 | |
1196 | return len; |
1197 | } |
1198 | |
1199 | /** |
1200 | * beiscsi_free_session_disp()- Display Avaliable Session |
1201 | * @dev: ptr to device not used. |
1202 | * @attr: device attribute, not used. |
1203 | * @buf: contains formatted text Session Count |
1204 | * |
1205 | * return |
1206 | * size of the formatted string |
1207 | **/ |
1208 | ssize_t |
1209 | beiscsi_free_session_disp(struct device *dev, struct device_attribute *attr, |
1210 | char *buf) |
1211 | { |
1212 | struct Scsi_Host *shost = class_to_shost(dev); |
1213 | struct beiscsi_hba *phba = iscsi_host_priv(shost); |
1214 | uint16_t ulp_num, len = 0; |
1215 | |
1216 | for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) { |
1217 | if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported)) |
1218 | len += scnprintf(buf: buf+len, PAGE_SIZE - len, |
1219 | fmt: "ULP%d : %d\n" , ulp_num, |
1220 | BEISCSI_ULP_AVLBL_CID(phba, ulp_num)); |
1221 | else |
1222 | len += scnprintf(buf: buf+len, PAGE_SIZE - len, |
1223 | fmt: "ULP%d : %d\n" , ulp_num, 0); |
1224 | } |
1225 | |
1226 | return len; |
1227 | } |
1228 | |
1229 | /** |
1230 | * beiscsi_adap_family_disp()- Display adapter family. |
1231 | * @dev: ptr to device to get priv structure |
1232 | * @attr: device attribute, not used. |
1233 | * @buf: contains formatted text driver name and version |
1234 | * |
1235 | * return |
1236 | * size of the formatted string |
1237 | **/ |
1238 | ssize_t |
1239 | beiscsi_adap_family_disp(struct device *dev, struct device_attribute *attr, |
1240 | char *buf) |
1241 | { |
1242 | uint16_t dev_id = 0; |
1243 | struct Scsi_Host *shost = class_to_shost(dev); |
1244 | struct beiscsi_hba *phba = iscsi_host_priv(shost); |
1245 | |
1246 | dev_id = phba->pcidev->device; |
1247 | switch (dev_id) { |
1248 | case BE_DEVICE_ID1: |
1249 | case OC_DEVICE_ID1: |
1250 | case OC_DEVICE_ID2: |
1251 | return snprintf(buf, PAGE_SIZE, |
1252 | fmt: "Obsolete/Unsupported BE2 Adapter Family\n" ); |
1253 | case BE_DEVICE_ID2: |
1254 | case OC_DEVICE_ID3: |
1255 | return snprintf(buf, PAGE_SIZE, fmt: "BE3-R Adapter Family\n" ); |
1256 | case OC_SKH_ID1: |
1257 | return snprintf(buf, PAGE_SIZE, fmt: "Skyhawk-R Adapter Family\n" ); |
1258 | default: |
1259 | return snprintf(buf, PAGE_SIZE, |
1260 | fmt: "Unknown Adapter Family: 0x%x\n" , dev_id); |
1261 | } |
1262 | } |
1263 | |
1264 | /** |
1265 | * beiscsi_phys_port_disp()- Display Physical Port Identifier |
1266 | * @dev: ptr to device not used. |
1267 | * @attr: device attribute, not used. |
1268 | * @buf: contains formatted text port identifier |
1269 | * |
1270 | * return |
1271 | * size of the formatted string |
1272 | **/ |
1273 | ssize_t |
1274 | beiscsi_phys_port_disp(struct device *dev, struct device_attribute *attr, |
1275 | char *buf) |
1276 | { |
1277 | struct Scsi_Host *shost = class_to_shost(dev); |
1278 | struct beiscsi_hba *phba = iscsi_host_priv(shost); |
1279 | |
1280 | return snprintf(buf, PAGE_SIZE, fmt: "Port Identifier : %u\n" , |
1281 | phba->fw_config.phys_port); |
1282 | } |
1283 | |
1284 | void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, |
1285 | struct wrb_handle *pwrb_handle, |
1286 | struct be_mem_descriptor *mem_descr, |
1287 | struct hwi_wrb_context *pwrb_context) |
1288 | { |
1289 | struct iscsi_wrb *pwrb = pwrb_handle->pwrb; |
1290 | |
1291 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, |
1292 | max_send_data_segment_length, pwrb, |
1293 | params->dw[offsetof(struct amap_beiscsi_offload_params, |
1294 | max_send_data_segment_length) / 32]); |
1295 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, type, pwrb, |
1296 | BE_TGT_CTX_UPDT_CMD); |
1297 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, |
1298 | first_burst_length, |
1299 | pwrb, |
1300 | params->dw[offsetof(struct amap_beiscsi_offload_params, |
1301 | first_burst_length) / 32]); |
1302 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, erl, pwrb, |
1303 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1304 | erl) / 32] & OFFLD_PARAMS_ERL)); |
1305 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, dde, pwrb, |
1306 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1307 | dde) / 32] & OFFLD_PARAMS_DDE) >> 2); |
1308 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, hde, pwrb, |
1309 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1310 | hde) / 32] & OFFLD_PARAMS_HDE) >> 3); |
1311 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ir2t, pwrb, |
1312 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1313 | ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4); |
1314 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, imd, pwrb, |
1315 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1316 | imd) / 32] & OFFLD_PARAMS_IMD) >> 5); |
1317 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, stat_sn, |
1318 | pwrb, |
1319 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1320 | exp_statsn) / 32] + 1)); |
1321 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, wrb_idx, |
1322 | pwrb, pwrb_handle->wrb_index); |
1323 | |
1324 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, |
1325 | max_burst_length, pwrb, params->dw[offsetof |
1326 | (struct amap_beiscsi_offload_params, |
1327 | max_burst_length) / 32]); |
1328 | |
1329 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb, |
1330 | pwrb, pwrb_handle->wrb_index); |
1331 | if (pwrb_context->plast_wrb) |
1332 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, |
1333 | ptr2nextwrb, |
1334 | pwrb_context->plast_wrb, |
1335 | pwrb_handle->wrb_index); |
1336 | pwrb_context->plast_wrb = pwrb; |
1337 | |
1338 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, |
1339 | session_state, pwrb, 0); |
1340 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, compltonack, |
1341 | pwrb, 1); |
1342 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, notpredblq, |
1343 | pwrb, 0); |
1344 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, mode, pwrb, |
1345 | 0); |
1346 | |
1347 | mem_descr += ISCSI_MEM_GLOBAL_HEADER; |
1348 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, |
1349 | pad_buffer_addr_hi, pwrb, |
1350 | mem_descr->mem_array[0].bus_address.u.a32.address_hi); |
1351 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, |
1352 | pad_buffer_addr_lo, pwrb, |
1353 | mem_descr->mem_array[0].bus_address.u.a32.address_lo); |
1354 | } |
1355 | |
1356 | void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, |
1357 | struct wrb_handle *pwrb_handle, |
1358 | struct hwi_wrb_context *pwrb_context) |
1359 | { |
1360 | struct iscsi_wrb *pwrb = pwrb_handle->pwrb; |
1361 | |
1362 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, |
1363 | max_burst_length, pwrb, params->dw[offsetof |
1364 | (struct amap_beiscsi_offload_params, |
1365 | max_burst_length) / 32]); |
1366 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, |
1367 | type, pwrb, |
1368 | BE_TGT_CTX_UPDT_CMD); |
1369 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, |
1370 | ptr2nextwrb, |
1371 | pwrb, pwrb_handle->wrb_index); |
1372 | if (pwrb_context->plast_wrb) |
1373 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, |
1374 | ptr2nextwrb, |
1375 | pwrb_context->plast_wrb, |
1376 | pwrb_handle->wrb_index); |
1377 | pwrb_context->plast_wrb = pwrb; |
1378 | |
1379 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, wrb_idx, |
1380 | pwrb, pwrb_handle->wrb_index); |
1381 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, |
1382 | max_send_data_segment_length, pwrb, |
1383 | params->dw[offsetof(struct amap_beiscsi_offload_params, |
1384 | max_send_data_segment_length) / 32]); |
1385 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, |
1386 | first_burst_length, pwrb, |
1387 | params->dw[offsetof(struct amap_beiscsi_offload_params, |
1388 | first_burst_length) / 32]); |
1389 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, |
1390 | max_recv_dataseg_len, pwrb, |
1391 | params->dw[offsetof(struct amap_beiscsi_offload_params, |
1392 | max_recv_data_segment_length) / 32]); |
1393 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, |
1394 | max_cxns, pwrb, BEISCSI_MAX_CXNS); |
1395 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, erl, pwrb, |
1396 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1397 | erl) / 32] & OFFLD_PARAMS_ERL)); |
1398 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, dde, pwrb, |
1399 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1400 | dde) / 32] & OFFLD_PARAMS_DDE) >> 2); |
1401 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, hde, pwrb, |
1402 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1403 | hde) / 32] & OFFLD_PARAMS_HDE) >> 3); |
1404 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, |
1405 | ir2t, pwrb, |
1406 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1407 | ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4); |
1408 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, imd, pwrb, |
1409 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1410 | imd) / 32] & OFFLD_PARAMS_IMD) >> 5); |
1411 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, |
1412 | data_seq_inorder, |
1413 | pwrb, |
1414 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1415 | data_seq_inorder) / 32] & |
1416 | OFFLD_PARAMS_DATA_SEQ_INORDER) >> 6); |
1417 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, |
1418 | pdu_seq_inorder, |
1419 | pwrb, |
1420 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1421 | pdu_seq_inorder) / 32] & |
1422 | OFFLD_PARAMS_PDU_SEQ_INORDER) >> 7); |
1423 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, max_r2t, |
1424 | pwrb, |
1425 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1426 | max_r2t) / 32] & |
1427 | OFFLD_PARAMS_MAX_R2T) >> 8); |
1428 | AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, stat_sn, |
1429 | pwrb, |
1430 | (params->dw[offsetof(struct amap_beiscsi_offload_params, |
1431 | exp_statsn) / 32] + 1)); |
1432 | } |
1433 | |
1434 | unsigned int beiscsi_invalidate_cxn(struct beiscsi_hba *phba, |
1435 | struct beiscsi_endpoint *beiscsi_ep) |
1436 | { |
1437 | struct be_invalidate_connection_params_in *req; |
1438 | struct be_ctrl_info *ctrl = &phba->ctrl; |
1439 | struct be_mcc_wrb *wrb; |
1440 | unsigned int tag = 0; |
1441 | |
1442 | mutex_lock(&ctrl->mbox_lock); |
1443 | wrb = alloc_mcc_wrb(phba, ref_tag: &tag); |
1444 | if (!wrb) { |
1445 | mutex_unlock(lock: &ctrl->mbox_lock); |
1446 | return 0; |
1447 | } |
1448 | |
1449 | req = embedded_payload(wrb); |
1450 | be_wrb_hdr_prepare(wrb, payload_len: sizeof(union be_invalidate_connection_params), |
1451 | embedded: true, sge_cnt: 0); |
1452 | be_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ISCSI_INI, |
1453 | OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION, |
1454 | cmd_len: sizeof(*req)); |
1455 | req->session_handle = beiscsi_ep->fw_handle; |
1456 | req->cid = beiscsi_ep->ep_cid; |
1457 | if (beiscsi_ep->conn) |
1458 | req->cleanup_type = BE_CLEANUP_TYPE_INVALIDATE; |
1459 | else |
1460 | req->cleanup_type = BE_CLEANUP_TYPE_ISSUE_TCP_RST; |
1461 | /** |
1462 | * 0 - non-persistent targets |
1463 | * 1 - save session info on flash |
1464 | */ |
1465 | req->save_cfg = 0; |
1466 | be_mcc_notify(phba, tag); |
1467 | mutex_unlock(lock: &ctrl->mbox_lock); |
1468 | return tag; |
1469 | } |
1470 | |
1471 | unsigned int beiscsi_upload_cxn(struct beiscsi_hba *phba, |
1472 | struct beiscsi_endpoint *beiscsi_ep) |
1473 | { |
1474 | struct be_ctrl_info *ctrl = &phba->ctrl; |
1475 | struct be_mcc_wrb *wrb; |
1476 | struct be_tcp_upload_params_in *req; |
1477 | unsigned int tag; |
1478 | |
1479 | mutex_lock(&ctrl->mbox_lock); |
1480 | wrb = alloc_mcc_wrb(phba, ref_tag: &tag); |
1481 | if (!wrb) { |
1482 | mutex_unlock(lock: &ctrl->mbox_lock); |
1483 | return 0; |
1484 | } |
1485 | |
1486 | req = embedded_payload(wrb); |
1487 | be_wrb_hdr_prepare(wrb, payload_len: sizeof(union be_tcp_upload_params), embedded: true, sge_cnt: 0); |
1488 | be_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_COMMON_TCP_UPLOAD, |
1489 | OPCODE_COMMON_TCP_UPLOAD, cmd_len: sizeof(*req)); |
1490 | req->id = beiscsi_ep->ep_cid; |
1491 | if (beiscsi_ep->conn) |
1492 | req->upload_type = BE_UPLOAD_TYPE_GRACEFUL; |
1493 | else |
1494 | req->upload_type = BE_UPLOAD_TYPE_ABORT; |
1495 | be_mcc_notify(phba, tag); |
1496 | mutex_unlock(lock: &ctrl->mbox_lock); |
1497 | return tag; |
1498 | } |
1499 | |
1500 | int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba, |
1501 | struct invldt_cmd_tbl *inv_tbl, |
1502 | unsigned int nents) |
1503 | { |
1504 | struct be_ctrl_info *ctrl = &phba->ctrl; |
1505 | struct invldt_cmds_params_in *req; |
1506 | struct be_dma_mem nonemb_cmd; |
1507 | struct be_mcc_wrb *wrb; |
1508 | unsigned int i, tag; |
1509 | struct be_sge *sge; |
1510 | int rc; |
1511 | |
1512 | if (!nents || nents > BE_INVLDT_CMD_TBL_SZ) |
1513 | return -EINVAL; |
1514 | |
1515 | nonemb_cmd.size = sizeof(union be_invldt_cmds_params); |
1516 | nonemb_cmd.va = dma_alloc_coherent(dev: &phba->ctrl.pdev->dev, |
1517 | size: nonemb_cmd.size, dma_handle: &nonemb_cmd.dma, |
1518 | GFP_KERNEL); |
1519 | if (!nonemb_cmd.va) { |
1520 | beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, |
1521 | "BM_%d : invldt_cmds_params alloc failed\n" ); |
1522 | return -ENOMEM; |
1523 | } |
1524 | |
1525 | mutex_lock(&ctrl->mbox_lock); |
1526 | wrb = alloc_mcc_wrb(phba, ref_tag: &tag); |
1527 | if (!wrb) { |
1528 | mutex_unlock(lock: &ctrl->mbox_lock); |
1529 | dma_free_coherent(dev: &phba->ctrl.pdev->dev, size: nonemb_cmd.size, |
1530 | cpu_addr: nonemb_cmd.va, dma_handle: nonemb_cmd.dma); |
1531 | return -ENOMEM; |
1532 | } |
1533 | |
1534 | req = nonemb_cmd.va; |
1535 | be_wrb_hdr_prepare(wrb, payload_len: nonemb_cmd.size, embedded: false, sge_cnt: 1); |
1536 | be_cmd_hdr_prepare(req_hdr: &req->hdr, CMD_SUBSYSTEM_ISCSI, |
1537 | OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS, |
1538 | cmd_len: sizeof(*req)); |
1539 | req->ref_handle = 0; |
1540 | req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE; |
1541 | for (i = 0; i < nents; i++) { |
1542 | req->table[i].icd = inv_tbl[i].icd; |
1543 | req->table[i].cid = inv_tbl[i].cid; |
1544 | req->icd_count++; |
1545 | } |
1546 | sge = nonembedded_sgl(wrb); |
1547 | sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma)); |
1548 | sge->pa_lo = cpu_to_le32(lower_32_bits(nonemb_cmd.dma)); |
1549 | sge->len = cpu_to_le32(nonemb_cmd.size); |
1550 | |
1551 | be_mcc_notify(phba, tag); |
1552 | mutex_unlock(lock: &ctrl->mbox_lock); |
1553 | |
1554 | rc = beiscsi_mccq_compl_wait(phba, tag, NULL, mbx_cmd_mem: &nonemb_cmd); |
1555 | if (rc != -EBUSY) |
1556 | dma_free_coherent(dev: &phba->ctrl.pdev->dev, size: nonemb_cmd.size, |
1557 | cpu_addr: nonemb_cmd.va, dma_handle: nonemb_cmd.dma); |
1558 | return rc; |
1559 | } |
1560 | |