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